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 /* from: static char sccsid[] = "@(#)w.c 5.29 (Berkeley) 4/23/91"; */ 42 static char rcsid[] = "$Id: w.c,v 1.7 1993/07/15 17:55:48 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 SPPWAIT 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 & 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 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:", tim/60); 350 tim %= 60; 351 printf("%02d", tim); 352 } else if (tim >= 0) 353 printf(" %2d", tim); 354 printf("%s", tail); 355 } 356 357 #include <varargs.h> 358 359 error(va_alist) 360 va_dcl 361 { 362 char *fmt; 363 va_list ap; 364 365 fprintf(stderr, "%s: ", program); 366 va_start(ap); 367 fmt = va_arg(ap, char *); 368 (void) vfprintf(stderr, fmt, ap); 369 va_end(ap); 370 fprintf(stderr, "\n"); 371 } 372