freebsd-dev/lib/libc/gen/getutxent.c
Ed Schouten a627ac61ab Implement <utmpx.h>.
The utmpx interface is the standardized interface of the user accounting
database. The standard only defines a subset of the functions that were
present in System V-like systems.

I'd like to highlight some of the traits my implementation has:

- The standard allows the on-disk format to be different than the
  in-memory representation (struct utmpx). Most operating systems don't
  do this, but we do. This allows us to keep our ABI more stable, while
  giving us the opportunity to modify the on-disk format. It also allows
  us to use a common file format across different architectures (i.e.
  byte ordering).

- Our implementation of pututxline() also updates wtmp and lastlog (now
  called utx.log and utx.lastlogin). This means the databases are more
  likely to be in sync.

- Care must be taken that our implementation discard any fields that are
  not applicable. For example, our DEAD_PROCESS records do not hold a
  TTY name. Just a time stamp, a record identifier and a process
  identifier. It also guarantees that strings (ut_host, ut_line and
  ut_user) are null terminated. ut_id is obviously not null terminated,
  because it's not a string.

- The API and its behaviour should be conformant to POSIX, but there may
  be things that slightly deviate from the standard. This implementation
  uses separate file descriptors when writing to the log files. It also
  doesn't use getutxid() to search for a field to overwrite. It uses an
  allocation strategy similar to getutxid(), but prevents DEAD_PROCESS
  records from accumulating.

Make sure libulog doesn't overwrite the manpages shipped with our C
library. Also keep the symbol list in Symbol.map sorted.

I'll bump __FreeBSD_version later this evening. I first want to convert
everything to <utmpx.h> and get rid of <utmp.h>.
2010-01-13 17:29:55 +00:00

233 lines
4.5 KiB
C

/*-
* Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "namespace.h"
#include <sys/endian.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <utmpx.h>
#include "utxdb.h"
#include "un-namespace.h"
static FILE *uf = NULL;
static int udb;
static struct utmpx utx;
int
setutxdb(int db, const char *file)
{
struct stat sb;
switch (db) {
case UTXDB_ACTIVE:
if (file == NULL)
file = _PATH_UTX_ACTIVE;
break;
case UTXDB_LASTLOGIN:
if (file == NULL)
file = _PATH_UTX_LASTLOGIN;
break;
case UTXDB_LOG:
if (file == NULL)
file = _PATH_UTX_LOG;
break;
default:
errno = EINVAL;
return (-1);
}
if (uf != NULL)
fclose(uf);
uf = fopen(file, "r");
if (uf == NULL)
return (-1);
/* Safety check: never use broken files. */
if (db != UTXDB_LOG && _fstat(fileno(uf), &sb) != -1 &&
sb.st_size % sizeof(struct futx) != 0) {
fclose(uf);
uf = NULL;
errno = EFTYPE;
return (-1);
}
udb = db;
return (0);
}
void
setutxent(void)
{
setutxdb(UTXDB_ACTIVE, NULL);
}
void
endutxent(void)
{
if (uf != NULL) {
fclose(uf);
uf = NULL;
}
}
static struct futx *
getfutxent(void)
{
static struct futx fu;
if (uf == NULL)
setutxent();
if (uf == NULL)
return (NULL);
if (udb == UTXDB_LOG) {
uint16_t len;
if (fread(&len, sizeof len, 1, uf) != 1)
return (NULL);
len = be16toh(len);
if (len > sizeof fu) {
/* Forward compatibility. */
if (fread(&fu, sizeof fu, 1, uf) != 1)
return (NULL);
fseek(uf, len - sizeof fu, SEEK_CUR);
} else {
/* Partial record. */
memset(&fu, 0, sizeof fu);
if (fread(&fu, len, 1, uf) != 1)
return (NULL);
}
} else {
if (fread(&fu, sizeof fu, 1, uf) != 1)
return (NULL);
}
return (&fu);
}
struct utmpx *
getutxent(void)
{
struct futx *fu;
fu = getfutxent();
if (fu == NULL)
return (NULL);
futx_to_utx(fu, &utx);
return (&utx);
}
struct utmpx *
getutxid(const struct utmpx *id)
{
struct futx *fu;
for (;;) {
fu = getfutxent();
if (fu == NULL)
return (NULL);
switch (fu->fu_type) {
case BOOT_TIME:
case OLD_TIME:
case NEW_TIME:
case SHUTDOWN_TIME:
if (fu->fu_type == id->ut_type)
goto found;
case USER_PROCESS:
case INIT_PROCESS:
case LOGIN_PROCESS:
case DEAD_PROCESS:
switch (id->ut_type) {
case USER_PROCESS:
case INIT_PROCESS:
case LOGIN_PROCESS:
case DEAD_PROCESS:
if (memcmp(fu->fu_id, id->ut_id,
MIN(sizeof fu->fu_id, sizeof id->ut_id)) == 0)
goto found;
}
}
}
found:
futx_to_utx(fu, &utx);
return (&utx);
}
struct utmpx *
getutxline(const struct utmpx *line)
{
struct futx *fu;
for (;;) {
fu = getfutxent();
if (fu == NULL)
return (NULL);
switch (fu->fu_type) {
case USER_PROCESS:
case LOGIN_PROCESS:
if (strncmp(fu->fu_line, line->ut_line,
MIN(sizeof fu->fu_line, sizeof line->ut_line)) == 0)
goto found;
}
}
found:
futx_to_utx(fu, &utx);
return (&utx);
}
struct utmpx *
getutxuser(const char *user)
{
struct futx *fu;
for (;;) {
fu = getfutxent();
if (fu == NULL)
return (NULL);
switch (fu->fu_type) {
case USER_PROCESS:
if (strncmp(fu->fu_user, user, sizeof fu->fu_user) == 0)
goto found;
}
}
found:
futx_to_utx(fu, &utx);
return (&utx);
}