Fix build of last(1).
authorSascha Wildner <saw@online.de>
Thu, 16 Dec 2010 16:42:53 +0000 (17:42 +0100)
committerSascha Wildner <saw@online.de>
Thu, 16 Dec 2010 16:43:24 +0000 (17:43 +0100)
usr.bin/last/want.c [new file with mode: 0644]

diff --git a/usr.bin/last/want.c b/usr.bin/last/want.c
new file mode 100644 (file)
index 0000000..8a23949
--- /dev/null
@@ -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 = "<stdin>";
+       } 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 */
+}