2 * Extended `who' command, version 1.9.
4 * (c) 1996--2001 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;
40 char line[UT_LINESIZE];
41 time_t login_time, click_time, total_time;
42 char user_name[UT_NAMESIZE+1];
44 char host_name[MAXHOSTSIZE+1];
49 static struct utrec *first_utrec;
50 static int usercnt, zombies, maxhost = 10;
60 fprintf(stderr, "ywho: out of memory!\n");
67 strcpy_padded(char *to, char *from, int size)
69 memcpy(to, from, size);
76 static struct utmp *ut;
77 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;
91 if (!strncmp(z, "tty", 3))
93 if (z[3] >= '0' && z[3] <= '9')
94 sprintf(u->line, "c%s", z+3);
98 else if (!strncmp(z, "pts/", 4))
100 u->login_time = ut->ut_time;
101 strcpy_padded(u->user_name, ut->ut_user, UT_NAMESIZE);
102 pw = getpwnam(u->user_name);
107 strcpy_padded(u->host_name, ut->ut_host,
108 (MAXHOSTSIZE > UT_HOSTSIZE ? UT_HOSTSIZE : MAXHOSTSIZE));
109 if ((hlen = strlen(u->host_name)) > maxhost)
111 strcpy(u->line, ut->ut_line);
115 if (!strncmp(z, "tty", 3))
118 sprintf(u->line, "c%s", z+3);
120 strcpy(u->line, z+3);
122 else if (!strncmp(z, "pts/", 4))
123 strcpy(u->line, z+4);
127 strcpy(device, "/dev/");
128 strcat(device, ut->ut_line);
129 if (stat(device, &st))
133 u->mesg = !!(S_IWGRP & st.st_mode);
134 u->click_time = st.st_atime;
136 if (u->click_time < st.st_mtime)
137 u->click_time = st.st_mtime;
138 if (u->click_time < st.st_ctime)
139 u->click_time = st.st_ctime;
145 printf("UT %s %s %d %d\n", u->user_name, u->host_name,
146 u->usr, u->login_pid);
165 printf("%02d.%02d", h, m);
171 printf("%2dd%02d", d, h);
179 memory(unsigned int i)
194 printf("%dG", (i+511U)/1024U);
206 if (f = fopen("/proc/version", "r"))
209 z = strchr(line, '(');
212 while (z != line && z[-1] == ' ')
216 z = line + strlen(line) - 1;
218 z = strstr(line, " version");
220 memmove(z, z+8, strlen(z+8)+1);
224 if (f = fopen("/proc/cpuinfo", "r"))
226 char a[32], b[32], c[32];
235 if (!strncmp(line, "cpu\t\t: ", 7))
240 else if (!strncmp(line, "cpu family\t: ",13))
242 z = line+13; strcpy(z + 1, "86\n");
245 else if (!strncmp(line, "model\t\t: ", 9))
250 else if (!strncmp(line, "model name\t: ", 13))
253 if (!strncmp(z, "AMD-K6", 6))
256 if ((w = strstr(z, "tm w/ multimedia")))
258 else if ((w = strstr(z, "(tm) 3D")))
263 else if (!strncmp(line, "mask\t\t: ", 8))
272 line[strlen(line)-1] = 0;
274 if (!strcmp(w, "Unknown"))
278 printf(" on %s", *b ? b : a);
283 if (f = fopen("/proc/uptime", "r"))
287 sscanf(line, "%d.%d%d.%d", &p, &p1, &q, &q1);
296 char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
298 tm = localtime(&now);
299 printf(" on %s %02d-%02d-%02d %02d.%02d:%02d", days[tm->tm_wday], tm->tm_mday, tm->tm_mon+1,
300 tm->tm_year%100, tm->tm_hour, tm->tm_min, tm->tm_sec);
301 printf(" (%u UE)\n", (unsigned int) now);
303 if (f = fopen("/proc/loadavg", "r"))
307 *strchr(line, '\n') = 0;
321 printf("R/T=%s, ", z);
325 printf("LAV=%s", line);
328 if (f = fopen("/proc/meminfo", "r"))
330 int free, buffers, stotal, sfree;
331 free = buffers = stotal = sfree = 0;
332 while (fgets(line, 256, f))
334 if (!strncmp(line, "MemFree:", 8))
335 sscanf(line+8, "%d", &free);
336 else if (!strncmp(line, "Buffers:", 8))
337 sscanf(line+8, "%d", &buffers);
338 else if (!strncmp(line, "SwapTotal:", 10))
339 sscanf(line+10, "%d", &stotal);
340 else if (!strncmp(line, "SwapFree:", 9))
341 sscanf(line+9, "%d", &sfree);
344 memory(1024*(free+buffers));
349 memory(1024*(stotal - sfree));
353 printf(", %d user%s.\n", usercnt, usercnt == 1 ? "" : "s");
362 unsigned cmdcols = 0;
365 if (!ioctl(1, TIOCGWINSZ, &win) && win.ws_col >= LEFTSIZE + maxhost + 10 && win.ws_col < 1024)
366 cmdcols = win.ws_col;
368 cmdcols -= LEFTSIZE + maxhost;
369 if (d = opendir("/proc"))
371 while (e = readdir(d))
374 if (sscanf(e->d_name, "%d", &i)==1)
376 struct procrec *p = xmalloc(sizeof(struct procrec) + cmdcols);
378 char name[256], eman[1024];
381 strcpy(name, "/proc/");
382 strcat(name, e->d_name);
383 if (!stat(name, &st))
385 p->next = first_procrec;
389 strcat(eman, "/cmdline");
390 if ((fil = open(eman, O_RDONLY)) >= 0)
392 int z = read(fil, p->cmd_line, cmdcols);
395 p->cmd_line[z] = 0x91;
399 strcat(eman, "/stat");
400 if ((fil = open(eman, O_RDONLY)) >= 0)
402 int z = read(fil, eman, 1023);
404 int trash, utim, stim, cutim, cstim;
408 k = strchr(eman, ')');
414 sscanf(k+4, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
415 &p->ppid, &p->pgrp, &p->sess, &trash, &trash,
416 &trash, &trash, &trash, &trash, &trash, &utim,
417 &stim, &cutim, &cstim);
419 p->tim = utim + stim;
420 p->ctim = cutim + cstim;
430 perror("unable to scan /proc");
438 struct utrec *u = first_utrec;
439 struct procrec *m, *n, *o, *q;
444 while (m && m->pid != u->login_pid)
454 if (q->sess == n->sess)
456 if (q->pid == n->ppid && n->usr == -1)
466 u->total_time = m->ctim;
470 printf("%s %s\n", u->user_name, o->cmd_line);
475 for(u=first_utrec; u; u=u->next)
477 for(m=first_procrec; m; m=m->next)
478 if (u->usr == m->usr)
483 printf("** %s %s\n", u->user_name, m->cmd_line);
487 for(m=first_procrec; m; m=m->next)
488 if (m->usr >= 2 && m->ppid == 1) /* Exclude no_user,root,bin */
490 for(u=first_utrec; u; u=u->next)
491 if (u->usr == m->usr)
495 u = xmalloc(sizeof(struct utrec));
496 u->next = first_utrec;
500 pw = getpwuid(u->usr = m->usr);
502 strcpy(u->user_name, pw->pw_name);
504 sprintf(u->user_name, "<%d>", m->usr);
513 u->total_time += m->ctim;
516 printf("// %s %s\n", u->user_name, m->cmd_line);
522 comp(struct utrec *a, struct utrec *b)
527 k = strcmp(a->user_name, b->user_name);
530 if (!a->host_name[0] && b->host_name[0])
532 return strcmp(a->line, b->line);
538 struct utrec *fi = NULL;
539 struct utrec *z, **y, **m, **l;
565 printf("Name Li MD %-*s LogT IdleT RunT Command\n", maxhost, "From");
566 for(u=first_utrec; u; u=u->next)
569 strcpy(u->line, "--");
570 printf("%-8.8s %-3s %c%c %-*.*s ",
574 u->detach ? 'D' : ' ',
580 if (u->login_time > now)
582 puttime(now - u->login_time);
584 if (u->click_time > now)
586 if (now - u->click_time >= 60)
587 puttime(now - u->click_time);
596 puttime((unsigned)u->total_time/(unsigned)HZ);
598 for (c = u->proc->cmd_line; *c != 0x91; c++)
600 if (*c < 0x20 || (*c >= 0x7f && *c < 0xa0))
607 printf(" <nothing>");
622 printf("!!! There %s %d zombie%s walking around.\n",
623 zombies == 1 ? "is" : "are",
625 zombies == 1 ? "" : "s" );