Importing usr.bin/who

This commit is contained in:
Thomas Cort 2013-03-15 23:43:44 +00:00 committed by Lionel Sambuc
parent 0022ee2cb5
commit b6d4a4c155
12 changed files with 1005 additions and 112 deletions

View File

@ -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

View File

@ -1,4 +0,0 @@
PROG= who
MAN=
.include <bsd.prog.mk>

View File

@ -1,72 +0,0 @@
/* who 1.5 - tell who is currently logged in Author: Kees J. Bot
* 9 Jul 1989
*/
#define nil 0
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <utmp.h>
#include <time.h>
#include <string.h>
#include <paths.h>
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 <account-file> | 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);
}

View File

@ -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

View File

@ -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).

View File

@ -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

View File

@ -30,7 +30,7 @@ SUBDIR= \
uniq \
\
\
\
who \
xinstall
.if !defined(__MINIX)

8
usr.bin/who/Makefile Normal file
View File

@ -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 <bsd.prog.mk>

329
usr.bin/who/utmpentry.c Normal file
View File

@ -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 <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: utmpentry.c,v 1.17 2009/05/01 14:26:10 christos Exp $");
#endif
#include <sys/stat.h>
#include <time.h>
#include <string.h>
#include <err.h>
#include <stdlib.h>
#ifdef SUPPORT_UTMP
#include <utmp.h>
#endif
#ifdef SUPPORT_UTMPX
#include <utmpx.h>
#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

76
usr.bin/who/utmpentry.h Normal file
View File

@ -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 <utmpx.h>
# define WHO_NAME_LEN _UTX_USERSIZE
# define WHO_LINE_LEN _UTX_LINESIZE
# define WHO_HOST_LEN _UTX_HOSTSIZE
#elif defined(SUPPORT_UTMP)
# include <utmp.h>
# 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);

199
usr.bin/who/who.1 Normal file
View File

@ -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 .

389
usr.bin/who/who.c Normal file
View File

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <locale.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifdef SUPPORT_UTMP
#include <utmp.h>
#endif
#ifdef SUPPORT_UTMPX
#include <utmpx.h>
#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);
}