]> mj.ucw.cz Git - ywho.git/blobdiff - ywho.c
make release: Reorganized my directory structure
[ywho.git] / ywho.c
diff --git a/ywho.c b/ywho.c
index 373e61369ec75a81a17661f5be93e09c1aa027f8..15d1b46da203a6b38e3ea269b3220f0c45df286c 100644 (file)
--- a/ywho.c
+++ b/ywho.c
@@ -1,7 +1,7 @@
 /*
- *     Extended `who' command, version 1.8.
+ *     Extended `who' command, version 1.12.
  *
- *     (c) 1996, 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *     (c) 1996--2010 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU General Public License. See file COPYING in any of the GNU packages.
 #include <pwd.h>
 #include <sys/stat.h>
 #include <asm/param.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
 
 #undef DEBUG
+#define MAXHOSTSIZE 24
+
+#ifdef DEBUG
+#define DBG(x,y...) printf(x,##y)
+#else
+#define DBG(x,y...) do { } while(0)
+#endif
 
 struct procrec {
   struct procrec *next;
   int pid, ppid, pgrp, sess;
-  int usr, state;
+  int uid, state, distance;
   time_t ctim, tim;
-  char cmd_line[34];
+  struct utrec *user;
+  char cmd_line[1];
 };
 
 static struct procrec *first_procrec;
@@ -34,18 +44,17 @@ static struct procrec *first_procrec;
 struct utrec {
   struct utrec *next;
   pid_t login_pid;
-  char line_id[4];
+  char line[UT_LINESIZE];
   time_t login_time, click_time, total_time;
   char user_name[UT_NAMESIZE+1];
-  int usr;
-  char host_name[17];
-  char line_name[12];
+  int uid;
+  char host_name[MAXHOSTSIZE+1];
   int mesg, detach;
   struct procrec *proc;
 };
 
 static struct utrec *first_utrec;
-static int usercnt, zombies;
+static int usercnt, zombies, maxhost = 10;
 static time_t now;
 
 static void *
@@ -73,6 +82,7 @@ readutmp(void)
 {
   static struct utmp *ut;
   static struct passwd *pw;
+  char *z;
   utmpname(UTMP_FILE);
   while (ut = getutent())
     if (ut->ut_type == USER_PROCESS && ut->ut_user[0])
@@ -80,48 +90,67 @@ readutmp(void)
        struct utrec *u = xmalloc(sizeof(struct utrec));
        struct stat st;
        char device[32];
+       size_t hlen;
+       bzero(u, sizeof(*u));
        u->next = first_utrec;
        first_utrec = u;
        u->login_pid = ut->ut_pid;
-       u->line_id[0] = ut->ut_id[0];
-       u->line_id[1] = ut->ut_id[1];
-       u->line_id[2] = 0;
+       z = ut->ut_line;
+       if (!strncmp(z, "tty", 3))
+         {
+           if (z[3] >= '0' && z[3] <= '9')
+             sprintf(u->line, "c%s", z+3);
+           else
+             strcpy(u->line, z+3);
+         }
+       else if (!strncmp(z, "pts/", 4))
+         strcpy(u->line, z+4);
        u->login_time = ut->ut_time;
        strcpy_padded(u->user_name, ut->ut_user, UT_NAMESIZE);
        pw = getpwnam(u->user_name);
        if (pw)
-         u->usr = pw->pw_uid;
+         u->uid = pw->pw_uid;
        else
-         u->usr = -1;
-       strcpy_padded(u->host_name, ut->ut_host, 16);
-       strcpy(u->line_name, ut->ut_line);
-       if (!u->line_id[0])
+         u->uid = -1;
+       strcpy_padded(u->host_name, ut->ut_host,
+         (MAXHOSTSIZE > UT_HOSTSIZE ? UT_HOSTSIZE : MAXHOSTSIZE));
+       if ((hlen = strlen(u->host_name)) > maxhost)
+         maxhost = hlen;
+       strcpy(u->line, ut->ut_line);
+       if (*u->line)
          {
-           char *z = u->line_name;
-           if (!strncmp(u->line_name, "tty", 3))
-             z += 3;
-           strncpy(u->line_id, z, 3);
-           u->line_id[3] = 0;
+           char *z = u->line;
+           if (!strncmp(z, "tty", 3))
+             {
+               if (isdigit(z[3]))
+                 sprintf(u->line, "c%s", z+3);
+               else
+                 strcpy(u->line, z+3);
+             }
+           else if (!strncmp(z, "pts/", 4))
+             strcpy(u->line, z+4);
+           else
+             strcpy(u->line, z);
          }
        strcpy(device, "/dev/");
-       strcat(device, u->line_name);
+       strcat(device, ut->ut_line);
        if (stat(device, &st))
          u->mesg = 2;
        else
          {
            u->mesg = !!(S_IWGRP & st.st_mode);
            u->click_time = st.st_atime;
-           if (u->click_time < st.st_atime)
-             u->click_time = st.st_atime;
+#if 0
+           if (u->click_time < st.st_mtime)
+             u->click_time = st.st_mtime;
            if (u->click_time < st.st_ctime)
              u->click_time = st.st_ctime;
+#endif
          }
        u->detach = 0;
        usercnt++;
-#ifdef DEBUG
-       printf("UT %s %s %d %d\n", u->user_name, u->host_name,
-              u->usr, u->login_pid);
-#endif
+       DBG("UTMP: %s %s %d %d\n", u->user_name, u->host_name,
+           u->uid, u->login_pid);
       }
   endutent();
 }
@@ -174,12 +203,13 @@ memory(unsigned int i)
 }
 
 static void
-dispsys(void)
+line1(void)
 {
   FILE *f;
-  char line[256], a[32], b[32], c[32];
-  char *z, *w;
-  w = NULL;
+  char line[256];
+  char *z;
+  int num_cpus = 0;
+
   if (f = fopen("/proc/version", "r"))
     {
       fgets(line, 256, f);
@@ -198,75 +228,60 @@ dispsys(void)
       printf(line);
       fclose(f);
     }
+
+  if (gethostname(line, sizeof(line)) >= 0)
+    printf(" (%s)", line);
+
   if (f = fopen("/proc/cpuinfo", "r"))
     {
-      strcpy(a, "???");
-      b[0] = 0;
-      c[0] = 0;
-      for(;;)
+      while (fgets(line, 256, f))
        {
-         fgets(line, 256, f);
-         if (feof(f))
-           break;
-         if (!strncmp(line, "cpu\t\t: ", 7))
-           {
-             z = line+7;
-             w = a;
-           }
-         else if (!strncmp(line, "model\t\t: ", 9))
-           {
-             z = line+9;
-             w = b;
-           }
-         else if (!strncmp(line, "mask\t\t: ", 8))
-           {
-             z = line+8;
-             w = c;
-           }
-         else
-           z = NULL;
-         if (z)
-           {
-             line[strlen(line)-1] = 0;
-             strcpy(w, z);
-             if (!strcmp(w, "Unknown"))
-               w[0] = 0;
-           }
+         if (!strncmp(line, "processor\t", 9))
+           num_cpus++;
        }
-      printf(" on %s", a);
-      if (*b)
-       printf("-%s", b);
-      if (*c)
-       printf("-%s", c);
+      printf(" [%d CPU%s]", num_cpus, (num_cpus != 1 ? "s" : ""));
       fclose(f);
     }
+
   if (f = fopen("/proc/uptime", "r"))
     {
       int p,q,p1,q1;
       fgets(line, 256, f);
       sscanf(line, "%d.%d%d.%d", &p, &p1, &q, &q1);
-      printf(", up ");
+      printf(" up ");
       puttime(p);
-      printf(", run ");
-      puttime(p-q);
+      printf(" run ");
+      puttime(num_cpus*p - q);
       fclose(f);
     }
+
   {
-    struct tm *tm;
     now = time(NULL);
-    tm = localtime(&now);
-    printf(" at %02d-%02d-%02d/%d %02d.%02d:%02d\n", tm->tm_mday, tm->tm_mon+1,
-          tm->tm_year, (tm->tm_wday+6)%7, tm->tm_hour, tm->tm_min, tm->tm_sec);
+    struct tm *tm = localtime(&now);
+    strftime(line, sizeof(line), "%a %Y-%m-%d %H.%M:%S", tm);
+    printf(" on %s\n", line);
   }
+}
+
+static void
+line2(void)
+{
+  FILE *f;
+  char line[256];
+  char *z;
+
   if (f = fopen("/proc/loadavg", "r"))
     {
       int i = 3;
       fgets(line, 256, f);
-      *strchr(line, '\n') = 0;
-      z = line-1;
+      z = strchr(line, '\n');
+      if (z)
+       *z = 0;
+      z = line;
       while (i-- && z)
        {
-         *z = '/';
+         if (z > line)
+           *z = '/';
          z = strchr(z, ' ');
        }
       if (z)
@@ -283,9 +298,10 @@ dispsys(void)
       printf("LAV=%s", line);
       fclose(f);
     }
+
   if (f = fopen("/proc/meminfo", "r"))
     {
-      int free, buffers, stotal, sfree;
+      int free, buffers, cached, stotal, sfree;
       free = buffers = stotal = sfree = 0;
       while (fgets(line, 256, f))
        {
@@ -293,13 +309,15 @@ dispsys(void)
            sscanf(line+8, "%d", &free);
          else if (!strncmp(line, "Buffers:", 8))
            sscanf(line+8, "%d", &buffers);
+         else if (!strncmp(line, "Cached:", 7))
+           sscanf(line+7, "%d", &cached);
          else if (!strncmp(line, "SwapTotal:", 10))
            sscanf(line+10, "%d", &stotal);
          else if (!strncmp(line, "SwapFree:", 9))
            sscanf(line+9, "%d", &sfree);
        }
       printf(", free ");
-      memory(1024*(free+buffers));
+      memory(1024*(free+buffers+cached));
       printf(" of RAM");
       if (stotal != sfree)
        {
@@ -308,7 +326,7 @@ dispsys(void)
          printf(" of swap");
        }
     }
-  printf(", %d user%s.\n", usercnt, usercnt == 1 ? "" : "s");
+  printf(", %d user%s\n", usercnt, usercnt == 1 ? "" : "s");
 }
 
 static void
@@ -316,34 +334,44 @@ readproc(void)
 {
   DIR *d;
   struct dirent *e;
+  struct winsize win;
+  unsigned cmdcols;
+#define LEFTSIZE 35
+  
+  if (!ioctl(1, TIOCGWINSZ, &win) && win.ws_col >= LEFTSIZE + maxhost + 10 && win.ws_col < 1024)
+    cmdcols = win.ws_col;
+  else
+    cmdcols = 80;
+  cmdcols -= LEFTSIZE + maxhost;
   if (d = opendir("/proc"))
     {
       while (e = readdir(d))
        {
          int i;
-         sscanf(e->d_name, "%d", &i);
-         if (i)
+         if (sscanf(e->d_name, "%d", &i)==1)
            {
-             struct procrec *p = xmalloc(sizeof(struct procrec));
+             struct procrec *p = xmalloc(sizeof(struct procrec) + cmdcols);
              struct stat st;
              char name[256], eman[1024];
              int fil;
+             bzero(p, sizeof(*p));
              p->pid = i;
              strcpy(name, "/proc/");
              strcat(name, e->d_name);
              if (!stat(name, &st))
                {
-                 p->next = first_procrec;
-                 first_procrec = p;
-                 p->usr = st.st_uid;
+                 p->uid = st.st_uid;
                  strcpy(eman, name);
                  strcat(eman, "/cmdline");
                  if ((fil = open(eman, O_RDONLY)) >= 0)
                    {
-                     int z = read(fil, p->cmd_line, sizeof(p->cmd_line) - 1);
+                     int y, z = read(fil, p->cmd_line, cmdcols);
                      if (z < 0)
                        z = 0;
-                     p->cmd_line[z] = 0x91;
+                     for (y=0; y<z; y++)
+                       if (!p->cmd_line[y])
+                         p->cmd_line[y] = ' ';
+                     p->cmd_line[z] = 0;
                      close(fil);
                    }
                  strcpy(eman, name);
@@ -351,14 +379,19 @@ readproc(void)
                  if ((fil = open(eman, O_RDONLY)) >= 0)
                    {
                      int z = read(fil, eman, 1023);
-                     char *k;
+                     char *j, *k;
                      int trash, utim, stim, cutim, cstim;
                      if (z < 0)
                        z = 0;
                      eman[z] = 0;
-                     k = strchr(eman, ')');
-                     if (k)
+                     if ((j = strchr(eman, '(')) && (k = strchr(j+1, ')')))
                        {
+                         *k = 0;
+                         if (!p->cmd_line[0])
+                           {
+                             strncpy(p->cmd_line, j+1, cmdcols);
+                             p->cmd_line[cmdcols] = 0;
+                           }
                          p->state = k[2];
                          if (p->state == 'Z')
                            zombies++;
@@ -366,6 +399,9 @@ readproc(void)
                                 &p->ppid, &p->pgrp, &p->sess, &trash, &trash,
                                 &trash, &trash, &trash, &trash, &trash, &utim,
                                 &stim, &cutim, &cstim);
+                         DBG("PROC: pid=%d ppid=%d pgrp=%d sess=%d uid=%d\n", p->pid, p->ppid, p->pgrp, p->sess, p->uid);
+                         p->next = first_procrec;
+                         first_procrec = p;
                        }
                      p->tim = utim + stim;
                      p->ctim = cutim + cstim;
@@ -386,88 +422,71 @@ readproc(void)
 static void
 solve(void)
 {
-  struct utrec *u = first_utrec;
-  struct procrec *m, *n, *o, *q;
+  struct utrec *u;
+  struct procrec *m, *n;
   struct passwd *pw;
-  while (u)
-    {
-      m = first_procrec;
-      while (m && m->pid != u->login_pid)
-       m = m->next;
-      o = m;
-      if (m)
-       {
-       retry:
-         n = first_procrec;
-         q = o;
-         while (n)
-           {
-             if (q->sess == n->sess)
-               n->usr = -1;
-             if (q->pid == n->ppid && n->usr == -1)
-               {
-                 o = n;
-                 goto retry;
-               }
-             n = n->next;
-           }
-       }
-      u->proc = o;
-      if (m)
-       u->total_time = m->ctim;
-#ifdef DEBUG
-      if (o)
-       {
-         printf("%s %s\n", u->user_name, o->cmd_line);
-       }
-#endif
-      u = u->next;
-    }
-  for(u=first_utrec; u; u=u->next)
+  int cnt;
+
+  /* Recognize login session process trees and find leaves of these trees */
+  for (u=first_utrec; u; u=u->next)
     {
-      for(m=first_procrec; m; m=m->next)
-       if (u->usr == m->usr)
+      for (m=first_procrec; m; m=m->next)
+       if (m->pid == u->login_pid)
          {
-           m->usr = -1;
-           u->detach++;
-#ifdef DEBUG
-           printf("** %s %s\n", u->user_name, m->cmd_line);
-#endif
+           m->user = u;
+           u->total_time = m->ctim;
+           u->proc = m;
+           DBG("** %d is login process for %s@%s\n", m->pid, u->user_name, u->line);
          }
     }
