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

98
bin/ps/extern.h Normal file
View file

@ -0,0 +1,98 @@
/* $NetBSD: extern.h,v 1.33 2010/05/31 03:18:33 rmind Exp $ */
/*-
* Copyright (c) 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.
*
* @(#)extern.h 8.3 (Berkeley) 4/2/94
*/
/*
* We expect to be included by ps.h, which will already have
* defined the types we use.
*/
extern double ccpu;
extern int eval, fscale, mempages, nlistread, rawcpu, maxslp, uspace;
extern int sumrusage, termwidth, totwidth;
extern int needenv, needcomm, commandonly;
extern uid_t myuid;
extern kvm_t *kd;
extern VAR var[];
extern VARLIST displaylist;
extern VARLIST sortlist;
void command(void *, VARENT *, int);
void cpuid(void *, VARENT *, int);
void cputime(void *, VARENT *, int);
int donlist(void);
int donlist_sysctl(void);
void fmt_puts(char *, int *);
void fmt_putc(int, int *);
void elapsed(void *, VARENT *, int);
double getpcpu(const struct kinfo_proc2 *);
double getpmem(const struct kinfo_proc2 *);
void gname(void *, VARENT *, int);
void groups(void *, VARENT *, int);
void groupnames(void *, VARENT *, int);
void logname(void *, VARENT *, int);
void longtname(void *, VARENT *, int);
void lname(void *, VARENT *, int);
void lstarted(void *, VARENT *, int);
void lstate(void *, VARENT *, int);
void maxrss(void *, VARENT *, int);
void nlisterr(struct nlist *);
void p_rssize(void *, VARENT *, int);
void pagein(void *, VARENT *, int);
void parsefmt(const char *);
void parsefmt_insert(const char *, VARENT **);
void parsesort(const char *);
VARENT * varlist_find(VARLIST *, const char *);
void emul(void *, VARENT *, int);
void pcpu(void *, VARENT *, int);
void pmem(void *, VARENT *, int);
void pnice(void *, VARENT *, int);
void pri(void *, VARENT *, int);
void printheader(void);
void putimeval(void *, VARENT *, int);
void pvar(void *, VARENT *, int);
void rgname(void *, VARENT *, int);
void rssize(void *, VARENT *, int);
void runame(void *, VARENT *, int);
void showkey(void);
void started(void *, VARENT *, int);
void state(void *, VARENT *, int);
void svgname(void *, VARENT *, int);
void svuname(void *, VARENT *, int);
void tdev(void *, VARENT *, int);
void tname(void *, VARENT *, int);
void tsize(void *, VARENT *, int);
void ucomm(void *, VARENT *, int);
void uname(void *, VARENT *, int);
void uvar(void *, VARENT *, int);
void vsize(void *, VARENT *, int);
void wchan(void *, VARENT *, int);

60
bin/ps/fmt.c Normal file
View file

@ -0,0 +1,60 @@
/* $NetBSD: fmt.c,v 1.21 2007/12/12 22:55:43 lukem Exp $ */
#include <sys/cdefs.h>
__RCSID("$NetBSD: fmt.c,v 1.21 2007/12/12 22:55:43 lukem Exp $");
#include <kvm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vis.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "ps.h"
void
fmt_puts(char *s, int *leftp)
{
static char *v = 0;
static int maxlen = 0;
char *nv;
int len, nlen;
if (*leftp == 0)
return;
len = strlen(s) * 4 + 1;
if (len > maxlen) {
if (maxlen == 0)
nlen = getpagesize();
else
nlen = maxlen;
while (len > nlen)
nlen *= 2;
nv = realloc(v, nlen);
if (nv == 0)
return;
v = nv;
maxlen = nlen;
}
len = strvis(v, s, VIS_TAB | VIS_NL | VIS_CSTYLE);
if (*leftp != -1) {
if (len > *leftp) {
v[*leftp] = '\0';
*leftp = 0;
} else
*leftp -= len;
}
(void)printf("%s", v);
}
void
fmt_putc(int c, int *leftp)
{
if (*leftp == 0)
return;
if (*leftp != -1)
*leftp -= 1;
putchar(c);
}

94
bin/ps/ps.h Normal file
View file

