]> mj.ucw.cz Git - ywho.git/blob - ywho.c
568ed64286ab3686ed2977e15d4c6def494aa084
[ywho.git] / ywho.c
1 /*
2  *              Extended `who' command, version 1.3.
3  *
4  *              (c) 1996 Martin Mares <mj@k332.feld.cvut.cz>
5  *
6  *              1.3 (16-96-96) - idle derived from atime instead of mtime.
7  *                                                      - displaying of current command fixed.
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <utmp.h>
16 #include <time.h>
17 #include <dirent.h>
18 #include <pwd.h>
19 #include <sys/stat.h>
20 #include <asm/param.h>
21
22 #undef DEBUG
23
24 struct procrec {
25         struct procrec *next;
26         int pid, ppid, pgrp, sess;
27         int usr, state;
28         time_t ctim, tim;
29         char cmd_line[34];
30         };
31
32 static struct procrec *first_procrec;
33
34 struct utrec {
35         struct utrec *next;
36         pid_t login_pid;
37         char line_id[4];
38         time_t login_time, click_time, total_time;
39         char user_name[UT_NAMESIZE+1];
40         int usr;
41         char host_name[17];
42         char line_name[12];
43         int mesg, detach;
44         struct procrec *proc;
45         };
46
47 static struct utrec *first_utrec;
48 static int usercnt, zombies;
49 static time_t now;
50
51 static void *
52 xmalloc(int i)
53 {
54 void *z;
55         z = malloc(i);
56         if (!z)
57                 {
58                 fprintf(stderr, "xwho: out of memory!\n");
59                 exit(1);
60                 }
61         return z;
62 }
63
64 static void
65 strcpy_padded(char *to, char *from, int size)
66 {
67         memcpy(to, from, size);
68         to[size] = 0;
69 }
70
71 static void
72 readutmp(void)
73 {
74 static struct utmp *ut;
75 static struct passwd *pw;
76         utmpname(UTMP_FILE);
77         while (ut = getutent())
78                 if (ut->ut_type == USER_PROCESS && ut->ut_user[0])
79                         {
80                         struct utrec *u = xmalloc(sizeof(struct utrec));
81                         struct stat st;
82                         char device[32];
83                                 u->next = first_utrec;
84                                 first_utrec = u;
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];
88                                 u->line_id[2] = 0;
89                                 u->login_time = ut->ut_time;
90                                 strcpy_padded(u->user_name, ut->ut_user, UT_NAMESIZE);
91                                 pw = getpwnam(u->user_name);
92                                 if (pw)
93                                         u->usr = pw->pw_uid;
94                                 else
95                                         u->usr = -1;
96                                 strcpy_padded(u->host_name, ut->ut_host, 16);
97                                 strcpy(u->line_name, ut->ut_line);
98                                 if (!u->line_id[0])
99                                         {
100                                         char *z = u->line_name;
101                                         if (!strncmp(u->line_name, "tty", 3))
102                                                 z += 3;
103                                         strncpy(u->line_id, z, 3);
104                                         u->line_id[3] = 0;
105                                         }
106                                 strcpy(device, "/dev/");
107                                 strcat(device, u->line_name);
108                                 if (stat(device, &st))
109                                         u->mesg = 2;
110                                 else
111                                         {
112                                         u->mesg = !!(S_IWOTH & st.st_mode);
113                                         u->click_time = st.st_atime;
114                                         if (u->click_time < st.st_atime)
115                                                 u->click_time = st.st_atime;
116                                         if (u->click_time < st.st_ctime)
117                                                 u->click_time = st.st_ctime;
118                                         }
119                                 u->detach = 0;
120                                 usercnt++;
121 #ifdef DEBUG
122                                 printf("UT %s %s %d %d\n", u->user_name, u->host_name,
123                                         u->usr, u->login_pid);
124 #endif
125                         }
126         endutent();
127 }
128
129 static void
130 puttime(int s)
131 {
132 int d, h, m;
133         if (s < 100)
134                 printf("%4ds", s);
135         else
136                 {
137                 m = s/60;
138                 s %= 60;
139                 h = m/60;
140                 m %= 60;
141                 if (h < 100)
142                         printf("%02d.%02d", h, m);
143                 else
144                         {
145                         d = h/24;
146                         h %= 24;
147                         if (d < 100)
148                                 printf("%2dd%02d", d, h);
149                         else
150                                 printf("%4dd", d);
151                         }
152                 }
153 }
154
155 static void
156 memory(unsigned int i)
157 {
158         if (i < 1000)
159                 printf("%dB", i);
160         else
161                 {
162                 i = (i+511)/1024;
163                 if (i < 1000)
164                         printf("%dK", i);
165                 else
166                         {
167                         i = (i+511)/1024;
168                         if (i < 1000)
169                                 printf("%dM", i);
170                         else
171                                 printf("%dG", (i+511U)/1024U);
172                         }
173                 }
174 }
175
176 static void
177 dispsys(void)
178 {
179 FILE *f;
180 char line[256], a[32], b[32], c[32];
181 char *z, *w;
182         w = NULL;
183         if (f = fopen("/proc/version", "r"))
184                 {
185                 fgets(line, 256, f);
186                 z = strchr(line, '(');
187                 if (z)
188                         {
189                         while (z != line && z[-1] == ' ')
190                                 z--;
191                         }
192                 else
193                         z = line + strlen(line) - 1;
194                 *z = 0;
195                 z = strstr(line, " version");
196                 if (z)
197                         memmove(z, z+8, strlen(z+8)+1);
198                 printf(line);
199                 fclose(f);
200                 }
201         if (f = fopen("/proc/cpuinfo", "r"))
202                 {
203                 strcpy(a, "???");
204                 b[0] = 0;
205                 c[0] = 0;
206                 for(;;)
207                         {
208                         fgets(line, 256, f);
209                         if (feof(f))
210                                 break;
211                         if (!strncmp(line, "cpu\t\t: ", 7))
212                                 {
213                                 z = line+7;
214                                 w = a;
215                                 }
216                         else if (!strncmp(line, "model\t\t: ", 9))
217                                 {
218                                 z = line+9;
219                                 w = b;
220                                 }
221                         else if (!strncmp(line, "mask\t\t: ", 8))
222                                 {
223                                 z = line+8;
224                                 w = c;
225                                 }
226                         else
227                                 z = NULL;
228                         if (z)
229                                 {
230                                 line[strlen(line)-1] = 0;
231                                 strcpy(w, z);
232                                 if (!strcmp(w, "Unknown"))
233                                         w[0] = 0;
234                                 }
235                         }
236                 printf(" on %s", a);
237                 if (*b)
238                         printf("-%s", b);
239                 if (*c)
240                         printf("-%s", c);
241                 fclose(f);
242                 }
243         if (f = fopen("/proc/uptime", "r"))
244                 {
245                 int p,q,p1,q1;
246                 fgets(line, 256, f);
247                 sscanf(line, "%d.%d%d.%d", &p, &p1, &q, &q1);
248                 printf(", up ");
249                 puttime(p);
250                 printf(", run ");
251                 puttime(p-q);
252                 fclose(f);
253                 }
254         {
255         struct tm *tm;
256                 now = time(NULL);
257                 tm = localtime(&now);
258                 printf(" at %02d-%02d-%02d/%d %02d.%02d:%02d\n", tm->tm_mday, tm->tm_mon+1,
259                         tm->tm_year, (tm->tm_wday+6)%7, tm->tm_hour, tm->tm_min, tm->tm_sec);
260         }
261         if (f = fopen("/proc/loadavg", "r"))
262                 {
263                 int i = 3;
264                 fgets(line, 256, f);
265                 *strchr(line, '\n') = 0;
266                 z = line-1;
267                 while (i-- && z)
268                         {
269                         *z = '/';
270                         z = strchr(z, ' ');
271                         }
272                 if (z)
273                         {
274                         char *k;
275                         *z++ = 0;
276                         k = strchr(z, ' ');
277                         if (k)
278                           *k = 0;
279                         printf("R/T=%s, ", z);
280                         }
281                 else
282                         z = line;
283                 printf("LAV=%s", line);
284                 fclose(f);
285                 }
286         if (f = fopen("/proc/meminfo", "r"))
287                 {
288                 int total, used, free, shared, buffers, totals, useds, frees;
289                 fgets(line, 256, f);
290                 fgets(line, 256, f);
291                 sscanf(line, "Mem:%d%d%d%d%d", &total, &used, &free, &shared, &buffers);
292                 fgets(line, 256, f);
293                 sscanf(line, "Swap:%d%d%d", &totals, &useds, &frees);
294                 printf(", free ");
295                 memory(free+buffers);
296                 printf(" of RAM");
297                 if (useds)
298                         {
299                         printf(", used ");
300                         memory(useds);
301                         printf(" of swap");
302                         }
303                 }
304         printf(", %d user%s.\n", usercnt, usercnt == 1 ? "" : "s");
305 }
306
307 static void
308 readproc(void)
309 {
310 DIR *d;
311 struct dirent *e;
312         if (d = opendir("/proc"))
313                 {
314                 while (e = readdir(d))
315                         {
316                         int i;
317                                 sscanf(e->d_name, "%d", &i);
318                                 if (i)
319                                         {
320                                         struct procrec *p = xmalloc(sizeof(struct procrec));
321                                         struct stat st;
322                                         char name[256], eman[1024];
323                                         int fil;
324                                                 p->pid = i;
325                                                 strcpy(name, "/proc/");
326                                                 strcat(name, e->d_name);
327                                                 if (!stat(name, &st))
328                                                         {
329                                                         p->next = first_procrec;
330                                                         first_procrec = p;
331                                                         p->usr = st.st_uid;
332                                                         strcpy(eman, name);
333                                                         strcat(eman, "/cmdline");
334                                                         if ((fil = open(eman, O_RDONLY)) >= 0)
335                                                                 {
336                                                                 int z = read(fil, p->cmd_line, 33);
337                                                                 if (z < 0)
338                                                                         z = 0;
339                                                                 p->cmd_line[z] = 0xff;
340                                                                 close(fil);
341                                                                 }
342                                                         strcpy(eman, name);
343                                                         strcat(eman, "/stat");
344                                                         if ((fil = open(eman, O_RDONLY)) >= 0)
345                                                                 {
346                                                                 int z = read(fil, eman, 1023);
347                                                                 char *k;
348                                                                 int trash, utim, stim, cutim, cstim;
349                                                                         if (z < 0)
350                                                                                 z = 0;
351                                                                         eman[z] = 0;
352                                                                         k = strchr(eman, ')');
353                                                                         if (k)
354                                                                                 {
355                                                                                 p->state = k[1];
356                                                                                 if (p->state == 'Z')
357                                                                                         zombies++;
358                                                                                 sscanf(k+3, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
359                                                                                         &p->ppid, &p->pgrp, &p->sess, &trash, &trash,
360                                                                                         &trash, &trash, &trash, &trash, &trash, &utim,
361                                                                                         &stim, &cutim, &cstim);
362                                                                                 }
363                                                                         p->tim = utim + stim;
364                                                                         p->ctim = cutim + cstim;
365                                                                         close(fil);
366                                                                 }
367                                                         }
368                                         }
369                         }
370                 closedir(d);
371                 }
372         else
373                 {
374                 perror("unable to scan /proc");
375                 exit(1);
376                 }
377 }
378
379 static void
380 solve(void)
381 {
382 struct utrec *u = first_utrec;
383 struct procrec *m, *n, *o, *q;
384 struct passwd *pw;
385         while (u)
386                 {
387                 m = first_procrec;
388                 while (m && m->pid != u->login_pid)
389                         m = m->next;
390                 o = m;
391                 if (m)
392                         {
393                 retry:
394                         n = first_procrec;
395                         q = o;
396                         while (n)
397                                 {
398                                 if (q->sess == n->sess)
399                                         n->usr = -1;
400                                 if (q->pid == n->ppid && n->usr == -1)
401                                         {
402                                         o = n;
403                                         goto retry;
404                                         }
405                                 n = n->next;
406                                 }
407                         }
408                 u->proc = o;
409                 if (m)
410                         u->total_time = m->ctim;
411 #ifdef DEBUG
412                 if (o)
413                         {
414                         printf("%s %s\n", u->user_name, o->cmd_line);
415                         }
416 #endif
417                 u = u->next;
418                 }
419         for(u=first_utrec; u; u=u->next)
420                 {
421                 for(m=first_procrec; m; m=m->next)
422                         if (u->usr == m->usr)
423                                 {
424                                 m->usr = -1;
425                                 u->detach++;
426 #ifdef DEBUG
427                                 printf("** %s %s\n", u->user_name, m->cmd_line);
428 #endif
429                                 }
430                 }
431         for(m=first_procrec; m; m=m->next)
432                 if (m->usr >= 2 && m->ppid == 1) /* Exclude no_user,root,bin */
433                         {
434                         for(u=first_utrec; u; u=u->next)
435                                 if (u->usr == m->usr)
436                                         break;
437                         if (!u)
438                                 {
439                                 u = xmalloc(sizeof(struct utrec));
440                                 u->next = first_utrec;
441                                 first_utrec = u;
442                                 u->login_pid = 0;
443                                 u->line_id[0] = 0;
444                                 pw = getpwuid(u->usr = m->usr);
445                                 if (pw)
446                                         strcpy(u->user_name, pw->pw_name);
447                                 else
448                                         sprintf(u->user_name, "<%d>", m->usr);
449                                 u->host_name[0] = 0;
450                                 u->line_name[0] = 0;
451                                 u->mesg = 3;
452                                 u->detach = 0;
453                                 u->proc = NULL;
454                                 u->total_time = 0;
455                                 }
456                         if (!u->proc)
457                                 u->proc = m;
458                         u->total_time += m->ctim;
459                         u->detach ++;
460 #ifdef DEBUG
461                         printf("// %s %s\n", u->user_name, m->cmd_line);
462 #endif
463                         }
464 }
465
466 static inline int
467 comp(struct utrec *a, struct utrec *b)
468 {
469 int k;
470         if (b->mesg == 3)
471                 return -1;
472         k = strcmp(a->user_name, b->user_name);
473         if (k)
474                 return k;
475         if (!a->host_name[0] && b->host_name[0])
476                 return -1;
477         return strcmp(a->line_id, b->line_id);
478 }
479
480 static void
481 sort(void)
482 {
483 struct utrec *fi = NULL;
484 struct utrec *z, **y, **m, **l;
485         l = &fi;
486         while (first_utrec)
487                 {
488                 y = &first_utrec;
489                 m = y;
490                 while (z = *y)
491                         {
492                         if (comp(z, *m) < 0)
493                                 m = y;
494                         y = &z->next;
495                         }
496                 z = *m;
497                 *m = z->next;
498                 *l = z;
499                 z->next = NULL;
500                 l = &z->next;
501                 }
502         first_utrec = fi;
503 }
504
505 static void
506 show(void)
507 {
508 struct utrec *u;
509 int i;
510 unsigned char *c;
511         printf("Name     Li  MD From              LogT  IdleT RunT  Command\n");
512         for(u=first_utrec; u; u=u->next)
513                 {
514                 if (!u->line_id[1])
515                         {
516                         if (u->line_id[0])
517                                 {
518                                 u->line_id[1] = u->line_id[0];
519                                 u->line_id[0] = 'c';
520                                 }
521                         else    
522                                 u->line_id[0] = u->line_id[1] = '-';
523                         }
524                 printf("%-8.8s %-3s %c%c %-17.17s ",
525                         u->user_name,
526                         u->line_id,
527                         u->mesg ? ' ' : '-',
528                         u->detach ? 'D' : ' ',
529                         u->host_name);
530                 if (u->mesg <= 1)
531                         {
532                         if (u->login_time > now)
533                                 u->login_time = now;
534                         puttime(now - u->login_time);
535                         putchar(' ');
536                         if (u->click_time > now)
537                                 u->click_time = now;
538                         if (now - u->click_time >= 60)
539                                 puttime(now - u->click_time);
540                         else
541                                 printf("     ");
542                         }
543                 else
544                         printf("?????      ");
545                 if (u->proc)
546                         {
547                         putchar(' ');
548                         puttime((unsigned)u->total_time/(unsigned)HZ);
549                         putchar(' ');
550                         i = 24;
551                         c = u->proc->cmd_line;
552                         while (*c != 0xff && i--)
553                                 {
554                                 putchar(*c ? *c : ' ');
555                                 c++;
556                                 }
557                         }
558                 else
559                         printf(" <nothing>");
560                 putchar('\n');
561                 }
562 }
563
564 int main(void)
565 {
566         readutmp();
567         dispsys();
568         readproc();
569         solve();
570         sort();
571         show();
572         if (zombies)
573                 {
574                 printf("There %s %d zombie%s walking around.",
575                         zombies == 1 ? "is" : "are",
576                         zombies,
577                         zombies == 1 ? "" : "s" );
578                 }
579         return 0;
580 }