Import NetBSD w(1) and uptime(1)

Change-Id: Id6cc36f4befbce4be3a471ae920d75972a44bef1
This commit is contained in:
David van Moolenbroek
2014-08-26 16:03:05 +00:00
parent 61df9b64d1
commit 11eaad3501
13 changed files with 1611 additions and 1 deletions

View File

@@ -29,7 +29,7 @@ SUBDIR= asa \
tr true tsort tty ul uname unexpand unifdef \
uniq units unvis unzip users \
uuidgen vis \
\
w \
wall wc what whereis who whois \
write xargs xinstall xstr yes

24
usr.bin/w/Makefile Normal file
View File

@@ -0,0 +1,24 @@
# $NetBSD: Makefile,v 1.21 2011/10/21 02:26:09 christos Exp $
# @(#)Makefile 8.1 (Berkeley) 6/6/93
.include <bsd.own.mk>
PROG= w
SRCS= fmt.c pr_time.c w.c
MAN= w.1 uptime.1
.if defined(__MINIX)
.PATH: ${NETBSDSRCDIR}/minix/usr.bin/w
SRCS+= minix_proc.c
CPPFLAGS+= -I${NETBSDSRCDIR}/minix/usr.bin/w
.else
DPADD= ${LIBKVM} ${LIBUTIL}
LDADD= -lkvm -lutil
.endif
LINKS= ${BINDIR}/w ${BINDIR}/uptime
CPPFLAGS+= -DSUPPORT_UTMP -DSUPPORT_UTMPX
.PATH: ${NETBSDSRCDIR}/bin/ps
COPTS.pr_time.c += -Wno-format-y2k
.include <bsd.prog.mk>

38
usr.bin/w/extern.h Normal file
View File

@@ -0,0 +1,38 @@
/* $NetBSD: extern.h,v 1.7 2011/10/21 02:26:09 christos Exp $ */
/*-
* Copyright (c) 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.
*
* @(#)extern.h 8.1 (Berkeley) 6/6/93
*/
struct kinfo_proc2;
void fmt_puts(char *, int *);
void fmt_putc(int, int *);
void pr_attime(time_t *, time_t *);
void pr_idle(time_t);

116
usr.bin/w/pr_time.c Normal file
View File

@@ -0,0 +1,116 @@
/* $NetBSD: pr_time.c,v 1.18 2011/08/17 13:48:11 christos Exp $ */
/*-
* Copyright (c) 1990, 1993, 1994
* 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)pr_time.c 8.2 (Berkeley) 4/4/94";
#else
__RCSID("$NetBSD: pr_time.c,v 1.18 2011/08/17 13:48:11 christos Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <tzfile.h>
#include "extern.h"
/*
* pr_attime --
* Print the time since the user logged in.
*
* Note: SCCS forces the bizarre string manipulation, things like
* %I% get replaced in the source code.
*/
void
pr_attime(time_t *started, time_t *now)
{
static char buf[256];
int tnow_yday;
struct tm *tp;
time_t diff;
tnow_yday = localtime(now)->tm_yday;
tp = localtime(started);
diff = *now - *started;
if (diff > SECSPERDAY * DAYSPERWEEK) {
/* If more than a week, use day-month-year. */
(void)strftime(buf, sizeof(buf), "%d%b%y", tp);
} else if (tp->tm_yday != tnow_yday) {
/* If not today, use day-hour-am/pm. Damn SCCS */
(void)strftime(buf, sizeof(buf), "%a%" "I%p", tp);
} else {
/* Default is hh:mm{am,pm}. Damn SCCS */
(void)strftime(buf, sizeof(buf), "%l:%" "M%p", tp);
}
buf[sizeof(buf) - 1] = '\0';
(void)fputs(buf, stdout);
}
/*
* pr_idle --
* Display the idle time.
*/
void
pr_idle(time_t idle)
{
int days;
if (idle == (time_t)-1) {
(void)printf(" ? ");
return;
}
days = idle / SECSPERDAY;
/* If idle more than 36 hours, print as a number of days. */
if (idle >= 48 * SECSPERHOUR)
printf(" %ddays ", days);
else if (idle >= 36 * SECSPERHOUR)
printf(" 1day ");
/* If idle more than an hour, print as HH:MM. */
else if (idle >= SECSPERHOUR)
(void)printf(" %2d:%02d ",
(int)(idle / SECSPERHOUR),
(int)((idle % SECSPERHOUR) / SECSPERMIN));
/* Else print the minutes idle. */
else
(void)printf(" %2d ", (int)(idle / SECSPERMIN));
}

