Initial revision
[freeradius.git] / src / main / raduse.c
1 /*
2  * raduse       Shows the usage of the modem lines on a terminal server.
3  *
4  * Version:     @(#)raduse  1.12  30-Jun-1999  miquels@cistron.nl
5  *
6  */
7
8 #include "autoconf.h"
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <time.h>
15 #include "sysutmp.h"
16 #include "conf.h"
17
18 #ifdef __svr4__
19 #  define ut_time ut_xtime
20 #endif
21
22 #define UTSIZE (sizeof(struct utmp))
23
24 #define HOURS 19
25
26 #define MAXLINES 64
27
28 struct line {
29   time_t lastout;
30   time_t inuse;
31   char hour[HOURS];
32 };
33 struct line lines[MAXLINES];
34 int nrlines = 35;
35
36 /*
37  *      List the terminal servers in the logfile.
38  */
39 void listnas(void)
40 {
41   FILE *fp;
42   FILE *pp;
43   time_t now, stop;
44   struct utmp ut;
45   char *p;
46   int first = 1;
47   char buf[128];
48   int found = 0;
49
50   /* Open the sort pipe. */
51   pp = popen("sort -u", "w");
52
53   /* Go back max. 1 day. */
54   time(&now);
55   stop = now - 3600 * HOURS;
56
57   /* Open wtmp file. */
58   if ((fp = fopen(RADWTMP, "r")) == NULL) {
59         perror(RADWTMP);
60         exit(1);
61   }
62   fseek(fp, -UTSIZE, SEEK_END);
63
64   /* Read structs backwards. */
65   while(1) {
66         /* Rewind if needed. */
67         if (!first && fseek(fp, -2 * UTSIZE, SEEK_CUR) < 0) break;
68         first = 0;
69
70         /* Read struct and see if we have to stop. */
71         if (ftell(fp) < UTSIZE) break;
72         fread(&ut, UTSIZE, 1, fp);
73         if (ut.ut_time < stop) break;
74
75         memset(buf, 0, sizeof(buf));
76         strncpy(buf, ut.ut_line, sizeof(ut.ut_line));
77
78         /* Get terminal server name. */
79         if ((p = strchr(buf, ':')) != NULL)
80                 p++;
81         else
82                 p = buf + 2;
83         fprintf(pp, "%s\n", p);
84         found = 1;
85   }
86   fclose(fp);
87   pclose(pp);
88
89   if (found == 0)
90         printf("raduse: no data found over the last 24 hours.\n");
91 }
92
93 /*
94  * Find out the usage of the ttys defined in
95  * struct line lines[] for the last 21 hours.
96  */
97 int fillstruct(int offset, char *nas)
98 {
99   FILE *fp;
100   time_t now, stop;
101   struct utmp ut;
102   int i, n, port;
103   int beg, end;
104   char *p;
105   int first = 1;
106   char buf[128];
107   int found = 0;
108
109   /* Go back max. 1 day. */
110   time(&now);
111   stop = now - 3600 * HOURS;
112
113   /* Open wtmp file. */
114   if ((fp = fopen(RADWTMP, "r")) == NULL) {
115         perror(RADWTMP);
116         exit(1);
117   }
118   fseek(fp, -UTSIZE, SEEK_END);
119
120   /* Read structs backwards. */
121   while(1) {
122         /* Rewind if needed. */
123         if (!first && fseek(fp, -2 * UTSIZE, SEEK_CUR) < 0) break;
124         first = 0;
125
126         /* Read struct and see if we have to stop. */
127         if (ftell(fp) < UTSIZE) break;
128         fread(&ut, UTSIZE, 1, fp);
129         if (ut.ut_time < stop) break;
130
131         memset(buf, 0, sizeof(buf));
132         strncpy(buf, ut.ut_line, sizeof(ut.ut_line));
133
134         /* Compare terminal server name. */
135         if ((p = strchr(buf, ':')) != NULL)
136                 p++;
137         else
138                 p = buf + 2;
139         if (strcmp(p, nas) != 0)
140                 continue;
141
142         found = 1;
143
144         /* Now see which tty this was. */
145         if ((p = strchr(buf, ':')) != NULL)
146                 *p = 0;
147         else
148                 buf[2] = 0;
149
150         port = atoi(buf);
151         if (port == 0 && buf[0] != '0')
152                 continue;
153         if (port < offset || port > offset + nrlines)
154                 continue;
155
156         i = port - offset;
157
158         /* Login or logout? */
159         if (ut.ut_user[0] == 0) {
160                 lines[i].lastout = ut.ut_time;
161                 continue;
162         }
163
164         /* Skip type LOGIN */
165         if (strncmp(ut.ut_user, "LOGIN", 5) == 0)
166                 continue;
167
168         /* A login. Fill out the hour string. */
169         beg = (now - ut.ut_time) / 3600;
170         if (lines[i].lastout == 0) {
171                 lines[i].inuse = 1;
172                 end = 0;
173         } else
174                 end = (now - lines[i].lastout) / 3600;
175         if (beg >= HOURS) beg = HOURS - 1;
176         if (end >= HOURS) end = HOURS - 1;
177
178         for(n = end; n <= beg; n++)
179                 lines[i].hour[n] = lines[i].lastout ? '*' : '@';
180
181   }
182   fclose(fp);
183
184   return found ? 0 : -1;
185 }
186
187 /*
188  * Draw something that vaguely resembles a graph showing the
189  * usage of the tty lines over the last 21 hours.
190  */
191 void drawit(int wide, int offset)
192 {
193   time_t now;
194   int i, n, hour;
195   struct tm *tm;
196   int thishour;
197   int star;
198
199   /* Find out current time. */
200   time(&now);
201   tm = localtime(&now);
202   thishour = tm->tm_hour;
203
204   /* Change lower spaces to dots. */
205   for(i = 0; i < nrlines; i++) {
206         n = 0;
207         for(hour = 0; hour < HOURS; hour++) {
208                 if (lines[i].hour[hour]) {
209                         n = 1;
210                 } else if (n)
211                         lines[i].hour[hour] = '.';
212         }
213   }
214
215   /* Prefix (show if line is in use now) */
216   printf("now|");
217   for(i = 0; i < nrlines; i++) {
218         if (wide)
219                 printf(" %c ", lines[i].inuse ? '@' : ' ');
220         else
221                 printf("%c ", lines[i].inuse ? '@' : ' ');
222   }
223   printf("\n");
224
225   /* Last 21 hours. */
226   for(hour = 0; hour < HOURS; hour++) {
227         printf("%02d |", thishour);
228         thishour--;
229         if (thishour < 0) thishour = 23;
230
231         for(i = 0; i < nrlines; i++) {
232                 star = ' ';
233                 if (lines[i].hour[hour])
234                         star = lines[i].hour[hour];
235                 if (wide)
236                         printf(" %c ", star);
237                 else
238                         printf("%c ", star);
239         }
240         /* EOL */
241         printf("\n");
242   }
243
244   /* Print a short suffix. */
245   printf("---+");
246   for(i = 0; i < nrlines; i++)
247         printf(wide ? "---" : "--");
248   printf("\n   |");
249   for(i = 0; i < nrlines; i++) {
250         if (wide)
251                 printf("%02d|", i + offset);
252         else
253                 printf("%d|", (i + offset) / 10);
254   }
255   if (!wide) {
256         printf("\n   |");
257         for(i = 0; i < nrlines; i++)
258                 printf("%d|", (i + offset) % 10);
259   }
260   printf("\n");
261 }
262
263 void usage()
264 {
265   fprintf(stderr, "Usage: raduse [-w] [-o offset] terminal-server\n");
266   fprintf(stderr, "       use raduse -l to find out a list of terminal servers\n");
267   exit(1);
268 }
269
270 int main(int argc, char **argv)
271 {
272   int wide = 0;
273   int c;
274   int offset = 0;
275   int list = 0;
276
277   while((c = getopt(argc, argv, "lwo:")) != EOF) switch(c) {
278         case 'w':
279                 wide = 1;
280                 break;
281         case 'o':
282                 offset = atoi(optarg);
283                 break;
284         case 'l':
285                 list = 1;
286                 break;
287         default:
288                 usage();
289                 break;
290   }
291
292   if (list) {
293         listnas();
294         exit(0);
295   }
296
297   if (wide) nrlines = 25;
298
299   if (optind >= argc) usage();
300
301   if (fillstruct(offset, argv[optind]) < 0) {
302         fprintf(stderr,
303    "raduse: %s: no data found (over the last 24 hours) (try raduse -l).\n",
304                 argv[optind]);
305         return 1;
306   }
307   drawit(wide, offset);
308
309   return 0;
310 }
311