#include <dirent.h>
#include <time.h>
#include <netinet/in.h>
+#include <getopt.h>
-#include "net.h"
+#include "nwho.h"
-static int is_uptime;
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);
+
+ struct out_host *host = xmalloc(sizeof(*host));
+ snprintf(host->name, sizeof(host->name), "%s", name);
+ host->pkt = pkt;
+
+ 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)
{
}
static void
-show_uptime(char *name, struct nwho_pkt *p)
+show_uptime(void)
{
- int i;
-
- if (now - ntohl(p->server_time) >= DEFAULT_DOWN_TIME)
+ for (int i=0; i<num_hosts; i++)
{
- printf("%-16s down\n", name);
- return;
- }
- printf("%-16s up ", name);
- puttime(ntohl(p->uptime));
- printf(" load");
- for(i=0; i<3; 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 nwho_pkt *p)
+show_users(void)
{
- int u;
- int m = ntohl(p->num_users);
- struct userinfo *i;
+ puts("Name Li M Where LogT IdleT");
- if (now - ntohl(p->server_time) >= DEFAULT_DOWN_TIME)
- return;
- for(u=0; u<m; u++)
+ for (int i=0; i<num_users; i++)
{
- i = &p->users[u];
- printf("%-8.8s %-7s %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
struct dirent *e;
struct nwho_pkt pkt;
int fd, r;
- int is = 0;
if (chdir(NWHO_SPOOL_DIR) < 0)
{
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;
}