58
usr.bin/w/uptime.1 Normal file
View File

@@ -0,0 +1,58 @@
.\" $NetBSD: uptime.1,v 1.10 2003/08/07 11:17:13 agc Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993, 1994
.\" 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.
.\"
.\" @(#)uptime.1 8.2 (Berkeley) 4/18/94
.\"
.Dd April 18, 1994
.Dt UPTIME 1
.Os
.Sh NAME
.Nm uptime
.Nd show how long system has been running
.Sh SYNOPSIS
.Nm
.Sh DESCRIPTION
The
.Nm
utility displays the current time,
the length of time the system has been up,
the number of users, and the load average of the system over the last
1, 5, and 15 minutes.
.Sh FILES
.Bl -tag -width /netbsd
.It Pa /netbsd
system name list
.El
.Sh SEE ALSO
.Xr w 1
.Sh HISTORY
The
.Nm
command appeared in
.Bx 3.0 .

126
usr.bin/w/w.1 Normal file
View File

@@ -0,0 +1,126 @@
.\" $NetBSD: w.1,v 1.18 2005/01/11 09:39:12 wiz Exp $
.\"
.\" Copyright (c) 1980, 1990, 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.
.\"
.\" @(#)w.1 8.1 (Berkeley) 6/6/93
.\"
.Dd January 11, 2005
.Dt W 1
.Os
.Sh NAME
.Nm w
.Nd who present users are and what they are doing
.Sh SYNOPSIS
.Nm
.Op Fl hinw
.Op Fl M Ar core
.Op Fl N Ar system
.Op Ar user
.Sh DESCRIPTION
The
.Nm
utility prints a summary of the current activity on the system,
including what each user is doing.
The first line displays the current time of day, how long the system has
been running, the number of users logged into the system, and the load
averages.
The load average numbers give the number of jobs in the run queue averaged
over 1, 5, and 15 minutes.
.Pp
The fields output are the user's login name, the name of the terminal the
user is on, the host from which the user is logged in, the time the user
logged on, the time since the user last typed anything,
and the name and arguments of the current process.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl h
Suppress the heading.
.It Fl i
Output is sorted by idle time.
.It Fl M
Extract values associated with the name list from the specified
core instead of the default
.Dq /dev/kmem .
.It Fl N
Extract the name list from the specified system instead of the
default
.Dq /netbsd .
.It Fl n
Show network addresses as numbers (normally
.Nm
interprets addresses and attempts to display them symbolically).
.It Fl w
Show wide output without truncating any fields.
.El
.Pp
If a
.Ar user
name is specified, the output is restricted to that user.
.Sh FILES
.Bl -tag -width /var/run/utmp -compact
.It Pa /var/run/utmp
list of users on the system
.El
.Sh SEE ALSO
.Xr finger 1 ,
.Xr ps 1 ,
.Xr uptime 1 ,
.Xr who 1
.Sh HISTORY
The
.Nm
command appeared in
.Bx 3.0 .
.Sh BUGS
The notion of the
.Dq current process
is muddy.
The current algorithm is ``the highest numbered process on the terminal
that is not ignoring interrupts, or, if there is none, the highest numbered
process on the terminal''.
This fails, for example, in critical sections of programs like the shell
and editor, or when faulty programs running in the background fork and fail
to ignore interrupts.
(In cases where no process can be found,
.Nm
prints
.Dq \- . )
.Pp
Background processes are not shown, even though they account for
much of the load on the system.
.Pp
Sometimes processes, typically those in the background, are printed with
null or garbaged arguments.
In these cases, the name of the command is printed in parentheses.
.Pp
The
.Nm
utility does not know about the new conventions for detection of background
jobs.
It will sometimes find a background job instead of the right one.

692
usr.bin/w/w.c Normal file
View File

