]> cygwin.com Git - cygwin-apps/cygutils.git/blob - src/last/utmpdump.c
Add col; regenerate autofiles
[cygwin-apps/cygutils.git] / src / last / utmpdump.c
1 /*
2 * utmpdump Simple program to dump UTMP and WTMP files in
3 * raw format, so they can be examined.
4 *
5 * Author: Miquel van Smoorenburg, <miquels@cistron.nl>
6 * Danek Duvall <duvall@alumni.princeton.edu>
7 *
8 * Version: @(#)utmpdump 2.79 12-Sep-2000
9 *
10 * This file is part of the sysvinit suite,
11 * Copyright 1991-2000 Miquel van Smoorenburg.
12 *
13 * Additional Copyright on this file 1998 Danek Duvall.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation in version 2 of the License.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 */
28
29 #if HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include "common.h"
34
35 /* special requirements moved to common.h */
36 /*
37 #include <utmp.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 */
41 /* end special requirements */
42
43 #include "oldutmp.h"
44
45 char *strptime (const char *, const char *, struct tm *);
46
47 struct utmp
48 oldtonew(struct oldutmp src)
49 {
50 struct utmp dest;
51
52 memset(&dest, 0, sizeof dest);
53 dest.ut_type = src.ut_type;
54 dest.ut_pid = src.ut_pid;
55 dest.ut_time = src.ut_oldtime;
56 dest.ut_addr = src.ut_oldaddr;
57 strncpy(dest.ut_id, src.ut_id, 4);
58 strncpy(dest.ut_line, src.ut_line, OLD_LINESIZE);
59 strncpy(dest.ut_user, src.ut_user, OLD_NAMESIZE);
60 strncpy(dest.ut_host, src.ut_host, OLD_HOSTSIZE);
61
62 return dest;
63 }
64
65 struct oldutmp
66 newtoold(struct utmp src)
67 {
68 struct oldutmp dest;
69
70 memset(&dest, 0, sizeof dest);
71 dest.ut_type = src.ut_type;
72 dest.ut_pid = src.ut_pid;
73 dest.ut_oldtime = src.ut_time;
74 dest.ut_oldaddr = src.ut_addr;
75 strncpy(dest.ut_id, src.ut_id, 4);
76 strncpy(dest.ut_line, src.ut_line, OLD_LINESIZE);
77 strncpy(dest.ut_user, src.ut_user, OLD_NAMESIZE);
78 strncpy(dest.ut_host, src.ut_host, OLD_HOSTSIZE);
79
80 return dest;
81 }
82
83 char *
84 timetostr(const time_t time)
85 {
86 static char s[29]; /* [Sun Sep 01 00:00:00 1998 PST] */
87
88 if (time != 0)
89 strftime(s, 29, "%a %b %d %T %Y %Z", localtime(&time));
90 else
91 s[0] = '\0';
92
93 return s;
94 }
95
96 time_t
97 strtotime(const char *s_time)
98 {
99 struct tm *tm = malloc(sizeof(*tm));
100
101 if (s_time[0] == ' ' || s_time[0] == '\0')
102 return (time_t)0;
103
104 strptime(s_time, "%a %b %d %T %Y", tm);
105
106 /* Cheesy way of checking for DST */
107 if (s_time[26] == 'D')
108 tm->tm_isdst = 1;
109
110 return mktime(tm);
111 }
112
113 #define cleanse(x) xcleanse(x, sizeof(x))
114 void
115 xcleanse(char *s, int len)
116 {
117 for ( ; *s && len-- > 0; s++)
118 if (!isprint(*s) || *s == '[' || *s == ']')
119 *s = '?';
120 }
121
122 void
123 unspace(char *s, int len)
124 {
125 while (*s && *s != ' ' && len--)
126 ++s;
127
128 if (len > 0)
129 *s = '\0';
130 }
131
132 void
133 print_utline(struct utmp ut)
134 {
135 char *addr_string, *time_string;
136 struct in_addr in;
137
138 in.s_addr = ut.ut_addr;
139 addr_string = inet_ntoa(in);
140 time_string = timetostr(ut.ut_time);
141 cleanse(ut.ut_id);
142 cleanse(ut.ut_user);
143 cleanse(ut.ut_line);
144 cleanse(ut.ut_host);
145
146 /* pid id user line host addr time */
147 printf("[%d] [%05d] [%-4.4s] [%-*.*s] [%-*.*s] [%-*.*s] [%-15.15s] [%-28.28s]\n",
148 ut.ut_type, ut.ut_pid, ut.ut_id, 8, UT_NAMESIZE, ut.ut_user,
149 12, UT_LINESIZE, ut.ut_line, 20, UT_HOSTSIZE, ut.ut_host,
150 addr_string, time_string);
151 }
152
153 void
154 dump(FILE *fp, int forever, int oldfmt)
155 {
156 struct utmp ut;
157 struct oldutmp uto;
158
159 if (forever)
160 fseek(fp, -10 * (oldfmt ? sizeof uto : sizeof ut), SEEK_END);
161
162 do {
163 if (oldfmt)
164 while (fread(&uto, sizeof uto, 1, fp) == 1)
165 print_utline(oldtonew(uto));
166 else
167 while (fread(&ut, sizeof ut, 1, fp) == 1)
168 print_utline(ut);
169 if (forever) sleep(1);
170 } while (forever);
171 }
172
173 /* This function won't work properly if there's a ']' or a ' ' in the real
174 * token. Thankfully, this should never happen. */
175 int
176 gettok(char *line, char *dest, int size, int eatspace)
177 {
178 int bpos, epos, eaten;
179 char *t;
180
181 bpos = strchr(line, '[') - line;
182 if (bpos < 0) {
183 fprintf(stderr, "Extraneous newline in file. Exiting.");
184 exit(1);
185 }
186 line += 1 + bpos;
187
188 epos = strchr(line, ']') - line;
189 if (epos < 0) {
190 fprintf(stderr, "Extraneous newline in file. Exiting.");
191 exit(1);
192 }
193 line[epos] = '\0';
194
195 eaten = bpos + epos + 1;
196
197 if (eatspace)
198 if ((t = strchr(line, ' ')))
199 *t = 0;
200
201 strncpy(dest, line, size);
202
203 return eaten + 1;
204 }
205
206 void
207 undump(FILE *fp, int forever, int oldfmt)
208 {
209 struct utmp ut;
210 struct oldutmp uto;
211 char s_addr[16], s_time[29], *linestart, *line;
212 int count = 0;
213
214 line = linestart = malloc(1024 * sizeof *linestart);
215 s_addr[15] = 0;
216 s_time[28] = 0;
217
218 while(fgets(linestart, 1023, fp))
219 {
220 line = linestart;
221 memset(&ut, '\0', sizeof(ut));
222 sscanf(line, "[%hd] [%d] [%4c] ", &ut.ut_type, &ut.ut_pid, ut.ut_id);
223
224 line += 19;
225 line += gettok(line, ut.ut_user, sizeof(ut.ut_user), 1);
226 line += gettok(line, ut.ut_line, sizeof(ut.ut_line), 1);
227 line += gettok(line, ut.ut_host, sizeof(ut.ut_host), 1);
228 line += gettok(line, s_addr, sizeof(s_addr)-1, 1);
229 line += gettok(line, s_time, sizeof(s_time)-1, 0);
230
231 ut.ut_addr = inet_addr(s_addr);
232 ut.ut_time = strtotime(s_time);
233
234 if (oldfmt) {
235 uto = newtoold(ut);
236 fwrite(&uto, sizeof(uto), 1, stdout);
237 } else
238 fwrite(&ut, sizeof(ut), 1, stdout);
239
240 ++count;
241 }
242
243 free(linestart);
244 }
245
246 void
247 usage(int result)
248 {
249 printf("Usage: utmpdump [ -froh ] [ filename ]\n");
250 exit(result);
251 }
252
253 int main(int argc, char **argv)
254 {
255 int c;
256 FILE *fp;
257 int reverse = 0, forever = 0, oldfmt = 0;
258
259 while ((c = getopt(argc, argv, "froh")) != EOF) {
260 switch (c) {
261 case 'r':
262 reverse = 1;
263 break;
264
265 case 'f':
266 forever = 1;
267 break;
268
269 case 'o':
270 oldfmt = 1;
271 break;
272
273 case 'h':
274 usage(0);
275 break;
276
277 default:
278 usage(1);
279 }
280 }
281
282 if (optind < argc) {
283 fprintf(stderr, "Utmp %sdump of %s\n", reverse ? "un" : "", argv[optind]);
284 if ((fp = fopen(argv[optind], "r")) == NULL) {
285 perror("Unable to open file");
286 exit(1);
287 }
288 }
289 else {
290 fprintf(stderr, "Utmp %sdump of stdin\n", reverse ? "un" : "");
291 fp = stdin;
292 }
293
294 if (reverse)
295 undump(fp, forever, oldfmt);
296 else
297 dump(fp, forever, oldfmt);
298
299 fclose(fp);
300
301 return 0;
302 }
303
304 /*
305 Everything after this point should be removed when the new cygwin dll is released, as this functionality has been added to it. The current dll is 1.3.6.
306 */
307
308 static const char *abb_weekdays[] = {
309 "Sun",
310 "Mon",
311 "Tue",
312 "Wed",
313 "Thu",
314 "Fri",
315 "Sat",
316 NULL
317 };
318
319 static const char *full_weekdays[] = {
320 "Sunday",
321 "Monday",
322 "Tuesday",
323 "Wednesday",
324 "Thursday",
325 "Friday",
326 "Saturday",
327 NULL
328 };
329
330 static const char *abb_month[] = {
331 "Jan",
332 "Feb",
333 "Mar",
334 "Apr",
335 "May",
336 "Jun",
337 "Jul",
338 "Aug",
339 "Sep",
340 "Oct",
341 "Nov",
342 "Dec",
343 NULL
344 };
345
346 static const char *full_month[] = {
347 "January",
348 "February",
349 "Mars",
350 "April",
351 "May",
352 "June",
353 "July",
354 "August",
355 "September",
356 "October",
357 "November",
358 "December",
359 NULL,
360 };
361
362 static const char *ampm[] = {
363 "am",
364 "pm",
365 NULL
366 };
367
368 /*
369 * tm_year is relative this year */
370 const int tm_year_base = 1900;
371
372 /*
373 * Return TRUE iff `year' was a leap year.
374 */
375
376 static int
377 is_leap_year (int year)
378 {
379 return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
380 }
381
382 static int
383 match_string (const char **buf, const char **strs)
384 {
385 int i = 0;
386
387 for (i = 0; strs[i] != NULL; ++i) {
388 int len = strlen (strs[i]);
389
390 if (strncasecmp (*buf, strs[i], len) == 0) {
391 *buf += len;
392 return i;
393 }
394 }
395 return -1;
396 }
397
398 static int
399 first_day (int year)
400 {
401 int ret = 4;
402
403 for (; year > 1970; --year)
404 ret = (ret + 365 + is_leap_year (year) ? 1 : 0) % 7;
405 return ret;
406 }
407
408 /*
409 * Set `timeptr' given `wnum' (week number [0, 53])
410 */
411
412 static void
413 set_week_number_sun (struct tm *timeptr, int wnum)
414 {
415 int fday = first_day (timeptr->tm_year + tm_year_base);
416
417 timeptr->tm_yday = wnum * 7 + timeptr->tm_wday - fday;
418 if (timeptr->tm_yday < 0) {
419 timeptr->tm_wday = fday;
420 timeptr->tm_yday = 0;
421 }
422 }
423
424 /*
425 * Set `timeptr' given `wnum' (week number [0, 53])
426 */
427
428 static void
429 set_week_number_mon (struct tm *timeptr, int wnum)
430 {
431 int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
432
433 timeptr->tm_yday = wnum * 7 + (timeptr->tm_wday + 6) % 7 - fday;
434 if (timeptr->tm_yday < 0) {
435 timeptr->tm_wday = (fday + 1) % 7;
436 timeptr->tm_yday = 0;
437 }
438 }
439
440 /*
441 * Set `timeptr' given `wnum' (week number [0, 53])
442 */
443
444 static void
445 set_week_number_mon4 (struct tm *timeptr, int wnum)
446 {
447 int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
448 int offset = 0;
449
450 if (fday < 4)
451 offset += 7;
452
453 timeptr->tm_yday = offset + (wnum - 1) * 7 + timeptr->tm_wday - fday;
454 if (timeptr->tm_yday < 0) {
455 timeptr->tm_wday = fday;
456 timeptr->tm_yday = 0;
457 }
458 }
459
460 /* strptime: roken */
461 char *
462 strptime (const char *buf, const char *format, struct tm *timeptr)
463 {
464 char c;
465
466 for (; (c = *format) != '\0'; ++format) {
467 char *s;
468 int ret;
469
470 if (isspace (c)) {
471 while (isspace (*buf))
472 ++buf;
473 } else if (c == '%' && format[1] != '\0') {
474 c = *++format;
475 if (c == 'E' || c == 'O')
476 c = *++format;
477 switch (c) {
478 case 'A' :
479 ret = match_string (&buf, full_weekdays);
480 if (ret < 0)
481 return NULL;
482 timeptr->tm_wday = ret;
483 break;
484 case 'a' :
485 ret = match_string (&buf, abb_weekdays);
486 if (ret < 0)
487 return NULL;
488 timeptr->tm_wday = ret;
489 break;
490 case 'B' :
491 ret = match_string (&buf, full_month);
492 if (ret < 0)
493 return NULL;
494 timeptr->tm_mon = ret;
495 break;
496 case 'b' :
497 case 'h' :
498 ret = match_string (&buf, abb_month);
499 if (ret < 0)
500 return NULL;
501 timeptr->tm_mon = ret;
502 break;
503 case 'C' :
504 ret = strtol (buf, &s, 10);
505 if (s == buf)
506 return NULL;
507 timeptr->tm_year = (ret * 100) - tm_year_base;
508 buf = s;
509 break;
510 case 'c' :
511 abort ();
512 case 'D' : /* %m/%d/%y */
513 s = strptime (buf, "%m/%d/%y", timeptr);
514 if (s == NULL)
515 return NULL;
516 buf = s;
517 break;
518 case 'd' :
519 case 'e' :
520 ret = strtol (buf, &s, 10);
521 if (s == buf)
522 return NULL;
523 timeptr->tm_mday = ret;
524 buf = s;
525 break;
526 case 'H' :
527 case 'k' :
528 ret = strtol (buf, &s, 10);
529 if (s == buf)
530 return NULL;
531 timeptr->tm_hour = ret;
532 buf = s;
533 break;
534 case 'I' :
535 case 'l' :
536 ret = strtol (buf, &s, 10);
537 if (s == buf)
538 return NULL;
539 if (ret == 12)
540 timeptr->tm_hour = 0;
541 else
542 timeptr->tm_hour = ret;
543 buf = s;
544 break;
545 case 'j' :
546 ret = strtol (buf, &s, 10);
547 if (s == buf)
548 return NULL;
549 timeptr->tm_yday = ret - 1;
550 buf = s;
551 break;
552 case 'm' :
553 ret = strtol (buf, &s, 10);
554 if (s == buf)
555 return NULL;
556 timeptr->tm_mon = ret - 1;
557 buf = s;
558 break;
559 case 'M' :
560 ret = strtol (buf, &s, 10);
561 if (s == buf)
562 return NULL;
563 timeptr->tm_min = ret;
564 buf = s;
565 break;
566 case 'n' :
567 if (*buf == '\n')
568 ++buf;
569 else
570 return NULL;
571 break;
572 case 'p' :
573 ret = match_string (&buf, ampm);
574 if (ret < 0)
575 return NULL;
576 if (timeptr->tm_hour == 0) {
577 if (ret == 1)
578 timeptr->tm_hour = 12;
579 } else
580 timeptr->tm_hour += 12;
581 break;
582 case 'r' : /* %I:%M:%S %p */
583 s = strptime (buf, "%I:%M:%S %p", timeptr);
584 if (s == NULL)
585 return NULL;
586 buf = s;
587 break;
588 case 'R' : /* %H:%M */
589 s = strptime (buf, "%H:%M", timeptr);
590 if (s == NULL)
591 return NULL;
592 buf = s;
593 break;
594 case 'S' :
595 ret = strtol (buf, &s, 10);
596 if (s == buf)
597 return NULL;
598 timeptr->tm_sec = ret;
599 buf = s;
600 break;
601 case 't' :
602 if (*buf == '\t')
603 ++buf;
604 else
605 return NULL;
606 break;
607 case 'T' : /* %H:%M:%S */
608 case 'X' :
609 s = strptime (buf, "%H:%M:%S", timeptr);
610 if (s == NULL)
611 return NULL;
612 buf = s;
613 break;
614 case 'u' :
615 ret = strtol (buf, &s, 10);
616 if (s == buf)
617 return NULL;
618 timeptr->tm_wday = ret - 1;
619 buf = s;
620 break;
621 case 'w' :
622 ret = strtol (buf, &s, 10);
623 if (s == buf)
624 return NULL;
625 timeptr->tm_wday = ret;
626 buf = s;
627 break;
628 case 'U' :
629 ret = strtol (buf, &s, 10);
630 if (s == buf)
631 return NULL;
632 set_week_number_sun (timeptr, ret);
633 buf = s;
634 break;
635 case 'V' :
636 ret = strtol (buf, &s, 10);
637 if (s == buf)
638 return NULL;
639 set_week_number_mon4 (timeptr, ret);
640 buf = s;
641 break;
642 case 'W' :
643 ret = strtol (buf, &s, 10);
644 if (s == buf)
645 return NULL;
646 set_week_number_mon (timeptr, ret);
647 buf = s;
648 break;
649 case 'x' :
650 s = strptime (buf, "%Y:%m:%d", timeptr);
651 if (s == NULL)
652 return NULL;
653 buf = s;
654 break;
655 case 'y' :
656 ret = strtol (buf, &s, 10);
657 if (s == buf)
658 return NULL;
659 if (ret < 70)
660 timeptr->tm_year = 100 + ret;
661 else
662 timeptr->tm_year = ret;
663 buf = s;
664 break;
665 case 'Y' :
666 ret = strtol (buf, &s, 10);
667 if (s == buf)
668 return NULL;
669 timeptr->tm_year = ret - tm_year_base;
670 buf = s;
671 break;
672 case 'Z' :
673 abort ();
674 case '\0' :
675 --format;
676 /* FALLTHROUGH */
677 case '%' :
678 if (*buf == '%')
679 ++buf;
680 else
681 return NULL;
682 break;
683 default :
684 if (*buf == '%' || *++buf == c)
685 ++buf;
686 else
687 return NULL;
688 break;
689 }
690 } else {
691 if (*buf == c)
692 ++buf;
693 else
694 return NULL;
695 }
696 }
697 return (char *)buf;
698 }
This page took 0.068561 seconds and 5 git commands to generate.