2 * Extended `who' command, version 1.8.
4 * (c) 1996--1998 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>
26 int pid, ppid, pgrp, sess;
32 static struct procrec *first_procrec;
38 time_t login_time, click_time, total_time;
39 char user_name[UT_NAMESIZE+1];
47 static struct utrec *first_utrec;
48 static int usercnt, zombies;
58 fprintf(stderr, "ywho: out of memory!\n");
65 strcpy_padded(char *to, char *from, int size)
67 memcpy(to, from, size);
74 static struct utmp *ut;
75 static struct passwd *pw;
77 while (ut = getutent())
78 if (ut->ut_type == USER_PROCESS && ut->ut_user[0])
80 struct utrec *u = xmalloc(sizeof(struct utrec));
83 u->next = first_utrec;
85 u->login_pid = ut->ut_pid;
86 u->line_id[0] = ut->ut_id[0];
87 u->line_id[1] = ut->ut_id[1];
89 u->login_time = ut->ut_time;
90 strcpy_padded(u->user_name, ut->ut_user, UT_NAMESIZE);
91 pw = getpwnam(u->user_name);
96 strcpy_padded(u->host_name, ut->ut_host, 16);
97 strcpy(u->line_name, ut->ut_line);
100 char *z = u->line_name;
101 if (!strncmp(u->line_name, "tty", 3))
103 strncpy(u->line_id, z, 3);
106 strcpy(device, "/dev/");
107 strcat(device, u->line_name);
108 if (stat(device, &st))
112 u->mesg = !!(S_IWGRP & st.st_mode);
113 u->click_time = st.st_atime;
115 if (u->click_time < st.st_mtime)
116 u->click_time = st.st_mtime;
117 if (u->click_time < st.st_ctime)
118 u->click_time = st.st_ctime;
124 printf("UT %s %s %d %d\n", u->user_name, u->host_name,
125 u->usr, u->login_pid);
144 printf("%02d.%02d", h, m);
150 printf("%2dd%02d", d, h);
158 memory(unsigned int i)
173 printf("%dG", (i+511U)/1024U);
182 char line[256], a[32], b[32], c[32];
185 if (f = fopen("/proc/version", "r"))
188 z = strchr(line, '(');
191 while (z != line && z[-1] == ' ')
195 z = line + strlen(line) - 1;
197 z = strstr(line, " version");
199 memmove(z, z+8, strlen(z+8)+1);
203 if (f = fopen("/proc/cpuinfo", "r"))
213 if (!strncmp(line, "cpu\t\t: ", 7))
218 else if (!strncmp(line, "model\t\t: ", 9))
223 else if (!strncmp(line, "mask\t\t: ", 8))
232 line[strlen(line)-1] = 0;
234 if (!strcmp(w, "Unknown"))
245 if (f = fopen("/proc/uptime", "r"))
249 sscanf(line, "%d.%d%d.%d", &p, &p1, &q, &q1);
259 tm = localtime(&now);
260 printf(" at %02d-%02d-%02d/%d %02d.%02d:%02d\n", tm->tm_mday, tm->tm_mon+1,
261 tm->tm_year, (tm->tm_wday+6)%7, tm->tm_hour, tm->tm_min, tm->tm_sec);
263 if (f = fopen("/proc/loadavg", "r"))
267 *strchr(line, '\n') = 0;
281 printf("R/T=%s, ", z);
285 printf("LAV=%s", line);
288 if (f = fopen("/proc/meminfo", "r"))
290 int free, buffers, stotal, sfree;
291 free = buffers = stotal = sfree = 0;
292 while (fgets(line, 256, f))
294 if (!strncmp(line, "MemFree:", 8))
295 sscanf(line+8, "%d", &free);
296 else if (!strncmp(line, "Buffers:", 8))
297 sscanf(line+8, "%d", &buffers);
298 else if (!strncmp(line, "SwapTotal:", 10))
299 sscanf(line+10, "%d", &stotal);
300 else if (!strncmp(line, "SwapFree:", 9))
301 sscanf(line+9, "%d", &sfree);
304 memory(1024*(free+buffers));
309 memory(1024*(stotal - sfree));
313 printf(", %d user%s.\n", usercnt, usercnt == 1 ? "" : "s");
321 if (d = opendir("/proc"))
323 while (e = readdir(d))
326 sscanf(e->d_name, "%d", &i);
329 struct procrec *p = xmalloc(sizeof(struct procrec));
331 char name[256], eman[1024];
334 strcpy(name, "/proc/");
335 strcat(name, e->d_name);
336 if (!stat(name, &st))
338 p->next = first_procrec;
342 strcat(eman, "/cmdline");
343 if ((fil = open(eman, O_RDONLY)) >= 0)
345 int z = read(fil, p->cmd_line, sizeof(p->cmd_line) - 1);
348 p->cmd_line[z] = 0x91;
352 strcat(eman, "/stat");
353 if ((fil = open(eman, O_RDONLY)) >= 0)
355 int z = read(fil, eman, 1023);
357 int trash, utim, stim, cutim, cstim;
361 k = strchr(eman, ')');
367 sscanf(k+4, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
368 &p->ppid, &p->pgrp, &p->sess, &trash, &trash,
369 &trash, &trash, &trash, &trash, &trash, &utim,
370 &stim, &cutim, &cstim);
372 p->tim = utim + stim;
373 p->ctim = cutim + cstim;
383 perror("unable to scan /proc");
391 struct utrec *u = first_utrec;
392 struct procrec *m, *n, *o, *q;
397 while (m && m->pid != u->login_pid)
407 if (q->sess == n->sess)
409 if (q->pid == n->ppid && n->usr == -1)
419 u->total_time = m->ctim;
423 printf("%s %s\n", u->user_name, o->cmd_line);
428 for(u=first_utrec; u; u=u->next)
430 for(m=first_procrec; m; m=m->next)
431 if (u->usr == m->usr)
436 printf("** %s %s\n", u->user_name, m->cmd_line);
440 for(m=first_procrec; m; m=m->next)
441 if (m->usr >= 2 && m->ppid == 1) /* Exclude no_user,root,bin */
443 for(u=first_utrec; u; u=u->next)
444 if (u->usr == m->usr)
448 u = xmalloc(sizeof(struct utrec));
449 u->next = first_utrec;
453 pw = getpwuid(u->usr = m->usr);
455 strcpy(u->user_name, pw->pw_name);
457 sprintf(u->user_name, "<%d>", m->usr);
467 u->total_time += m->ctim;
470 printf("// %s %s\n", u->user_name, m->cmd_line);
476 comp(struct utrec *a, struct utrec *b)
481 k = strcmp(a->user_name, b->user_name);
484 if (!a->host_name[0] && b->host_name[0])
486 return strcmp(a->line_id, b->line_id);
492 struct utrec *fi = NULL;
493 struct utrec *z, **y, **m, **l;
520 printf("Name Li MD From LogT IdleT RunT Command\n");
521 for(u=first_utrec; u; u=u->next)
527 u->line_id[1] = u->line_id[0];
531 u->line_id[0] = u->line_id[1] = '-';
533 printf("%-8.8s %-3s %c%c %-17.17s ",
537 u->detach ? 'D' : ' ',
541 if (u->login_time > now)
543 puttime(now - u->login_time);
545 if (u->click_time > now)
547 if (now - u->click_time >= 60)
548 puttime(now - u->click_time);
557 puttime((unsigned)u->total_time/(unsigned)HZ);
560 c = u->proc->cmd_line;
561 while (*c != 0x91 && i--)
563 if (*c < 0x20 || (*c >= 0x7f && *c < 0xa0))
571 printf(" <nothing>");
586 printf("!!! There %s %d zombie%s walking around.\n",
587 zombies == 1 ? "is" : "are",
589 zombies == 1 ? "" : "s" );