2 * Extended `who' command, version 1.9.
4 * (c) 1996--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU General Public License. See file COPYING in any of the GNU packages.
20 #include <asm/param.h>
21 #include <sys/ioctl.h>
25 #define MAXHOSTSIZE 24
29 int pid, ppid, pgrp, sess;
35 static struct procrec *first_procrec;
41 time_t login_time, click_time, total_time;
42 char user_name[UT_NAMESIZE+1];
44 char host_name[MAXHOSTSIZE+1];
50 static struct utrec *first_utrec;
51 static int usercnt, zombies, maxhost = 10;
61 fprintf(stderr, "ywho: out of memory!\n");
68 strcpy_padded(char *to, char *from, int size)
70 memcpy(to, from, size);
77 static struct utmp *ut;
78 static struct passwd *pw;
80 while (ut = getutent())
81 if (ut->ut_type == USER_PROCESS && ut->ut_user[0])
83 struct utrec *u = xmalloc(sizeof(struct utrec));
87 u->next = first_utrec;
89 u->login_pid = ut->ut_pid;
90 u->line_id[0] = ut->ut_id[0];
91 u->line_id[1] = ut->ut_id[1];
93 u->login_time = ut->ut_time;
94 strcpy_padded(u->user_name, ut->ut_user, UT_NAMESIZE);
95 pw = getpwnam(u->user_name);
100 strcpy_padded(u->host_name, ut->ut_host,
101 (MAXHOSTSIZE > UT_HOSTSIZE ? UT_HOSTSIZE : MAXHOSTSIZE));
102 if ((hlen = strlen(u->host_name)) > maxhost)
104 strcpy(u->line_name, ut->ut_line);
107 char *z = u->line_name;
108 if (!strncmp(u->line_name, "tty", 3))
110 if (!strncmp(z, "pts/", 4))
112 strncpy(u->line_id, z, 3);
114 if (u->line_id[0] == '/')
117 strcpy(device, "/dev/");
118 strcat(device, u->line_name);
119 if (stat(device, &st))
123 u->mesg = !!(S_IWGRP & st.st_mode);
124 u->click_time = st.st_atime;
126 if (u->click_time < st.st_mtime)
127 u->click_time = st.st_mtime;
128 if (u->click_time < st.st_ctime)
129 u->click_time = st.st_ctime;
135 printf("UT %s %s %d %d\n", u->user_name, u->host_name,
136 u->usr, u->login_pid);
155 printf("%02d.%02d", h, m);
161 printf("%2dd%02d", d, h);
169 memory(unsigned int i)
184 printf("%dG", (i+511U)/1024U);
193 char line[256], a[32], b[32], c[32];
196 if (f = fopen("/proc/version", "r"))
199 z = strchr(line, '(');
202 while (z != line && z[-1] == ' ')
206 z = line + strlen(line) - 1;
208 z = strstr(line, " version");
210 memmove(z, z+8, strlen(z+8)+1);
214 if (f = fopen("/proc/cpuinfo", "r"))
224 if (!strncmp(line, "cpu\t\t: ", 7))
229 else if (!strncmp(line, "cpu family\t: ",13))
231 z = line+13; strcpy(z + 1, "86\n");
234 else if (!strncmp(line, "model\t\t: ", 9))
239 else if (!strncmp(line, "model name\t: ", 13))
242 if (!strncmp(z, "AMD-K6", 6))
245 if ((w = strstr(z, "tm w/ multimedia")))
247 else if ((w = strstr(z, "(tm) 3D")))
252 else if (!strncmp(line, "mask\t\t: ", 8))
261 line[strlen(line)-1] = 0;
263 if (!strcmp(w, "Unknown"))
267 printf(" on %s", *b ? b : a);
272 if (f = fopen("/proc/uptime", "r"))
276 sscanf(line, "%d.%d%d.%d", &p, &p1, &q, &q1);
286 tm = localtime(&now);
287 printf(" at %02d-%02d-%02d/%d %02d.%02d:%02d\n", tm->tm_mday, tm->tm_mon+1,
288 tm->tm_year, (tm->tm_wday+6)%7, tm->tm_hour, tm->tm_min, tm->tm_sec);
290 if (f = fopen("/proc/loadavg", "r"))
294 *strchr(line, '\n') = 0;
308 printf("R/T=%s, ", z);
312 printf("LAV=%s", line);
315 if (f = fopen("/proc/meminfo", "r"))
317 int free, buffers, stotal, sfree;
318 free = buffers = stotal = sfree = 0;
319 while (fgets(line, 256, f))
321 if (!strncmp(line, "MemFree:", 8))
322 sscanf(line+8, "%d", &free);
323 else if (!strncmp(line, "Buffers:", 8))
324 sscanf(line+8, "%d", &buffers);
325 else if (!strncmp(line, "SwapTotal:", 10))
326 sscanf(line+10, "%d", &stotal);
327 else if (!strncmp(line, "SwapFree:", 9))
328 sscanf(line+9, "%d", &sfree);
331 memory(1024*(free+buffers));
336 memory(1024*(stotal - sfree));
340 printf(", %d user%s.\n", usercnt, usercnt == 1 ? "" : "s");
349 unsigned cmdcols = 0;
352 if (!ioctl(1, TIOCGWINSZ, &win) && win.ws_col >= LEFTSIZE + maxhost + 10 && win.ws_col < 1024)
353 cmdcols = win.ws_col;
355 cmdcols -= LEFTSIZE + maxhost;
356 if (d = opendir("/proc"))
358 while (e = readdir(d))
361 if (sscanf(e->d_name, "%d", &i)==1)
363 struct procrec *p = xmalloc(sizeof(struct procrec) + cmdcols);
365 char name[256], eman[1024];
368 strcpy(name, "/proc/");
369 strcat(name, e->d_name);
370 if (!stat(name, &st))
372 p->next = first_procrec;
376 strcat(eman, "/cmdline");
377 if ((fil = open(eman, O_RDONLY)) >= 0)
379 int z = read(fil, p->cmd_line, cmdcols);
382 p->cmd_line[z] = 0x91;
386 strcat(eman, "/stat");
387 if ((fil = open(eman, O_RDONLY)) >= 0)
389 int z = read(fil, eman, 1023);
391 int trash, utim, stim, cutim, cstim;
395 k = strchr(eman, ')');
401 sscanf(k+4, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
402 &p->ppid, &p->pgrp, &p->sess, &trash, &trash,
403 &trash, &trash, &trash, &trash, &trash, &utim,
404 &stim, &cutim, &cstim);
406 p->tim = utim + stim;
407 p->ctim = cutim + cstim;
417 perror("unable to scan /proc");
425 struct utrec *u = first_utrec;
426 struct procrec *m, *n, *o, *q;
431 while (m && m->pid != u->login_pid)
441 if (q->sess == n->sess)
443 if (q->pid == n->ppid && n->usr == -1)
453 u->total_time = m->ctim;
457 printf("%s %s\n", u->user_name, o->cmd_line);
462 for(u=first_utrec; u; u=u->next)
464 for(m=first_procrec; m; m=m->next)
465 if (u->usr == m->usr)
470 printf("** %s %s\n", u->user_name, m->cmd_line);
474 for(m=first_procrec; m; m=m->next)
475 if (m->usr >= 2 && m->ppid == 1) /* Exclude no_user,root,bin */
477 for(u=first_utrec; u; u=u->next)
478 if (u->usr == m->usr)
482 u = xmalloc(sizeof(struct utrec));
483 u->next = first_utrec;
487 pw = getpwuid(u->usr = m->usr);
489 strcpy(u->user_name, pw->pw_name);
491 sprintf(u->user_name, "<%d>", m->usr);
501 u->total_time += m->ctim;
504 printf("// %s %s\n", u->user_name, m->cmd_line);
510 comp(struct utrec *a, struct utrec *b)
515 k = strcmp(a->user_name, b->user_name);
518 if (!a->host_name[0] && b->host_name[0])
520 return strcmp(a->line_id, b->line_id);
526 struct utrec *fi = NULL;
527 struct utrec *z, **y, **m, **l;
553 printf("Name Li MD %-*s LogT IdleT RunT Command\n", maxhost, "From");
554 for(u=first_utrec; u; u=u->next)
556 if (isdigit(u->line_id[0]))
557 sprintf(u->line_id, "c%d", atoi(u->line_id));
559 strcpy(u->line_id, "--");
560 printf("%-8.8s %-3s %c%c %-*.*s ",
564 u->detach ? 'D' : ' ',
570 if (u->login_time > now)
572 puttime(now - u->login_time);
574 if (u->click_time > now)
576 if (now - u->click_time >= 60)
577 puttime(now - u->click_time);
586 puttime((unsigned)u->total_time/(unsigned)HZ);
588 for (c = u->proc->cmd_line; *c != 0x91; c++)
590 if (*c < 0x20 || (*c >= 0x7f && *c < 0xa0))
597 printf(" <nothing>");
612 printf("!!! There %s %d zombie%s walking around.\n",
613 zombies == 1 ? "is" : "are",
615 zombies == 1 ? "" : "s" );