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