Subject: better w(1)
To: None <current-users@netbsd.org>
From: Darren Reed <darrenr@reed.wattle.id.au>
List: current-users
Date: 06/20/1999 23:04:21
Years ago I rewrote w(1) to show users that were `hidden' care of xterm
and screen. Recently I ported that to NetBSD-1.4, including taking the
time to make the appropriate changes in output. The result could be
put in place of the current w except that it's probably slower (not using
utmp means more work has to be done) and may(?) do something strange on
some ports (I can only test i386/arm32). For those who remember what
w(1) used to show, I added a "-1" command line option. Please test out
the code below. To compile, save it as "ww.c" and do as follows:
cc ww.c /usr/src/usr.bin/w/pr_time.c -o ww -lkvm
Oh, it still needs to run as root (setuid if you want to use it for more
than testing).
I'm interested in hearing from anyone with comments bugs/criticisms, etc.
Suitable as a wholesale replacement for the current w(1) ?
Cheers,
Darren
/*
* Copyright (C) 1994-1999 Darren Reed. avalon@coombs.anu.edu.au
* All rights reserved.
*/
#include <sys/types.h>
#include <sys/time.h>
#define _KERNEL
#define _LKM
#include <sys/signal.h>
#define _SYS_RESOURCE_H_
#include <sys/param.h>
#undef _SYS_RESOURCE_H_
#include <sys/proc.h>
#include <sys/ucred.h>
#include <sys/file.h>
#include <sys/resource.h>
#include <sys/user.h>
#include <vm/vm_param.h>
#undef _KERNEL
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <sys/tty.h>
#include <sys/socket.h>
#include <dev/cons.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <pwd.h>
#include <paths.h>
#include <nlist.h>
#include <kvm.h>
#include <fcntl.h>
#include <stdio.h>
#include <netdb.h>
#include <utmp.h>
#include <ttyent.h>
#define memset(a,b,c) bzero(a,c)
#define strrchr rindex
extern char *optarg;
extern int optind;
#ifndef MIN
# define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
# define MAX(a,b) (((a)>(b))?(a):(b))
#endif
#define OPT_DEBUG 0x01
#define OPT_NOHDR 0x02
#define OPT_LONG 0x04
#define OPT_NOUSERS 0x08
#define OPT_SMALL 0x10
#define OPT_V1 0x20
#define OPT_NORES 0x40
#define OPT_WIDE 0x80
struct nlist names[] = {
{ "_proc", 0, 0, 0, 0},
{ "_nproc", 0, 0, 0, 0},
{ "_avenrun", 0, 0, 0, 0},
{ "_boottime", 0, 0, 0, 0},
{ "_cn_tab", 0, 0, 0, 0},
#define NL_PROC 0
#define NL_NPROC 1
#define NL_LOADAV 2
#define NL_BOOT 3
#define NL_CONS 4
{ (char *)NULL, 0, 0, 0, 0 }
};
typedef struct Proc {
struct kinfo_proc *p_k;
struct proc *p_p;
struct user p_u;
struct pstats *p_us;
struct session p_s;
dev_t p_t;
int p_gotu;
} Proc;
static char obuff[8192];
static kvm_t *kptr = NULL;
static dev_t condev = 0;
static dev_t ttyp0 = 0;
static dev_t tty00 = 0;
static dev_t ttyE0 = 0;
static dev_t ttyv0 = 0;
static struct utmp *utblock = NULL,
*utblockend = NULL;
static char *kernel = _PATH_UNIX;
static char *core = _PATH_MEM;
static u_int utblocksz = 0;
static char domain[MAXHOSTNAMELEN];
void
fatal(status, msg)
int status;
char *msg;
{
perror(msg);
kill(getpid(), 11);
}
void
kvminit()
{
if (!kptr)
kptr = kvm_openfiles(kernel, core, _PATH_DRUM, O_RDONLY, "ww");
if (!kptr)
fatal(-1, "open kmem");
if (kvm_nlist(kptr, names) == -1)
fatal(1, "nlist");
}
void
kmemcpy(buf, pos, n)
char *buf;
u_long pos;
int n;
{
if (!n)
return;
if (kvm_read(kptr, pos, buf, n) != n) {
fprintf(stderr, "pos=%lx buf=%p n=%d\n", pos, buf, n);
fprintf(stderr, "kvm_read: %s\n", kvm_geterr(kptr));
fatal(-1, "kvm_read");
}
}
char *
leading(buf)
char *buf;
{
register char *s = buf;
while (*s && (*s != '0'))
*s++;
if (*s && (*(s-1) < '0' || *(s-1) > '9') && (*(s-1) != ':'))
while (*s == '0')
*s++ = ' ';
if ((*s >= '0' && *s <= '9') || !*s)
return buf;
if (*s == ':')
*s++ = ' ';
while (*s == '0')
*s++ = ' ';
return buf;
}
char *
printtime(now, login)
register time_t now;
time_t login;
{
static char tbuf[32];
register char *s;
register struct tm *tm;
if (login == 0)
return " -";
tm = localtime(&login);
(void) sprintf(tbuf, " %02d:%02d%cm",
(tm->tm_hour % 12) ? tm->tm_hour % 12 : 12,
tm->tm_min, (tm->tm_hour > 11) ? 'p' : 'a');
(void) leading(tbuf+1);
return tbuf;
}
char *
cputime(pp)
register struct Proc *pp;
{
static char longbuf[32];
register u_long tot1 = 0, tot2 = 0;
register struct rusage *r;
register long t1, t2;
if (pp->p_gotu == 1) {
r = &pp->p_us->p_ru;
tot2 = r->ru_utime.tv_sec + r->ru_stime.tv_sec;
t2 = r->ru_utime.tv_usec + r->ru_stime.tv_usec;
r = &pp->p_us->p_cru;
tot1 = r->ru_utime.tv_sec + r->ru_stime.tv_sec;
t1 = r->ru_utime.tv_usec + r->ru_stime.tv_usec;
tot1 += t1 / 1000000;
tot2 += t2 / 1000000;
tot1 += tot2;
}
(void) sprintf(longbuf, " %3d:%02d %3d:%02d",
tot1/60, tot1%60, tot2/60, tot2%60);
(void) leading(longbuf+1);
(void) leading(strrchr(longbuf,' ') + 1);
return longbuf;
}
int
sortproc(p1, p2)
Proc **p1, **p2;
{
register struct proc *pr1, *pr2;
register dev_t t1, t2;
register long d;
if (!*p1 && !*p2)
return 0;
else if (!*p1)
return 1;
else if (!*p2)
return -1;
pr1 = (*p1)->p_p, pr2 = (*p2)->p_p;
if ((pr1->p_pid >= 0) && (pr1->p_pid <= PID_MAX)) {
if ((pr2->p_pid < 0) || (pr2->p_pid > PID_MAX))
return pr1->p_pid;
}
if ((pr2->p_pid >= 0) && (pr2->p_pid <= PID_MAX)) {
if ((pr1->p_pid < 0) || (pr1->p_pid > PID_MAX))
return -pr2->p_pid;
}
t1 = (*p1)->p_t, t2 = (*p2)->p_t;
if (t1 == condev && t2 != condev)
return -1;
if (t1 != condev && t2 == condev)
return 1;
if (t1 >= 0 && t2 >= 0)
{
if (d = t1 - t2)
return d;
if (pr1->p_stat == SRUN && pr2->p_stat != SRUN)
return 1;
if (pr1->p_stat != SRUN && pr2->p_stat == SRUN)
return -1;
if (pr1->p_stat == SZOMB && pr2->p_stat != SZOMB)
return -1;
if (pr1->p_stat != SZOMB && pr2->p_stat == SZOMB)
return 1;
if (pr1->p_flag & P_INMEM && !(pr2->p_flag & P_INMEM))
return 1;
if (!(pr1->p_flag & P_INMEM) && pr2->p_flag & P_INMEM)
return -1;
return pr1->p_pid - pr2->p_pid;
}
if (t1 < 0 && t2 < 0)
return pr1->p_pid - pr2->p_pid;
else if (t1 < 0)
return -1;
return 1;
}
char *
findtty(tty, uid, idle, alttty)
register dev_t tty;
register uid_t *uid;
register time_t *idle;
char **alttty;
{
static char buf[64];
static char hex[17] = "0123456789abcdef";
register char *s = buf + 5;
struct stat sb;
dev_t maj;
char c;
*alttty = NULL;
if (tty == -1)
return NULL;
(void) strcpy(buf, _PATH_DEV);
maj = major(tty);
if (maj == ttyp0 || maj == ttyE0 || maj == ttyv0 || maj == tty00)
{
*s++ = 't';
*s++ = 't';
*s++ = 'y';
if (maj == ttyp0)
c = 'p';
else if (maj == ttyE0)
c = 'E';
else if (maj == ttyv0)
c = 'v';
else if (maj == tty00)
c = '0';
else {
*uid = -1;
*idle = time(NULL);
return "???";
}
*s++ = c + ((tty & 0xff) >> 4);
*s++ = hex[(tty & 0xf)];
*s = '\0';
if (stat(buf, &sb) == 0) {
*uid = sb.st_uid;
*idle = sb.st_atime;
if ((tty == condev) && stat(_PATH_CONSOLE, &sb) == 0) {
*alttty = buf + 5;
return "console";
}
return buf+5;
}
}
*uid = -1;
*idle = time(NULL);
return NULL;
}
void
init_utmp()
{
struct stat sb;
caddr_t map;
int fd;
fd = open(_PATH_UTMP, O_RDONLY);
if (fd >= 0) {
if (fstat(fd, &sb) == 0) {
map = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd,0);
if (map == (caddr_t)-1)
perror("mmap");
else {
utblocksz = sb.st_size;
utblock = (struct utmp *)map;
utblockend = (struct utmp*)((char*)utblock +
utblocksz);
}
close(fd);
}
}
}
struct utmp *
ut_findtty(tty)
char *tty;
{
struct utmp *u, *ue;
if (!utblock || !utblockend || !utblocksz)
return NULL;
for (u = utblock; u < utblockend; u++)
if (*u->ut_name && !strcmp(tty, u->ut_line))
return u;
return NULL;
}
void
init_console(flags)
int flags;
{
struct consdev cd, *cons;
char ttypath[32], *s;
struct stat sb;
if ((names[NL_CONS].n_value != 0)) {
kmemcpy((char *)&cons, names[NL_CONS].n_value, sizeof(cons));
kmemcpy((char *)&cd, cons, sizeof(cd));
if (flags & OPT_DEBUG)
fprintf(stderr, "consdev.cn_dev = %#x\n", cd.cn_dev);
condev = cd.cn_dev;
} else if (stat(_PATH_CONSOLE, &sb) != -1) {
condev = sb.st_rdev;
if (flags & OPT_DEBUG)
fprintf(stderr, "console at %#x\n", condev);
}
snprintf(ttypath, sizeof(ttypath), "%sttyXX", _PATH_DEV);
s = ttypath + strlen(ttypath);
s -= 2;
if (*s != 'X')
return;
s[1] = '0';
s[0] = 'p';
if (stat(ttypath, &sb) != -1) {
ttyp0 = major(sb.st_rdev);
if (flags & OPT_DEBUG)
fprintf(stderr, "%s at %#x\n", ttypath, ttyp0);
}
s[0] = '0';
if (stat(ttypath, &sb) != -1) {
tty00 = major(sb.st_rdev);
if (flags & OPT_DEBUG)
fprintf(stderr, "%s at %#x\n", ttypath, tty00);
}
s[0] = 'E';
if (stat(ttypath, &sb) != -1) {
ttyE0 = major(sb.st_rdev);
if (flags & OPT_DEBUG)
fprintf(stderr, "%s at %#x\n", ttypath, ttyE0);
}
s[0] = 'v';
if (stat(ttypath, &sb) != -1) {
ttyv0 = major(sb.st_rdev);
if (flags & OPT_DEBUG)
fprintf(stderr, "%s at %#x\n", ttypath, ttyv0);
}
}
struct users {
uid_t uid;
int name[12];
struct users *next;
};
static struct users *utab[2003];
void
init_utab()
{
memset((char *)utab, 0, sizeof(utab));
}
int
hash(uid)
uid_t uid;
{
register int hv = (int)uid;
hv += hv + hv & 0xf + hv << 3;
hv %= 2003;
return hv;
}
void
add_user_entry(pw)
register struct passwd *pw;
{
register struct users *up;
register int hv;
hv = hash((uid_t)pw->pw_uid);
up = (struct users *)malloc(sizeof(*up));
(void) sprintf((char *)up->name, "%-8.8s", pw->pw_name);
up->uid = pw->pw_uid;
up->next = utab[hv];
utab[hv] = up;
}
int
checkprint(a0, login, tty)
char *a0, *login, *tty;
{
struct ttyent *t;
if (!a0 || !*a0)
return 0;
t = getttynam(tty);
if (!t || !(t->ty_status & TTY_ON))
return 0;
if (!strcmp(login, "root") && !strncmp(t->ty_getty, a0, strlen(a0)))
return -1;
return 0;
}
void
printhost(login, tty, idle, flags)
char *login, *tty;
time_t idle;
int flags;
{
struct hostent *h;
char *s, host[19];
struct utmp *u;
time_t now;
u = ut_findtty(tty);
if (u == NULL || !*u->ut_host)
strcpy(host, "-");
else if (isdigit(*u->ut_host) && !(flags & OPT_NORES)) {
struct in_addr in;
in.s_addr = inet_addr(u->ut_host);
h = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
if (h != NULL && h->h_name != NULL) {
s = strchr(h->h_name, '.');
if (s && !strcmp(s + 1, domain))
*s = '\0';
strncpy(host, h->h_name, sizeof(host));
} else {
snprintf(host, sizeof(host), "(%s)", u->ut_host);
}
} else
strncpy(host, u->ut_host, MIN(UT_HOSTSIZE, sizeof(host)));
printf(" %-16.16s", host);
if (u == NULL) {
printf(" ");
} else {
now = time(NULL);
pr_attime(&u->ut_time, &now);
}
pr_idle(idle);
}
char *
getuser(uid, login)
register uid_t uid;
char *login;
{
static char uidstr[6];
register struct passwd *pw;
register struct users *up;
u_int hv = hash(uid);
for (up = utab[hv]; up; up = up->next)
if (uid == up->uid)
break;
if (!up && (pw = getpwuid((int)uid)))
{
add_user_entry(pw);
return getuser(uid, login);
}
if ((login != NULL) && strcmp(login, (char *)up->name))
return login;
if (up == NULL) {
snprintf(uidstr, sizeof(uidstr), "%u", uid);
uidstr[sizeof(uidstr) - 1] = '\0';
return uidstr;
}
return (char *)up->name;
}
void
printprocs(pl, np, fuser, flags)
Proc **pl;
int np;
char *fuser;
int flags;
{
register Proc **p, *pp, *ps = NULL;
register struct proc *pr;
register struct pstats *us;
register int i;
time_t li = 0x7fffffff, ti, now = time((time_t *)NULL), diff;
uid_t uid, who = 0;
char tbuf[32], *tty, *login = NULL, **av, **ap, *realtty;
char psargs[160];
struct session *sp;
dev_t pst = 0;
int len;
for (i = np, p = pl; i >= 0; i--, p++)
{
if (!(pp = *p))
if (ps)
goto dump;
else
break;
pr = pp->p_p;
if (flags & OPT_DEBUG)
fprintf(stderr, "\t[%s]\t%-6d [%s] %x %#x\n",
pp->p_s.s_login, pr->p_pid, pr->p_comm,
pp->p_t, *(p+1));
sp = &pp->p_s;
if (!sp->s_ttyp)
continue;
who = pp->p_k->kp_eproc.e_pcred.p_ruid;
if (!pst || pst != pp->p_t)
tty = findtty(pp->p_t, &uid, &ti, &realtty);
if (!who && uid)
who = uid;
if (uid && who != uid)
continue;
if (!uid || uid == who)
ps = pp, pst = pp->p_t;
if (!ps)
continue;
if (!tty)
continue;
if (pp->p_t == -1)
continue;
pr->p_comm[MAXCOMLEN] = '\0';
if (!*pr->p_comm)
continue;
if (!*(p+1))
if (ps)
goto dump;
else
break;
if (pp->p_t == (*(p+1))->p_t || !ps)
continue;
dump:
pr = ps->p_p;
login = ps->p_s.s_login;
if (!*login) {
putchar('#');
login = NULL;
}
login = getuser(who, login);
if (fuser && strcmp(fuser, login))
continue;
av = kvm_getargv(kptr, ps->p_k, sizeof(psargs));
if (av && av[0] && ((checkprint(av[0], login, tty) == -1) ||
(realtty != NULL &&
checkprint(av[0], login, realtty) == -1)))
continue;
diff = now - ti;
if (flags & OPT_V1) {
if (pp->p_gotu == 1) {
us = pp->p_us;
if ((u_long)us->p_start.tv_sec < (u_long)li &&
us->p_start.tv_sec)
li = us->p_start.tv_sec;
} else
li = 0;
printf("%-8s ", login);
if (flags & OPT_SMALL) {
if (!strncmp(tty, "tty", 3))
printf("%2.2s", tty + 3);
else
printf("%2.2s", tty);
} else {
(void) printf("%-8.8s", tty);
(void) fputs(printtime(now, li), stdout);
}
if (diff < 0)
diff = 0;
diff /= 60;
(void) sprintf(tbuf, " %03d:%02d", diff/60, diff%60);
(void) fputs(leading(tbuf)+1, stdout);
if (!(flags & OPT_SMALL)) {
(void) fputs(cputime(ps), stdout);
len = 32;
} else
len = 55;
fputs(" ", stdout);
} else {
printf("%-10s ", login);
if (!strncmp(tty, "tty", 3))
printf("%2.2s", tty + 3);
else
printf("%2.2s", tty);
printhost(login, tty, diff, flags);
len = 34;
}
if (flags & OPT_WIDE)
len += 80;
if (len > sizeof(psargs))
len = sizeof(psargs);
*psargs = '\0';
ap = av;
for (ap = av; (ap != NULL) && (*ap != NULL); ap++) {
if (*psargs)
(void) strcat(psargs, " ");
(void) strcat(psargs, *ap);
}
if (av && *av && strstr(*av, pr->p_comm)) {
if (!(flags & OPT_WIDE))
psargs[len] = '\0';
printf("%s\n", psargs, len);
} else {
if (!(flags & OPT_WIDE)) {
len -= strlen(pr->p_comm);
len -= 3;
psargs[len] = '\0';
}
printf("(%s) %s\n", pr->p_comm, psargs);
}
li = 0x7fffffff;
tty = NULL;
ps = NULL;
pst = 0;
fflush(stdout);
}
}
int
user_count(pt, cnt)
register Proc **pt;
register int cnt;
{
register struct kinfo_proc *kp;
register struct session *sp;
register int uc = 0;
dev_t i, majm = 0;
for (; *pt && cnt; cnt--, pt++)
{
kp = (*pt)->p_k;
if (!kp || !kp->kp_eproc.e_jobc || !kp->kp_eproc.e_tsess)
continue;
sp = &(*pt)->p_s;
if (!sp->s_ttyp || !sp->s_ttyvp)
continue;
if ((i = (*pt)->p_t) != majm)
{
uc++;
majm = i;
}
}
return uc;
}
Proc
**readprocs(flags, np)
int flags;
int *np;
{
register struct kinfo_proc *kp;
register struct proc *pr;
register Proc *pp;
register char *s;
register int i;
struct kinfo_proc *kt;
Proc *p, **ppl;
int mib[3] = { CTL_KERN, KERN_MAXPROC, 0 }, sz = 0, len;
len = sizeof(sz);
if (sysctl(mib, 2, &sz, &len, NULL, 0) == -1) {
perror("sysctl(KERN,PROC_MAXPROC)");
exit(-1);
}
if (flags & OPT_DEBUG)
fprintf(stderr, "maxproc = %d\n", sz);
len = sz * sizeof(*kt);
kt = (struct kinfo_proc *)malloc(len);
bzero((char *)kt, len);
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_ALL;
if (sysctl(mib, 3, kt, &len, NULL, 0) == -1) {
perror("sysctl(KERN,PROC,PROC_ALL)");
exit(-1);
}
*np = sz = len / sizeof(*kt);
if (flags & OPT_DEBUG)
fprintf(stderr, "numproc = %d\n", sz);
p = (Proc *)malloc((u_int)sizeof(*p) * (sz + 1));
ppl = (Proc **)malloc((u_int)sizeof(*ppl) * (sz + 1));
bzero((char *)p, sizeof(*p) * (sz + 1));
bzero((char *)ppl, sizeof(*ppl) * (sz + 1));
for (i = 0, pp = p, kp = kt; i < sz; i++, pp++, kp++) {
pp->p_p = pr = &kp->kp_proc;
pp->p_k = kp;
pp->p_t = kp->kp_eproc.e_tdev;
if (kp->kp_eproc.e_tsess)
kmemcpy((char *)&pp->p_s, (u_long)kp->kp_eproc.e_tsess,
sizeof(pp->p_s));
if (((flags & (OPT_V1|OPT_SMALL)) == OPT_V1) &&
(pr->p_addr != NULL)) {
pp->p_us = &pp->p_u.u_stats;
if (kvm_read(kptr, (u_long)&pr->p_addr->u_stats,
(char *)pp->p_us, sizeof(*pp->p_us)) ==
sizeof(*pp->p_us))
pp->p_gotu = 1;
else if (kvm_read(kptr, (u_long)pr->p_addr,
(char *)&pp->p_u, sizeof(pp->p_u)) ==
sizeof(pp->p_u))
pp->p_gotu = 1;
else
pp->p_gotu = 0;
}
pp->p_p = pr;
ppl[i] = pp;
}
qsort((char *)ppl, i, sizeof(p), sortproc);
return ppl;
}
void
showload(pl, np, flags)
Proc **pl;
int np, flags;
{
int users = 0, mib[2] = { CTL_KERN, KERN_BOOTTIME }, len;
time_t now = time((time_t *)NULL), upfor;
struct loadavg avg;
struct timeval boot;
struct tm *tm;
double loadav[3];
char c;
len = sizeof(boot);
(void) sysctl(mib, 2, &boot, &len, NULL, 0);
mib[0] = CTL_VM;
mib[1] = VM_LOADAVG;
len = sizeof(avg);
(void) sysctl(mib, 2, &avg, &len, NULL, 0);
loadav[0] = (double)avg.ldavg[0] / avg.fscale;
loadav[1] = (double)avg.ldavg[1] / avg.fscale;
loadav[2] = (double)avg.ldavg[2] / avg.fscale;
tm = localtime(&now);
upfor = now - boot.tv_sec;
upfor /= 60;
users = user_count(pl, np);
if (flags & OPT_V1)
fputc(' ', stdout);
(void) printf("%2d:%02d",
(tm->tm_hour > 12) ? tm->tm_hour - 12 : tm->tm_hour,
tm->tm_min);
if (tm->tm_hour > 11)
c = 'P';
else
c = 'A';
if (flags & OPT_V1) {
c = tolower(c);
fputc(c, stdout);
fputs("m ", stdout);
} else {
fputc(c, stdout);
fputs("M ", stdout);
}
fputs("up ", stdout);
if (upfor > 1440) {
(void) printf("%d days, ", upfor/1440);
upfor %= 1440;
}
(void) printf("%2d:%02d, %d users,", upfor/60, upfor%60, users);
(void) printf(" load average: %.2f, %.2f, %.2f\n",
loadav[0], loadav[1], loadav[2]);
fflush(stdout);
}
int
main(argc, argv)
int argc;
char **argv;
{
int flags = 0, np = 0, c;
char *s, *fuser = NULL;
Proc **pl;
init_utab();
setbuffer(stdout, obuff, sizeof(obuff));
while ((c = getopt(argc, argv, "1dhlM:nN:suw")) != -1)
switch (c)
{
case '1' :
flags |= OPT_V1;
break;
case 'd' :
flags |= OPT_DEBUG;
break;
case 'h' :
flags |= OPT_NOHDR;
break;
case 'l' :
flags |= OPT_LONG;
break;
case 'M' :
core = optarg;
setgid(getgid());
setuid(getuid());
break;
case 'N' :
kernel = optarg;
setgid(getgid());
setuid(getuid());
break;
case 'n' :
flags |= OPT_NORES;
break;
case 's' :
flags |= OPT_SMALL;
break;
case 'u' :
flags |= OPT_NOUSERS;
break;
case 'w' :
flags |= OPT_WIDE;
break;
}
if (argc - optind)
fuser = argv[optind];
kvminit();
setgid(getgid());
setuid(getuid());
if (!(flags & OPT_NORES)) {
gethostname(domain, sizeof(domain));
s = strchr(domain, '.');
if (s == NULL)
domain[0] = '\0';
else
memmove(domain, s + 1, strlen(s + 1) + 1);
} else
domain[0] = '\0';
init_utmp();
init_console(flags);
pl = readprocs(flags, &np);
if (!(flags & OPT_NOHDR))
showload(pl, np, flags);
if (flags & OPT_NOUSERS)
exit(0);
if ((flags & OPT_V1) && !(flags & (OPT_NOHDR|OPT_SMALL)))
printf("User tty login@ idle JCPU PCPU what\n");
else if (!(flags & (OPT_V1|OPT_NOHDR)))
printf("USER TTY FROM LOGIN@ IDLE WHAT\n");
else if (flags & OPT_SMALL)
printf("User tty idle what\n");
fflush(stdout);
(void) setpwent();
printprocs(pl, np, fuser, flags);
exit(0);
}