last.c revision 77328
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1987, 1993, 1994 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 3260833Sjake * 3360833Sjake * $FreeBSD: head/usr.bin/last/last.c 77328 2001-05-28 09:57:19Z ru $ 341590Srgrimes */ 351590Srgrimes 361590Srgrimes#ifndef lint 371590Srgrimesstatic char copyright[] = 381590Srgrimes"@(#) Copyright (c) 1987, 1993, 1994\n\ 391590Srgrimes The Regents of the University of California. All rights reserved.\n"; 401590Srgrimes#endif /* not lint */ 411590Srgrimes 421590Srgrimes#ifndef lint 431590Srgrimesstatic char sccsid[] = "@(#)last.c 8.2 (Berkeley) 4/2/94"; 441590Srgrimes#endif /* not lint */ 451590Srgrimes 461590Srgrimes#include <sys/param.h> 471590Srgrimes#include <sys/stat.h> 481590Srgrimes 491590Srgrimes#include <err.h> 501590Srgrimes#include <fcntl.h> 5174588Sache#include <langinfo.h> 5216438Sache#include <locale.h> 531590Srgrimes#include <paths.h> 541590Srgrimes#include <signal.h> 551590Srgrimes#include <stdio.h> 561590Srgrimes#include <stdlib.h> 571590Srgrimes#include <string.h> 581590Srgrimes#include <time.h> 591590Srgrimes#include <unistd.h> 601590Srgrimes#include <utmp.h> 6111547Sdg#include <sys/queue.h> 621590Srgrimes 631590Srgrimes#define NO 0 /* false/no */ 641590Srgrimes#define YES 1 /* true/yes */ 6577291Sdd#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; 661590Srgrimes 671590Srgrimesstatic struct utmp buf[1024]; /* utmp read buffer */ 681590Srgrimes 691590Srgrimestypedef struct arg { 701590Srgrimes char *name; /* argument */ 711590Srgrimes#define HOST_TYPE -2 721590Srgrimes#define TTY_TYPE -3 731590Srgrimes#define USER_TYPE -4 741590Srgrimes int type; /* type of arg */ 751590Srgrimes struct arg *next; /* linked list pointer */ 761590Srgrimes} ARG; 771590SrgrimesARG *arglist; /* head of linked list */ 781590Srgrimes 7960938SjakeLIST_HEAD(ttylisthead, ttytab) ttylist; 8011547Sdg 8111547Sdgstruct ttytab { 8236062Sjb time_t logout; /* log out time */ 831590Srgrimes char tty[UT_LINESIZE + 1]; /* terminal name */ 8460938Sjake LIST_ENTRY(ttytab) list; 8511547Sdg}; 861590Srgrimes 871590Srgrimesstatic long currentout, /* current logout value */ 881590Srgrimes maxrec; /* records to display */ 891590Srgrimesstatic char *file = _PATH_WTMP; /* wtmp file */ 9036434Sdannystatic int sflag = 0; /* show delta in seconds */ 9136434Sdannystatic int width = 5; /* show seconds in delta */ 9274588Sachestatic int d_first; 9377291Sddstatic time_t snaptime; /* if != 0, we will only 9477291Sdd * report users logged in 9577291Sdd * at this snapshot time 9677291Sdd */ 971590Srgrimes 981590Srgrimesvoid addarg __P((int, char *)); 991590Srgrimesvoid hostconv __P((char *)); 1001590Srgrimesvoid onintr __P((int)); 1011590Srgrimeschar *ttyconv __P((char *)); 10277291Sddtime_t dateconv __P((char *)); 10311547Sdgint want __P((struct utmp *)); 1041590Srgrimesvoid wtmp __P((void)); 1051590Srgrimes 10636434Sdannyvoid 10736434Sdannyusage(void) 10836434Sdanny{ 10936434Sdanny (void)fprintf(stderr, 11036434Sdanny "usage: last [-#] [-f file] [-h hostname] [-t tty] [-s|w] [user ...]\n"); 11136434Sdanny exit(1); 11236434Sdanny} 11336434Sdanny 1141590Srgrimesint 1151590Srgrimesmain(argc, argv) 1161590Srgrimes int argc; 1171590Srgrimes char *argv[]; 1181590Srgrimes{ 1191590Srgrimes int ch; 1201590Srgrimes char *p; 1211590Srgrimes 12216438Sache (void) setlocale(LC_TIME, ""); 12374588Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 12416438Sache 1251590Srgrimes maxrec = -1; 12677291Sdd snaptime = 0; 12777291Sdd while ((ch = getopt(argc, argv, "0123456789d:f:h:st:w")) != -1) 1281590Srgrimes switch (ch) { 1291590Srgrimes case '0': case '1': case '2': case '3': case '4': 1301590Srgrimes case '5': case '6': case '7': case '8': case '9': 1311590Srgrimes /* 1321590Srgrimes * kludge: last was originally designed to take 1331590Srgrimes * a number after a dash. 1341590Srgrimes */ 1351590Srgrimes if (maxrec == -1) { 1361590Srgrimes p = argv[optind - 1]; 1371590Srgrimes if (p[0] == '-' && p[1] == ch && !p[2]) 1381590Srgrimes maxrec = atol(++p); 1391590Srgrimes else 1401590Srgrimes maxrec = atol(argv[optind] + 1); 1411590Srgrimes if (!maxrec) 1421590Srgrimes exit(0); 1431590Srgrimes } 1441590Srgrimes break; 14577291Sdd case 'd': 14677291Sdd snaptime = dateconv(optarg); 14777291Sdd break; 1481590Srgrimes case 'f': 1491590Srgrimes file = optarg; 1501590Srgrimes break; 1511590Srgrimes case 'h': 1521590Srgrimes hostconv(optarg); 1531590Srgrimes addarg(HOST_TYPE, optarg); 1541590Srgrimes break; 15536434Sdanny case 's': 15636434Sdanny sflag++; /* Show delta as seconds */ 15736434Sdanny break; 1581590Srgrimes case 't': 1591590Srgrimes addarg(TTY_TYPE, ttyconv(optarg)); 1601590Srgrimes break; 16136434Sdanny case 'w': 16236434Sdanny width = 8; 16336434Sdanny break; 1641590Srgrimes case '?': 1651590Srgrimes default: 16636434Sdanny usage(); 1671590Srgrimes } 1681590Srgrimes 16936434Sdanny if (sflag && width == 8) usage(); 17036434Sdanny 1711590Srgrimes if (argc) { 1721590Srgrimes setlinebuf(stdout); 1731590Srgrimes for (argv += optind; *argv; ++argv) { 1741590Srgrimes#define COMPATIBILITY 1751590Srgrimes#ifdef COMPATIBILITY 1761590Srgrimes /* code to allow "last p5" to work */ 1771590Srgrimes addarg(TTY_TYPE, ttyconv(*argv)); 1781590Srgrimes#endif 1791590Srgrimes addarg(USER_TYPE, *argv); 1801590Srgrimes } 1811590Srgrimes } 1821590Srgrimes wtmp(); 1831590Srgrimes exit(0); 1841590Srgrimes} 1851590Srgrimes 1861590Srgrimes/* 1871590Srgrimes * wtmp -- 1881590Srgrimes * read through the wtmp file 1891590Srgrimes */ 1901590Srgrimesvoid 1911590Srgrimeswtmp() 1921590Srgrimes{ 1931590Srgrimes struct utmp *bp; /* current structure */ 19419223Sjoerg struct ttytab *tt, *ttx; /* ttylist entry */ 1951590Srgrimes struct stat stb; /* stat of file for size */ 19636062Sjb long bl; 19736062Sjb time_t delta; /* time difference */ 1981590Srgrimes int bytes, wfd; 19916438Sache char *crmsg; 20016438Sache char ct[80]; 20116438Sache struct tm *tm; 20277291Sdd int snapfound = 0; /* found snapshot entry? */ 2031590Srgrimes 20411547Sdg LIST_INIT(&ttylist); 20511547Sdg 2061590Srgrimes if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1) 2071590Srgrimes err(1, "%s", file); 2081590Srgrimes bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf); 2091590Srgrimes 2101590Srgrimes (void)time(&buf[0].ut_time); 2111590Srgrimes (void)signal(SIGINT, onintr); 2121590Srgrimes (void)signal(SIGQUIT, onintr); 2131590Srgrimes 2141590Srgrimes while (--bl >= 0) { 2151590Srgrimes if (lseek(wfd, (off_t)(bl * sizeof(buf)), L_SET) == -1 || 2161590Srgrimes (bytes = read(wfd, buf, sizeof(buf))) == -1) 2171590Srgrimes err(1, "%s", file); 2181590Srgrimes for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) { 2191590Srgrimes /* 2201590Srgrimes * if the terminal line is '~', the machine stopped. 2211590Srgrimes * see utmp(5) for more info. 2221590Srgrimes */ 2231590Srgrimes if (bp->ut_line[0] == '~' && !bp->ut_line[1]) { 2241590Srgrimes /* everybody just logged out */ 22570467Sphk for (tt = LIST_FIRST(&ttylist); tt;) { 22611547Sdg LIST_REMOVE(tt, list); 22719223Sjoerg ttx = tt; 22870467Sphk tt = LIST_NEXT(tt, list); 22919223Sjoerg free(ttx); 23011547Sdg } 2311590Srgrimes currentout = -bp->ut_time; 2321590Srgrimes crmsg = strncmp(bp->ut_name, "shutdown", 2331590Srgrimes UT_NAMESIZE) ? "crash" : "shutdown"; 23477291Sdd /* 23577291Sdd * if we're in snapshot mode, we want to 23677291Sdd * exit if this shutdown/reboot appears 23777291Sdd * while we we are tracking the active 23877291Sdd * range 23977291Sdd */ 24077291Sdd if (snaptime && snapfound) 24177291Sdd return; 24277291Sdd /* 24377291Sdd * don't print shutdown/reboot entries 24477291Sdd * unless flagged for 24577291Sdd */ 24677291Sdd if (!snaptime && want(bp)) { 24716438Sache tm = localtime(&bp->ut_time); 24874588Sache (void) strftime(ct, sizeof(ct), 24974588Sache d_first ? "%a %e %b %R" : 25074588Sache "%a %b %e %R", 25174588Sache tm); 25274588Sache printf("%-*.*s %-*.*s %-*.*s %s\n", 2531590Srgrimes UT_NAMESIZE, UT_NAMESIZE, 2541590Srgrimes bp->ut_name, UT_LINESIZE, 2551590Srgrimes UT_LINESIZE, bp->ut_line, 2561590Srgrimes UT_HOSTSIZE, UT_HOSTSIZE, 25774588Sache bp->ut_host, ct); 2581590Srgrimes if (maxrec != -1 && !--maxrec) 2591590Srgrimes return; 2601590Srgrimes } 2611590Srgrimes continue; 2621590Srgrimes } 2631590Srgrimes /* 2641590Srgrimes * if the line is '{' or '|', date got set; see 2651590Srgrimes * utmp(5) for more info. 2661590Srgrimes */ 2671590Srgrimes if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|') 2681590Srgrimes && !bp->ut_line[1]) { 26977291Sdd if (want(bp) && !snaptime) { 27016438Sache tm = localtime(&bp->ut_time); 27174588Sache (void) strftime(ct, sizeof(ct), 27274588Sache d_first ? "%a %e %b %R" : 27374588Sache "%a %b %e %R", 27474588Sache tm); 27574588Sache printf("%-*.*s %-*.*s %-*.*s %s\n", 27611547Sdg UT_NAMESIZE, UT_NAMESIZE, bp->ut_name, 27711547Sdg UT_LINESIZE, UT_LINESIZE, bp->ut_line, 27811547Sdg UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host, 27974588Sache ct); 2801590Srgrimes if (maxrec && !--maxrec) 2811590Srgrimes return; 2821590Srgrimes } 2831590Srgrimes continue; 2841590Srgrimes } 28577291Sdd /* find associated tty */ 28677291Sdd LIST_FOREACH(tt, &ttylist, list) 28777291Sdd if (!strncmp(tt->tty, bp->ut_line, UT_LINESIZE)) 28877291Sdd break; 28977291Sdd 29077291Sdd if (tt == NULL) { 29177291Sdd /* add new one */ 29277291Sdd tt = malloc(sizeof(struct ttytab)); 29377291Sdd if (tt == NULL) 29477291Sdd err(1, "malloc failure"); 29577291Sdd tt->logout = currentout; 29677291Sdd strncpy(tt->tty, bp->ut_line, UT_LINESIZE); 29777291Sdd LIST_INSERT_HEAD(&ttylist, tt, list); 29877291Sdd } 29977291Sdd 30077291Sdd /* 30177291Sdd * print record if not in snapshot mode and wanted 30277291Sdd * or in snapshot mode and in snapshot range 30377291Sdd */ 30477291Sdd if (bp->ut_name[0] && (want(bp) || 30577291Sdd (bp->ut_time < snaptime && 30677291Sdd (tt->logout > snaptime || tt->logout < 1)))) { 30777291Sdd snapfound = 1; 30877291Sdd /* 30977291Sdd * when uucp and ftp log in over a network, the entry in 31077291Sdd * the utmp file is the name plus their process id. See 31177291Sdd * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information. 31277291Sdd */ 31377291Sdd if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1)) 31477291Sdd bp->ut_line[3] = '\0'; 31577291Sdd else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1)) 31677291Sdd bp->ut_line[4] = '\0'; 31777291Sdd tm = localtime(&bp->ut_time); 31877291Sdd (void) strftime(ct, sizeof(ct), 31977291Sdd d_first ? "%a %e %b %R" : 32077291Sdd "%a %b %e %R", 32177291Sdd tm); 32277291Sdd printf("%-*.*s %-*.*s %-*.*s %s ", 32377291Sdd UT_NAMESIZE, UT_NAMESIZE, bp->ut_name, 32477291Sdd UT_LINESIZE, UT_LINESIZE, bp->ut_line, 32577291Sdd UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host, 32677291Sdd ct); 32777291Sdd if (!tt->logout) 32877291Sdd puts(" still logged in"); 32977291Sdd else { 33077291Sdd if (tt->logout < 0) { 33177291Sdd tt->logout = -tt->logout; 33277291Sdd printf("- %s", crmsg); 33377291Sdd } 33411547Sdg else { 33577291Sdd tm = localtime(&tt->logout); 33677291Sdd (void) strftime(ct, sizeof(ct), "%R", tm); 33777291Sdd printf("- %s", ct); 33877291Sdd } 33977291Sdd delta = tt->logout - bp->ut_time; 34077291Sdd if ( sflag ) { 34177291Sdd printf(" (%8lu)\n", 34277291Sdd delta); 34377291Sdd } else { 34477291Sdd tm = gmtime(&delta); 34577291Sdd (void) strftime(ct, sizeof(ct), 34677291Sdd width >= 8 ? "%T" : "%R", 34777291Sdd tm); 34877291Sdd if (delta < 86400) 34974588Sache printf(" (%s)\n", ct); 35077291Sdd else 35174588Sache printf(" (%ld+%s)\n", 35274588Sache delta / 86400, ct); 3531590Srgrimes } 3541590Srgrimes } 35577291Sdd if (maxrec != -1 && !--maxrec) 35677291Sdd return; 3571590Srgrimes } 35877328Sru tt->logout = bp->ut_time; 3591590Srgrimes } 3601590Srgrimes } 36116438Sache tm = localtime(&buf[0].ut_time); 36235658Ssteve (void) strftime(ct, sizeof(ct), "\nwtmp begins %c\n", tm); 36362871Skris printf("%s", ct); 3641590Srgrimes} 3651590Srgrimes 3661590Srgrimes/* 3671590Srgrimes * want -- 3681590Srgrimes * see if want this entry 3691590Srgrimes */ 3701590Srgrimesint 37111547Sdgwant(bp) 3721590Srgrimes struct utmp *bp; 3731590Srgrimes{ 3741590Srgrimes ARG *step; 3751590Srgrimes 37677291Sdd if (snaptime) 37777291Sdd return (NO); 37877291Sdd 3791590Srgrimes if (!arglist) 3801590Srgrimes return (YES); 3811590Srgrimes 3821590Srgrimes for (step = arglist; step; step = step->next) 3831590Srgrimes switch(step->type) { 3841590Srgrimes case HOST_TYPE: 3851590Srgrimes if (!strncasecmp(step->name, bp->ut_host, UT_HOSTSIZE)) 3861590Srgrimes return (YES); 3871590Srgrimes break; 3881590Srgrimes case TTY_TYPE: 3891590Srgrimes if (!strncmp(step->name, bp->ut_line, UT_LINESIZE)) 3901590Srgrimes return (YES); 3911590Srgrimes break; 3921590Srgrimes case USER_TYPE: 3931590Srgrimes if (!strncmp(step->name, bp->ut_name, UT_NAMESIZE)) 3941590Srgrimes return (YES); 3951590Srgrimes break; 3961590Srgrimes } 3971590Srgrimes return (NO); 3981590Srgrimes} 3991590Srgrimes 4001590Srgrimes/* 4011590Srgrimes * addarg -- 4021590Srgrimes * add an entry to a linked list of arguments 4031590Srgrimes */ 4041590Srgrimesvoid 4051590Srgrimesaddarg(type, arg) 4061590Srgrimes int type; 4071590Srgrimes char *arg; 4081590Srgrimes{ 4091590Srgrimes ARG *cur; 4101590Srgrimes 4111590Srgrimes if (!(cur = (ARG *)malloc((u_int)sizeof(ARG)))) 4121590Srgrimes err(1, "malloc failure"); 4131590Srgrimes cur->next = arglist; 4141590Srgrimes cur->type = type; 4151590Srgrimes cur->name = arg; 4161590Srgrimes arglist = cur; 4171590Srgrimes} 4181590Srgrimes 4191590Srgrimes/* 4201590Srgrimes * hostconv -- 4211590Srgrimes * convert the hostname to search pattern; if the supplied host name 4221590Srgrimes * has a domain attached that is the same as the current domain, rip 4231590Srgrimes * off the domain suffix since that's what login(1) does. 4241590Srgrimes */ 4251590Srgrimesvoid 4261590Srgrimeshostconv(arg) 4271590Srgrimes char *arg; 4281590Srgrimes{ 4291590Srgrimes static int first = 1; 4301590Srgrimes static char *hostdot, name[MAXHOSTNAMELEN]; 4311590Srgrimes char *argdot; 4321590Srgrimes 4331590Srgrimes if (!(argdot = strchr(arg, '.'))) 4341590Srgrimes return; 4351590Srgrimes if (first) { 4361590Srgrimes first = 0; 4371590Srgrimes if (gethostname(name, sizeof(name))) 4381590Srgrimes err(1, "gethostname"); 4391590Srgrimes hostdot = strchr(name, '.'); 4401590Srgrimes } 4411590Srgrimes if (hostdot && !strcasecmp(hostdot, argdot)) 4421590Srgrimes *argdot = '\0'; 4431590Srgrimes} 4441590Srgrimes 4451590Srgrimes/* 4461590Srgrimes * ttyconv -- 4471590Srgrimes * convert tty to correct name. 4481590Srgrimes */ 4491590Srgrimeschar * 4501590Srgrimesttyconv(arg) 4511590Srgrimes char *arg; 4521590Srgrimes{ 4531590Srgrimes char *mval; 4541590Srgrimes 4551590Srgrimes /* 4561590Srgrimes * kludge -- we assume that all tty's end with 4571590Srgrimes * a two character suffix. 4581590Srgrimes */ 4591590Srgrimes if (strlen(arg) == 2) { 4601590Srgrimes /* either 6 for "ttyxx" or 8 for "console" */ 4611590Srgrimes if (!(mval = malloc((u_int)8))) 4621590Srgrimes err(1, "malloc failure"); 4631590Srgrimes if (!strcmp(arg, "co")) 4641590Srgrimes (void)strcpy(mval, "console"); 4651590Srgrimes else { 4661590Srgrimes (void)strcpy(mval, "tty"); 4671590Srgrimes (void)strcpy(mval + 3, arg); 4681590Srgrimes } 4691590Srgrimes return (mval); 4701590Srgrimes } 4711590Srgrimes if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1)) 4721590Srgrimes return (arg + 5); 4731590Srgrimes return (arg); 4741590Srgrimes} 4751590Srgrimes 4761590Srgrimes/* 47777291Sdd * dateconv -- 47877291Sdd * Convert the snapshot time in command line given in the format 47977291Sdd * [[CC]YY]MMDDhhmm[.SS]] to a time_t. 48077291Sdd * Derived from atime_arg1() in usr.bin/touch/touch.c 48177291Sdd */ 48277291Sddtime_t 48377291Sdddateconv(arg) 48477291Sdd char *arg; 48577291Sdd{ 48677291Sdd time_t timet; 48777291Sdd struct tm *t; 48877291Sdd int yearset; 48977291Sdd char *p; 49077291Sdd 49177291Sdd /* Start with the current time. */ 49277291Sdd if (time(&timet) < 0) 49377291Sdd err(1, "time"); 49477291Sdd if ((t = localtime(&timet)) == NULL) 49577291Sdd err(1, "localtime"); 49677291Sdd 49777291Sdd /* [[CC]YY]MMDDhhmm[.SS] */ 49877291Sdd if ((p = strchr(arg, '.')) == NULL) 49977291Sdd t->tm_sec = 0; /* Seconds defaults to 0. */ 50077291Sdd else { 50177291Sdd if (strlen(p + 1) != 2) 50277291Sdd goto terr; 50377291Sdd *p++ = '\0'; 50477291Sdd t->tm_sec = ATOI2(p); 50577291Sdd } 50677291Sdd 50777291Sdd yearset = 0; 50877291Sdd switch (strlen(arg)) { 50977291Sdd case 12: /* CCYYMMDDhhmm */ 51077291Sdd t->tm_year = ATOI2(arg); 51177291Sdd t->tm_year *= 100; 51277291Sdd yearset = 1; 51377291Sdd /* FALLTHOUGH */ 51477291Sdd case 10: /* YYMMDDhhmm */ 51577291Sdd if (yearset) { 51677291Sdd yearset = ATOI2(arg); 51777291Sdd t->tm_year += yearset; 51877291Sdd } else { 51977291Sdd yearset = ATOI2(arg); 52077291Sdd if (yearset < 69) 52177291Sdd t->tm_year = yearset + 2000; 52277291Sdd else 52377291Sdd t->tm_year = yearset + 1900; 52477291Sdd } 52577291Sdd t->tm_year -= 1900; /* Convert to UNIX time. */ 52677291Sdd /* FALLTHROUGH */ 52777291Sdd case 8: /* MMDDhhmm */ 52877291Sdd t->tm_mon = ATOI2(arg); 52977291Sdd --t->tm_mon; /* Convert from 01-12 to 00-11 */ 53077291Sdd t->tm_mday = ATOI2(arg); 53177291Sdd t->tm_hour = ATOI2(arg); 53277291Sdd t->tm_min = ATOI2(arg); 53377291Sdd break; 53477291Sdd case 4: /* hhmm */ 53577291Sdd t->tm_hour = ATOI2(arg); 53677291Sdd t->tm_min = ATOI2(arg); 53777291Sdd break; 53877291Sdd default: 53977291Sdd goto terr; 54077291Sdd } 54177291Sdd t->tm_isdst = -1; /* Figure out DST. */ 54277291Sdd timet = mktime(t); 54377291Sdd if (timet == -1) 54477291Sddterr: errx(1, 54577291Sdd "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); 54677291Sdd return timet; 54777291Sdd} 54877291Sdd 54977291Sdd 55077291Sdd/* 5511590Srgrimes * onintr -- 5521590Srgrimes * on interrupt, we inform the user how far we've gotten 5531590Srgrimes */ 5541590Srgrimesvoid 5551590Srgrimesonintr(signo) 5561590Srgrimes int signo; 5571590Srgrimes{ 55816438Sache char ct[80]; 55916438Sache struct tm *tm; 5601590Srgrimes 56116438Sache tm = localtime(&buf[0].ut_time); 56274588Sache (void) strftime(ct, sizeof(ct), 56374588Sache d_first ? "%a %e %b %R" : "%a %b %e %R", 56474588Sache tm); 56574588Sache printf("\ninterrupted %s\n", ct); 5661590Srgrimes if (signo == SIGINT) 5671590Srgrimes exit(1); 5681590Srgrimes (void)fflush(stdout); /* fix required for rsh */ 5691590Srgrimes} 570