Merge branch 'vendor/AWK'
[dragonfly.git] / usr.bin / last / last.c
1 /*      $NetBSD: last.c,v 1.15 2000/06/30 06:19:58 simonb Exp $ */
2
3 /*
4  * Copyright (c) 1987, 1993, 1994
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by the University of
18  *      California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)last.c      8.2 (Berkeley) 4/2/94";
40 #endif
41 __RCSID("$NetBSD: last.c,v 1.15 2000/06/30 06:19:58 simonb Exp $");
42 #endif /* not lint */
43
44 #include <sys/param.h>
45 #include <sys/stat.h>
46
47 #include <err.h>
48 #include <fcntl.h>
49 #include <paths.h>
50 #include <signal.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <time.h>
55 #include <tzfile.h>
56 #include <unistd.h>
57 #ifdef SUPPORT_UTMPX
58 #include <utmpx.h>
59 #endif
60 #ifdef SUPPORT_UTMP
61 #include <utmp.h>
62 #endif
63
64 #ifndef UT_NAMESIZE
65 #define UT_NAMESIZE 8
66 #define UT_LINESIZE 8
67 #define UT_HOSTSIZE 16
68 #endif
69 #ifndef SIGNATURE
70 #define SIGNATURE -1
71 #endif
72
73
74
75 #define NO      0                       /* false/no */
76 #define YES     1                       /* true/yes */
77
78 #define TBUFLEN 30                      /* length of time string buffer */
79 #define TFMT    "%a %b %d %R"           /* strftime format string */
80 #define LTFMT   "%a %b %d %Y %T"        /* strftime long format string */
81 #define TFMTS   "%R"                    /* strftime format string - time only */
82 #define LTFMTS  "%T"                    /* strftime long format string - " */
83
84 /* fmttime() flags */
85 #define FULLTIME        0x1             /* show year, seconds */
86 #define TIMEONLY        0x2             /* show time only, not date */
87 #define GMT             0x4             /* show time at GMT, for offsets only */
88
89 #define MAXUTMP         1024;
90
91 typedef struct arg {
92         char    *name;                  /* argument */
93 #define HOST_TYPE       -2
94 #define TTY_TYPE        -3
95 #define USER_TYPE       -4
96         int     type;                   /* type of arg */
97         struct arg      *next;          /* linked list pointer */
98 } ARG;
99 static ARG      *arglist;               /* head of linked list */
100
101 typedef struct ttytab {
102         time_t  logout;                 /* log out time */
103         char    tty[128];               /* terminal name */
104         struct ttytab   *next;          /* linked list pointer */
105 } TTY;
106 static TTY      *ttylist;               /* head of linked list */
107
108 static time_t   currentout;             /* current logout value */
109 static long     maxrec;                 /* records to display */
110 static int      fulltime = 0;           /* Display seconds? */
111
112 int      main(int, char *[]);
113
114 static void      addarg(int, char *);
115 static TTY      *addtty(const char *);
116 static void      hostconv(char *);
117 static char     *ttyconv(char *);
118 #ifdef SUPPORT_UTMPX
119 static void      wtmpx(const char *, int, int, int);
120 #endif
121 #ifdef SUPPORT_UTMP
122 static void      wtmp(const char *, int, int, int);
123 #endif
124 static char     *fmttime(time_t, int);
125 static void      usage(void);
126
127 static
128 void usage(void)
129 {
130         (void)fprintf(stderr, "Usage: %s [-#%s] [-f file] [-t tty]"
131             " [-h hostname] [-T] [user ...]\n", getprogname(),
132 #ifdef SUPPORT_UTMPX
133             "w"
134 #else
135             ""
136 #endif
137         );
138         exit(1);
139 }
140
141 int
142 main(int argc, char *argv[])
143 {
144         int ch;
145         char *p;
146         const char *file = NULL;
147         int namesize = UT_NAMESIZE;
148         int linesize = UT_LINESIZE;
149         int hostsize = UT_HOSTSIZE;
150
151         maxrec = -1;
152
153         while ((ch = getopt(argc, argv, "0123456789f:h:H:L:N:t:T")) != -1)
154                 switch (ch) {
155                 case '0': case '1': case '2': case '3': case '4':
156                 case '5': case '6': case '7': case '8': case '9':
157                         /*
158                          * kludge: last was originally designed to take
159                          * a number after a dash.
160                          */
161                         if (maxrec == -1) {
162                                 p = argv[optind - 1];
163                                 if (p[0] == '-' && p[1] == ch && !p[2])
164                                         maxrec = atol(++p);
165                                 else
166                                         maxrec = atol(argv[optind] + 1);
167                                 if (!maxrec)
168                                         exit(0);
169                         }
170                         break;
171                 case 'f':
172                         file = optarg;
173                         break;
174                 case 'h':
175                         hostconv(optarg);
176                         addarg(HOST_TYPE, optarg);
177                         break;
178                 case 't':
179                         addarg(TTY_TYPE, ttyconv(optarg));
180                         break;
181                 case 'U':
182                         namesize = atoi(optarg);
183                         break;
184                 case 'L':
185                         linesize = atoi(optarg);
186                         break;
187                 case 'H':
188                         hostsize = atoi(optarg);
189                         break;
190                 case 'T':
191                         fulltime = 1;
192                         break;
193                 case '?':
194                 default:
195                         usage();
196                 }
197
198         if (argc) {
199                 setlinebuf(stdout);
200                 for (argv += optind; *argv; ++argv) {
201 #define COMPATIBILITY
202 #ifdef  COMPATIBILITY
203                         /* code to allow "last p5" to work */
204                         addarg(TTY_TYPE, ttyconv(*argv));
205 #endif
206                         addarg(USER_TYPE, *argv);
207                 }
208         }
209         if (file == NULL) {
210                 /* XXX: for now, default to utmp */
211 #ifdef SUPPORT_UTMP
212                 if (access(_PATH_WTMP, R_OK) == 0)
213                         file = _PATH_WTMP;
214                 else
215 #endif
216 #ifdef SUPPORT_UTMPX
217                 if (access(_PATH_WTMPX, R_OK) == 0)
218                         file = _PATH_WTMPX;
219 #endif
220                 if (file == NULL)
221 #if defined(SUPPORT_UTMPX) && defined(SUPPORT_UTMP)
222                         errx(1, "Cannot access `%s' or `%s'", _PATH_WTMPX,
223                             _PATH_WTMP);
224 #elif defined(SUPPORT_UTMPX)
225                         errx(1, "Cannot access `%s'", _PATH_WTMPX);
226 #elif defined(SUPPORT_UTMP)
227                         errx(1, "Cannot access `%s'", _PATH_WTMP);
228 #else
229                         errx(1, "No utmp or utmpx support compiled in.");
230 #endif
231         }
232 #if defined(SUPPORT_UTMPX) && defined(SUPPORT_UTMP)
233         if (file[strlen(file) - 1] == 'x')
234                 wtmpx(file, namesize, linesize, hostsize);
235         else
236                 wtmp(file, namesize, linesize, hostsize);
237 #elif defined(SUPPORT_UTMPX)
238         wtmpx(file, namesize, linesize, hostsize);
239 #elif defined(SUPPORT_UTMP)
240         wtmp(file, namesize, linesize, hostsize);
241 #else
242         errx(1, "Nu utmp or utmpx support compiled in.");
243 #endif
244         exit(0);
245 }
246
247
248 /*
249  * addarg --
250  *      add an entry to a linked list of arguments
251  */
252 static void
253 addarg(int type, char *arg)
254 {
255         ARG *cur;
256
257         if (!(cur = (ARG *)malloc((u_int)sizeof(ARG))))
258                 err(1, "malloc failure");
259         cur->next = arglist;
260         cur->type = type;
261         cur->name = arg;
262         arglist = cur;
263 }
264
265 /*
266  * addtty --
267  *      add an entry to a linked list of ttys
268  */
269 static TTY *
270 addtty(const char *tty)
271 {
272         TTY *cur;
273
274         if (!(cur = (TTY *)malloc((u_int)sizeof(TTY))))
275                 err(1, "malloc failure");
276         cur->next = ttylist;
277         cur->logout = currentout;
278         memmove(cur->tty, tty, sizeof(cur->tty));
279         return (ttylist = cur);
280 }
281
282 /*
283  * hostconv --
284  *      convert the hostname to search pattern; if the supplied host name
285  *      has a domain attached that is the same as the current domain, rip
286  *      off the domain suffix since that's what login(1) does.
287  */
288 static void
289 hostconv(char *arg)
290 {
291         static int first = 1;
292         static char *hostdot, name[MAXHOSTNAMELEN + 1];
293         char *argdot;
294
295         if (!(argdot = strchr(arg, '.')))
296                 return;
297         if (first) {
298                 first = 0;
299                 if (gethostname(name, sizeof(name)))
300                         err(1, "gethostname");
301                 name[sizeof(name) - 1] = '\0';
302                 hostdot = strchr(name, '.');
303         }
304         if (hostdot && !strcasecmp(hostdot, argdot))
305                 *argdot = '\0';
306 }
307
308 /*
309  * ttyconv --
310  *      convert tty to correct name.
311  */
312 static char *
313 ttyconv(char *arg)
314 {
315         char *mval;
316
317         /*
318          * kludge -- we assume that all tty's end with
319          * a two character suffix.
320          */
321         if (strlen(arg) == 2) {
322                 /* either 6 for "ttyxx" or 8 for "console" */
323                 if (!(mval = malloc((u_int)8)))
324                         err(1, "malloc failure");
325                 if (!strcmp(arg, "co"))
326                         (void)strcpy(mval, "console");
327                 else {
328                         (void)strcpy(mval, "tty");
329                         (void)strcpy(mval + 3, arg);
330                 }
331                 return (mval);
332         }
333         if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
334                 return (arg + 5);
335         return (arg);
336 }
337
338 /*
339  * fmttime --
340  *      return pointer to (static) formatted time string.
341  */
342 static char *
343 fmttime(time_t t, int flags)
344 {
345         struct tm *tm;
346         static char tbuf[TBUFLEN];
347
348         tm = (flags & GMT) ? gmtime(&t) : localtime(&t);
349         strftime(tbuf, sizeof(tbuf),
350             (flags & TIMEONLY)
351              ? (flags & FULLTIME ? LTFMTS : TFMTS)
352              : (flags & FULLTIME ? LTFMT : TFMT),
353             tm);
354         return (tbuf);
355 }
356
357 #ifdef SUPPORT_UTMP
358 #define TYPE(a) 0
359 #define NAMESIZE UT_NAMESIZE
360 #define LINESIZE UT_LINESIZE
361 #define HOSTSIZE UT_HOSTSIZE
362 #define ut_timefld ut_time
363 #define FIRSTVALID 0
364 #include "want.c"
365 #undef TYPE
366 #undef NAMESIZE
367 #undef LINESIZE
368 #undef HOSTSIZE
369 #undef ut_timefld
370 #undef FIRSTVALID
371 #endif
372
373 #ifdef SUPPORT_UTMPX
374 #define utmp utmpx
375 #define want wantx
376 #define wtmp wtmpx
377 #define buf bufx
378 #define onintr onintrx
379 #define TYPE(a) (a)->ut_type
380 #define NAMESIZE UTX_USERSIZE
381 #define LINESIZE UTX_LINESIZE
382 #define HOSTSIZE UTX_HOSTSIZE
383 #define ut_timefld ut_xtime
384 #define FIRSTVALID 1
385 #include "want.c"
386 #endif