From 5b57d28ffb6e1ef86b50f7d05d977826eae89bfe Mon Sep 17 00:00:00 2001 From: Kiyoshi Aman Date: Fri, 1 Feb 2019 22:55:37 +0000 Subject: initial population --- usr.bin/who/utmpentry.c | 329 ++++++++++++++++++++++++++++++++++++++++ usr.bin/who/utmpentry.h | 76 ++++++++++ usr.bin/who/who.1 | 197 ++++++++++++++++++++++++ usr.bin/who/who.c | 391 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 993 insertions(+) create mode 100644 usr.bin/who/utmpentry.c create mode 100644 usr.bin/who/utmpentry.h create mode 100644 usr.bin/who/who.1 create mode 100644 usr.bin/who/who.c (limited to 'usr.bin/who') diff --git a/usr.bin/who/utmpentry.c b/usr.bin/who/utmpentry.c new file mode 100644 index 0000000..c74397b --- /dev/null +++ b/usr.bin/who/utmpentry.c @@ -0,0 +1,329 @@ +/* $NetBSD: utmpentry.c,v 1.18 2015/11/21 15:01:43 christos Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 +#ifndef lint +__RCSID("$NetBSD: utmpentry.c,v 1.18 2015/11/21 15:01:43 christos Exp $"); +#endif + +#include + +#include +#include +#include +#include + +#ifdef SUPPORT_UTMP +#include +#endif +#ifdef SUPPORT_UTMPX +#include +#endif + +#include "utmpentry.h" + + +/* Fail the compile if x is not true, by constructing an illegal type. */ +#define COMPILE_ASSERT(x) /*LINTED null effect */ \ + ((void)sizeof(struct { unsigned : ((x) ? 1 : -1); })) + + +#ifdef SUPPORT_UTMP +static void getentry(struct utmpentry *, struct utmp *); +static struct timespec utmptime = {0, 0}; +#endif +#ifdef SUPPORT_UTMPX +static void getentryx(struct utmpentry *, struct utmpx *); +static struct timespec utmpxtime = {0, 0}; +#endif +#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) +static int setup(const char *); +static void adjust_size(struct utmpentry *e); +#endif + +size_t maxname = 8, maxline = 8, maxhost = 16; +int etype = 1 << USER_PROCESS; +static size_t numutmp = 0; +static struct utmpentry *ehead; + +#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) +static void +adjust_size(struct utmpentry *e) +{ + size_t max; + + if ((max = strlen(e->name)) > maxname) + maxname = max; + if ((max = strlen(e->line)) > maxline) + maxline = max; + if ((max = strlen(e->host)) > maxhost) + maxhost = max; +} + +static int +setup(const char *fname) +{ + int what = 3; + struct stat st; + const char *sfname; + + if (fname == NULL) { +#ifdef SUPPORT_UTMPX + setutxent(); +#endif +#ifdef SUPPORT_UTMP + setutent(); +#endif + } else { + size_t len = strlen(fname); + if (len == 0) + errx(1, "Filename cannot be 0 length."); + what = fname[len - 1] == 'x' ? 1 : 2; + if (what == 1) { +#ifdef SUPPORT_UTMPX + if (utmpxname(fname) == 0) + warnx("Cannot set utmpx file to `%s'", + fname); +#else + warnx("utmpx support not compiled in"); +#endif + } else { +#ifdef SUPPORT_UTMP + if (utmpname(fname) == 0) + warnx("Cannot set utmp file to `%s'", + fname); +#else + warnx("utmp support not compiled in"); +#endif + } + } +#ifdef SUPPORT_UTMPX + if (what & 1) { + sfname = fname ? fname : _PATH_UTMPX; + if (stat(sfname, &st) == -1) { + warn("Cannot stat `%s'", sfname); + what &= ~1; + } else { + if (timespeccmp(&st.st_mtimespec, &utmpxtime, >)) + utmpxtime = st.st_mtimespec; + else + what &= ~1; + } + } +#endif +#ifdef SUPPORT_UTMP + if (what & 2) { + sfname = fname ? fname : _PATH_UTMP; + if (stat(sfname, &st) == -1) { + warn("Cannot stat `%s'", sfname); + what &= ~2; + } else { + if (timespeccmp(&st.st_mtimespec, &utmptime, >)) + utmptime = st.st_mtimespec; + else + what &= ~2; + } + } +#endif + return what; +} +#endif + +void +endutentries(void) +{ + struct utmpentry *ep; + +#ifdef SUPPORT_UTMP + timespecclear(&utmptime); +#endif +#ifdef SUPPORT_UTMPX + timespecclear(&utmpxtime); +#endif + ep = ehead; + while (ep) { + struct utmpentry *sep = ep; + ep = ep->next; + free(sep); + } + ehead = NULL; + numutmp = 0; +} + +size_t +getutentries(const char *fname, struct utmpentry **epp) +{ +#ifdef SUPPORT_UTMPX + struct utmpx *utx; +#endif +#ifdef SUPPORT_UTMP + struct utmp *ut; +#endif +#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX) + struct utmpentry *ep; + int what = setup(fname); + struct utmpentry **nextp = &ehead; + switch (what) { + case 0: + /* No updates */ + *epp = ehead; + return numutmp; + default: + /* Need to re-scan */ + ehead = NULL; + numutmp = 0; + } +#endif + +#ifdef SUPPORT_UTMPX + while ((what & 1) && (utx = getutxent()) != NULL) { + if (fname == NULL && ((1 << utx->ut_type) & etype) == 0) + continue; + if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) { + warn(NULL); + return 0; + } + getentryx(ep, utx); + *nextp = ep; + nextp = &(ep->next); + } +#endif + +#ifdef SUPPORT_UTMP + if ((etype & (1 << USER_PROCESS)) != 0) { + while ((what & 2) && (ut = getutent()) != NULL) { + if (fname == NULL && (*ut->ut_name == '\0' || + *ut->ut_line == '\0')) + continue; + /* Don't process entries that we have utmpx for */ + for (ep = ehead; ep != NULL; ep = ep->next) { + if (strncmp(ep->line, ut->ut_line, + sizeof(ut->ut_line)) == 0) + break; + } + if (ep != NULL) + continue; + if ((ep = calloc(1, sizeof(*ep))) == NULL) { + warn(NULL); + return 0; + } + getentry(ep, ut); + *nextp = ep; + nextp = &(ep->next); + } + } +#endif + numutmp = 0; +#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX) + if (ehead != NULL) { + struct utmpentry *from = ehead, *save; + + ehead = NULL; + while (from != NULL) { + for (nextp = &ehead; + (*nextp) && strcmp(from->line, (*nextp)->line) > 0; + nextp = &(*nextp)->next) + continue; + save = from; + from = from->next; + save->next = *nextp; + *nextp = save; + numutmp++; + } + } + *epp = ehead; + return numutmp; +#else + *epp = NULL; + return 0; +#endif +} + +#ifdef SUPPORT_UTMP +static void +getentry(struct utmpentry *e, struct utmp *up) +{ + COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name)); + COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line)); + COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host)); + + /* + * e has just been calloc'd. We don't need to clear it or + * append null-terminators, because its length is strictly + * greater than the source string. Use strncpy to _read_ + * up->ut_* because they may not be terminated. For this + * reason we use the size of the _source_ as the length + * argument. + */ + (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); + (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); + (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); + + e->tv.tv_sec = up->ut_time; + e->tv.tv_usec = 0; + e->pid = 0; + e->term = 0; + e->exit = 0; + e->sess = 0; + e->type = USER_PROCESS; + adjust_size(e); +} +#endif + +#ifdef SUPPORT_UTMPX +static void +getentryx(struct utmpentry *e, struct utmpx *up) +{ + COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name)); + COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line)); + COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host)); + + /* + * e has just been calloc'd. We don't need to clear it or + * append null-terminators, because its length is strictly + * greater than the source string. Use strncpy to _read_ + * up->ut_* because they may not be terminated. For this + * reason we use the size of the _source_ as the length + * argument. + */ + (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); + (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); + (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); + + e->tv = up->ut_tv; + e->pid = up->ut_pid; + e->term = up->ut_exit.e_termination; + e->exit = up->ut_exit.e_exit; + e->sess = up->ut_session; + e->type = up->ut_type; + adjust_size(e); +} +#endif diff --git a/usr.bin/who/utmpentry.h b/usr.bin/who/utmpentry.h new file mode 100644 index 0000000..263a33a --- /dev/null +++ b/usr.bin/who/utmpentry.h @@ -0,0 +1,76 @@ +/* $NetBSD: utmpentry.h,v 1.8 2015/11/21 15:01:43 christos Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#if defined(SUPPORT_UTMPX) +# include +# define WHO_NAME_LEN _UTX_USERSIZE +# define WHO_LINE_LEN _UTX_LINESIZE +# define WHO_HOST_LEN _UTX_HOSTSIZE +#elif defined(SUPPORT_UTMP) +# include +# define WHO_NAME_LEN UT_NAMESIZE +# define WHO_LINE_LEN UT_LINESIZE +# define WHO_HOST_LEN UT_HOSTSIZE +#else +# error Either SUPPORT_UTMPX or SUPPORT_UTMP must be defined! +#endif + + +struct utmpentry { + char name[WHO_NAME_LEN + 1]; + char line[WHO_LINE_LEN + 1]; + char host[WHO_HOST_LEN + 1]; + struct timeval tv; + pid_t pid; + uint16_t term; + uint16_t exit; + uint16_t sess; + uint16_t type; + struct utmpentry *next; +}; + +extern size_t maxname, maxline, maxhost; +extern int etype; + +/* + * getutentries provides a linked list of struct utmpentry and returns + * the number of entries. The first argument, if not null, names an + * alternate utmp(x) file to look in. + * + * The memory returned by getutentries belongs to getutentries. The + * list returned (or elements of it) may be returned again later if + * utmp hasn't changed in the meantime. + * + * endutentries clears and frees the cached data. + */ + +size_t getutentries(const char *, struct utmpentry **); +void endutentries(void); diff --git a/usr.bin/who/who.1 b/usr.bin/who/who.1 new file mode 100644 index 0000000..3873b47 --- /dev/null +++ b/usr.bin/who/who.1 @@ -0,0 +1,197 @@ +.\" $NetBSD: who.1,v 1.24 2018/05/11 16:36:57 sevan Exp $ +.\" +.\" Copyright (c) 1986, 1991, 1993 +.\" The Regents of the University of California. 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. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. +.\" +.\" @(#)who.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd May 11, 2018 +.Dt WHO 1 +.Os +.Sh NAME +.Nm who +.Nd display who is logged in +.Sh SYNOPSIS +.Nm +.Op Fl abdHlmqrsTtuv +.Op Ar file +.Nm +.Ar am i +.Sh DESCRIPTION +The +.Nm +utility displays a list of all users currently logged on, showing for +each user the login name, tty name, the date and time of login, and +hostname if not local. +.Pp +Available options: +.Bl -tag -width file +.It Fl a +Same as +.Fl -bdlprTtuv . +.It Fl b +Time of last system boot. +.It Fl d +Print dead processes. +.It Fl H +Write column headings above the regular output. +.It Fl l +Print system login processes. +.It Fl m +Only print information about the current terminal. +This is the POSIX way of saying +.Nm +.Ar am i . +.It Fl p +Print active processes spawned by +.Xr init 8 . +.It Fl q +.Dq Quick mode : +List only the names and the number of users currently logged on. +When this option is used, all other options are ignored. +.It Fl r +Print the current runlevel. +Supported runlevels are: +.Bl -tag -width "s (SINGLE_USER)" +.It Dv d Pq Dv DEATH +The system has halted. +.It Dv s Pq Dv SINGLE_USER +The system is running in single user mode. +.It Dv r Pq Dv RUNCOM +The system is executing +.Pa /etc/rc . +.It Dv t Pq Dv READ_TTYS +The system is processing +.Pa /etc/ttys . +.It Dv m Pq Dv MULTI_USER +The system is running in multi-user mode. +.It Dv T Pq Dv CLEAN_TTYS +The system is in the process of stopping processes +associated with terminal devices. +.It Dv c Pq Dv CATATONIA +The system is in the process of shutting down and will +not create new processes. +.El +.It Fl s +List only the name, line and time fields. +This is the default. +.It Fl T +Print a character after the user name indicating the state of the +terminal line: +.Sq + +if the terminal is writable; +.Sq - +if it is not; +and +.Sq \&? +if a bad line is encountered. +.It Fl t +Print last system clock change. +.It Fl u +Print the idle time for each user, and the associated process ID. +.It Fl v +When printing of more information is requested with +.Fl u , +this switch can be used to also printed +process termination signals, +process exit status, +session id for windowing +and the type of the entry, see documentation of ut_type in +.Xr getutxent 3 . +.It Ar \&am I +Returns the invoker's real user name. +.It Ar file +By default, +.Nm +gathers information from the file +.Pa /var/run/utmpx . +An alternative +.Ar file +may be specified which is usually +.Pa /var/log/wtmpx +(or +.Pa /var/log/wtmp , +or +.Pa /var/log/wtmpx.[0-6] +or +.Pa /var/log/wtmp.[0-6] +depending on site policy as +.Pa wtmpx +can grow quite large and daily versions may or may not +be kept around after compression by +.Xr ac 8 ) . +The +.Pa wtmpx +and +.Pa wtmp +file contains a record of every login, logout, +crash, shutdown and date change +since +.Pa wtmpx +and +.Pa wtmp +were last truncated or +created. +.El +.Pp +If +.Pa /var/log/wtmpx +or +.Pa /var/log/wtmp +are being used as the file, the user name may be empty +or one of the special characters '|', '}' and '~'. +Logouts produce an output line without any user name. +For more information on the +special characters, see +.Xr utmp 5 . +.Sh FILES +.Bl -tag -width /var/log/wtmp.[0-6] -compact +.It Pa /var/run/utmp +.It Pa /var/run/utmpx +.It Pa /var/log/wtmp +.It Pa /var/log/wtmp.[0-6] +.It Pa /var/log/wtmpx +.It Pa /var/log/wtmpx.[0-6] +.El +.Sh SEE ALSO +.Xr last 1 , +.Xr mesg 1 , +.Xr users 1 , +.Xr getuid 2 , +.Xr utmp 5 , +.Xr utmpx 5 +.Sh STANDARDS +The +.Nm +utility is expected to conform to +.St -p1003.2-92 . +.Sh HISTORY +A +.Nm +utility appeared in +.At v1 : +.Lk http://cm.bell-labs.com/cm/cs/who/dmr/pdfs/man14.pdf diff --git a/usr.bin/who/who.c b/usr.bin/who/who.c new file mode 100644 index 0000000..f0c6564 --- /dev/null +++ b/usr.bin/who/who.c @@ -0,0 +1,391 @@ +/* $NetBSD: who.c,v 1.25 2015/11/21 15:01:43 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1989, 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)who.c 8.1 (Berkeley) 6/6/93"; +#endif +__RCSID("$NetBSD: who.c,v 1.25 2015/11/21 15:01:43 christos Exp $"); +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SUPPORT_UTMP +#include +#endif +#ifdef SUPPORT_UTMPX +#include +#endif + +#include "utmpentry.h" + +static void output_labels(void); +static void who_am_i(const char *, int); +static void usage(void) __dead; +static void process(const char *, int); +static void eprint(const struct utmpentry *); +static void print(const char *, const char *, time_t, const char *, pid_t pid, + uint16_t term, uint16_t xit, uint16_t sess, uint16_t type); +static void quick(const char *); + +static int show_term; /* show term state */ +static int show_idle; /* show idle time */ +static int show_details; /* show exit status etc. */ + +struct ut_type_names { + int type; + const char *name; +} ut_type_names[] = { +#ifdef SUPPORT_UTMPX + { EMPTY, "empty" }, + { RUN_LVL, "run level" }, + { BOOT_TIME, "boot time" }, + { OLD_TIME, "old time" }, + { NEW_TIME, "new time" }, + { INIT_PROCESS, "init process" }, + { LOGIN_PROCESS, "login process" }, + { USER_PROCESS, "user process" }, + { DEAD_PROCESS, "dead process" }, +#if defined(_NETBSD_SOURCE) + { ACCOUNTING, "accounting" }, + { SIGNATURE, "signature" }, + { DOWN_TIME, "down time" }, +#endif /* _NETBSD_SOURCE */ +#endif /* SUPPORT_UTMPX */ + { -1, "unknown" } +}; + +int +main(int argc, char *argv[]) +{ + int c, only_current_term, show_labels, quick_mode, default_mode; + int et = 0; + + setlocale(LC_ALL, ""); + + only_current_term = show_term = show_idle = show_labels = 0; + quick_mode = default_mode = 0; + + while ((c = getopt(argc, argv, "abdHlmpqrsTtuv")) != -1) { + switch (c) { + case 'a': + et = -1; + show_idle = show_details = 1; + break; + case 'b': + et |= (1 << BOOT_TIME); + break; + case 'd': + et |= (1 << DEAD_PROCESS); + break; + case 'H': + show_labels = 1; + break; + case 'l': + et |= (1 << LOGIN_PROCESS); + break; + case 'm': + only_current_term = 1; + break; + case 'p': + et |= (1 << INIT_PROCESS); + break; + case 'q': + quick_mode = 1; + break; + case 'r': + et |= (1 << RUN_LVL); + break; + case 's': + default_mode = 1; + break; + case 'T': + show_term = 1; + break; + case 't': + et |= (1 << NEW_TIME); + break; + case 'u': + show_idle = 1; + break; + case 'v': + show_details = 1; + break; + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (et != 0) + etype = et; + + if (chdir("/dev")) { + err(EXIT_FAILURE, "cannot change directory to /dev"); + /* NOTREACHED */ + } + + if (default_mode) + only_current_term = show_term = show_idle = 0; + + switch (argc) { + case 0: /* who */ + if (quick_mode) { + quick(NULL); + } else if (only_current_term) { + who_am_i(NULL, show_labels); + } else { + process(NULL, show_labels); + } + break; + case 1: /* who utmp_file */ + if (quick_mode) { + quick(*argv); + } else if (only_current_term) { + who_am_i(*argv, show_labels); + } else { + process(*argv, show_labels); + } + break; + case 2: /* who am i */ + who_am_i(NULL, show_labels); + break; + default: + usage(); + /* NOTREACHED */ + } + + return 0; +} + +static char * +strrstr(const char *str, const char *pat) +{ + const char *estr; + size_t len; + if (*pat == '\0') + return __UNCONST(str); + + len = strlen(pat); + + for (estr = str + strlen(str); str < estr; estr--) + if (strncmp(estr, pat, len) == 0) + return __UNCONST(estr); + return NULL; +} + +static void +who_am_i(const char *fname, int show_labels) +{ + struct passwd *pw; + const char *p; + char *t; + time_t now; + struct utmpentry *ehead, *ep; + + /* search through the utmp and find an entry for this tty */ + if ((p = ttyname(STDIN_FILENO)) != NULL) { + + /* strip directory prefixes for ttys */ + if ((t = strrstr(p, "/pts/")) != NULL || + (t = strrchr(p, '/')) != NULL) + p = t + 1; + + (void)getutentries(fname, &ehead); + for (ep = ehead; ep; ep = ep->next) + if (strcmp(ep->line, p) == 0) { + if (show_labels) + output_labels(); + eprint(ep); + return; + } + } else + p = "tty??"; + + (void)time(&now); + pw = getpwuid(getuid()); + if (show_labels) + output_labels(); + print(pw ? pw->pw_name : "?", p, now, "", getpid(), 0, 0, 0, 0); +} + +static void +process(const char *fname, int show_labels) +{ + struct utmpentry *ehead, *ep; + (void)getutentries(fname, &ehead); + if (show_labels) + output_labels(); + for (ep = ehead; ep != NULL; ep = ep->next) + eprint(ep); +} + +static void +eprint(const struct utmpentry *ep) +{ + print(ep->name, ep->line, (time_t)ep->tv.tv_sec, ep->host, ep->pid, + ep->term, ep->exit, ep->sess, ep->type); +} + +static void +print(const char *name, const char *line, time_t t, const char *host, + pid_t pid, uint16_t term, uint16_t xit, uint16_t sess, uint16_t type) +{ + struct stat sb; + char state; + static time_t now = 0; + time_t idle; + const char *types = NULL; + size_t i; + char *tstr; + + state = '?'; + idle = 0; + + for (i = 0; ut_type_names[i].type >= 0; i++) { + types = ut_type_names[i].name; + if (ut_type_names[i].type == type) + break; + } + + if (show_term || show_idle) { + if (now == 0) + time(&now); + + if (stat(line, &sb) == 0) { + state = (sb.st_mode & 020) ? '+' : '-'; + idle = now - sb.st_atime; + } + + } + + (void)printf("%-*.*s ", (int)maxname, (int)maxname, name); + + if (show_term) + (void)printf("%c ", state); + + (void)printf("%-*.*s ", (int)maxline, (int)maxline, line); + tstr = ctime(&t); + (void)printf("%.12s ", tstr ? tstr + 4 : "?"); + + if (show_idle) { + if (idle < 60) + (void)printf(" . "); + else if (idle < (24 * 60 * 60)) + (void)printf("%02ld:%02ld ", + (long)(idle / (60 * 60)), + (long)(idle % (60 * 60)) / 60); + else + (void)printf(" old "); + + (void)printf("\t%6d", pid); + + if (show_details) { + if (type == RUN_LVL) + (void)printf("\tnew=%c old=%c", term, xit); + else + (void)printf("\tterm=%d exit=%d", term, xit); + (void)printf(" sess=%d", sess); + (void)printf(" type=%s ", types); + } + } + + if (*host) + (void)printf("\t(%.*s)", (int)maxhost, host); + (void)putchar('\n'); +} + +static void +output_labels(void) +{ + (void)printf("%-*.*s ", (int)maxname, (int)maxname, "USER"); + + if (show_term) + (void)printf("S "); + + (void)printf("%-*.*s ", (int)maxline, (int)maxline, "LINE"); + (void)printf("WHEN "); + + if (show_idle) { + (void)printf("IDLE "); + (void)printf("\t PID"); + + (void)printf("\tCOMMENT"); + } + + (void)putchar('\n'); +} + +static void +quick(const char *fname) +{ + struct utmpentry *ehead, *ep; + int num = 0; + + (void)getutentries(fname, &ehead); + for (ep = ehead; ep != NULL; ep = ep->next) { + (void)printf("%-*s ", (int)maxname, ep->name); + if ((++num % 8) == 0) + (void)putchar('\n'); + } + if (num % 8) + (void)putchar('\n'); + + (void)printf("# users = %d\n", num); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [-abdHlmqrsTtuv] [file]\n\t%s am i\n", + getprogname(), getprogname()); + exit(EXIT_FAILURE); +} -- cgit v1.2.3-70-g09d2