@ -0,0 +1,94 @@
/* $NetBSD: ps.h,v 1.26 2006/10/02 17:54:35 apb Exp $ */
/*-
* Copyright (c) 1990, 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.
*
* @(#)ps.h 8.1 (Berkeley) 5/31/93
*/
#include <sys/queue.h>
#define UNLIMITED 0 /* unlimited terminal width */
#define PRINTMODE 0 /* print values */
#define WIDTHMODE 1 /* determine width of column */
enum type {
UNSPECIFIED,
CHAR, UCHAR, SHORT, USHORT, INT, UINT, LONG, ULONG,
KPTR, KPTR24, INT32, UINT32, SIGLIST, INT64, UINT64,
TIMEVAL, CPUTIME, PCPU, VSIZE
};
/* Variables. */
typedef SIMPLEQ_HEAD(varlist, varent) VARLIST;
typedef struct varent {
SIMPLEQ_ENTRY(varent) next;
struct var *var;
} VARENT;
typedef struct var {
const char *name; /* name(s) of variable */
const char *header; /* header, possibly changed from default */
#define COMM 0x01 /* needs exec arguments and environment (XXX) */
#define ARGV0 0x02 /* only print argv[0] */
#define LJUST 0x04 /* left adjust on output (trailing blanks) */
#define INF127 0x08 /* 127 = infinity: if > 127, print 127. */
#define LWP 0x10 /* dispatch to kinfo_lwp routine */
#define UAREA 0x20 /* need to check p_uvalid */
#define ALIAS 0x40 /* entry is alias for 'header' */
u_int flag;
/* output routine */
void (*oproc)(void *, struct varent *, int);
/*
* The following (optional) elements are hooks for passing information
* to the generic output routine: pvar (that which prints simple
* elements from struct kinfo_proc2).
*/
int off; /* offset in structure */
enum type type; /* type of element */
const char *fmt; /* printf format */
/* current longest element */
int width; /* printing width */
int64_t longestp; /* longest positive signed value */
int64_t longestn; /* longest negative signed value */
u_int64_t longestu; /* longest unsigned value */
double longestpd; /* longest positive double */
double longestnd; /* longest negative double */
} VAR;
#define OUTPUT(vent, ki, kl, mode) do { \
if ((vent)->var->flag & LWP) \
((vent)->var->oproc)((void *)(kl), (vent), (mode)); \
else \
((vent)->var->oproc)((void *)(ki), (vent), (mode)); \
} while (/*CONSTCOND*/ 0)
#include "extern.h"

View file

@ -538,6 +538,7 @@
./usr/bin/unxz minix-sys ./usr/bin/unxz minix-sys
./usr/bin/unzip minix-sys ./usr/bin/unzip minix-sys
./usr/bin/update minix-sys ./usr/bin/update minix-sys
./usr/bin/uptime minix-sys
./usr/bin/users minix-sys ./usr/bin/users minix-sys
./usr/bin/uud minix-sys ./usr/bin/uud minix-sys
./usr/bin/uudecode minix-sys ./usr/bin/uudecode minix-sys
@ -549,6 +550,7 @@
./usr/bin/view minix-sys ./usr/bin/view minix-sys
./usr/bin/vis minix-sys ./usr/bin/vis minix-sys
./usr/bin/vol minix-sys ./usr/bin/vol minix-sys
./usr/bin/w minix-sys
./usr/bin/wall minix-sys ./usr/bin/wall minix-sys
./usr/bin/wc minix-sys ./usr/bin/wc minix-sys
./usr/bin/what minix-sys ./usr/bin/what minix-sys
@ -2529,6 +2531,7 @@
./usr/man/man1/unvis.1 minix-sys ./usr/man/man1/unvis.1 minix-sys
./usr/man/man1/unxz.1 minix-sys ./usr/man/man1/unxz.1 minix-sys
./usr/man/man1/unzip.1 minix-sys ./usr/man/man1/unzip.1 minix-sys
./usr/man/man1/uptime.1 minix-sys
./usr/man/man1/users.1 minix-sys ./usr/man/man1/users.1 minix-sys
./usr/man/man1/uud.1 minix-sys ./usr/man/man1/uud.1 minix-sys
./usr/man/man1/uue.1 minix-sys ./usr/man/man1/uue.1 minix-sys
@ -2537,6 +2540,7 @@
./usr/man/man1/view.1 minix-sys ./usr/man/man1/view.1 minix-sys
./usr/man/man1/vis.1 minix-sys ./usr/man/man1/vis.1 minix-sys
./usr/man/man1/vol.1 minix-sys ./usr/man/man1/vol.1 minix-sys
./usr/man/man1/w.1 minix-sys
./usr/man/man1/wait.1 minix-sys ./usr/man/man1/wait.1 minix-sys
./usr/man/man1/wall.1 minix-sys ./usr/man/man1/wall.1 minix-sys
./usr/man/man1/wc.1 minix-sys ./usr/man/man1/wc.1 minix-sys

View file