+  do
+    {
+      cnt = 0;
+      for (m=first_procrec; m; m=m->next)
+       if (!m->user)
+         for (n=first_procrec; n; n=n->next)
+           if (n->pid == m->ppid && n->user)
+             {
+               u = m->user = n->user;
+               m->distance = n->distance + 1;
+               if (!u->proc || u->proc->distance < m->distance)
+                 u->proc = m;
+               cnt++;
+               DBG("** %d at distance %d for %s@%s\n", m->pid, m->distance, u->user_name, u->line);
+               break;
+             }
+    }
+  while (cnt);
+
+  /* Process the remaining processes */
   for(m=first_procrec; m; m=m->next)
-    if (m->usr >= 2 && m->ppid == 1) /* Exclude no_user,root,bin */
-      {
-       for(u=first_utrec; u; u=u->next)
-         if (u->usr == m->usr)
-           break;
-       if (!u)
-         {
-           u = xmalloc(sizeof(struct utrec));
-           u->next = first_utrec;
-           first_utrec = u;
-           u->login_pid = 0;
-           u->line_id[0] = 0;
-           pw = getpwuid(u->usr = m->usr);
-           if (pw)
-             strcpy(u->user_name, pw->pw_name);
-           else
-             sprintf(u->user_name, "<%d>", m->usr);
-           u->host_name[0] = 0;
-           u->line_name[0] = 0;
-           u->mesg = 3;
-           u->detach = 0;
-           u->proc = NULL;
-           u->total_time = 0;
-         }
-       if (!u->proc)
-         u->proc = m;
-       u->total_time += m->ctim;
-       u->detach ++;
-#ifdef DEBUG
-       printf("// %s %s\n", u->user_name, m->cmd_line);
-#endif
-      }
+    {
+      if (m->user)
+       continue;
+      for(u=first_utrec; u; u=u->next)
+       if (u->uid == m->uid)
+         break;
+      if (!u)
+       {
+         if (m->uid < 2 || m->ppid != 1)
+           continue;
+         u = xmalloc(sizeof(struct utrec));
+         bzero(u, sizeof(*u));
+         u->next = first_utrec;
+         first_utrec = u;
+         pw = getpwuid(u->uid = m->uid);
+         if (pw)
+           strcpy(u->user_name, pw->pw_name);
+         else
+           sprintf(u->user_name, "<%d>", m->uid);
+         u->mesg = 3;
+       }
+      if (!u->proc)
+       u->proc = m;
+      u->total_time += m->ctim;
+      u->detach++;
+      DBG("** daemon %s (%s)\n", m->cmd_line, u->user_name);
+    }
 }
 
 static inline int
