From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- shell_cmds/who/utmpentry.c | 348 ++++++++++++++++++++++++++++++++++ shell_cmds/who/utmpentry.h | 78 ++++++++ shell_cmds/who/who.1 | 130 +++++++++++++ shell_cmds/who/who.c | 453 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1009 insertions(+) create mode 100644 shell_cmds/who/utmpentry.c create mode 100644 shell_cmds/who/utmpentry.h create mode 100644 shell_cmds/who/who.1 create mode 100644 shell_cmds/who/who.c (limited to 'shell_cmds/who') diff --git a/shell_cmds/who/utmpentry.c b/shell_cmds/who/utmpentry.c new file mode 100644 index 0000000..b0e0914 --- /dev/null +++ b/shell_cmds/who/utmpentry.c @@ -0,0 +1,348 @@ +/* $NetBSD: utmpentry.c,v 1.15 2008/07/13 20:07:48 dholland 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.15 2008/07/13 20:07:48 dholland Exp $"); +#endif + +#include + +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#endif /* __APPLE__ */ + +#ifdef SUPPORT_UTMP +#include +#endif +#ifdef SUPPORT_UTMPX +#include +#endif + +#include "utmpentry.h" + +#ifdef __APPLE__ +#define timespecclear(tsp) (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L) +#define timespeccmp(tsp, usp, cmp) \ + (((tsp)->tv_sec == (usp)->tv_sec) ? \ + ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \ + ((tsp)->tv_sec cmp (usp)->tv_sec)) +#endif /* __APPLE__ */ + +/* Fail the compile if x is not true, by constructing an illegal type. */ +#define COMPILE_ASSERT(x) ((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 + +int maxname = 8, maxline = 8, maxhost = 16; +int etype = 1 << USER_PROCESS; +static int numutmp = 0; +static struct utmpentry *ehead; + +#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) +static void +adjust_size(struct utmpentry *e) +{ + int 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."); +#ifdef __APPLE__ + what = 1; +#else /* !__APPLE__ */ + what = fname[len - 1] == 'x' ? 1 : 2; +#endif /* __APPLE__ */ + 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; +} + +int +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) { +#ifdef __APPLE__ + if (((1 << utx->ut_type) & etype) == 0) +#else /* !__APPLE__ */ + if (fname == NULL && ((1 << utx->ut_type) & etype) == 0) +#endif /* __APPLE__ */ + 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; +#ifndef __APPLE__ + e->term = up->ut_exit.e_termination; + e->exit = up->ut_exit.e_exit; + e->sess = up->ut_session; +#endif /* !__APPLE__ */ + e->type = up->ut_type; + adjust_size(e); +} +#endif diff --git a/shell_cmds/who/utmpentry.h b/shell_cmds/who/utmpentry.h new file mode 100644 index 0000000..012478a --- /dev/null +++ b/shell_cmds/who/utmpentry.h @@ -0,0 +1,78 @@ +/* $NetBSD: utmpentry.h,v 1.7 2008/07/13 20:07:49 dholland 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; +#ifndef __APPLE__ + uint16_t term; + uint16_t exit; + uint16_t sess; +#endif /* !__APPLE__ */ + uint16_t type; + struct utmpentry *next; +}; + +extern int 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. + */ + +int getutentries(const char *, struct utmpentry **); +void endutentries(void); diff --git a/shell_cmds/who/who.1 b/shell_cmds/who/who.1 new file mode 100644 index 0000000..dbcbdf1 --- /dev/null +++ b/shell_cmds/who/who.1 @@ -0,0 +1,130 @@ +.\" $NetBSD: who.1,v 1.22 2007/01/18 00:15:05 wiz 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 January 17, 2007 +.Dt WHO 1 +.Os +.Sh NAME +.Nm who +.Nd display who is logged in +.Sh SYNOPSIS +.Nm +.Op Fl abdHlmpqrsTtu +.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: +.Pp +.Bl -tag -width file +.It Fl a +Same as +.Fl bdlprTtu . +.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 (unsupported). +.It Fl m +Only print information about the current terminal. +This is the +.Tn POSIX +way of saying +.Nm +.Ar am i . +.It Fl p +Print active processes spawned by +.Xr launchd 8 +(unsupported). +.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. +This is meaningless on Mac OS X. +.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 (unsupported). +.It Fl u +Print the idle time for each user, and the associated process ID. +.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. +.El +.Sh FILES +.Bl -tag -width /var/run/utmpx -compact +.It Pa /var/run/utmpx +.El +.Sh SEE ALSO +.Xr last 1 , +.Xr mesg 1 , +.Xr users 1 , +.Xr getuid 2 , +.Xr utmpx 5 +.Sh STANDARDS +The +.Nm +utility conforms to +.St -p1003.1-2001 . +.Sh HISTORY +A +.Nm +utility appeared in +.At v6 . diff --git a/shell_cmds/who/who.c b/shell_cmds/who/who.c new file mode 100644 index 0000000..f0e356f --- /dev/null +++ b/shell_cmds/who/who.c @@ -0,0 +1,453 @@ +/* $NetBSD: who.c,v 1.23 2008/07/24 15:35:41 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.23 2008/07/24 15:35:41 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 +#ifdef __APPLE__ +#include +#include +#include +#endif /* __APPLE__ */ + +#include "utmpentry.h" + +#ifdef __APPLE__ +#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) +#endif /* __APPLE__ */ + +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 */ +#ifndef __APPLE__ +static int show_details; /* show exit status etc. */ +#endif /* !__APPLE__ */ + +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; +#ifdef __APPLE__ + show_idle = 1; +#else /* !__APPLE__ */ + show_idle = show_details = 1; +#endif /* __APPLE__ */ + 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; +#ifndef __APPLE__ + case 'v': + show_details = 1; + break; +#endif /* !__APPLE__ */ + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (et != 0) + etype = et; + +#ifndef __APPLE__ + if (chdir("/dev")) { + err(EXIT_FAILURE, "cannot change directory to /dev"); + /* NOTREACHED */ + } +#endif /* !__APPLE__ */ + + 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); +#ifdef __APPLE__ + if ((etype & (1 << RUN_LVL)) != 0) { + printf(" . run-level 3\n"); + } +#endif /* __APPLE__ */ +} + +static void +eprint(const struct utmpentry *ep) +{ + print(ep->name, ep->line, (time_t)ep->tv.tv_sec, ep->host, ep->pid, +#ifdef __APPLE__ + 0, 0, 0, ep->type); +#else /* !__APPLE__ */ + ep->term, ep->exit, ep->sess, ep->type); +#endif /* __APPLE__ */ +} + +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; + + 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); + +#ifdef __APPLE__ + char tty[PATH_MAX + 1]; + snprintf(tty, sizeof(tty), "%s%s", _PATH_DEV, line); + if (stat(tty, &sb) == 0) { +#else /* !__APPLE__ */ + if (stat(line, &sb) == 0) { +#endif /* __APPLE__ */ + state = (sb.st_mode & 020) ? '+' : '-'; + idle = now - sb.st_atime; + } + + } + +#ifdef __APPLE__ + switch (type) { + case LOGIN_PROCESS: + (void)printf("%-*.*s ", maxname, maxname, "LOGIN"); + break; + case BOOT_TIME: + (void)printf("%-*.*s ", maxname, maxname, "reboot"); + break; + default: + (void)printf("%-*.*s ", maxname, maxname, name); + break; + } +#else /* !__APPLE__ */ + (void)printf("%-*.*s ", maxname, maxname, name); +#endif /* __APPLE__ */ + + if (show_term) + (void)printf("%c ", state); + +#ifdef __APPLE__ + (void)printf("%-*.*s ", maxline, maxline, type == BOOT_TIME ? "~" : line); +#else /* !__APPLE__ */ + (void)printf("%-*.*s ", maxline, maxline, line); +#endif /* __APPLE__ */ + (void)printf("%.12s ", ctime(&t) + 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); + +#ifndef __APPLE__ + 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); + } +#endif /* !__APPLE__ */ + } + +#ifdef __APPLE__ + /* 6179576 */ + if (type == DEAD_PROCESS) + (void)printf("\tterm=%d exit=%d", 0, 0); +#endif /* __APPLE__ */ + + if (*host) + (void)printf("\t(%.*s)", maxhost, host); + (void)putchar('\n'); +} + +static void +output_labels(void) +{ + (void)printf("%-*.*s ", maxname, maxname, "USER"); + + if (show_term) + (void)printf("S "); + + (void)printf("%-*.*s ", maxline, 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 ", 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) +{ +#ifdef __APPLE__ + (void)fprintf(stderr, "Usage: %s [-abdHlmpqrsTtu] [file]\n\t%s am i\n", +#else /* !__APPLE__ */ + (void)fprintf(stderr, "Usage: %s [-abdHlmqrsTtuv] [file]\n\t%s am i\n", +#endif /* __APPLE__ */ + getprogname(), getprogname()); + exit(EXIT_FAILURE); +} -- cgit v1.2.3-56-ge451