1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)w.c 5.27 (Berkeley) 03/22/91"; 15 #endif not lint 16 17 /* 18 * w - print system status (who and what) 19 * 20 * This program is similar to the systat command on Tenex/Tops 10/20 21 * 22 */ 23 #include <sys/param.h> 24 #include <utmp.h> 25 #include <sys/time.h> 26 #include <sys/stat.h> 27 #include <sys/proc.h> 28 #include <sys/user.h> 29 #include <sys/ioctl.h> 30 #include <sys/tty.h> 31 #include <nlist.h> 32 #include <kvm.h> 33 #include <ctype.h> 34 #include <paths.h> 35 #include <string.h> 36 #include <stdio.h> 37 38 #ifdef SPPWAIT 39 #define NEWVM 40 #endif 41 #ifndef NEWVM 42 #include <machine/pte.h> 43 #include <sys/vm.h> 44 #endif 45 46 char *program; 47 int ttywidth; /* width of tty */ 48 int argwidth; /* width of tty */ 49 int header = 1; /* true if -h flag: don't print heading */ 50 int wcmd = 1; /* true if this is w(1), and not uptime(1) */ 51 int nusers; /* number of users logged in now */ 52 char * sel_user; /* login of particular user selected */ 53 time_t now; /* the current time of day */ 54 struct timeval boottime; 55 time_t uptime; /* time of last reboot & elapsed time since */ 56 struct utmp utmp; 57 struct winsize ws; 58 int sortidle; /* sort bu idle time */ 59 60 61 /* 62 * One of these per active utmp entry. 63 */ 64 struct entry { 65 struct entry *next; 66 struct utmp utmp; 67 dev_t tdev; /* dev_t of terminal */ 68 int idle; /* idle time of terminal in minutes */ 69 struct proc *proc; /* list of procs in foreground */ 70 char *args; /* arg list of interesting process */ 71 } *ep, *ehead = NULL, **nextp = &ehead; 72 73 struct nlist nl[] = { 74 { "_boottime" }, 75 #define X_BOOTTIME 0 76 #if defined(hp300) 77 { "_cn_tty" }, 78 #define X_CNTTY 1 79 #endif 80 { "" }, 81 }; 82 83 #define USAGE "[ -hi ] [ user ]" 84 #define usage() fprintf(stderr, "usage: %s: %s\n", program, USAGE) 85 86 main(argc, argv) 87 char **argv; 88 { 89 register int i; 90 struct winsize win; 91 register struct proc *p; 92 struct eproc *e; 93 struct stat *stp, *ttystat(); 94 FILE *ut; 95 char *cp; 96 int ch; 97 extern char *optarg; 98 extern int optind; 99 char *attime(); 100 101 program = argv[0]; 102 /* 103 * are we w(1) or uptime(1) 104 */ 105 if ((cp = rindex(program, '/')) || *(cp = program) == '-') 106 cp++; 107 if (*cp == 'u') 108 wcmd = 0; 109 110 while ((ch = getopt(argc, argv, "hiflsuw")) != EOF) 111 switch((char)ch) { 112 case 'h': 113 header = 0; 114 break; 115 case 'i': 116 sortidle++; 117 break; 118 case 'f': case 'l': case 's': case 'u': case 'w': 119 error("[-flsuw] no longer supported"); 120 usage(); 121 exit(1); 122 case '?': 123 default: 124 usage(); 125 exit(1); 126 } 127 argc -= optind; 128 argv += optind; 129 if (argc == 1) { 130 sel_user = argv[0]; 131 argv++, argc--; 132 } 133 if (argc) { 134 usage(); 135 exit(1); 136 } 137 138 if (header && kvm_nlist(nl) != 0) { 139 error("can't get namelist"); 140 exit (1); 141 } 142 time(&now); 143 ut = fopen(_PATH_UTMP, "r"); 144 while (fread(&utmp, sizeof(utmp), 1, ut)) { 145 if (utmp.ut_name[0] == '\0') 146 continue; 147 nusers++; 148 if (wcmd == 0 || (sel_user && 149 strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0)) 150 continue; 151 if ((ep = (struct entry *) 152 calloc(1, sizeof (struct entry))) == NULL) { 153 error("out of memory"); 154 exit(1); 155 } 156 *nextp = ep; 157 nextp = &(ep->next); 158 bcopy(&utmp, &(ep->utmp), sizeof (struct utmp)); 159 stp = ttystat(ep->utmp.ut_line); 160 ep->tdev = stp->st_rdev; 161 #if defined(hp300) 162 /* 163 * XXX If this is the console device, attempt to ascertain 164 * the true console device dev_t. 165 */ 166 if (ep->tdev == 0) { 167 static dev_t cn_dev; 168 169 if (nl[X_CNTTY].n_value) { 170 struct tty cn_tty, *cn_ttyp; 171 172 if (kvm_read(nl[X_CNTTY].n_value, 173 &cn_ttyp, sizeof (cn_ttyp)) > 0) { 174 (void)kvm_read(cn_ttyp, &cn_tty, 175 sizeof (cn_tty)); 176 cn_dev = cn_tty.t_dev; 177 } 178 nl[X_CNTTY].n_value = 0; 179 } 180 ep->tdev = cn_dev; 181 } 182 #endif 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((off_t)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 & SCTTY) == 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 ep->args = strdup(kvm_getargs(ep->proc, kvm_getu(ep->proc))); 270 if (ep->args == NULL) { 271 error("out of memory"); 272 exit(1); 273 } 274 } 275 /* sort by idle time */ 276 if (sortidle && ehead != NULL) { 277 struct entry *from = ehead, *save; 278 279 ehead = NULL; 280 while (from != NULL) { 281 for (nextp = &ehead; 282 (*nextp) && from->idle >= (*nextp)->idle; 283 nextp = &(*nextp)->next) 284 ; 285 save = from; 286 from = from->next; 287 save->next = *nextp; 288 *nextp = save; 289 } 290 } 291 292 for (ep = ehead; ep != NULL; ep = ep->next) { 293 printf("%-*.*s %-2.2s %-*.*s %s", 294 UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name, 295 strncmp(ep->utmp.ut_line, "tty", 3) == 0 ? 296 ep->utmp.ut_line+3 : ep->utmp.ut_line, 297 UT_HOSTSIZE, UT_HOSTSIZE, *ep->utmp.ut_host ? 298 ep->utmp.ut_host : "-", 299 attime(&ep->utmp.ut_time)); 300 if (ep->idle >= 36 * 60) 301 printf(" %ddays ", (ep->idle + 12 * 60) / (24 * 60)); 302 else 303 prttime(ep->idle, " "); 304 printf("%.*s\n", argwidth, ep->args); 305 } 306 exit(0); 307 } 308 309 struct stat * 310 ttystat(line) 311 { 312 static struct stat statbuf; 313 char ttybuf[sizeof (_PATH_DEV) + UT_LINESIZE + 1]; 314 315 sprintf(ttybuf, "%s/%.*s", _PATH_DEV, UT_LINESIZE, line); 316 (void) stat(ttybuf, &statbuf); 317 318 return (&statbuf); 319 } 320 321 /* 322 * prttime prints a time in hours and minutes or minutes and seconds. 323 * The character string tail is printed at the end, obvious 324 * strings to pass are "", " ", or "am". 325 */ 326 prttime(tim, tail) 327 time_t tim; 328 char *tail; 329 { 330 331 if (tim >= 60) { 332 printf(" %2d:", tim/60); 333 tim %= 60; 334 printf("%02d", tim); 335 } else if (tim >= 0) 336 printf(" %2d", tim); 337 printf("%s", tail); 338 } 339 340 #include <varargs.h> 341 342 warning(va_alist) 343 va_dcl 344 { 345 char *fmt; 346 va_list ap; 347 348 fprintf(stderr, "%s: warning: ", program); 349 va_start(ap); 350 fmt = va_arg(ap, char *); 351 (void) vfprintf(stderr, fmt, ap); 352 va_end(ap); 353 fprintf(stderr, "\n"); 354 } 355 356 error(va_alist) 357 va_dcl 358 { 359 char *fmt; 360 va_list ap; 361 362 fprintf(stderr, "%s: ", program); 363 va_start(ap); 364 fmt = va_arg(ap, char *); 365 (void) vfprintf(stderr, fmt, ap); 366 va_end(ap); 367 fprintf(stderr, "\n"); 368 } 369 370 syserror(va_alist) 371 va_dcl 372 { 373 char *fmt; 374 va_list ap; 375 extern errno; 376 377 fprintf(stderr, "%s: ", program); 378 va_start(ap); 379 fmt = va_arg(ap, char *); 380 (void) vfprintf(stderr, fmt, ap); 381 va_end(ap); 382 fprintf(stderr, ": %s\n", strerror(errno)); 383 } 384