From 991609f48522503361a773cd5d7e429662d9bd2c Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Thu, 16 Dec 2010 17:42:53 +0100 Subject: [PATCH] Fix build of last(1). --- usr.bin/last/want.c | 315 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 usr.bin/last/want.c diff --git a/usr.bin/last/want.c b/usr.bin/last/want.c new file mode 100644 index 0000000000..8a2394901a --- /dev/null +++ b/usr.bin/last/want.c @@ -0,0 +1,315 @@ +/* $NetBSD: want.c,v 1.13 2009/04/12 13:07:21 lukem Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +static struct utmp *buf; + +static void onintr(int); +static int want(struct utmp *, int); +static const char *gethost(struct utmp *, const char *, int); + +static const char * +/*ARGSUSED*/ +gethost(struct utmp *ut, const char *host, int numeric) +{ +#if FIRSTVALID == 0 + return numeric ? "" : host; +#else + if (numeric) { + static char hbuf[512]; + hbuf[0] = '\0'; + (void)sockaddr_snprintf(hbuf, sizeof(hbuf), "%a", + (struct sockaddr *)&ut->ut_ss); + return hbuf; + } else + return host; +#endif +} + +#define NULTERM(what) \ + if (check ## what) \ + (void)strlcpy(what ## p = what ## buf, bp->ut_ ## what, \ + sizeof(what ## buf)); \ + else \ + what ## p = bp->ut_ ## what + +/* + * wtmp -- + * read through the wtmp file + */ +void +wtmp(const char *file, int namesz, int linesz, int hostsz, int numeric) +{ + struct utmp *bp; /* current structure */ + TTY *T; /* tty list entry */ + struct stat stb; /* stat of file for sz */ + off_t offset; + int wfd; + char *ct; + const char *crmsg; + size_t len = sizeof(*buf) * MAXUTMP; + char namebuf[sizeof(bp->ut_name) + 1], *namep; + char linebuf[sizeof(bp->ut_line) + 1], *linep; + char hostbuf[sizeof(bp->ut_host) + 1], *hostp; + int checkname = namesz > (int)sizeof(bp->ut_name); + int checkline = linesz > (int)sizeof(bp->ut_line); + int checkhost = hostsz > (int)sizeof(bp->ut_host); + + if ((buf = malloc(len)) == NULL) + err(EXIT_FAILURE, "Cannot allocate utmp buffer"); + + crmsg = NULL; + + if (!strcmp(file, "-")) { + wfd = STDIN_FILENO; + file = ""; + } else if ((wfd = open(file, O_RDONLY, 0)) < 0) { + err(EXIT_FAILURE, "%s", file); + } + + if (lseek(wfd, 0, SEEK_CUR) < 0) { + const char *dir; + char *tfile; + int tempfd; + ssize_t tlen; + + if (ESPIPE != errno) { + err(EXIT_FAILURE, "lseek"); + } + dir = getenv("TMPDIR"); + if (asprintf(&tfile, "%s/last.XXXXXX", dir ? dir : _PATH_TMP) == -1) + err(EXIT_FAILURE, "asprintf"); + tempfd = mkstemp(tfile); + if (tempfd < 0) { + err(EXIT_FAILURE, "mkstemp"); + } + unlink(tfile); + for (;;) { + tlen = read(wfd, buf, len); + if (tlen < 0) { + err(1, "%s: read", file); + } + if (tlen == 0) { + break; + } + if (write(tempfd, buf, tlen) != tlen) { + err(1, "%s: write", tfile); + } + } + wfd = tempfd; + } + + if (fstat(wfd, &stb) == -1) + err(EXIT_FAILURE, "%s: fstat", file); + if (!S_ISREG(stb.st_mode)) + errx(EXIT_FAILURE, "%s: Not a regular file", file); + + buf[FIRSTVALID].ut_timefld = time(NULL); + (void)signal(SIGINT, onintr); + (void)signal(SIGQUIT, onintr); + + offset = stb.st_size; + /* Ignore trailing garbage or partial record */ + offset -= offset % (off_t) sizeof(*buf); + + while (offset >= (off_t) sizeof(*buf)) { + ssize_t ret, i; + size_t size; + + size = MIN((off_t)len, offset); + offset -= size; /* Always a multiple of sizeof(*buf) */ + ret = pread(wfd, buf, size, offset); + if (ret < 0) { + err(EXIT_FAILURE, "%s: pread", file); + } else if ((size_t) ret < size) { + err(EXIT_FAILURE, "%s: Unexpected end of file", file); + } + + for (i = ret / sizeof(*buf) - 1; i >= 0; i--) { + bp = &buf[i]; + + NULTERM(name); + NULTERM(line); + NULTERM(host); + /* + * if the terminal line is '~', the machine stopped. + * see utmp(5) for more info. + */ + if (linep[0] == '~' && !linep[1]) { + /* everybody just logged out */ + for (T = ttylist; T; T = T->next) + T->logout = -bp->ut_timefld; + currentout = -bp->ut_timefld; + crmsg = strncmp(namep, "shutdown", + namesz) ? "crash" : "shutdown"; + if (want(bp, NO)) { + ct = fmttime(bp->ut_timefld, fulltime); + printf("%-*.*s %-*.*s %-*.*s %s\n", + namesz, namesz, namep, + linesz, linesz, linep, + hostsz, hostsz, + gethost(bp, hostp, numeric), ct); + if (maxrec != -1 && !--maxrec) + return; + } + continue; + } + /* + * if the line is '{' or '|', date got set; see + * utmp(5) for more info. + */ + if ((linep[0] == '{' || linep[0] == '|') && !linep[1]) { + if (want(bp, NO)) { + ct = fmttime(bp->ut_timefld, fulltime); + printf("%-*.*s %-*.*s %-*.*s %s\n", + namesz, namesz, namep, + linesz, linesz, linep, + hostsz, hostsz, + gethost(bp, hostp, numeric), + ct); + if (maxrec && !--maxrec) + return; + } + continue; + } + /* find associated tty */ + for (T = ttylist;; T = T->next) { + if (!T) { + /* add new one */ + T = addtty(linep); + break; + } + if (!strncmp(T->tty, linep, LINESIZE)) + break; + } + if (TYPE(bp) == SIGNATURE) + continue; + if (namep[0] && want(bp, YES)) { + ct = fmttime(bp->ut_timefld, fulltime); + printf("%-*.*s %-*.*s %-*.*s %s ", + namesz, namesz, namep, + linesz, linesz, linep, + hostsz, hostsz, + gethost(bp, hostp, numeric), + ct); + if (!T->logout) + puts(" still logged in"); + else { + time_t delta; /* time difference */ + + if (T->logout < 0) { + T->logout = -T->logout; + printf("- %s", crmsg); + } + else + printf("- %s", + fmttime(T->logout, + fulltime | TIMEONLY)); + delta = T->logout - bp->ut_timefld; + if (delta < SECSPERDAY) + printf(" (%s)\n", + fmttime(delta, + fulltime | TIMEONLY | GMT)); + else + printf(" (%lld+%s)\n", + (long long) + delta / SECSPERDAY, + fmttime(delta, + fulltime | TIMEONLY | GMT)); + } + if (maxrec != -1 && !--maxrec) + return; + } + T->logout = bp->ut_timefld; + } + } + fulltime = 1; /* show full time */ + crmsg = fmttime(buf[FIRSTVALID].ut_timefld, FULLTIME); + if ((ct = strrchr(file, '/')) != NULL) + ct++; + printf("\n%s begins %s\n", ct ? ct : file, crmsg); +} + +/* + * want -- + * see if want this entry + */ +static int +want(struct utmp *bp, int check) +{ + ARG *step; + + if (check) { + /* + * when uucp and ftp log in over a network, the entry in + * the utmp file is the name plus their process id. See + * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information. + */ + if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1)) + bp->ut_line[3] = '\0'; + else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1)) + bp->ut_line[4] = '\0'; + } + if (!arglist) + return (YES); + + for (step = arglist; step; step = step->next) + switch(step->type) { + case HOST_TYPE: + if (!strncasecmp(step->name, bp->ut_host, HOSTSIZE)) + return (YES); + break; + case TTY_TYPE: + if (!strncmp(step->name, bp->ut_line, LINESIZE)) + return (YES); + break; + case USER_TYPE: + if (!strncmp(step->name, bp->ut_name, NAMESIZE)) + return (YES); + break; + } + return (NO); +} + +/* + * onintr -- + * on interrupt, we inform the user how far we've gotten + */ +static void +onintr(int signo) +{ + /* FIXME: None of this is allowed in a signal handler */ + printf("\ninterrupted %s\n", fmttime(buf[FIRSTVALID].ut_timefld, + FULLTIME)); + if (signo == SIGINT) { + (void)raise_default_signal(signo); + exit(EXIT_FAILURE); + } + (void)fflush(stdout); /* fix required for rsh */ +} -- 2.41.0