@ -0,0 +1,253 @@
/* MINIX3 implementations of a subset of some BSD-kernel-specific functions. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <sys/sysctl.h> /* for KERN_PROC_ */
#include <minix/paths.h>
#include <minix/procfs.h>
#include "minix_proc.h"
/*
* Parse a procfs psinfo file, and fill the given minix_proc structure with the
* results. Return 1 on success, or 0 if this process should be skipped.
*/
static int
parse_psinfo(FILE *fp, int op, int __unused arg, pid_t pid,
struct minix_proc *p)
{
char type, state, pstate, name[256];
unsigned int uid, pgrp, dev;
int version;
assert(op == KERN_PROC_ALL); /* this is all we support right now */
if (fscanf(fp, "%d", &version) != 1 || version != PSINFO_VERSION)
return 0;
if (fscanf(fp, " %c %*d %255s %c %*d %*d %*u %*u %*u %*u",
&type, name, &state) != 3)
return 0;
if (type != TYPE_USER)
return 0; /* user processes only */
if (fscanf(fp, " %*u %*u %*u %c %*d %u %*u %u %*d %*c %*d %u",
&pstate, &uid, &pgrp, &dev) != 4)
return 0;
/* The fields as expected by the main w(1) code. */
p->p_pid = pid;
p->p__pgid = (pid_t)pgrp;
p->p_tpgid = (dev != 0) ? (pid_t)pgrp : 0;
p->p_tdev = (dev_t)dev;
strlcpy(p->p_comm, name, sizeof(p->p_comm));
/* Some fields we need for ranking ("sorting") processes later. */
p->p_minix_state = state;
p->p_minix_pstate = pstate;
return 1;
}
/*
* The w(1)-specific implementation of kvm_getproc2. Return an array of
* process information structures (of type minix_proc), along with the number
* of processes in the resulting array. Return NULL on failure, in which case
* errno should be set to something meaningful.
*/
struct minix_proc *
minix_getproc(void * __unused dummy, int op, int arg, int elemsize, int *cnt)
{
struct minix_proc *procs;
char path[PATH_MAX];
DIR *dp;
FILE *fp;
struct dirent *de;
pid_t pid, *pids;
unsigned int i, npids, size;
int e;
assert(elemsize == sizeof(struct minix_proc));
/*
* First see how much memory we will need in order to store the actual
* process data. We store the PIDs in a (relatively small) allocated
* memory area immediately, so that we don't have to reiterate through
* the /proc directory twice.
*/
if ((dp = opendir(_PATH_PROC)) == NULL)
return NULL;
if ((pids = malloc(size = sizeof(pid_t) * 64)) == NULL) {
e = errno;
closedir(dp);
errno = e;
return NULL;
}
npids = 0;
while ((de = readdir(dp)) != NULL) {
if ((pid = (pid_t)atoi(de->d_name)) > 0) {
if (sizeof(pid_t) * npids == size &&
(pids = realloc(pids, size *= 2)) == NULL)
break;
pids[npids++] = pid;
}
}
closedir(dp);
/* No results, or out of memory? Then bail out. */
if (npids == 0 || pids == NULL) {
if (pids != NULL) {
e = errno;
free(pids);
errno = e;
} else
errno = ENOENT; /* no processes found */
return NULL;
}
/* Now obtain actual process data for the PIDs we obtained. */
if ((procs = malloc(sizeof(struct minix_proc) * npids)) == NULL) {
e = errno;
free(pids);
errno = e;
return NULL;
}
*cnt = 0;
for (i = 0; i < npids; i++) {
pid = pids[i];
snprintf(path, sizeof(path), _PATH_PROC "/%u/psinfo", pid);
/* Processes may legitimately disappear between calls. */
if ((fp = fopen(path, "r")) == NULL)
continue;
if (parse_psinfo(fp, op, arg, pid, &procs[*cnt]))
(*cnt)++;
fclose(fp);
}
free(pids);
/* The returned data is not freed, but we are called only once. */
return procs;
}
/*
* A w(1)-specific MINIX3 implementation of kvm_getargv2. Return an array of
* strings representing the command line of the given process, optionally (if
* not 0) limited to a number of printable characters if the arguments were
* to be printed with a space in between. Return NULL on failure. Since the
* caller will not use earlier results after calling this function again, we
* can safely return static results.
*/
char **
minix_getargv(void * __unused dummy, const struct minix_proc * p, int nchr)
{
#define MAX_ARGS 32
static char *argv[MAX_ARGS+1], buf[4096];
char path[PATH_MAX];
ssize_t i, bytes;
int fd, argc;
/* Get the command line of the process from procfs. */
snprintf(path, sizeof(path), _PATH_PROC "/%u/cmdline", p->p_pid);
if ((fd = open(path, O_RDONLY)) < 0)
return NULL;
bytes = read(fd, buf, sizeof(buf));
close(fd);
if (bytes <= 0)
return NULL;
/*
* Construct an array of arguments. Stop whenever we run out of bytes
* or printable characters (simply counting the null characters as
* spaces), or whenever we fill up our argument array. Note that this
* is security-sensitive code, as it effectively processes (mostly-)
* arbitrary input from other users.
*/
bytes--; /* buffer should/will be null terminated */
if (nchr != 0 && bytes > nchr)
bytes = nchr;
argc = 0;
for (i = 0; i < bytes && argc < MAX_ARGS; i++) {
if (i == 0 || buf[i-1] == 0)
argv[argc++] = &buf[i];
}
buf[i] = 0;
argv[argc] = NULL;
return argv;
}
/*
* A w(1)-specific implementation of proc_compare_wrapper. Return 0 if the
* first given process is more worthy of being shown as the representative
* process of what a user is doing, or 1 for the second process. Since procfs
* currently does not expose enough information to do this well, we use some
* very basic heuristics, and leave a proper implementation to future work.
*/
int
minix_proc_compare(const struct minix_proc * p1, const struct minix_proc * p2)
{
static const int state_prio[] = /* best to worst */
{ STATE_RUN, STATE_WAIT, STATE_SLEEP, STATE_STOP, STATE_ZOMBIE };
unsigned int i;
int sp1 = -1, sp2 = -1;
if (p1 == NULL) return 1;
if (p2 == NULL) return 0;
/*
* Pick any runnable candidate over a waiting candidate, any waiting
* candidate over a sleeping candidate, etcetera. The rationale is
* roughly as follows: runnable means that something is definitely
* happening; waiting means that probably something interesting is
* happening, which eliminates e.g. shells; sleeping means that not
* much is going on; stopped and zombified means that definitely
* nothing is going on.
*/
for (i = 0; i < sizeof(state_prio) / sizeof(state_prio[0]); i++) {
if (p1->p_minix_state == state_prio[i]) sp1 = i;
if (p2->p_minix_state == state_prio[i]) sp2 = i;
}
if (sp1 != sp2)
return (sp1 > sp2);
/*
* Pick any non-PM-sleeping process over any PM-sleeping process.
* Here the rationale is that PM-sleeping processes are typically
* waiting for another process, which means that the other process is
* probably more worthy of reporting. Again, the shell is an example
* of a process we'd rather not report if there's something else.
*/
if (sp1 == STATE_SLEEP) {
if (p1->p_minix_pstate != PSTATE_NONE) return 1;
if (p2->p_minix_pstate != PSTATE_NONE) return 0;
}
/*
* Pick the candidate with the largest PID. The rationale is that
* statistically that will most likely yield the most recently spawned
* process, which makes it the most interesting process as well.
*/
return p1->p_pid < p2->p_pid;
}

