Home | History | Annotate | Line # | Download | only in w
w.c revision 1.10
      1 /*-
      2  * Copyright (c) 1980, 1991 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 char copyright[] =
     36 "@(#) Copyright (c) 1980, 1991 The Regents of the University of California.\n\
     37  All rights reserved.\n";
     38 #endif /* not lint */
     39 
     40 #ifndef lint
     41 /*static char sccsid[] = "from: @(#)w.c	5.29 (Berkeley) 4/23/91";*/
     42 static char rcsid[] = "$Id: w.c,v 1.10 1994/05/05 02:08:58 cgd Exp $";
     43 #endif /* not lint */
     44 
     45 /*
     46  * w - print system status (who and what)
     47  *
     48  * This program is similar to the systat command on Tenex/Tops 10/20
     49  *
     50  */
     51 #include <sys/param.h>
     52 #include <utmp.h>
     53 #include <sys/time.h>
     54 #include <sys/stat.h>
     55 #include <sys/proc.h>
     56 #include <sys/user.h>
     57 #include <sys/ioctl.h>
     58 #include <sys/tty.h>
     59 #include <nlist.h>
     60 #include <kvm.h>
     61 #include <ctype.h>
     62 #include <paths.h>
     63 #include <string.h>
     64 #include <stdio.h>
     65 #include <vis.h>
     66 
     67 #ifdef P_PPWAIT
     68 #define NEWVM
     69 #endif
     70 #ifndef NEWVM
     71 #include <machine/pte.h>
     72 #include <sys/vm.h>
     73 #endif
     74 
     75 char	*program;
     76 int	ttywidth;		/* width of tty */
     77 int	argwidth;		/* width of tty */
     78 int	header = 1;		/* true if -h flag: don't print heading */
     79 int	wcmd = 1;		/* true if this is w(1), and not uptime(1) */
     80 int	nusers;			/* number of users logged in now */
     81 char *	sel_user;		/* login of particular user selected */
     82 time_t	now;			/* the current time of day */
     83 struct	timeval boottime;
     84 time_t	uptime;			/* time of last reboot & elapsed time since */
     85 struct	utmp utmp;
     86 struct	winsize ws;
     87 int	sortidle;		/* sort bu idle time */
     88 
     89 
     90 /*
     91  * One of these per active utmp entry.
     92  */
     93 struct	entry {
     94 	struct	entry *next;
     95 	struct	utmp utmp;
     96 	dev_t	tdev;		/* dev_t of terminal */
     97 	int	idle;		/* idle time of terminal in minutes */
     98 	struct	proc *proc;	/* list of procs in foreground */
     99 	char	*args;		/* arg list of interesting process */
    100 } *ep, *ehead = NULL, **nextp = &ehead;
    101 
    102 struct nlist nl[] = {
    103 	{ "_boottime" },
    104 #define X_BOOTTIME	0
    105 	{ "" },
    106 };
    107 
    108 #define USAGE "[ -hi ] [ user ]"
    109 #define usage()	fprintf(stderr, "usage: %s: %s\n", program, USAGE)
    110 
    111 main(argc, argv)
    112 	int argc;
    113 	char **argv;
    114 {
    115 	register int i;
    116 	struct winsize win;
    117 	register struct proc *p;
    118 	struct eproc *e;
    119 	struct stat *stp, *ttystat();
    120 	FILE *ut;
    121 	char *cp;
    122 	char *vis_args;
    123 	int ch;
    124 	extern char *optarg;
    125 	extern int optind;
    126 	char *attime();
    127 
    128 	program = argv[0];
    129 	/*
    130 	 * are we w(1) or uptime(1)
    131 	 */
    132 	if ((cp = rindex(program, '/')) || *(cp = program) == '-')
    133 		cp++;
    134 	if (*cp == 'u')
    135 		wcmd = 0;
    136 
    137 	while ((ch = getopt(argc, argv, "hiflsuw")) != EOF)
    138 		switch((char)ch) {
    139 		case 'h':
    140 			header = 0;
    141 			break;
    142 		case 'i':
    143 			sortidle++;
    144 			break;
    145 		case 'f': case 'l': case 's': case 'u': case 'w':
    146 			error("[-flsuw] no longer supported");
    147 			usage();
    148 			exit(1);
    149 		case '?':
    150 		default:
    151 			usage();
    152 			exit(1);
    153 		}
    154 	argc -= optind;
    155 	argv += optind;
    156 
    157 	if (*argv)
    158 		sel_user = *argv;
    159 
    160 	if (header && kvm_nlist(nl) != 0) {
    161 		error("can't get namelist");
    162 		exit (1);
    163 	}
    164 	time(&now);
    165 	ut = fopen(_PATH_UTMP, "r");
    166 	while (fread(&utmp, sizeof(utmp), 1, ut)) {
    167 		if (utmp.ut_name[0] == '\0')
    168 			continue;
    169 		nusers++;
    170 		if (wcmd == 0 || (sel_user &&
    171 		    strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0))
    172 			continue;
    173 		if ((ep = (struct entry *)
    174 		     calloc(1, sizeof (struct entry))) == NULL) {
    175 			error("out of memory");
    176 			exit(1);
    177 		}
    178 		*nextp = ep;
    179 		nextp = &(ep->next);
    180 		bcopy(&utmp, &(ep->utmp), sizeof (struct utmp));
    181 		stp = ttystat(ep->utmp.ut_line);
    182 		ep->tdev = stp->st_rdev;
    183 		ep->idle = ((now - stp->st_atime) + 30) / 60; /* secs->mins */
    184 		if (ep->idle < 0)
    185 			ep->idle = 0;
    186 	}
    187 	fclose(ut);
    188 
    189 	if (header || wcmd == 0) {
    190 		double	avenrun[3];
    191 		int days, hrs, mins;
    192 
    193 		/*
    194 		 * Print time of day
    195 		 */
    196 		fputs(attime(&now), stdout);
    197 		/*
    198 		 * Print how long system has been up.
    199 		 * (Found by looking for "boottime" in kernel)
    200 		 */
    201 		(void)kvm_read((void *)nl[X_BOOTTIME].n_value, &boottime,
    202 		    sizeof (boottime));
    203 		uptime = now - boottime.tv_sec;
    204 		uptime += 30;
    205 		days = uptime / (60*60*24);
    206 		uptime %= (60*60*24);
    207 		hrs = uptime / (60*60);
    208 		uptime %= (60*60);
    209 		mins = uptime / 60;
    210 
    211 		printf("  up");
    212 		if (days > 0)
    213 			printf(" %d day%s,", days, days>1?"s":"");
    214 		if (hrs > 0 && mins > 0) {
    215 			printf(" %2d:%02d,", hrs, mins);
    216 		} else {
    217 			if (hrs > 0)
    218 				printf(" %d hr%s,", hrs, hrs>1?"s":"");
    219 			if (mins > 0)
    220 				printf(" %d min%s,", mins, mins>1?"s":"");
    221 		}
    222 
    223 		/* Print number of users logged in to system */
    224 		printf("  %d user%s", nusers, nusers>1?"s":"");
    225 
    226 		/*
    227 		 * Print 1, 5, and 15 minute load averages.
    228 		 */
    229 		printf(",  load average:");
    230 		(void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
    231 		for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) {
    232 			if (i > 0)
    233 				printf(",");
    234 			printf(" %.2f", avenrun[i]);
    235 		}
    236 		printf("\n");
    237 		if (wcmd == 0)		/* if uptime(1) then done */
    238 			exit(0);
    239 #define HEADER	"USER    TTY FROM              LOGIN@  IDLE WHAT\n"
    240 #define WUSED	(sizeof (HEADER) - sizeof ("WHAT\n"))
    241 		printf(HEADER);
    242 	}
    243 
    244 	while ((p = kvm_nextproc()) != NULL) {
    245 		if (p->p_stat == SZOMB || (p->p_flag & P_CONTROLT) == 0)
    246 			continue;
    247 		e = kvm_geteproc(p);
    248 		for (ep = ehead; ep != NULL; ep = ep->next) {
    249 			if (ep->tdev == e->e_tdev && e->e_pgid == e->e_tpgid) {
    250 				/*
    251 				 * Proc is in foreground of this terminal
    252 				 */
    253 				if (proc_compare(ep->proc, p))
    254 					ep->proc = p;
    255 				break;
    256 			}
    257 		}
    258 	}
    259 	if ((ioctl(1, TIOCGWINSZ, &ws) == -1 &&
    260 	     ioctl(2, TIOCGWINSZ, &ws) == -1 &&
    261 	     ioctl(0, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0)
    262 	       ttywidth = 79;
    263         else
    264 	       ttywidth = ws.ws_col - 1;
    265 	argwidth = ttywidth - WUSED;
    266 	if (argwidth < 4)
    267 		argwidth = 8;
    268 	for (ep = ehead; ep != NULL; ep = ep->next) {
    269 		if (!ep->proc) {
    270 			ep->args = NULL;
    271 			continue;
    272 		}
    273 		ep->args = strdup(kvm_getargs(ep->proc, kvm_getu(ep->proc)));
    274 		if (ep->args == NULL) {
    275 			error("out of memory");
    276 			exit(1);
    277 		}
    278 	}
    279 	/* sort by idle time */
    280 	if (sortidle && ehead != NULL) {
    281 		struct entry *from = ehead, *save;
    282 
    283 		ehead = NULL;
    284 		while (from != NULL) {
    285 			for (nextp = &ehead;
    286 			    (*nextp) && from->idle >= (*nextp)->idle;
    287 			    nextp = &(*nextp)->next)
    288 				;
    289 			save = from;
    290 			from = from->next;
    291 			save->next = *nextp;
    292 			*nextp = save;
    293 		}
    294 	}
    295 
    296 	if ((vis_args = (char *)malloc(argwidth * 4 + 1)) == NULL) {
    297 		error("out of memory");
    298 		exit(1);
    299 	}
    300 	for (ep = ehead; ep != NULL; ep = ep->next) {
    301 		printf("%-*.*s %-2.2s %-*.*s %s",
    302 			UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
    303 			strncmp(ep->utmp.ut_line, "tty", 3) == 0 ?
    304 				ep->utmp.ut_line+3 : ep->utmp.ut_line,
    305 			UT_HOSTSIZE, UT_HOSTSIZE, *ep->utmp.ut_host ?
    306 				ep->utmp.ut_host : "-",
    307 			attime(&ep->utmp.ut_time));
    308 		if (ep->idle >= 36 * 60)
    309 			printf(" %ddays ", (ep->idle + 12 * 60) / (24 * 60));
    310 		else if (ep->idle == 0)
    311 			printf("     - ");
    312 		else
    313 			prttime(ep->idle, " ");
    314 		if (ep->args)
    315 	        	strvisx(vis_args, ep->args,
    316 				(strlen(ep->args) > argwidth) ?
    317 					argwidth : strlen(ep->args),
    318 				VIS_TAB|VIS_NL|VIS_NOSLASH);
    319 		printf("%.*s\n", argwidth, ep->args ? vis_args : "-");
    320 	}
    321 	free(vis_args);
    322 
    323 	exit(0);
    324 }
    325 
    326 struct stat *
    327 ttystat(line)
    328 {
    329 	static struct stat statbuf;
    330 	char ttybuf[sizeof (_PATH_DEV) + UT_LINESIZE + 1];
    331 
    332 	sprintf(ttybuf, "%s/%.*s", _PATH_DEV, UT_LINESIZE, line);
    333 	(void) stat(ttybuf, &statbuf);
    334 
    335 	return (&statbuf);
    336 }
    337 
    338 /*
    339  * prttime prints a time in hours and minutes or minutes and seconds.
    340  * The character string tail is printed at the end, obvious
    341  * strings to pass are "", " ", or "am".
    342  */
    343 prttime(tim, tail)
    344 	time_t tim;
    345 	char *tail;
    346 {
    347 
    348 	if (tim >= 60)
    349 		printf(" %2d:%02d", tim/60, tim%60);
    350 	else if (tim >= 0)
    351 		printf("    %2d", tim);
    352 	printf("%s", tail);
    353 }
    354 
    355 #include <varargs.h>
    356 
    357 error(va_alist)
    358 	va_dcl
    359 {
    360 	char *fmt;
    361 	va_list ap;
    362 
    363 	fprintf(stderr, "%s: ", program);
    364 	va_start(ap);
    365 	fmt = va_arg(ap, char *);
    366 	(void) vfprintf(stderr, fmt, ap);
    367 	va_end(ap);
    368 	fprintf(stderr, "\n");
    369 }
    370