]> mj.ucw.cz Git - nwho.git/blob - nwho.c
Debian: Packaging for Stretch
[nwho.git] / nwho.c
1 /*
2  *      The Remote User Information Lister
3  *
4  *      (c) 1997--2010 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <dirent.h>
13 #include <time.h>
14 #include <netinet/in.h>
15 #include <getopt.h>
16
17 #include "nwho.h"
18
19 static time_t now;
20
21 struct out_host {
22   char name[32];
23   struct nwho_pkt *pkt;
24 };
25
26 struct out_user {
27   struct userinfo *user;
28   struct out_host *host;
29 };
30
31 static struct out_host **host_array;
32 static int num_hosts;
33 static int max_hosts = 16;
34
35 static struct out_user *user_array;
36 static int num_users;
37 static int max_users = 16;
38
39 static void *
40 xmalloc(size_t size)
41 {
42   void *p = malloc(size);
43   if (!p)
44     die("Out of memory");
45   return p;
46 }
47
48 static struct out_host *
49 new_host(struct nwho_pkt *orig_pkt, char *name)
50 {
51   int len = nwho_pkt_size(orig_pkt);
52   struct nwho_pkt *pkt = xmalloc(len);
53   memcpy(pkt, orig_pkt, len);
54
55   struct out_host *host = xmalloc(sizeof(*host));
56   snprintf(host->name, sizeof(host->name), "%s", name);
57   host->pkt = pkt;
58
59   if (!host_array || num_hosts >= max_hosts)
60     {
61       max_hosts *= 2;
62       host_array = realloc(host_array, max_hosts * sizeof(struct out_host));
63     }
64   host_array[num_hosts++] = host;
65
66   return host;
67 }
68
69 static void
70 new_user(struct out_host *host, struct userinfo *ui)
71 {
72   if (!user_array || num_users >= max_users)
73     {
74       max_users *= 2;
75       user_array = realloc(user_array, max_users * sizeof(struct out_user));
76     }
77   user_array[num_users++] = (struct out_user) {
78     .user = ui,
79     .host = host
80   };
81 }
82
83 static int
84 cmp_users_by_hosts(const void *va, const void *vb)
85 {
86   const struct out_user *a = va;
87   const struct out_user *b = vb;
88   return strcmp(a->host->name, b->host->name);
89 }
90
91 static int
92 cmp_users_by_names(const void *va, const void *vb)
93 {
94   const struct out_user *a = va;
95   const struct out_user *b = vb;
96   return strcmp(a->user->name, b->user->name);
97 }
98
99 static void
100 sort_users(int by_hosts)
101 {
102   qsort(user_array, num_users, sizeof(user_array[0]),
103     (by_hosts ? cmp_users_by_hosts : cmp_users_by_names));
104 }
105
106 static int
107 cmp_hosts(const void *va, const void *vb)
108 {
109   const struct out_host * const *a = va;
110   const struct out_host * const *b = vb;
111   return strcmp((*a)->name, (*b)->name);
112 }
113
114 static void
115 sort_hosts(void)
116 {
117   qsort(host_array, num_hosts, sizeof(host_array[0]), cmp_hosts);
118 }
119
120 static void
121 puttime(int s)
122 {
123   int d, h, m;
124   if (s < 100)
125     printf("%4ds", s);
126   else
127     {
128       m = s/60;
129       s %= 60;
130       h = m/60;
131       m %= 60;
132       if (h < 100)
133         printf("%02d.%02d", h, m);
134       else
135         {
136           d = h/24;
137           h %= 24;
138           if (d < 100)
139             printf("%2dd%02d", d, h);
140           else
141             printf("%4dd", d);
142         }
143     }
144 }
145
146 static void
147 show_uptime(void)
148 {
149   for (int i=0; i<num_hosts; i++)
150     {
151       struct out_host *h = host_array[i];
152       struct nwho_pkt *p = h->pkt;
153
154       if (now - ntohl(p->server_time) >= DEFAULT_DOWN_TIME)
155         {
156           printf("%-16s down\n", h->name);
157           continue;
158         }
159       printf("%-16s up ", h->name);
160       puttime(ntohl(p->uptime));
161       printf("  load");
162       for(int j=0; j<3; j++)
163         {
164           int l = ntohl(p->avl[j]);
165           printf(" %2d.%02d", l/100, l%100);
166         }
167       printf(" %3d users\n", (int) ntohl(p->num_users));
168     }
169 }
170
171 static void
172 show_users(void)
173 {
174   puts("Name     Li      M Where            LogT  IdleT");
175
176   for (int i=0; i<num_users; i++)
177     {
178       struct out_host *h = user_array[i].host;
179       struct userinfo *u = user_array[i].user;
180
181       if (now - ntohl(h->pkt->server_time) >= DEFAULT_DOWN_TIME)
182         continue;
183       printf("%-8.8s %-7s %c %-16s ", u->name, u->con, (u->mesg_y ? ' ' : '-'), h->name);
184       puttime(ntohl(u->login_time));
185       putchar(' ');
186       puttime(ntohl(u->idle_time));
187       putchar('\n');
188     }
189
190   for (int i=0; i<num_hosts; i++)
191     {
192       struct out_host *h = host_array[i];
193       if (ntohl(h->pkt->num_users) >= MAX_USERS)
194         printf("%s: MAX_USERS reached!\n", h->name);
195     }
196 }
197
198 static void
199 scan(void)
200 {
201   DIR *d;
202   struct dirent *e;
203   struct nwho_pkt pkt;
204   int fd, r;
205
206   if (chdir(NWHO_SPOOL_DIR) < 0)
207     {
208       fprintf(stderr, "chdir(" NWHO_SPOOL_DIR "): %m\n");
209       exit(1);
210     }
211   d = opendir(".");
212   if (!d)
213     {
214       perror("opendir");
215       exit(1);
216     }
217   while (e = readdir(d))
218     if (e->d_name[0] != '.')
219       {
220         fd = open(e->d_name, O_RDONLY);
221         if (fd < 0)
222           {
223             fprintf(stderr, "%s: %m\n", e->d_name);
224             continue;
225           }
226         r = read(fd, &pkt, sizeof(pkt));
227         close(fd);
228         if (r < sizeof(struct nwho_pkt) - MAX_USERS*sizeof(struct userinfo)
229             || pkt.magic != htonl(NWHO_MAGIC)
230             || r != sizeof(struct nwho_pkt) - (MAX_USERS - ntohl(pkt.num_users))*sizeof(struct userinfo))
231           {
232             fprintf(stderr, "%s: Malformed record\n", e->d_name);
233             continue;
234           }
235         struct out_host *host = new_host(&pkt, e->d_name);
236         for (int i=0; i < ntohl(pkt.num_users); i++)
237           new_user(host, &host->pkt->users[i]);
238       }
239   closedir(d);
240 }
241
242 static void
243 usage(void)
244 {
245   printf("\
246 Usage: nwho <options>\n\
247    or: nuptime <options>\n\
248 \n\
249 Options:\n\
250 -h      Sort user list by hosts (default: by users)\n\
251 -u      Display host uptimes (default if called as `nuptime')\n\
252 ");
253   exit(0);
254 }
255
256 int
257 main(int argc, char **argv)
258 {
259   if (argc == 2 && !strcmp(argv[1], "--version"))
260     {
261       printf("nwho " STRINGIFY(VERSION) "\n");
262       return 0;
263     }
264   if (argc == 2 && !strcmp(argv[1], "--help"))
265     usage();
266
267   int opt;
268   int uptime_mode = !!strstr(argv[0], "uptime");
269   int want_sort_by_hosts = 0;
270
271   while ((opt = getopt(argc, argv, "hu")) >= 0)
272     switch (opt)
273       {
274       case 'h':
275         want_sort_by_hosts = 1;
276         break;
277       case 'u':
278         uptime_mode = 1;
279         break;
280       default:
281         fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
282         exit(1);
283       }
284   if (optind < argc)
285     {
286       fprintf(stderr, "This program does not need any arguments. Try `%s --help' for more information.\n", argv[0]);
287       exit(1);
288     }
289
290   now = time(NULL);
291   scan();
292   if (!num_hosts)
293     {
294       puts("No data available.");
295       return 0;
296     }
297
298   if (!uptime_mode)
299     {
300       sort_users(want_sort_by_hosts);
301       show_users();
302     }
303   else
304     {
305       sort_hosts();
306       show_uptime();
307     }
308   return 0;
309 }