Annotation of src/usr.bin/last/last.c, Revision 1.50
1.50 ! deraadt 1: /* $OpenBSD: last.c,v 1.49 2015/08/20 22:32:41 deraadt Exp $ */
1.1 deraadt 2: /* $NetBSD: last.c,v 1.6 1994/12/24 16:49:02 cgd Exp $ */
3:
4: /*
5: * Copyright (c) 1987, 1993, 1994
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.26 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: #include <sys/stat.h>
34:
1.35 chl 35: #include <ctype.h>
1.1 deraadt 36: #include <err.h>
37: #include <fcntl.h>
1.38 fgsch 38: #include <libgen.h>
1.1 deraadt 39: #include <paths.h>
40: #include <signal.h>
41: #include <stdio.h>
42: #include <stdlib.h>
43: #include <string.h>
44: #include <time.h>
45: #include <unistd.h>
1.45 deraadt 46: #include <limits.h>
1.1 deraadt 47: #include <utmp.h>
48:
49: #define NO 0 /* false/no */
50: #define YES 1 /* true/yes */
1.18 mickey 51: #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
1.1 deraadt 52:
53: static struct utmp buf[1024]; /* utmp read buffer */
54:
1.33 deraadt 55: struct arg {
1.1 deraadt 56: char *name; /* argument */
57: #define HOST_TYPE -2
58: #define TTY_TYPE -3
59: #define USER_TYPE -4
60: int type; /* type of arg */
1.33 deraadt 61: struct arg *next; /* linked list pointer */
62: } *arglist;
1.1 deraadt 63:
1.33 deraadt 64: struct ttytab {
1.1 deraadt 65: time_t logout; /* log out time */
66: char tty[UT_LINESIZE + 1]; /* terminal name */
1.33 deraadt 67: struct ttytab*next; /* linked list pointer */
68: } *ttylist;
1.1 deraadt 69:
70: static time_t currentout; /* current logout value */
1.33 deraadt 71: static long maxrec = -1; /* records to display */
1.1 deraadt 72: static char *file = _PATH_WTMP; /* wtmp file */
1.6 mickey 73: static int fulltime = 0; /* Display seconds? */
1.33 deraadt 74: static time_t snaptime = 0; /* report only at this time */
75: static int calculate = 0;
76: static int seconds = 0;
1.1 deraadt 77:
1.19 millert 78: void addarg(int, char *);
1.33 deraadt 79: struct ttytab *addtty(char *);
1.19 millert 80: void hostconv(char *);
81: void onintr(int);
82: char *ttyconv(char *);
83: time_t dateconv(char *);
84: int want(struct utmp *, int);
85: void wtmp(void);
86: void checkargs(void);
1.40 guenther 87: void print_entry(const struct utmp *);
1.22 deraadt 88: void usage(void);
1.1 deraadt 89:
1.28 deraadt 90: #define NAME_WIDTH 9
1.14 fgsch 91: #define HOST_WIDTH 24
1.48 millert 92:
93: #define SECSPERDAY (24 * 60 * 60)
1.13 deraadt 94:
1.1 deraadt 95: int
1.27 deraadt 96: main(int argc, char *argv[])
1.1 deraadt 97: {
1.31 millert 98: const char *errstr;
1.33 deraadt 99: int ch, lastch = '\0', newarg = 1, prevoptind = 1;
1.50 ! deraadt 100:
! 101: if (pledge("stdio rpath", NULL) == -1)
! 102: err(1, "pledge");
1.1 deraadt 103:
1.32 millert 104: while ((ch = getopt(argc, argv, "0123456789cf:h:n:st:d:T")) != -1) {
1.1 deraadt 105: switch (ch) {
106: case '0': case '1': case '2': case '3': case '4':
107: case '5': case '6': case '7': case '8': case '9':
108: /*
109: * kludge: last was originally designed to take
110: * a number after a dash.
111: */
1.32 millert 112: if (newarg || !isdigit(lastch))
113: maxrec = 0;
114: else if (maxrec > INT_MAX / 10)
115: usage();
116: maxrec = (maxrec * 10) + (ch - '0');
1.1 deraadt 117: break;
1.9 downsj 118: case 'c':
1.46 deraadt 119: calculate = 1;
1.9 downsj 120: break;
1.1 deraadt 121: case 'f':
122: file = optarg;
123: break;
124: case 'h':
125: hostconv(optarg);
126: addarg(HOST_TYPE, optarg);
127: break;
1.31 millert 128: case 'n':
129: maxrec = strtonum(optarg, 0, LONG_MAX, &errstr);
130: if (errstr != NULL)
131: errx(1, "number of lines is %s: %s", errstr,
132: optarg);
133: if (maxrec == 0)
134: exit(0);
135: break;
1.9 downsj 136: case 's':
1.46 deraadt 137: seconds = 1;
1.9 downsj 138: break;
1.1 deraadt 139: case 't':
140: addarg(TTY_TYPE, ttyconv(optarg));
141: break;
1.4 jdm 142: case 'd':
143: snaptime = dateconv(optarg);
144: break;
1.6 mickey 145: case 'T':
1.9 downsj 146: fulltime = 1;
1.6 mickey 147: break;
1.1 deraadt 148: default:
1.22 deraadt 149: usage();
1.1 deraadt 150: }
1.32 millert 151: lastch = ch;
152: newarg = optind != prevoptind;
153: prevoptind = optind;
154: }
155: if (maxrec == 0)
156: exit(0);
1.1 deraadt 157:
158: if (argc) {
1.43 millert 159: setvbuf(stdout, NULL, _IOLBF, 0);
1.1 deraadt 160: for (argv += optind; *argv; ++argv) {
161: #define COMPATIBILITY
162: #ifdef COMPATIBILITY
163: /* code to allow "last p5" to work */
164: addarg(TTY_TYPE, ttyconv(*argv));
165: #endif
166: addarg(USER_TYPE, *argv);
167: }
168: }
1.18 mickey 169:
1.5 jdm 170: checkargs();
1.1 deraadt 171: wtmp();
172: exit(0);
173: }
174:
175: /*
1.33 deraadt 176: * if snaptime is set, print warning if usernames, or -t or -h
177: * flags are also provided
1.5 jdm 178: */
179: void
1.27 deraadt 180: checkargs(void)
1.5 jdm 181: {
1.18 mickey 182: int ttyflag = 0;
1.33 deraadt 183: struct arg *step;
1.5 jdm 184:
1.33 deraadt 185: if (!snaptime || !arglist)
1.5 jdm 186: return;
187:
188: for (step = arglist; step; step = step->next)
189: switch (step->type) {
190: case HOST_TYPE:
1.7 deraadt 191: (void)fprintf(stderr,
192: "Warning: Ignoring hostname flag\n");
1.5 jdm 193: break;
194: case TTY_TYPE:
1.18 mickey 195: if (!ttyflag) { /* don't print this twice */
1.7 deraadt 196: (void)fprintf(stderr,
197: "Warning: Ignoring tty flag\n");
1.5 jdm 198: ttyflag = 1;
199: }
200: break;
201: case USER_TYPE:
1.7 deraadt 202: (void)fprintf(stderr,
203: "Warning: Ignoring username[s]\n");
1.5 jdm 204: break;
205: default:
1.20 millert 206: break;
1.5 jdm 207: /* PRINT NOTHING */
208: }
1.18 mickey 209: }
1.5 jdm 210:
1.40 guenther 211: void
212: print_entry(const struct utmp *bp)
213: {
214: printf("%-*.*s %-*.*s %-*.*s ",
215: NAME_WIDTH, UT_NAMESIZE, bp->ut_name,
216: UT_LINESIZE, UT_LINESIZE, bp->ut_line,
217: HOST_WIDTH, UT_HOSTSIZE, bp->ut_host);
218:
219: if (seconds)
220: printf("%lld", (long long)bp->ut_time);
221: else {
222: struct tm *tm;
223:
224: tm = localtime(&bp->ut_time);
225: if (tm == NULL) {
226: /* bogus entry? format as epoch time... */
227: printf("%lld", (long long)bp->ut_time);
228: } else {
229: char tim[40];
230:
231: strftime(tim, sizeof tim,
232: fulltime ? "%a %b %d %H:%M:%S" : "%a %b %d %H:%M",
233: tm);
234: printf("%s", tim);
235: }
236: }
237: }
238:
1.5 jdm 239:
240: /*
1.33 deraadt 241: * read through the wtmp file
1.1 deraadt 242: */
243: void
1.27 deraadt 244: wtmp(void)
1.1 deraadt 245: {
1.33 deraadt 246: time_t delta, total = 0;
247: int timesize, wfd, snapfound = 0;
1.44 tedu 248: char *ct, *crmsg = "invalid";
1.33 deraadt 249: struct utmp *bp;
250: struct stat stb;
251: ssize_t bytes;
1.8 deraadt 252: off_t bl;
1.33 deraadt 253: struct ttytab *T;
254:
1.1 deraadt 255: if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1)
256: err(1, "%s", file);
257: bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf);
258:
1.6 mickey 259: if (fulltime)
260: timesize = 8; /* HH:MM:SS */
261: else
262: timesize = 5; /* HH:MM */
263:
1.1 deraadt 264: (void)time(&buf[0].ut_time);
265: (void)signal(SIGINT, onintr);
266: (void)signal(SIGQUIT, onintr);
267:
268: while (--bl >= 0) {
1.11 millert 269: if (lseek(wfd, bl * sizeof(buf), SEEK_SET) == -1 ||
1.1 deraadt 270: (bytes = read(wfd, buf, sizeof(buf))) == -1)
271: err(1, "%s", file);
272: for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) {
273: /*
274: * if the terminal line is '~', the machine stopped.
275: * see utmp(5) for more info.
276: */
277: if (bp->ut_line[0] == '~' && !bp->ut_line[1]) {
278: /* everybody just logged out */
279: for (T = ttylist; T; T = T->next)
280: T->logout = -bp->ut_time;
281: currentout = -bp->ut_time;
282: crmsg = strncmp(bp->ut_name, "shutdown",
283: UT_NAMESIZE) ? "crash" : "shutdown";
1.33 deraadt 284:
1.18 mickey 285: /*
286: * if we're in snapshot mode, we want to
1.4 jdm 287: * exit if this shutdown/reboot appears
288: * while we we are tracking the active
289: * range
290: */
1.33 deraadt 291: if (snaptime && snapfound) {
292: close(wfd);
1.4 jdm 293: return;
1.33 deraadt 294: }
295:
1.18 mickey 296: /*
1.4 jdm 297: * don't print shutdown/reboot entries
1.18 mickey 298: * unless flagged for
299: */
1.5 jdm 300: if (want(bp, NO)) {
1.40 guenther 301: print_entry(bp);
302: printf("\n");
1.33 deraadt 303: if (maxrec != -1 && !--maxrec) {
304: close(wfd);
1.1 deraadt 305: return;
1.33 deraadt 306: }
1.1 deraadt 307: }
308: continue;
309: }
1.33 deraadt 310:
1.1 deraadt 311: /*
312: * if the line is '{' or '|', date got set; see
313: * utmp(5) for more info.
314: */
1.33 deraadt 315: if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|') &&
316: !bp->ut_line[1]) {
1.5 jdm 317: if (want(bp, NO)) {
1.40 guenther 318: print_entry(bp);
319: printf("\n");
1.33 deraadt 320: if (maxrec && !--maxrec) {
321: close(wfd);
1.1 deraadt 322: return;
1.33 deraadt 323: }
1.1 deraadt 324: }
325: continue;
326: }
1.33 deraadt 327:
1.1 deraadt 328: /* find associated tty */
329: for (T = ttylist;; T = T->next) {
330: if (!T) {
331: /* add new one */
332: T = addtty(bp->ut_line);
333: break;
334: }
335: if (!strncmp(T->tty, bp->ut_line, UT_LINESIZE))
336: break;
337: }
1.33 deraadt 338:
1.18 mickey 339: /*
1.4 jdm 340: * print record if not in snapshot mode and wanted
341: * or in snapshot mode and in snapshot range
342: */
343: if (bp->ut_name[0] &&
1.28 deraadt 344: ((want(bp, YES)) || (bp->ut_time < snaptime &&
345: (T->logout > snaptime || !T->logout ||
346: T->logout < 0)))) {
1.4 jdm 347: snapfound = 1;
1.40 guenther 348: print_entry(bp);
349: printf(" ");
1.33 deraadt 350:
1.1 deraadt 351: if (!T->logout)
352: puts(" still logged in");
353: else {
354: if (T->logout < 0) {
355: T->logout = -T->logout;
356: printf("- %s", crmsg);
1.9 downsj 357: } else {
1.18 mickey 358: if (seconds)
1.40 guenther 359: printf("- %lld",
360: (long long)T->logout);
1.9 downsj 361: else
362: printf("- %*.*s",
363: timesize, timesize,
364: ctime(&T->logout)+11);
1.1 deraadt 365: }
366: delta = T->logout - bp->ut_time;
1.9 downsj 367: if (seconds)
1.40 guenther 368: printf(" (%lld)\n",
369: (long long)delta);
1.9 downsj 370: else {
371: if (delta < SECSPERDAY)
372: printf(" (%*.*s)\n",
373: timesize, timesize,
374: asctime(gmtime(&delta))+11);
375: else
1.39 guenther 376: printf(" (%lld+%*.*s)\n",
377: (long long)delta / SECSPERDAY,
1.9 downsj 378: timesize, timesize,
379: asctime(gmtime(&delta))+11);
380: }
381: if (calculate)
382: total += delta;
1.1 deraadt 383: }
1.33 deraadt 384: if (maxrec != -1 && !--maxrec) {
385: close(wfd);
1.1 deraadt 386: return;
1.33 deraadt 387: }
1.1 deraadt 388: }
389: T->logout = bp->ut_time;
390: }
1.9 downsj 391: }
1.33 deraadt 392: close(wfd);
1.9 downsj 393: if (calculate) {
394: if ((total / SECSPERDAY) > 0) {
395: int days = (total / SECSPERDAY);
396: total -= (days * SECSPERDAY);
397:
398: printf("\nTotal time: %d days, %*.*s\n",
1.28 deraadt 399: days, timesize, timesize,
400: asctime(gmtime(&total))+11);
1.9 downsj 401: } else
402: printf("\nTotal time: %*.*s\n",
1.28 deraadt 403: timesize, timesize,
404: asctime(gmtime(&total))+11);
1.1 deraadt 405: }
406: ct = ctime(&buf[0].ut_time);
1.37 lum 407: printf("\n%s begins %10.10s %*.*s %4.4s\n", basename(file), ct,
408: timesize, timesize, ct + 11, ct + 20);
1.1 deraadt 409: }
410:
411: /*
1.33 deraadt 412: * see if want this entry
1.1 deraadt 413: */
414: int
1.27 deraadt 415: want(struct utmp *bp, int check)
1.1 deraadt 416: {
1.33 deraadt 417: struct arg *step;
1.1 deraadt 418:
1.15 deraadt 419: if (check) {
1.1 deraadt 420: /*
1.42 okan 421: * some entries, such as ftp and uucp, will
422: * include process name plus id; exclude entries
423: * that start with 'console' and 'tty' from
424: * having the process id stripped.
1.1 deraadt 425: */
1.42 okan 426: if ((strncmp(bp->ut_line, "console", strlen("console")) != 0) &&
427: (strncmp(bp->ut_line, "tty", strlen("tty")) != 0)) {
428: char *s;
429: for (s = bp->ut_line;
430: *s != '\0' && !isdigit((unsigned char)*s); s++)
431: ;
432: *s = '\0';
433: }
1.15 deraadt 434: }
1.5 jdm 435:
1.18 mickey 436: if (snaptime) /* if snaptime is set, return NO */
1.5 jdm 437: return (NO);
438:
1.1 deraadt 439: if (!arglist)
440: return (YES);
441:
442: for (step = arglist; step; step = step->next)
1.33 deraadt 443: switch (step->type) {
1.1 deraadt 444: case HOST_TYPE:
445: if (!strncasecmp(step->name, bp->ut_host, UT_HOSTSIZE))
446: return (YES);
447: break;
448: case TTY_TYPE:
449: if (!strncmp(step->name, bp->ut_line, UT_LINESIZE))
450: return (YES);
451: break;
452: case USER_TYPE:
453: if (!strncmp(step->name, bp->ut_name, UT_NAMESIZE))
454: return (YES);
455: break;
1.5 jdm 456: }
457:
1.1 deraadt 458: return (NO);
459: }
460:
461: /*
1.33 deraadt 462: * add an entry to a linked list of arguments
1.1 deraadt 463: */
464: void
1.27 deraadt 465: addarg(int type, char *arg)
1.1 deraadt 466: {
1.33 deraadt 467: struct arg *cur;
1.1 deraadt 468:
1.49 deraadt 469: if (!(cur = malloc((u_int)sizeof(struct arg))))
1.1 deraadt 470: err(1, "malloc failure");
471: cur->next = arglist;
472: cur->type = type;
473: cur->name = arg;
474: arglist = cur;
475: }
476:
477: /*
1.33 deraadt 478: * add an entry to a linked list of ttys
1.1 deraadt 479: */
1.33 deraadt 480: struct ttytab *
1.27 deraadt 481: addtty(char *ttyname)
1.1 deraadt 482: {
1.33 deraadt 483: struct ttytab *cur;
1.1 deraadt 484:
1.49 deraadt 485: if (!(cur = malloc((u_int)sizeof(struct ttytab))))
1.1 deraadt 486: err(1, "malloc failure");
487: cur->next = ttylist;
488: cur->logout = currentout;
489: memmove(cur->tty, ttyname, UT_LINESIZE);
490: return (ttylist = cur);
491: }
492:
493: /*
1.33 deraadt 494: * convert the hostname to search pattern; if the supplied host name
495: * has a domain attached that is the same as the current domain, rip
496: * off the domain suffix since that's what login(1) does.
1.1 deraadt 497: */
498: void
1.27 deraadt 499: hostconv(char *arg)
1.1 deraadt 500: {
1.45 deraadt 501: static char *hostdot, name[HOST_NAME_MAX+1];
1.1 deraadt 502: static int first = 1;
503: char *argdot;
504:
505: if (!(argdot = strchr(arg, '.')))
506: return;
507: if (first) {
508: first = 0;
509: if (gethostname(name, sizeof(name)))
510: err(1, "gethostname");
511: hostdot = strchr(name, '.');
512: }
513: if (hostdot && !strcasecmp(hostdot, argdot))
514: *argdot = '\0';
515: }
516:
517: /*
1.33 deraadt 518: * convert tty to correct name.
1.1 deraadt 519: */
520: char *
1.27 deraadt 521: ttyconv(char *arg)
1.1 deraadt 522: {
1.33 deraadt 523: size_t len = 8;
1.1 deraadt 524: char *mval;
525:
526: /*
527: * kludge -- we assume that all tty's end with
528: * a two character suffix.
529: */
530: if (strlen(arg) == 2) {
531: /* either 6 for "ttyxx" or 8 for "console" */
1.21 deraadt 532: if (!(mval = malloc(len)))
1.1 deraadt 533: err(1, "malloc failure");
534: if (!strcmp(arg, "co"))
1.21 deraadt 535: (void)strlcpy(mval, "console", len);
536: else
537: snprintf(mval, len, "tty%s", arg);
1.1 deraadt 538: return (mval);
539: }
540: if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
541: return (arg + 5);
542: return (arg);
543: }
1.4 jdm 544:
1.18 mickey 545: /*
546: * Convert the snapshot time in command line given in the format
1.23 deraadt 547: * [[[CC]YY]MMDD]hhmm[.SS]] to a time_t.
1.18 mickey 548: * Derived from atime_arg1() in usr.bin/touch/touch.c
1.4 jdm 549: */
550: time_t
1.27 deraadt 551: dateconv(char *arg)
1.4 jdm 552: {
1.7 deraadt 553: time_t timet;
554: struct tm *t;
555: int yearset;
556: char *p;
557:
558: /* Start with the current time. */
559: if (time(&timet) < 0)
560: err(1, "time");
561: if ((t = localtime(&timet)) == NULL)
562: err(1, "localtime");
563:
1.23 deraadt 564: /* [[[CC]YY]MMDD]hhmm[.SS] */
1.7 deraadt 565: if ((p = strchr(arg, '.')) == NULL)
1.18 mickey 566: t->tm_sec = 0; /* Seconds defaults to 0. */
1.7 deraadt 567: else {
568: if (strlen(p + 1) != 2)
569: goto terr;
570: *p++ = '\0';
571: t->tm_sec = ATOI2(p);
572: }
573:
574: yearset = 0;
575: switch (strlen(arg)) {
1.22 deraadt 576: case 12: /* CCYYMMDDhhmm */
1.7 deraadt 577: t->tm_year = ATOI2(arg);
578: t->tm_year *= 100;
579: yearset = 1;
1.29 otto 580: /* FALLTHROUGH */
1.22 deraadt 581: case 10: /* YYMMDDhhmm */
1.7 deraadt 582: if (yearset) {
583: yearset = ATOI2(arg);
584: t->tm_year += yearset;
585: } else {
586: yearset = ATOI2(arg);
587: if (yearset < 69)
588: t->tm_year = yearset + 2000;
589: else
590: t->tm_year = yearset + 1900;
591: }
1.28 deraadt 592: t->tm_year -= 1900; /* Convert to UNIX time. */
1.7 deraadt 593: /* FALLTHROUGH */
594: case 8: /* MMDDhhmm */
595: t->tm_mon = ATOI2(arg);
1.18 mickey 596: --t->tm_mon; /* Convert from 01-12 to 00-11 */
1.7 deraadt 597: t->tm_mday = ATOI2(arg);
598: t->tm_hour = ATOI2(arg);
599: t->tm_min = ATOI2(arg);
600: break;
601: case 4: /* hhmm */
602: t->tm_hour = ATOI2(arg);
603: t->tm_min = ATOI2(arg);
604: break;
605: default:
606: goto terr;
607: }
1.18 mickey 608: t->tm_isdst = -1; /* Figure out DST. */
1.7 deraadt 609: timet = mktime(t);
610: if (timet == -1)
1.28 deraadt 611: terr: errx(1, "out of range or illegal time specification: "
612: "[[[CC]YY]MMDD]hhmm[.SS]");
1.22 deraadt 613: return (timet);
1.4 jdm 614: }
615:
1.1 deraadt 616:
617: /*
1.33 deraadt 618: * on interrupt, we inform the user how far we've gotten
1.1 deraadt 619: */
620: void
1.27 deraadt 621: onintr(int signo)
1.1 deraadt 622: {
1.47 deraadt 623: char str[1024], *ct, ctbuf[26];
1.1 deraadt 624:
1.47 deraadt 625: ct = ctime_r(&buf[0].ut_time, ctbuf);
1.25 deraadt 626: snprintf(str, sizeof str, "\ninterrupted %10.10s %8.8s \n",
627: ct, ct + 11);
628: write(STDOUT_FILENO, str, strlen(str));
1.1 deraadt 629: if (signo == SIGINT)
1.25 deraadt 630: _exit(1);
1.22 deraadt 631: }
632:
633: void
634: usage(void)
635: {
636: extern char *__progname;
637:
638: fprintf(stderr,
1.34 jmc 639: "usage: %s [-csT] [-d date] [-f file] [-h host]"
640: " [-n number] [-t tty] [user ...]\n", __progname);
1.22 deraadt 641: exit(1);
1.1 deraadt 642: }