1 /*- 2 * Copyright (c) 1980, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980, 1991 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)w.c 5.29 (Berkeley) 04/23/91"; 16 #endif /* not lint */ 17 18 /* 19 * w - print system status (who and what) 20 * 21 * This program is similar to the systat command on Tenex/Tops 10/20 22 * 23 */ 24 #include <sys/param.h> 25 #include <utmp.h> 26 #include <sys/time.h> 27 #include <sys/stat.h> 28 #include <sys/proc.h> 29 #include <sys/user.h> 30 #include <sys/ioctl.h> 31 #include <sys/tty.h> 32 #include <nlist.h> 33 #include <kvm.h> 34 #include <ctype.h> 35 #include <paths.h> 36 #include <string.h> 37 #include <stdio.h> 38 39 #ifdef SPPWAIT 40 #define NEWVM 41 #endif 42 #ifndef NEWVM 43 #include <machine/pte.h> 44 #include <sys/vm.h> 45 #endif 46 47 char *program; 48 int ttywidth; /* width of tty */ 49 int argwidth; /* width of tty */ 50 int header = 1; /* true if -h flag: don't print heading */ 51 int wcmd = 1; /* true if this is w(1), and not uptime(1) */ 52 int nusers; /* number of users logged in now */ 53 char * sel_user; /* login of particular user selected */ 54 time_t now; /* the current time of day */ 55 struct timeval boottime; 56 time_t uptime; /* time of last reboot & elapsed time since */ 57 struct utmp utmp; 58 struct winsize ws; 59 int sortidle; /* sort bu idle time */ 60 61 62 /* 63 * One of these per active utmp entry. 64 */ 65 struct entry { 66 struct entry *next; 67 struct utmp utmp; 68 dev_t tdev; /* dev_t of terminal */ 69 int idle; /* idle time of terminal in minutes */ 70 struct proc *proc; /* list of procs in foreground */ 71 char *args; /* arg list of interesting process */ 72 } *ep, *ehead = NULL, **nextp = &ehead; 73 74 struct nlist nl[] = { 75 { "_boottime" }, 76 #define X_BOOTTIME 0 77 #if defined(hp300) 78 { "_cn_tty" }, 79 #define X_CNTTY 1 80 #endif 81 { "" }, 82 }; 83 84 #define USAGE "[ -hi ] [ user ]" 85 #define usage() fprintf(stderr, "usage: %s: %s\n", program, USAGE) 86 87 main(argc, argv) 88 int argc; 89 char **argv; 90 { 91 register int i; 92 struct winsize win; 93 register struct proc *p; 94 struct eproc *e; 95 struct stat *stp, *ttystat(); 96 FILE *ut; 97 char *cp; 98 int ch; 99 extern char *optarg; 100 extern int optind; 101 char *attime(); 102 103 program = argv[0]; 104 /* 105 * are we w(1) or uptime(1) 106 */ 107 if ((cp = rindex(program, '/')) || *(cp = program) == '-') 108 cp++; 109 if (*cp == 'u') 110 wcmd = 0; 111 112 while ((ch = getopt(argc, argv, "hiflsuw")) != EOF) 113 switch((char)ch) { 114 case 'h': 115 header = 0; 116 break; 117 case 'i': 118 sortidle++; 119 break; 120 case 'f': case 'l': case 's': case 'u': case 'w': 121 error("[-flsuw] no longer supported"); 122 usage(); 123 exit(1); 124 case '?': 125 default: 126 usage(); 127 exit(1); 128 } 129 argc -= optind; 130 argv += optind; 131 132 if (*argv) 133 sel_user = *argv; 134 135 if (header && kvm_nlist(nl) != 0) { 136 error("can't get namelist"); 137 exit (1); 138 } 139 time(&now); 140 ut = fopen(_PATH_UTMP, "r"); 141 while (fread(&utmp, sizeof(utmp), 1, ut)) { 142 if (utmp.ut_name[0] == '\0') 143 continue; 144 nusers++; 145 if (wcmd == 0 || (sel_user && 146 strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0)) 147 continue; 148 if ((ep = (struct entry *) 149 calloc(1, sizeof (struct entry))) == NULL) { 150 error("out of memory"); 151 exit(1); 152 } 153 *nextp = ep; 154 nextp = &(ep->next); 155 bcopy(&utmp, &(ep->utmp), sizeof (struct utmp)); 156 stp = ttystat(ep->utmp.ut_line); 157 ep->tdev = stp->st_rdev; 158 #if defined(hp300) 159 /* 160 * XXX If this is the console device, attempt to ascertain 161 * the true console device dev_t. 162 */ 163 if (ep->tdev == 0) { 164 static dev_t cn_dev; 165 166 if (nl[X_CNTTY].n_value) { 167 struct tty cn_tty, *cn_ttyp; 168 169 if (kvm_read((void *)nl[X_CNTTY].n_value, 170 &cn_ttyp, sizeof(cn_ttyp)) > 0) { 171 (void)kvm_read(cn_ttyp, &cn_tty, 172 sizeof (cn_tty)); 173 cn_dev = cn_tty.t_dev; 174 } 175 nl[X_CNTTY].n_value = 0; 176 } 177 ep->tdev = cn_dev; 178 } 179 #endif 180 ep->idle = ((now - stp->st_atime) + 30) / 60; /* secs->mins */ 181 if (ep->idle < 0) 182 ep->idle = 0; 183 } 184 fclose(ut); 185 186 if (header || wcmd == 0) { 187 double avenrun[3]; 188 int days, hrs, mins; 189 190 /* 191 * Print time of day 192 */ 193 fputs(attime(&now), stdout); 194 /* 195 * Print how long system has been up. 196 * (Found by looking for "boottime" in kernel) 197 */ 198 (void)kvm_read((void *)nl[X_BOOTTIME].n_value, &boottime, 199 sizeof (boottime)); 200 uptime = now - boottime.tv_sec; 201 uptime += 30; 202 days = uptime / (60*60*24); 203 uptime %= (60*60*24); 204 hrs = uptime / (60*60); 205 uptime %= (60*60); 206 mins = uptime / 60; 207 208 printf(" up"); 209 if (days > 0) 210 printf(" %d day%s,", days, days>1?"s":""); 211 if (hrs > 0 && mins > 0) { 212 printf(" %2d:%02d,", hrs, mins); 213 } else { 214 if (hrs > 0) 215 printf(" %d hr%s,", hrs, hrs>1?"s":""); 216 if (mins > 0) 217 printf(" %d min%s,", mins, mins>1?"s":""); 218 } 219 220 /* Print number of users logged in to system */ 221 printf(" %d user%s", nusers, nusers>1?"s":""); 222 223 /* 224 * Print 1, 5, and 15 minute load averages. 225 */ 226 printf(", load average:"); 227 (void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 228 for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) { 229 if (i > 0) 230 printf(","); 231 printf(" %.2f", avenrun[i]); 232 } 233 printf("\n"); 234 if (wcmd == 0) /* if uptime(1) then done */ 235 exit(0); 236 #define HEADER "USER TTY FROM LOGIN@ IDLE WHAT\n" 237 #define WUSED (sizeof (HEADER) - sizeof ("WHAT\n")) 238 printf(HEADER); 239 } 240 241 while ((p = kvm_nextproc()) != NULL) { 242 if (p->p_stat == SZOMB || (p->p_flag & SCTTY) == 0) 243 continue; 244 e = kvm_geteproc(p); 245 for (ep = ehead; ep != NULL; ep = ep->next) { 246 if (ep->tdev == e->e_tdev && e->e_pgid == e->e_tpgid) { 247 /* 248 * Proc is in foreground of this terminal 249 */ 250 if (proc_compare(ep->proc, p)) 251 ep->proc = p; 252 break; 253 } 254 } 255 } 256 if ((ioctl(1, TIOCGWINSZ, &ws) == -1 && 257 ioctl(2, TIOCGWINSZ, &ws) == -1 && 258 ioctl(0, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0) 259 ttywidth = 79; 260 else 261 ttywidth = ws.ws_col - 1; 262 argwidth = ttywidth - WUSED; 263 if (argwidth < 4) 264 argwidth = 8; 265 for (ep = ehead; ep != NULL; ep = ep->next) { 266 ep->args = strdup(kvm_getargs(ep->proc, kvm_getu(ep->proc))); 267 if (ep->args == NULL) { 268 error("out of memory"); 269 exit(1); 270 } 271 } 272 /* sort by idle time */ 273 if (sortidle && ehead != NULL) { 274 struct entry *from = ehead, *save; 275 276 ehead = NULL; 277 while (from != NULL) { 278 for (nextp = &ehead; 279 (*nextp) && from->idle >= (*nextp)->idle; 280 nextp = &(*nextp)->next) 281 ; 282 save = from; 283 from = from->next; 284 save->next = *nextp; 285 *nextp = save; 286 } 287 } 288 289 for (ep = ehead; ep != NULL; ep = ep->next) { 290 printf("%-*.*s %-2.2s %-*.*s %s", 291 UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name, 292 strncmp(ep->utmp.ut_line, "tty", 3) == 0 ? 293 ep->utmp.ut_line+3 : ep->utmp.ut_line, 294 UT_HOSTSIZE, UT_HOSTSIZE, *ep->utmp.ut_host ? 295 ep->utmp.ut_host : "-", 296 attime(&ep->utmp.ut_time)); 297 if (ep->idle >= 36 * 60) 298 printf(" %ddays ", (ep->idle + 12 * 60) / (24 * 60)); 299 else 300 prttime(ep->idle, " "); 301 printf("%.*s\n", argwidth, ep->args); 302 } 303 exit(0); 304 } 305 306 struct stat * 307 ttystat(line) 308 { 309 static struct stat statbuf; 310 char ttybuf[sizeof (_PATH_DEV) + UT_LINESIZE + 1]; 311 312 sprintf(ttybuf, "%s/%.*s", _PATH_DEV, UT_LINESIZE, line); 313 (void) stat(ttybuf, &statbuf); 314 315 return (&statbuf); 316 } 317 318 /* 319 * prttime prints a time in hours and minutes or minutes and seconds. 320 * The character string tail is printed at the end, obvious 321 * strings to pass are "", " ", or "am". 322 */ 323 prttime(tim, tail) 324 time_t tim; 325 char *tail; 326 { 327 328 if (tim >= 60) { 329 printf(" %2d:", tim/60); 330 tim %= 60; 331 printf("%02d", tim); 332 } else if (tim >= 0) 333 printf(" %2d", tim); 334 printf("%s", tail); 335 } 336 337 #include <varargs.h> 338 339 error(va_alist) 340 va_dcl 341 { 342 char *fmt; 343 va_list ap; 344 345 fprintf(stderr, "%s: ", program); 346 va_start(ap); 347 fmt = va_arg(ap, char *); 348 (void) vfprintf(stderr, fmt, ap); 349 va_end(ap); 350 fprintf(stderr, "\n"); 351 } 352