]> mj.ucw.cz Git - nwho.git/blobdiff - nwho.c
Make the systemd service be ordered after autofs.service, so that it is ordered befor...
[nwho.git] / nwho.c
diff --git a/nwho.c b/nwho.c
index dedaecadb6cb9d71ee5c44a00933d19c6ea48ec6..7e89b652ec318b8be8a8aa54d3a4d0d9c24e2de0 100644 (file)
--- a/nwho.c
+++ b/nwho.c
@@ -1,10 +1,7 @@
 /*
- *     The Remote User Information Lister 1.8
+ *     The Remote User Information Lister
  *
- *     (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.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.
+ *     (c) 1997--2010 Martin Mares <mj@ucw.cz>
  */
 
 #include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <dirent.h>
+#include <time.h>
 #include <netinet/in.h>
-#include <asm/types.h>
+#include <getopt.h>
+
+#include "nwho.h"
+
+static time_t now;
+
+struct out_host {
+  char name[32];
+  struct nwho_pkt *pkt;
+};
+
+struct out_user {
+  struct userinfo *user;
+  struct out_host *host;
+};
+
+static struct out_host **host_array;
+static int num_hosts;
+static int max_hosts = 16;
+
+static struct out_user *user_array;
+static int num_users;
+static int max_users = 16;
+
+static void *
+xmalloc(size_t size)
+{
+  void *p = malloc(size);
+  if (!p)
+    die("Out of memory");
+  return p;
+}
+
+static struct out_host *
+new_host(struct nwho_pkt *orig_pkt, char *name)
+{
+  int len = nwho_pkt_size(orig_pkt);
+  struct nwho_pkt *pkt = xmalloc(len);
+  memcpy(pkt, orig_pkt, len);
 
-#include "net.h"
+  struct out_host *host = xmalloc(sizeof(*host));
+  snprintf(host->name, sizeof(host->name), "%s", name);
+  host->pkt = pkt;
 
-static int is_uptime;
+  if (!host_array || num_hosts >= max_hosts)
+    {
+      max_hosts *= 2;
+      host_array = realloc(host_array, max_hosts * sizeof(struct out_host));
+    }
+  host_array[num_hosts++] = host;
+
+  return host;
+}
+
+static void
+new_user(struct out_host *host, struct userinfo *ui)
+{
+  if (!user_array || num_users >= max_users)
+    {
+      max_users *= 2;
+      user_array = realloc(user_array, max_users * sizeof(struct out_user));
+    }
+  user_array[num_users++] = (struct out_user) {
+    .user = ui,
+    .host = host
+  };
+}
+
+static int
+cmp_users_by_hosts(const void *va, const void *vb)
+{
+  const struct out_user *a = va;
+  const struct out_user *b = vb;
+  return strcmp(a->host->name, b->host->name);
+}
+
+static int
+cmp_users_by_names(const void *va, const void *vb)
+{
+  const struct out_user *a = va;
+  const struct out_user *b = vb;
+  return strcmp(a->user->name, b->user->name);
+}
+
+static void
+sort_users(int by_hosts)
+{
+  qsort(user_array, num_users, sizeof(user_array[0]),
+    (by_hosts ? cmp_users_by_hosts : cmp_users_by_names));
+}
+
+static int
+cmp_hosts(const void *va, const void *vb)
+{
+  const struct out_host * const *a = va;
+  const struct out_host * const *b = vb;
+  return strcmp((*a)->name, (*b)->name);
+}
+
+static void
+sort_hosts(void)
+{
+  qsort(host_array, num_hosts, sizeof(host_array[0]), cmp_hosts);
+}
 
 static void
 puttime(int s)
@@ -47,39 +144,55 @@ puttime(int s)
 }
 
 static void
-show_uptime(char *name, struct rywho_pkt *p)
+show_uptime(void)
 {
-  int i;
-
-  printf("%-16s up ", name);
-  puttime(ntohl(p->uptime));
-  printf("  load");
-  for(i=0; i<3; i++)
+  for (int i=0; i<num_hosts; i++)
     {
-      int l = ntohl(p->avl[i]);
-      printf(" %2d.%02d", l/100, l%100);
+      struct out_host *h = host_array[i];
+      struct nwho_pkt *p = h->pkt;
+
+      if (now - ntohl(p->server_time) >= DEFAULT_DOWN_TIME)
+       {
+         printf("%-16s down\n", h->name);
+         continue;
+       }
+      printf("%-16s up ", h->name);
+      puttime(ntohl(p->uptime));
+      printf("  load");
+      for(int j=0; j<3; j++)
+       {
+         int l = ntohl(p->avl[j]);
+         printf(" %2d.%02d", l/100, l%100);
+       }
+      printf(" %3d users\n", (int) ntohl(p->num_users));
     }
-  printf(" %3d users\n", (int) ntohl(p->num_users));
 }
 
 static void