View file

@ -0,0 +1,47 @@
#ifndef _W_MINIX_PROC_H
#define _W_MINIX_PROC_H
/*
* This header file is tailored very specifically to the needs of w(1), which
* needs process information but uses a BSD infrastructure (namely, the Kernel
* Data Access Library or, eh, KVM.. huh?) which we cannot implement in MINIX3
* without making a very, very large number of changes all over the place.
*
* In order to allow w(1) to function on MINIX3, we override some of the KVM
* functionality with MINIX3 implementations, by means of #defines. While that
* is indeed butt ugly, this approach does have advantages: we are able to
* implement the full expected functionality with minimal changes to w(1)
* itself, and whenever w(1) uses a KVM function or a process information field
* that this header does not supply, w(1) will break during compilation.
*/
struct minix_proc {
pid_t p_pid; /* process ID */
pid_t p__pgid; /* process group ID */
pid_t p_tpgid; /* tty process group ID (= p_pgid or 0) */
dev_t p_tdev; /* controlling terminal (= tty rdev or 0) */
char p_minix_state; /* minix specific: process kernel state */
char p_minix_pstate; /* minix specific: process PM state */
char p_comm[256]; /* simple command line (= process name) */
};
#undef kinfo_proc2
#define kinfo_proc2 minix_proc
struct minix_proc *minix_getproc(void *dummy, int op, int arg, int elemsize,
int *cnt);
#undef kvm_getproc2
#define kvm_getproc2 minix_getproc
#undef kvm_geterr
#define kvm_geterr(dummy) strerror(errno)
char **minix_getargv(void *dummy, const struct minix_proc *p, int nchr);
#undef kvm_getargv2
#define kvm_getargv2 minix_getargv
int minix_proc_compare(const struct minix_proc *p1,
const struct minix_proc *p2);
#undef proc_compare_wrapper
#define proc_compare_wrapper minix_proc_compare
#endif /* !_W_MINIX_PROC_H */

View file

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