From b6d4a4c155b8d689603434c3da8b55571af40e3b Mon Sep 17 00:00:00 2001 From: Thomas Cort Date: Fri, 15 Mar 2013 23:43:44 +0000 Subject: [PATCH] Importing usr.bin/who --- commands/Makefile | 2 +- commands/who/Makefile | 4 - commands/who/who.c | 72 -------- man/man1/Makefile | 2 +- man/man1/who.1 | 33 ---- releasetools/nbsd_ports | 1 + usr.bin/Makefile | 2 +- usr.bin/who/Makefile | 8 + usr.bin/who/utmpentry.c | 329 +++++++++++++++++++++++++++++++++ usr.bin/who/utmpentry.h | 76 ++++++++ usr.bin/who/who.1 | 199 ++++++++++++++++++++ usr.bin/who/who.c | 389 ++++++++++++++++++++++++++++++++++++++++ 12 files changed, 1005 insertions(+), 112 deletions(-) delete mode 100644 commands/who/Makefile delete mode 100644 commands/who/who.c delete mode 100644 man/man1/who.1 create mode 100644 usr.bin/who/Makefile 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 diff --git a/commands/Makefile b/commands/Makefile index c5eeee6d9..8e78cfc91 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -29,7 +29,7 @@ SUBDIR= add_route arp ash at backup banner basename btrace cal \ telnetd term termcap tget time touch tr \ truncate tty udpstat umount uname unexpand \ unstack update uud uue version vol wc \ - whereis which who write writeisofs fetch \ + whereis which write writeisofs fetch \ xargs yes zdump zmodem pkgin_cd pkgin_all \ worldstone updateboot update_bootcfg diff --git a/commands/who/Makefile b/commands/who/Makefile deleted file mode 100644 index 34b50e4ad..000000000 --- a/commands/who/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -PROG= who -MAN= - -.include diff --git a/commands/who/who.c b/commands/who/who.c deleted file mode 100644 index eebeaceea..000000000 --- a/commands/who/who.c +++ /dev/null @@ -1,72 +0,0 @@ -/* who 1.5 - tell who is currently logged in Author: Kees J. Bot - * 9 Jul 1989 - */ -#define nil 0 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -char PATH_UTMP[] = _PATH_UTMP; - -char day[] = "SunMonTueWedThuFriSat"; -char month[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; - -int main(int argc, char **argv) -{ - char *tmp= PATH_UTMP; - FILE *f; - struct utmp ut; - struct tm *tm; - int slot, wtmp= 0, once= 0; - - if (argc > 3) { - fprintf(stderr, "Usage: who | who am i\n"); - exit(1); - } - if (argc == 2) { - tmp= argv[1]; - wtmp= 1; - } - - if ((f= fopen(tmp, "r")) == nil) { - fprintf(stderr, "who: can't open %s\n", tmp); - exit(1); - } - if (argc == 3) { - if ((slot= ttyslot()) < 0) { - fprintf(stderr, "who: no access to terminal.\n"); - exit(1); - } - fseek(f, (off_t) sizeof(ut) * slot, 0); - once= 1; - } - - while (fread((char *) &ut, sizeof(ut), 1, f) == 1) { - if (!wtmp && ut.ut_name[0] == 0) continue; - - tm= localtime(&ut.ut_time); - - printf("%-9.8s %-9.8s %.3s %.3s %2d %02d:%02d", - ut.ut_name, - ut.ut_line, - day + (3 * tm->tm_wday), - month + (3 * tm->tm_mon), - tm->tm_mday, - tm->tm_hour, - tm->tm_min - ); - - if (ut.ut_host[0] != 0) printf(" (%.*s)", - (int) sizeof(ut.ut_host), ut.ut_host); - - printf("\n"); - if (once) break; - } - exit(0); -} diff --git a/man/man1/Makefile b/man/man1/Makefile index aa405d5e9..8661dec80 100644 --- a/man/man1/Makefile +++ b/man/man1/Makefile @@ -21,7 +21,7 @@ MAN= ash.1 at.1 banner.1 basename.1 \ term.1 termcap.1 tget.1 time.1 tr.1 true.1 \ truncate.1 tty.1 umount.1 uname.1 unexpand.1 \ uud.1 uue.1 vol.1 wc.1 whereis.1 which.1 \ - who.1 write.1 xargs.1 yap.1 yes.1 linkfarm.1 pkg_view.1 + write.1 xargs.1 yap.1 yes.1 linkfarm.1 pkg_view.1 MLINKS += ash.1 sh.1 MLINKS += ash.1 ..1 diff --git a/man/man1/who.1 b/man/man1/who.1 deleted file mode 100644 index 75735ed31..000000000 --- a/man/man1/who.1 +++ /dev/null @@ -1,33 +0,0 @@ -.TH WHO 1 -.SH NAME -who \- print list of currently logged in users -.SH SYNOPSIS -\fBwho\fR [\fIfile\fR]\fR -.br -.de FL -.TP -\\fB\\$1\\fR -\\$2 -.. -.de EX -.TP 20 -\\fB\\$1\\fR -# \\$2 -.. -.SH EXAMPLES -.TP 20 -.B who -# Print user names, terminals and times -.SH DESCRIPTION -.PP -\fIWho\fR prints a list of currently logged in users. For each one, -the user name, terminal, and login time is printed. -This program gets its information from the file \fI/etc/utmp\fR, which -is updated by init and login. -If the file does not exist, neither of these will create it, and -\fIwho\fR will not work. Note that if you decide to create an empty -\fI/usr/adm/wtmp\fR to enable the login accounting, it will grow forever and -eventually fill up your disk unless you manually truncate it from time to time. -If an optional file name is provided, the logins in that file will be printed. -.SH "SEE ALSO" -.BR utmp (5). diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index 4abea3f2d..65ceef899 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -158,6 +158,7 @@ 2012/10/17 12:00:00,usr.bin/tput 2012/10/17 12:00:00,usr.bin/tsort 2010/10/06 07:59:18,usr.bin/uniq +2013/03/15 12:00:00,usr.bin/who 2012/10/17 12:00:00,usr.bin/xinstall 2012/02/10 16:16:12,usr.sbin/chroot 2011/11/03 20:46:41,usr.sbin/installboot diff --git a/usr.bin/Makefile b/usr.bin/Makefile index ab54878a1..fc39a7285 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -30,7 +30,7 @@ SUBDIR= \ uniq \ \ \ - \ + who \ xinstall .if !defined(__MINIX) diff --git a/usr.bin/who/Makefile b/usr.bin/who/Makefile new file mode 100644 index 000000000..347ba538c --- /dev/null +++ b/usr.bin/who/Makefile @@ -0,0 +1,8 @@ +# $NetBSD: Makefile,v 1.9 2009/04/14 22:15:29 lukem Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= who +SRCS= who.c utmpentry.c +CPPFLAGS+= -DSUPPORT_UTMPX -DSUPPORT_UTMP + +.include diff --git a/usr.bin/who/utmpentry.c b/usr.bin/who/utmpentry.c new file mode 100644 index 000000000..ac15d08c7 --- /dev/null +++ b/usr.bin/who/utmpentry.c @@ -0,0 +1,329 @@ +/* $NetBSD: utmpentry.c,v 1.17 2009/05/01 14:26:10 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.17 2009/05/01 14:26:10 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 + +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."); + 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; +} + +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) { + 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 000000000..5f7bf83c3 --- /dev/null +++ b/usr.bin/who/utmpentry.h @@ -0,0 +1,76 @@ +/* $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; + uint16_t term; + uint16_t exit; + uint16_t sess; + 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/usr.bin/who/who.1 b/usr.bin/who/who.1 new file mode 100644 index 000000000..e64c38e64 --- /dev/null +++ b/usr.bin/who/who.1 @@ -0,0 +1,199 @@ +.\" $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 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: +.Pp +.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 +.Tn 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 v6 . diff --git a/usr.bin/who/who.c b/usr.bin/who/who.c new file mode 100644 index 000000000..9dd4e40ac --- /dev/null +++ b/usr.bin/who/who.c @@ -0,0 +1,389 @@ +/* $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 + +#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; + + 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 ", maxname, maxname, name); + + if (show_term) + (void)printf("%c ", state); + + (void)printf("%-*.*s ", maxline, maxline, line); + (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); + + 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)", 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) +{ + (void)fprintf(stderr, "Usage: %s [-abdHlmqrsTtuv] [file]\n\t%s am i\n", + getprogname(), getprogname()); + exit(EXIT_FAILURE); +}