@@ -0,0 +1,692 @@
/* $NetBSD: w.c,v 1.77 2013/09/09 19:20:38 christos Exp $ */
/*-
* Copyright (c) 1980, 1991, 1993, 1994
* 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.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993, 1994\
The Regents of the University of California. All rights reserved.");
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)w.c 8.6 (Berkeley) 6/30/94";
#else
__RCSID("$NetBSD: w.c,v 1.77 2013/09/09 19:20:38 christos Exp $");
#endif
#endif /* not lint */
/*
* w - print system status (who and what)
*
* This program is similar to the systat command on Tenex/Tops 10/20
*
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <netdb.h>
#include <nlist.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
#ifdef SUPPORT_UTMP
#include <utmp.h>
#endif
#ifdef SUPPORT_UTMPX
#include <utmpx.h>
#endif
#include <vis.h>
#include "extern.h"
#ifdef __minix
/* MINIX3 note: please see this header for information about the port. */
#include "minix_proc.h"
#endif /* __minix */
struct timeval boottime;
struct winsize ws;
kvm_t *kd;
time_t now; /* the current time of day */
int ttywidth; /* width of tty */
int argwidth; /* width of tty left to print process args */
int header = 1; /* true if -h flag: don't print heading */
int nflag; /* true if -n flag: don't convert addrs */
int wflag; /* true if -w flag: wide printout */
int sortidle; /* sort bu idle time */
char *sel_user; /* login of particular user selected */
char domain[MAXHOSTNAMELEN + 1];
int maxname = 8, maxline = 3, maxhost = 16;
/*
* One of these per active utmp entry.
*/
struct entry {
struct entry *next;
char name[UTX_USERSIZE + 1];
char line[UTX_LINESIZE + 1];
char host[UTX_HOSTSIZE + 1];
char type[2];
struct timeval tv;
dev_t tdev; /* dev_t of terminal */
time_t idle; /* idle time of terminal in seconds */
struct kinfo_proc2 *tp; /* `most interesting' tty proc */
struct kinfo_proc2 *pp; /* pid proc */
pid_t pid; /* pid or ~0 if not known */
} *ehead = NULL, **nextp = &ehead;
static void pr_args(struct kinfo_proc2 *);
static void pr_header(time_t *, int);
#ifndef __minix
static int proc_compare_wrapper(const struct kinfo_proc2 *,
const struct kinfo_proc2 *);
#endif /* !__minix */
#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
static int ttystat(const char *, struct stat *);
static void process(struct entry *);
#endif
static void fixhost(struct entry *ep);
__dead static void usage(int);
int
main(int argc, char **argv)
{
struct kinfo_proc2 *kp;
struct entry *ep;
int ch, i, nentries, nusers, wcmd, curtain, use_sysctl;
char *memf, *nlistf, *usrnp;
const char *options;
time_t then;
#ifndef __minix
size_t len;
#endif /* !__minix */
#ifdef SUPPORT_UTMP
struct utmp *ut;
#endif
#ifdef SUPPORT_UTMPX
struct utmpx *utx;
#endif
const char *progname;
#ifndef __minix
char errbuf[_POSIX2_LINE_MAX];
#endif /* !__minix */
setprogname(argv[0]);
/* Are we w(1) or uptime(1)? */
progname = getprogname();
if (*progname == '-')
progname++;
if (*progname == 'u') {
wcmd = 0;
options = "";
} else {
wcmd = 1;
options = "hiM:N:nw";
}
memf = nlistf = NULL;
while ((ch = getopt(argc, argv, options)) != -1)
switch (ch) {
case 'h':
header = 0;
break;
case 'i':
sortidle = 1;
break;
case 'M':
header = 0;
memf = optarg;
break;
case 'N':
nlistf = optarg;
break;
case 'n':
nflag = 1;
break;
case 'w':
wflag = 1;
break;
case '?':
default:
usage(wcmd);
}
argc -= optind;
argv += optind;
use_sysctl = (memf == NULL && nlistf == NULL);
#ifndef __minix
if ((kd = kvm_openfiles(nlistf, memf, NULL,
memf == NULL ? KVM_NO_FILES : O_RDONLY, errbuf)) == NULL)
errx(1, "%s", errbuf);
#else
if (!use_sysctl)
errx(1, "The -M and -N flags are not supported on MINIX3.");
kd = NULL;
#endif /* __minix */
(void)time(&now);
if (use_sysctl) {
#ifndef __minix
len = sizeof(curtain);
if (sysctlbyname("security.curtain", &curtain, &len,
NULL, 0) == -1)
#endif /* !__minix */
curtain = 0;
}
#ifdef SUPPORT_UTMPX
setutxent();
#endif
#ifdef SUPPORT_UTMP
setutent();
#endif
if (*argv)
sel_user = *argv;
nusers = 0;
#ifdef SUPPORT_UTMPX
while ((utx = getutxent()) != NULL) {
if (utx->ut_type != USER_PROCESS)
continue;
++nusers;
if (sel_user &&
strncmp(utx->ut_name, sel_user, sizeof(utx->ut_name)) != 0)
continue;
if ((ep = calloc(1, sizeof(struct entry))) == NULL)
err(1, NULL);
(void)memcpy(ep->name, utx->ut_name, sizeof(utx->ut_name));
(void)memcpy(ep->line, utx->ut_line, sizeof(utx->ut_line));
ep->name[sizeof(utx->ut_name)] = '\0';
ep->line[sizeof(utx->ut_line)] = '\0';
if (!nflag || getnameinfo((struct sockaddr *)&utx->ut_ss,
utx->ut_ss.ss_len, ep->host, sizeof(ep->host), NULL, 0,
NI_NUMERICHOST) != 0) {
(void)memcpy(ep->host, utx->ut_host,
sizeof(utx->ut_host));
ep->host[sizeof(utx->ut_host)] = '\0';
}
fixhost(ep);
ep->type[0] = 'x';
ep->tv = utx->ut_tv;
ep->pid = utx->ut_pid;
*nextp = ep;
nextp = &(ep->next);
if (wcmd != 0)
process(ep);
}
#endif
#ifdef SUPPORT_UTMP
while ((ut = getutent()) != NULL) {
if (ut->ut_name[0] == '\0')
continue;
if (sel_user &&
strncmp(ut->ut_name, sel_user, sizeof(ut->ut_name)) != 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;
++nusers;
if ((ep = calloc(1, sizeof(struct entry))) == NULL)
err(1, NULL);
(void)memcpy(ep->name, ut->ut_name, sizeof(ut->ut_name));
(void)memcpy(ep->line, ut->ut_line, sizeof(ut->ut_line));
(void)memcpy(ep->host, ut->ut_host, sizeof(ut->ut_host));
ep->name[sizeof(ut->ut_name)] = '\0';
ep->line[sizeof(ut->ut_line)] = '\0';
ep->host[sizeof(ut->ut_host)] = '\0';
fixhost(ep);
ep->tv.tv_sec = ut->ut_time;
*nextp = ep;
nextp = &(ep->next);
if (wcmd != 0)
process(ep);
}
#endif
#ifdef SUPPORT_UTMPX
endutxent();
#endif
#ifdef SUPPORT_UTMP
endutent();
#endif
if (header || wcmd == 0) {
pr_header(&now, nusers);
if (wcmd == 0)
exit (0);
}
if ((kp = kvm_getproc2(kd, KERN_PROC_ALL, 0,
sizeof(struct kinfo_proc2), &nentries)) == NULL)
errx(1, "%s", kvm_geterr(kd));
/* Include trailing space because TTY header starts one column early. */
for (i = 0; i < nentries; i++, kp++) {
for (ep = ehead; ep != NULL; ep = ep->next) {
if (ep->tdev != 0 && ep->tdev == kp->p_tdev &&
kp->p__pgid == kp->p_tpgid) {
/*
* Proc is in foreground of this
* terminal
*/
if (proc_compare_wrapper(ep->tp, kp))
ep->tp = kp;
break;
}
if (ep->pid != 0 && ep->pid == kp->p_pid) {
ep->pp = kp;
break;
}
}
}
if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 &&
ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 &&
ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0)
ttywidth = 79;
else
ttywidth = ws.ws_col - 1;
if (!wflag && maxhost > (ttywidth / 3))
maxhost = ttywidth / 3;
argwidth = printf("%-*s TTY %-*s %*s IDLE WHAT\n",
maxname, "USER", maxhost, "FROM",
7 /* "dddhhXm" */, "LOGIN@");
argwidth -= sizeof("WHAT\n") - 1 /* NUL */;
argwidth = ttywidth - argwidth;
if (argwidth < 4)
argwidth = 8;
if (wflag)
argwidth = -1;
/* sort by idle time */
if (sortidle && ehead != NULL) {
struct entry *from = ehead, *save;
ehead = NULL;
while (from != NULL) {
for (nextp = &ehead;
(*nextp) && from->idle >= (*nextp)->idle;
nextp = &(*nextp)->next)
continue;
save = from;
from = from->next;
save->next = *nextp;
*nextp = save;
}
}
#if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX)
else if (ehead != NULL) {
struct entry *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;
}
}
#endif
if (!nflag) {
int rv;
char *p;
rv = gethostname(domain, sizeof(domain));
domain[sizeof(domain) - 1] = '\0';
if (rv < 0 || (p = strchr(domain, '.')) == 0)
domain[0] = '\0';
else
memmove(domain, p, strlen(p) + 1);
}
for (ep = ehead; ep != NULL; ep = ep->next) {
if (ep->tp != NULL)
kp = ep->tp;
else if (ep->pp != NULL)
kp = ep->pp;
else if (ep->pid != 0) {
if (curtain)
kp = NULL;
else {
warnx("Stale utmp%s entry: %s %s %s",
ep->type, ep->name, ep->line, ep->host);
continue;
}
}
#ifndef __minix
usrnp = (kp == NULL) ? ep->name : kp->p_login;
#else
usrnp = ep->name; /* TODO: implement getlogin/setlogin */
#endif /* __minix */
(void)printf("%-*s %-7.7s %-*.*s ",
maxname, usrnp, ep->line,
maxhost, maxhost, ep->host);
then = (time_t)ep->tv.tv_sec;
pr_attime(&then, &now);
pr_idle(ep->idle);
pr_args(kp);
(void)printf("\n");
}
exit(0);
}
static void
pr_args(struct kinfo_proc2 *kp)
{
char **argv;
int left;
if (kp == 0)
goto nothing;
left = argwidth;
argv = kvm_getargv2(kd, kp, (argwidth < 0) ? 0 : argwidth);
if (argv == 0) {
if (kp->p_comm == 0) {
goto nothing;
} else {
fmt_putc('(', &left);
fmt_puts((char *)kp->p_comm, &left);
fmt_putc(')', &left);
return;
}
}
while (*argv) {
fmt_puts(*argv, &left);
argv++;
fmt_putc(' ', &left);
}
return;
nothing:
putchar('-');
}
static void
pr_header(time_t *nowp, int nusers)
{
double avenrun[3];
time_t uptime;
int days, hrs, mins;
int mib[2];
size_t size, i;
char buf[256];
/*
* Print time of day.
*
* SCCS forces the string manipulation below, as it replaces
* %, M, and % in a character string with the file name.
*/
(void)strftime(buf, sizeof(buf), "%l:%" "M%p", localtime(nowp));
buf[sizeof(buf) - 1] = '\0';
(void)printf("%s ", buf);
/*
* Print how long system has been up.
* (Found by looking getting "boottime" from the kernel)
*/
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
size = sizeof(boottime);
if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
boottime.tv_sec != 0) {
uptime = now - boottime.tv_sec;
uptime += 30;
if (uptime > SECSPERMIN) {
days = uptime / SECSPERDAY;
uptime %= SECSPERDAY;
hrs = uptime / SECSPERHOUR;
uptime %= SECSPERHOUR;
mins = uptime / SECSPERMIN;
(void)printf(" up");
if (days > 0)
(void)printf(" %d day%s,", days,
days > 1 ? "s" : "");
if (hrs > 0 && mins > 0)
(void)printf(" %2d:%02d,", hrs, mins);
else {
if (hrs > 0)
(void)printf(" %d hr%s,",
hrs, hrs > 1 ? "s" : "");
if (mins > 0)
(void)printf(" %d min%s,",
mins, mins > 1 ? "s" : "");
}
}
}
/* Print number of users logged in to system */
(void)printf(" %d user%s", nusers, nusers != 1 ? "s" : "");
/*
* Print 1, 5, and 15 minute load averages.
*/
if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1)
(void)printf(", no load average information available\n");
else {
(void)printf(", load averages:");
for (i = 0; i < (sizeof(avenrun) / sizeof(avenrun[0])); i++) {
if (i > 0)
(void)printf(",");
(void)printf(" %.2f", avenrun[i]);
}
(void)printf("\n");
}
}
#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
static int
ttystat(const char *line, struct stat *st)
{
char ttybuf[MAXPATHLEN];
(void)snprintf(ttybuf, sizeof(ttybuf), "%s%s", _PATH_DEV, line);
return stat(ttybuf, st);
}
static void
process(struct entry *ep)
{
struct stat st;
time_t touched;
int max;
if ((max = strlen(ep->name)) > maxname)
maxname = max;
if ((max = strlen(ep->line)) > maxline)
maxline = max;
if ((max = strlen(ep->host)) > maxhost)
maxhost = max;
ep->tdev = 0;
ep->idle = (time_t)-1;
#ifdef SUPPORT_UTMP
/*
* Hack to recognize and correctly parse
* ut entry made by ftpd. The "tty" used
* by ftpd is not a real tty, just identifier in
* form ftpPID. Pid parsed from the "tty name"
* is used later to match corresponding process.
* NB: This is only used for utmp entries. For utmpx,
* we already have the pid.
*/
if (ep->pid == 0 && strncmp(ep->line, "ftp", 3) == 0) {
ep->pid = strtol(ep->line + 3, NULL, 10);
return;
}
#endif
if (ttystat(ep->line, &st) == -1)
return;
ep->tdev = st.st_rdev;
/*
* If this is the console device, attempt to ascertain
* the true console device dev_t.
*/
if (ep->tdev == 0) {
int mib[2];
size_t size;
mib[0] = CTL_KERN;
mib[1] = KERN_CONSDEV;
size = sizeof(dev_t);
(void) sysctl(mib, 2, &ep->tdev, &size, NULL, 0);
}
touched = st.st_atime;
if (touched < ep->tv.tv_sec) {
/* tty untouched since before login */
touched = ep->tv.tv_sec;
}
if ((ep->idle = now - touched) < 0)
ep->idle = 0;
}
#endif
#ifndef __minix
static int
proc_compare_wrapper(const struct kinfo_proc2 *p1,
const struct kinfo_proc2 *p2)
{
struct kinfo_lwp *l1, *l2;
int cnt;
if (p1 == NULL)
return 1;
l1 = kvm_getlwps(kd, p1->p_pid, 0, sizeof(*l1), &cnt);
if (l1 == NULL || cnt == 0)
return 1;
l2 = kvm_getlwps(kd, p2->p_pid, 0, sizeof(*l1), &cnt);
if (l2 == NULL || cnt == 0)
return 0;
return proc_compare(p1, l1, p2, l2);
}
#endif /* !__minix */
static void
fixhost(struct entry *ep)
{
char host_buf[sizeof(ep->host)];
char *p, *x;
struct hostent *hp;
struct in_addr l;
strlcpy(host_buf, *ep->host ? ep->host : "-", sizeof(host_buf));
p = host_buf;
/*
* XXX: Historical behavior, ':' in hostname means X display number,
* IPv6 not handled.
*/
for (x = p; x < &host_buf[sizeof(host_buf)]; x++)
if (*x == '\0' || *x == ':')
break;
if (x == p + sizeof(host_buf) || *x != ':')
x = NULL;
else
*x++ = '\0';
if (!nflag && inet_aton(p, &l) &&
(hp = gethostbyaddr((char *)&l, sizeof(l), AF_INET))) {
if (domain[0] != '\0') {
p = hp->h_name;
p += strlen(hp->h_name);
p -= strlen(domain);
if (p > hp->h_name &&
strcasecmp(p, domain) == 0)
*p = '\0';
}
p = hp->h_name;
}
if (x)
(void)snprintf(ep->host, sizeof(ep->host), "%s:%s", p, x);
else
strlcpy(ep->host, p, sizeof(ep->host));
}
static void
usage(int wcmd)
{
if (wcmd)
(void)fprintf(stderr,
"Usage: %s [-hinw] [-M core] [-N system] [user]\n",
getprogname());
else
(void)fprintf(stderr, "Usage: %s\n", getprogname());
exit(1);
}