diff --git a/include/Makefile b/include/Makefile index 68a7e8da0354..21cdd563abc0 100644 --- a/include/Makefile +++ b/include/Makefile @@ -23,8 +23,8 @@ INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h _ctype.h ctype.h \ stdbool.h stddef.h stdio.h stdlib.h string.h stringlist.h \ strings.h sysexits.h tar.h termios.h tgmath.h \ time.h timeconv.h timers.h ttyent.h \ - ulimit.h unistd.h utime.h utmp.h uuid.h varargs.h vis.h wchar.h \ - wctype.h wordexp.h + ulimit.h unistd.h utime.h utmp.h utmpx.h uuid.h varargs.h vis.h \ + wchar.h wctype.h wordexp.h MHDRS= float.h floatingpoint.h stdarg.h diff --git a/include/utmpx.h b/include/utmpx.h new file mode 100644 index 000000000000..22707e4d3681 --- /dev/null +++ b/include/utmpx.h @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2010 Ed Schouten + * 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. + * + * $FreeBSD$ + */ + +#ifndef _UTMPX_H_ +#define _UTMPX_H_ + +#include +#include +#include + +#ifndef _PID_T_DECLARED +typedef __pid_t pid_t; +#define _PID_T_DECLARED +#endif + +struct utmpx { + short ut_type; /* Type of entry. */ + struct timeval ut_tv; /* Time entry was made. */ + char ut_id[8]; /* Record identifier. */ + pid_t ut_pid; /* Process ID. */ + char ut_user[32]; /* User login name. */ + char ut_line[16]; /* Device name. */ +#if __BSD_VISIBLE + char ut_host[128]; /* Remote hostname. */ +#else + char __ut_host[128]; +#endif + char __ut_spare[64]; +}; + +#define EMPTY 0 /* No valid user accounting information. */ +#define BOOT_TIME 1 /* Time of system boot. */ +#define OLD_TIME 2 /* Time when system clock changed. */ +#define NEW_TIME 3 /* Time after system clock changed. */ +#define USER_PROCESS 4 /* A process. */ +#define INIT_PROCESS 5 /* A process spawned by the init process. */ +#define LOGIN_PROCESS 6 /* The session leader of a logged-in user. */ +#define DEAD_PROCESS 7 /* A session leader who has exited. */ +#if __BSD_VISIBLE +#define SHUTDOWN_TIME 8 /* Time of system shutdown. */ +#endif + +#if __BSD_VISIBLE +#define UTXDB_ACTIVE 0 /* Active login sessions. */ +#define UTXDB_LASTLOGIN 1 /* Last login sessions. */ +#define UTXDB_LOG 2 /* Log indexed by time. */ +#endif + +__BEGIN_DECLS +void endutxent(void); +struct utmpx *getutxent(void); +struct utmpx *getutxid(const struct utmpx *); +struct utmpx *getutxline(const struct utmpx *); +struct utmpx *pututxline(const struct utmpx *); +void setutxent(void); + +#if __BSD_VISIBLE +struct utmpx *getutxuser(const char *); +int setutxdb(int, const char *); +#endif +__END_DECLS + +#endif /* !_UTMPX_H_ */ diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 2abfe57d8efb..2c0cb780c641 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -18,12 +18,12 @@ SRCS+= __getosreldate.c __xuname.c \ gethostname.c getloadavg.c getlogin.c getmntinfo.c getnetgrent.c \ getosreldate.c getpagesize.c getpagesizes.c \ getpeereid.c getprogname.c getpwent.c getttyent.c \ - getusershell.c getvfsbyname.c glob.c \ + getusershell.c getutxent.c getvfsbyname.c glob.c \ initgroups.c isatty.c isinf.c isnan.c jrand48.c lcong48.c \ lockf.c lrand48.c mrand48.c nftw.c nice.c \ nlist.c nrand48.c opendir.c \ pause.c pmadvise.c popen.c posix_spawn.c \ - psignal.c pw_scan.c pwcache.c \ + psignal.c pututxline.c pw_scan.c pwcache.c \ raise.c readdir.c readpassphrase.c rewinddir.c \ scandir.c seed48.c seekdir.c sem.c sem_new.c semctl.c \ setdomainname.c sethostname.c setjmperr.c setmode.c \ @@ -32,7 +32,7 @@ SRCS+= __getosreldate.c __xuname.c \ sysconf.c sysctl.c sysctlbyname.c sysctlnametomib.c \ syslog.c telldir.c termios.c time.c times.c timezone.c tls.c \ ttyname.c ttyslot.c ualarm.c ulimit.c uname.c unvis.c \ - usleep.c utime.c valloc.c vis.c wait.c wait3.c waitpid.c \ + usleep.c utime.c utxdb.c valloc.c vis.c wait.c wait3.c waitpid.c \ wordexp.c SYM_MAPS+=${.CURDIR}/gen/Symbol.map @@ -54,7 +54,7 @@ MAN+= alarm.3 arc4random.3 \ getgrent.3 getgrouplist.3 gethostname.3 getloadavg.3 \ getmntinfo.3 getnetgrent.3 getosreldate.3 getpagesize.3 \ getpagesizes.3 getpass.3 getpeereid.3 getprogname.3 getpwent.3 \ - getttyent.3 getusershell.3 getvfsbyname.3 \ + getttyent.3 getusershell.3 getutxent.3 getvfsbyname.3 \ glob.3 initgroups.3 isgreater.3 ldexp.3 lockf.3 makecontext.3 \ modf.3 \ nice.3 nlist.3 pause.3 popen.3 \ @@ -126,6 +126,10 @@ MLINKS+=getttyent.3 endttyent.3 getttyent.3 getttynam.3 \ getttyent.3 isdialuptty.3 getttyent.3 isnettty.3 \ getttyent.3 setttyent.3 MLINKS+=getusershell.3 endusershell.3 getusershell.3 setusershell.3 +MLINKS+=getutxent.3 endutxent.3 getutxent.3 getutxid.3 \ + getutxent.3 getutxline.3 getutxent.3 getutxuser.3 \ + getutxent.3 pututxline.3 getutxent.3 setutxdb.3 \ + getutxent.3 setutxent.3 MLINKS+=glob.3 globfree.3 MLINKS+=isgreater.3 isgreaterequal.3 isgreater.3 isless.3 \ isgreater.3 islessequal.3 isgreater.3 islessgreater.3 \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index e7d59bb7126b..534c81acffd4 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -359,17 +359,25 @@ FBSD_1.1 { FBSD_1.2 { basename_r; + endutxent; getpagesizes; + getutxent; + getutxid; + getutxline; + getutxuser; + pututxline; sem_close; sem_destroy; sem_getvalue; sem_init; sem_open; + sem_post; sem_timedwait; sem_trywait; - sem_post; - sem_wait; sem_unlink; + sem_wait; + setutxdb; + setutxent; }; FBSDprivate_1.0 { diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 new file mode 100644 index 000000000000..57887b131728 --- /dev/null +++ b/lib/libc/gen/getutxent.3 @@ -0,0 +1,440 @@ +.\" Copyright (c) 2010 Ed Schouten +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.Dd January 8, 2010 +.Os +.Dt GETUTXENT 3 +.Sh NAME +.Nm endutxent , +.Nm getutxent , +.Nm getutxid , +.Nm getutxline , +.Nm getutxuser , +.Nm pututxline , +.Nm setutxdb , +.Nm setutxent +.Nd user accounting database functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In utmpx.h +.Ft void +.Fn endutxent "void" +.Ft struct utmpx * +.Fn getutxent "void" +.Ft struct utmpx * +.Fn getutxid "const struct utmpx *id" +.Ft struct utmpx * +.Fn getutxline "const struct utmpx *line" +.Ft struct utmpx * +.Fn getutxuser "const char *user" +.Ft struct utmpx * +.Fn pututxline "const struct utmpx *utmpx" +.Ft int +.Fn setutxdb "int type" "const char *file" +.Ft void +.Fn setutxent "void" +.Sh DESCRIPTION +These functions operate on the user accounting database which stores +records of various system activities, such as user login and logouts, +but also system startups and shutdowns and modifications to the system's +clock. +The system stores these records in three databases, each having a +different purpose: +.Bl -tag -width indent +.It Pa /var/run/utx.active +Log of currently active user login sessions. +This file is similar to the traditional +.Pa utmp +file. +This file only contains process related entries, such as user login and +logout records. +.It Pa /var/log/utx.lastlogin +Log of last user login entries per user. +This file is similar to the traditional +.Pa lastlog +file. +This file only contains user login records for users who have at least +logged in once. +.It Pa /var/log/utx.log +Log of all entries, sorted by date of addition. +This file is similar to the traditional +.Pa wtmp +file. +This file may contain any type of record described below. +.El +.Pp +Each entry in these databases is defined by the structure +.Vt utmpx +found in the include file +.In utmpx.h : +.Bd -literal -offset indent +struct utmpx { + short ut_type; /* Type of entry. */ + struct timeval ut_tv; /* Time entry was made. */ + char ut_id[]; /* Record identifier. */ + pid_t ut_pid; /* Process ID. */ + char ut_user[]; /* User login name. */ + char ut_line[]; /* Device name. */ + char ut_host[]; /* Remote hostname. */ +}; +.Ed +.Pp +The +.Fa ut_type +field indicates the type of the log entry, which can have one of the +following values: +.Bl -tag -width LOGIN_PROCESS +.It Dv EMPTY +No valid user accounting information. +.It Dv BOOT_TIME +Identifies time of system boot. +.It Dv SHUTDOWN_TIME +Identifies time of system shutdown. +.It Dv OLD_TIME +Identifies time when system clock changed. +.It Dv NEW_TIME +Identifies time after system clock changed. +.It Dv USER_PROCESS +Identifies a process. +.It Dv INIT_PROCESS +Identifies a process spawned by the init process. +.It Dv LOGIN_PROCESS +Identifies the session leader of a logged-in user. +.It Dv DEAD_PROCESS +Identifies a session leader who has exited. +.El +.Pp +Entries of type +.Dv INIT_PROCESS +and +.Dv LOGIN_PROCESS +are not processed by this implementation. +.Pp +Other fields inside the structure are: +.Bl -tag -width ut_user +.It Fa ut_tv +The time the event occured. +This field is used for all types of entries. +.It Fa ut_id +An identifier that is used to refer to the entry. +This identifier can be used to remove or replace a login entry by +writing a new entry to the database containing the same value for +.Fa ut_id . +This field is only applicable to entries of type +.Dv USER_PROCESS , +.Dv INIT_PROCESS , +.Dv LOGIN_PROCESS +and +.Dv DEAD_PROCESS . +.It Fa ut_pid +The process identifier of the session leader of the login session. +This field is only applicable to entries of type +.Dv USER_PROCESS , +.Dv INIT_PROCESS , +.Dv LOGIN_PROCESS +and +.Dv DEAD_PROCESS . +.It Fa ut_user +The user login name corresponding with the login session. +This field is only applicable to entries of type +.Dv USER_PROCESS +and +.Dv INIT_PROCESS . +For +.Dv INIT_PROCESS +entries this entry typically contains the name of the login process. +.It Fa ut_line +The name of the TTY character device, without the leading +.Pa /dev/ +prefix, corresponding with the device used to facilitate the user login +session. +If no TTY character device is used, this field is left blank. +This field is only applicable to entries of type +.Dv USER_PROCESS . +.It Fa ut_host +The network hostname of the remote system, connecting to perform a user +login. +If the user login session is not performed across a network, this field +is left blank. +This field is only applicable to entries of type +.Dv USER_PROCESS . +.El +.Pp +This implementation guarantees all inapplicable fields are discarded. +The +.Fa ut_user , +.Fa ut_line +and +.Fa ut_host +fields of the structure returned by the library functions are also +guaranteed to be null-terminated in this implementation. +.Pp +The +.Fn getutxent +function can be used to read the next entry from the user accounting +database. +.Pp +The +.Fn getutxid +function searches for the next entry in the database of which the +behaviour is based on the +.Fa ut_type +field of +.Fa id . +If +.Fa ut_type +has a value of +.Dv BOOT_TIME , +.Dv SHUTDOWN_TIME , +.Dv OLD_TIME +or +.Dv NEW_TIME , +it will return the next entry whose +.Fa ut_type +has an equal value. +If +.Fa ut_type +has a value of +.Dv USER_PROCESS , +.Dv INIT_PROCESS , +.Dv LOGIN_PROCESS +or +.Dv DEAD_PROCESS , +it will return the next entry whose +.Fa ut_type +has one of the previously mentioned values and whose +.Fa ut_id +is equal. +.Pp +The +.Fn getutxline +function searches for the next entry in the database whose +.Fa ut_type +has a value of +.Dv USER_PROCESS +or +.Dv LOGIN_PROCESS +and whose +.Fa ut_line +is equal to the the same field in +.Fa line . +.Pp +The +.Fn getutxuser +function searches for the next entry in the database whose +.Fa ut_type +has a value of +.Dv USER_PROCESS +and whose +.Fa ut_user +is equal to +.Fa user . +.Pp +The previously mentioned functions will automatically try to open the +user accounting database if not already done so. +The +.Fn setutxdb +and +.Fn setutxent +functions allow the database to be opened manually, causing the offset +within the user accounting database to be rewound. +The +.Fn endutxent +function closes the database. +.Pp +The +.Fn setutxent +database always opens the active sessions database. +The +.Fn setutxdb +function opens the database identified by +.Fa type , +whose value is either +.Dv UTXDB_ACTIVE , +.Dv UTXDB_LASTLOGIN +or +.Dv UTXDB_LOG . +It will open a custom file with filename +.Fa file +instead of the system-default if +.Fa file +is not null. +Care must be taken that when using a custom filename, +.Fa type +still has to match with the actual format, since each database may use +its own file format. +.Pp +The +.Fn pututxline +function writes record +.Fa utmpx +to the system-default user accounting databases. +The value of +.Fa ut_type +determines which databases are modified. +.Pp +Entries of type +.Dv BOOT_TIME , +.Dv SHUTDOWN_TIME , +.Dv OLD_TIME +and +.Dv NEW_TIME +will only be written to +.Pa /var/log/utx.log . +.Pp +Entries of type +.Dv USER_PROCESS +will also be written to +.Pa /var/run/utx.active . +It will only be written to +.Pa /var/log/utx.lastlogin +if +.Fa ut_tv +for that user has a greater value than the existing entry or when no +entry for the user has been found. +.Pp +Entries of type +.Dv DEAD_PROCESS +will only be written to +.Pa /var/log/utx.log +and +.Pa /var/run/utx.active +if a corresponding +.Dv USER_PROCESS , +.Dv INIT_PROCESS +or +.Dv LOGIN_PROCESS +entry whose +.Fa ut_id +is equal has been found in the latter. +.Pp +In addition, entries of type +.Dv BOOT_TIME +and +.Dv SHUTDOWN_TIME +will cause all entries in +.Pa /var/run/utx.active +to be discarded. +.Pp +All entries whose type has not been mentioned previously, are discarded +by this implementation of +.Fn pututxline . +.Sh RETURN VALUES +The +.Fn getutxent , +.Fn getutxid , +.Fn getutxline , +and +.Fn getutxuser +functions return a pointer to an +.Vt utmpx +structure that matches the mentioned constraints on success or +.Dv NULL +when reaching the end-of-file or when an error occurs. +.Pp +The +.Fn pututxline +function returns a pointer to an +.Vt utmpx +structure containing a copy of the structure written to disk upon +success. +It returns +.Dv NULL +when the provided +.Vt utmpx +is invalid. +This may be because +.Fa ut_type +is invalid or +.Fa ut_type +has a value of +.Dv DEAD_PROCESS +and an entry with an identifier with a value equal to the field +.Fa ut_id +was not found. +.Pp +The +.Fn setutxdb +function returns 0 if the user accounting database was opened +successfully. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +In addition to the error conditions described in +.Xr fopen 3 , +the +.Fn setutxdb +function can generate the following errors: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa type +argument contains a value not supported by this implementation. +.It Bq Er EFTYPE +The file format is invalid. +.El +.Sh SEE ALSO +.Xr last 1 , +.Xr write 1 , +.Xr getpid 2 , +.Xr gettimeofday 2 , +.Xr tty 4 , +.Xr ac 8 , +.Xr newsyslog 8 +.Sh STANDARDS +The +.Fn endutxent , +.Fn getutxent , +.Fn getutxid , +.Fn getutxline , +.Fn pututxline +and +.Fn setutxent +functions are expected to conform to +.St -p1003.1-2008 . +.Pp +The +.Fn getutxuser +and +.Fn setutxdb +functions, +the +.Fa ut_host +field of the +.Vt utmpx +structure and +.Dv SHUTDOWN_TIME +are extensions. +.Sh HISTORY +These functions appeared in +.Fx 9.0 . +They replaced the +.In utmp.h +interface. +.Sh AUTHORS +.An Ed Schouten Aq ed@FreeBSD.org diff --git a/lib/libc/gen/getutxent.c b/lib/libc/gen/getutxent.c new file mode 100644 index 000000000000..13efac06c70e --- /dev/null +++ b/lib/libc/gen/getutxent.c @@ -0,0 +1,232 @@ +/*- + * Copyright (c) 2010 Ed Schouten + * 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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#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); +} diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c new file mode 100644 index 000000000000..8c2e91dd43fc --- /dev/null +++ b/lib/libc/gen/pututxline.c @@ -0,0 +1,277 @@ +/*- + * Copyright (c) 2010 Ed Schouten + * 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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "utxdb.h" +#include "un-namespace.h" + +static FILE * +futx_open(const char *file) +{ + int fd; + FILE *fp; + struct stat sb; + + fd = _open(file, O_CREAT|O_RDWR|O_EXLOCK, 0644); + if (fd < 0) + return (NULL); + + /* Safety check: never use broken files. */ + if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) { + _close(fd); + return (NULL); + } + + fp = fdopen(fd, "r+"); + if (fp == NULL) { + _close(fd); + return (NULL); + } + + return (fp); +} + +static void +utx_active_add(const struct futx *fu) +{ + FILE *fp; + struct futx fe; + off_t partial = -1; + + /* + * Register user login sessions. Overwrite entries of sessions + * that have already been terminated. + */ + fp = futx_open(_PATH_UTX_ACTIVE); + if (fp == NULL) + return; + while (fread(&fe, sizeof fe, 1, fp) == 1) { + switch (fe.fu_type) { + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + case DEAD_PROCESS: + /* Overwrite when ut_id matches. */ + if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) == 0) { + fseeko(fp, -sizeof fe, SEEK_CUR); + goto exact; + } + if (fe.fu_type != DEAD_PROCESS) + break; + /* FALLTHROUGH */ + default: + /* Allow us to overwrite unused records. */ + if (partial == -1) + partial = fseeko(fp, 0, SEEK_CUR) - sizeof fe; + break; + } + } + + /* + * No exact match found. Use the partial match. If no partial + * match was found, just append a new record. + */ + if (partial != -1) + fseeko(fp, partial, SEEK_SET); +exact: + fwrite(fu, sizeof *fu, 1, fp); + fclose(fp); +} + +static int +utx_active_remove(struct futx *fu) +{ + FILE *fp; + struct futx fe; + + /* + * Remove user login sessions, having the same ut_id. + */ + fp = futx_open(_PATH_UTX_ACTIVE); + if (fp == NULL) + return (0); + while (fread(&fe, sizeof fe, 1, fp) == 1) { + switch (fe.fu_type) { + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) != 0) + continue; + + /* + * Prevent login sessions from having a negative + * timespan. + */ + if (be64toh(fu->fu_tv) < be64toh(fe.fu_tv)) + fu->fu_tv = fe.fu_tv; + + /* Terminate session. */ + fseeko(fp, -sizeof fe, SEEK_CUR); + fwrite(fu, sizeof *fu, 1, fp); + fclose(fp); + return (0); + } + } + + fclose(fp); + return (1); +} + +static void +utx_active_purge(void) +{ + + truncate(_PATH_UTX_ACTIVE, 0); +} + +static void +utx_lastlogin_add(const struct futx *fu) +{ + FILE *fp; + struct futx fe; + + /* + * Write an entry to lastlogin. Overwrite the entry if the + * current user already has an entry. If not, append a new + * entry. + */ + fp = futx_open(_PATH_UTX_LASTLOGIN); + if (fp == NULL) + return; + while (fread(&fe, sizeof fe, 1, fp) == 1) { + if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0) + continue; + + /* Prevent lowering the time value. */ + if (be64toh(fu->fu_tv) <= be64toh(fe.fu_tv)) + goto done; + + /* Found a previous lastlogin entry for this user. */ + fseeko(fp, -sizeof fe, SEEK_CUR); + break; + } + fwrite(fu, sizeof *fu, 1, fp); +done: + fclose(fp); +} + +static void +utx_lastlogin_upgrade(void) +{ + int fd; + struct stat sb; + + fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR, 0644); + if (fd < 0) + return; + + /* + * Truncate broken lastlogin files. In the future we should + * check for older versions of the file format here and try to + * upgrade it. + */ + if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) + ftruncate(fd, 0); + _close(fd); +} + +static void +utx_log_add(const struct futx *fu) +{ + int fd; + uint16_t l; + struct iovec vec[2]; + + /* + * Append an entry to the log file. We only need to append + * records to this file, so to conserve space, trim any trailing + * zero-bytes. Prepend a length field, indicating the length of + * the record, excluding the length field itself. + */ + for (l = sizeof *fu; l > 0 && ((const char *)fu)[l - 1] == '\0'; l--); + vec[0].iov_base = &l; + vec[0].iov_len = sizeof l; + vec[1].iov_base = __DECONST(void *, fu); + vec[1].iov_len = l; + l = htobe16(l); + + fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND, 0644); + if (fd < 0) + return; + _writev(fd, vec, 2); + _close(fd); +} + +struct utmpx * +pututxline(const struct utmpx *utmpx) +{ + struct futx fu; + static struct utmpx ut; + + utx_to_futx(utmpx, &fu); + + switch (fu.fu_type) { + case BOOT_TIME: + case SHUTDOWN_TIME: + utx_active_purge(); + utx_lastlogin_upgrade(); + break; + case OLD_TIME: + case NEW_TIME: + break; + case USER_PROCESS: + utx_active_add(&fu); + utx_lastlogin_add(&fu); + break; +#if 0 /* XXX: Are these records of any use to us? */ + case INIT_PROCESS: + case LOGIN_PROCESS: + utx_active_add(&fu); + break; +#endif + case DEAD_PROCESS: + if (utx_active_remove(&fu) != 0) + return (NULL); + break; + default: + return (NULL); + } + + utx_log_add(&fu); + futx_to_utx(&fu, &ut); + return (&ut); +} diff --git a/lib/libc/gen/utxdb.c b/lib/libc/gen/utxdb.c new file mode 100644 index 000000000000..d7e2b34029ff --- /dev/null +++ b/lib/libc/gen/utxdb.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 2010 Ed Schouten + * 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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include "utxdb.h" +#include "un-namespace.h" + +#define UTOF_STRING(ut, fu, field) do { \ + strncpy((fu)->fu_ ## field, (ut)->ut_ ## field, \ + MIN(sizeof (fu)->fu_ ## field, sizeof (ut)->ut_ ## field)); \ +} while (0) +#define UTOF_ID(ut, fu) do { \ + memcpy((fu)->fu_id, (ut)->ut_id, \ + MIN(sizeof (fu)->fu_id, sizeof (ut)->ut_id)); \ +} while (0) +#define UTOF_PID(ut, fu) do { \ + (fu)->fu_pid = htobe32((ut)->ut_pid); \ +} while (0) +#define UTOF_TYPE(ut, fu) do { \ + (fu)->fu_type = (ut)->ut_type; \ +} while (0) +#define UTOF_TV(ut, fu) do { \ + (fu)->fu_tv = htobe64((uint64_t)(ut)->ut_tv.tv_sec * 1000000 + \ + (uint64_t)(ut)->ut_tv.tv_usec); \ +} while (0) + +void +utx_to_futx(const struct utmpx *ut, struct futx *fu) +{ + + memset(fu, 0, sizeof *fu); + + switch (ut->ut_type) { + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + /* Extension: shutdown time. */ + case SHUTDOWN_TIME: + break; + case USER_PROCESS: + UTOF_ID(ut, fu); + UTOF_STRING(ut, fu, user); + UTOF_STRING(ut, fu, line); + /* Extension: host name. */ + UTOF_STRING(ut, fu, host); + UTOF_PID(ut, fu); + break; + case INIT_PROCESS: + UTOF_ID(ut, fu); + UTOF_PID(ut, fu); + break; + case LOGIN_PROCESS: + UTOF_ID(ut, fu); + UTOF_STRING(ut, fu, user); + UTOF_PID(ut, fu); + break; + case DEAD_PROCESS: + UTOF_ID(ut, fu); + UTOF_PID(ut, fu); + break; + default: + fu->fu_type = EMPTY; + return; + } + + UTOF_TYPE(ut, fu); + UTOF_TV(ut, fu); +} + +#define FTOU_STRING(fu, ut, field) do { \ + strncpy((ut)->ut_ ## field, (fu)->fu_ ## field, \ + MIN(sizeof (ut)->ut_ ## field - 1, sizeof (fu)->fu_ ## field)); \ +} while (0) +#define FTOU_ID(fu, ut) do { \ + memcpy((ut)->ut_id, (fu)->fu_id, \ + MIN(sizeof (ut)->ut_id, sizeof (fu)->fu_id)); \ +} while (0) +#define FTOU_PID(fu, ut) do { \ + (ut)->ut_pid = be32toh((fu)->fu_pid); \ +} while (0) +#define FTOU_TYPE(fu, ut) do { \ + (ut)->ut_type = (fu)->fu_type; \ +} while (0) +#define FTOU_TV(fu, ut) do { \ + uint64_t t; \ + t = be64toh((fu)->fu_tv); \ + (ut)->ut_tv.tv_sec = t / 1000000; \ + (ut)->ut_tv.tv_usec = t % 1000000; \ +} while (0) + +void +futx_to_utx(const struct futx *fu, struct utmpx *ut) +{ + + memset(ut, 0, sizeof *ut); + + switch (fu->fu_type) { + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + /* Extension: shutdown time. */ + case SHUTDOWN_TIME: + break; + case USER_PROCESS: + FTOU_ID(fu, ut); + FTOU_STRING(fu, ut, user); + FTOU_STRING(fu, ut, line); + /* Extension: host name. */ + FTOU_STRING(fu, ut, host); + FTOU_PID(fu, ut); + break; + case INIT_PROCESS: + FTOU_ID(fu, ut); + FTOU_PID(fu, ut); + break; + case LOGIN_PROCESS: + FTOU_ID(fu, ut); + FTOU_STRING(fu, ut, user); + FTOU_PID(fu, ut); + break; + case DEAD_PROCESS: + FTOU_ID(fu, ut); + FTOU_PID(fu, ut); + break; + default: + ut->ut_type = EMPTY; + return; + } + + FTOU_TYPE(fu, ut); + FTOU_TV(fu, ut); +} diff --git a/lib/libc/gen/utxdb.h b/lib/libc/gen/utxdb.h new file mode 100644 index 000000000000..ec0201365932 --- /dev/null +++ b/lib/libc/gen/utxdb.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2010 Ed Schouten + * 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. + * + * $FreeBSD$ + */ + +#ifndef _UTXDB_H_ +#define _UTXDB_H_ + +#include + +#define _PATH_UTX_ACTIVE "/var/run/utx.active" +#define _PATH_UTX_LASTLOGIN "/var/log/utx.lastlogin" +#define _PATH_UTX_LOG "/var/log/utx.log" + +/* + * Entries in struct futx are ordered by how often they are used. In + * utx.log only entries will be written until the last non-zero byte, + * which means we want to put the hostname at the end. Most primitive + * records only store a ut_type and ut_tv, which means we want to store + * those at the front. + */ + +struct utmpx; + +struct futx { + uint8_t fu_type; + uint64_t fu_tv; + char fu_id[8]; + uint32_t fu_pid; + char fu_user[32]; + char fu_line[16]; + char fu_host[128]; +} __packed; + +void utx_to_futx(const struct utmpx *, struct futx *); +void futx_to_utx(const struct futx *, struct utmpx *); + +#endif /* !_UTXDB_H_ */ diff --git a/lib/libulog/Makefile b/lib/libulog/Makefile index c05e156da3ff..466fc1d7119b 100644 --- a/lib/libulog/Makefile +++ b/lib/libulog/Makefile @@ -26,13 +26,6 @@ MLINKS+=ulog_getutxent.3 ulog_endutxent.3 \ utempter_remove_added_record.3 removeFromUtmp.3 \ utempter_remove_record.3 removeLineFromUtmp.3 -# Add links to -style functions. -MLINKS+=ulog_endutxent.3 endutxent.3 \ - ulog_getutxent.3 getutxent.3 \ - ulog_getutxline.3 getutxline.3 \ - ulog_pututxline.3 pututxline.3 \ - ulog_setutxent.3 setutxent.3 - VERSION_DEF= ${.CURDIR}/../libc/Versions.def SYMBOL_MAPS= ${.CURDIR}/Symbol.map