@@ -481,7 +500,7 @@ comp(struct utrec *a, struct utrec *b)
     return k;
   if (!a->host_name[0] && b->host_name[0])
     return -1;
-  return strcmp(a->line_id, b->line_id);
+  return strcmp(a->line, b->line);
 }
 
 static void
@@ -513,26 +532,19 @@ static void
 show(void)
 {
   struct utrec *u;
-  int i;
   unsigned char *c;
-  printf("Name     Li  MD From              LogT  IdleT RunT  Command\n");
+  printf("Name     Li  MD %-*s LogT  IdleT RunT  Command\n", maxhost, "From");
   for(u=first_utrec; u; u=u->next)
     {
-      if (!u->line_id[1])
-       {
-         if (u->line_id[0])
-           {
-             u->line_id[1] = u->line_id[0];
-             u->line_id[0] = 'c';
-           }
-         else  
-           u->line_id[0] = u->line_id[1] = '-';
-       }
-      printf("%-8.8s %-3s %c%c %-17.17s ",
+      if (!u->line[0])
+       strcpy(u->line, "--");
+      printf("%-8.8s %-3s %c%c %-*.*s ",
             u->user_name,
-            u->line_id,
+            u->line,
             u->mesg ? ' ' : '-',
             u->detach ? 'D' : ' ',
+            maxhost,
+            maxhost,
             u->host_name);
       if (u->mesg <= 1)
        {
@@ -554,15 +566,12 @@ show(void)
          putchar(' ');
          puttime((unsigned)u->total_time/(unsigned)HZ);
          putchar(' ');
-         i = 24;
-         c = u->proc->cmd_line;
-         while (*c != 0x91 && i--)
+         for (c = (unsigned char *) u->proc->cmd_line; *c; c++)
            {
              if (*c < 0x20 || (*c >= 0x7f && *c < 0xa0))
                putchar(' ');
              else
                putchar(*c);
-             c++;
            }
        }
       else
@@ -574,7 +583,8 @@ show(void)
 int main(void)
 {
   readutmp();
-  dispsys();
+  line1();
+  line2();
   readproc();
   solve();
   sort();