-show_users(char *name, struct rywho_pkt *p)
+show_users(void)
 {
-  int u;
-  int m = ntohl(p->num_users);
-  struct userinfo *i;
+  puts("Name     Li      M Where            LogT  IdleT");
 
-  for(u=0; u<m; u++)
+  for (int i=0; i<num_users; i++)
     {
-      i = &p->users[u];
-      printf("%-8.8s %-3s %c %-16s ", i->name, i->con, (i->mesg_y ? ' ' : '-'), name);
-      puttime(ntohl(i->login_time));
+      struct out_host *h = user_array[i].host;
+      struct userinfo *u = user_array[i].user;
+
+      if (now - ntohl(h->pkt->server_time) >= DEFAULT_DOWN_TIME)
+       continue;
+      printf("%-8.8s %-7s %c %-16s ", u->name, u->con, (u->mesg_y ? ' ' : '-'), h->name);
+      puttime(ntohl(u->login_time));
       putchar(' ');
-      puttime(ntohl(i->idle_time));
+      puttime(ntohl(u->idle_time));
       putchar('\n');
     }
-  if (m == MAX_USERS)
-    printf("%s: MAX_USERS reached!\n", name);
+
+  for (int i=0; i<num_hosts; i++)
+    {
+      struct out_host *h = host_array[i];
+      if (ntohl(h->pkt->num_users) >= MAX_USERS)
+       printf("%s: MAX_USERS reached!\n", h->name);
+    }
 }
 
 static void
@@ -87,13 +200,12 @@ scan(void)
 {
   DIR *d;
   struct dirent *e;
-  struct rywho_pkt pkt;
+  struct nwho_pkt pkt;
   int fd, r;
-  int is = 0;
 
-  if (chdir(YWHO_SPOOL_DIR) < 0)
+  if (chdir(NWHO_SPOOL_DIR) < 0)
     {
-      fprintf(stderr, "chdir(" YWHO_SPOOL_DIR "): %m\n");
+      fprintf(stderr, "chdir(" NWHO_SPOOL_DIR "): %m\n");
       exit(1);
     }
   d = opendir(".");
@@ -113,32 +225,85 @@ scan(void)
          }
        r = read(fd, &pkt, sizeof(pkt));
        close(fd);
-       if (r < sizeof(struct rywho_pkt) - MAX_USERS*sizeof(struct userinfo)
-           || r != sizeof(struct rywho_pkt) - (MAX_USERS - ntohl(pkt.num_users))*sizeof(struct userinfo))
+       if (r < sizeof(struct nwho_pkt) - MAX_USERS*sizeof(struct userinfo)
+           || pkt.magic != htonl(NWHO_MAGIC)
+           || r != sizeof(struct nwho_pkt) - (MAX_USERS - ntohl(pkt.num_users))*sizeof(struct userinfo))
          {
            fprintf(stderr, "%s: Malformed record\n", e->d_name);
            continue;
          }
-       (is_uptime ? show_uptime : show_users)(e->d_name, &pkt);
-       is = 1;
+       struct out_host *host = new_host(&pkt, e->d_name);
+       for (int i=0; i < ntohl(pkt.num_users); i++)
+         new_user(host, &host->pkt->users[i]);
       }
   closedir(d);
-  if (!is)
-    puts("No data available.");
+}
+
+static void
+usage(void)
+{
+  printf("\
+Usage: nwho <options>\n\
+   or: nuptime <options>\n\
+\n\
+Options:\n\
+-h     Sort user list by hosts (default: by users)\n\
+-u     Display host uptimes (default if called as `nuptime')\n\
+");
+  exit(0);
 }
 
 int
 main(int argc, char **argv)
 {
-  if (strstr(argv[0], "uptime"))
-    is_uptime = 1;
-  if (argc != 1)
+  if (argc == 2 && !strcmp(argv[1], "--version"))
     {
-      fprintf(stderr, "Usage: %s\n", argv[0]);
-      return 1;
+      printf("nwho " STRINGIFY(VERSION) "\n");
+      return 0;
     }
-  if (!is_uptime)
-    puts("Name     Li  M Where            LogT  IdleT");
+  if (argc == 2 && !strcmp(argv[1], "--help"))
+    usage();
+
+  int opt;
+  int uptime_mode = !!strstr(argv[0], "uptime");
+  int want_sort_by_hosts = 0;
+
+  while ((opt = getopt(argc, argv, "hu")) >= 0)
+    switch (opt)
+      {
+      case 'h':
+       want_sort_by_hosts = 1;
+       break;
+      case 'u':
+       uptime_mode = 1;
+       break;
+      default:
+       fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
+       exit(1);
+      }
+  if (optind < argc)
+    {
+      fprintf(stderr, "This program does not need any arguments. Try `%s --help' for more information.\n", argv[0]);
+      exit(1);
+    }
+
+  now = time(NULL);
   scan();
+  if (!num_hosts)
+    {
+      puts("No data available.");
+      return 0;
+    }
+
+  if (!uptime_mode)
+    {
+      sort_users(want_sort_by_hosts);
+      show_users();
+    }
+  else
+    {
+      sort_hosts();
+      show_uptime();
+    }
   return 0;
 }