Fix OPSYS constant in pkg_install tools
[minix3.git] / usr.bin / last / want.c
blobffd389175d841a9d790a3faa68b23cdcf4f29d61
1 /* $NetBSD: want.c,v 1.17 2012/03/15 03:04:05 dholland Exp $ */
3 /*
4 * Copyright (c) 1987, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 static struct utmp *buf;
32 static time_t seentime;
34 static void onintr(int);
35 static int want(struct utmp *, int);
36 static const char *gethost(struct utmp *, const char *, int);
38 static const char *
39 /*ARGSUSED*/
40 gethost(struct utmp *ut, const char *host, int numeric)
42 #if HAS_UT_SS == 0
43 return numeric ? "" : host;
44 #else
45 if (numeric) {
46 static char hbuf[512];
47 hbuf[0] = '\0';
48 (void)sockaddr_snprintf(hbuf, sizeof(hbuf), "%a",
49 (struct sockaddr *)&ut->ut_ss);
50 return hbuf;
51 } else
52 return host;
53 #endif
56 #define NULTERM(what) \
57 if (check ## what) \
58 (void)strlcpy(what ## p = what ## buf, bp->ut_ ## what, \
59 sizeof(what ## buf)); \
60 else \
61 what ## p = bp->ut_ ## what
64 * wtmp --
65 * read through the wtmp file
67 static void
68 wtmp(const char *file, int namesz, int linesz, int hostsz, int numeric)
70 struct utmp *bp; /* current structure */
71 TTY *T; /* tty list entry */
72 struct stat stb; /* stat of file for sz */
73 off_t offset;
74 int wfd;
75 char *ct;
76 const char *crmsg;
77 size_t len = sizeof(*buf) * MAXUTMP;
78 char namebuf[sizeof(bp->ut_name) + 1], *namep;
79 char linebuf[sizeof(bp->ut_line) + 1], *linep;
80 char hostbuf[sizeof(bp->ut_host) + 1], *hostp;
81 int checkname = namesz > (int)sizeof(bp->ut_name);
82 int checkline = linesz > (int)sizeof(bp->ut_line);
83 int checkhost = hostsz > (int)sizeof(bp->ut_host);
85 if ((buf = malloc(len)) == NULL)
86 err(EXIT_FAILURE, "Cannot allocate utmp buffer");
88 crmsg = NULL;
90 if (!strcmp(file, "-")) {
91 wfd = STDIN_FILENO;
92 file = "<stdin>";
93 } else if ((wfd = open(file, O_RDONLY, 0)) < 0) {
94 err(EXIT_FAILURE, "%s", file);
97 if (lseek(wfd, 0, SEEK_CUR) < 0) {
98 const char *dir;
99 char *tfile;
100 int tempfd;
101 ssize_t tlen;
103 if (ESPIPE != errno) {
104 err(EXIT_FAILURE, "lseek");
106 dir = getenv("TMPDIR");
107 if (asprintf(&tfile, "%s/last.XXXXXX", dir ? dir : _PATH_TMP) == -1)
108 err(EXIT_FAILURE, "asprintf");
109 tempfd = mkstemp(tfile);
110 if (tempfd < 0) {
111 err(EXIT_FAILURE, "mkstemp");
113 unlink(tfile);
114 for (;;) {
115 tlen = read(wfd, buf, len);
116 if (tlen < 0) {
117 err(1, "%s: read", file);
119 if (tlen == 0) {
120 break;
122 if (write(tempfd, buf, tlen) != tlen) {
123 err(1, "%s: write", tfile);
126 wfd = tempfd;
129 if (fstat(wfd, &stb) == -1)
130 err(EXIT_FAILURE, "%s: fstat", file);
131 if (!S_ISREG(stb.st_mode))
132 errx(EXIT_FAILURE, "%s: Not a regular file", file);
134 seentime = stb.st_mtime;
135 (void)signal(SIGINT, onintr);
136 (void)signal(SIGQUIT, onintr);
138 offset = stb.st_size;
139 /* Ignore trailing garbage or partial record */
140 offset -= offset % (off_t) sizeof(*buf);
142 while (offset >= (off_t) sizeof(*buf)) {
143 ssize_t ret, i;
144 size_t size;
146 size = MIN((off_t)len, offset);
147 offset -= size; /* Always a multiple of sizeof(*buf) */
148 ret = pread(wfd, buf, size, offset);
149 if (ret < 0) {
150 err(EXIT_FAILURE, "%s: pread", file);
151 } else if ((size_t) ret < size) {
152 err(EXIT_FAILURE, "%s: Unexpected end of file", file);
155 for (i = ret / sizeof(*buf) - 1; i >= 0; i--) {
156 bp = &buf[i];
158 NULTERM(name);
159 NULTERM(line);
160 NULTERM(host);
162 seentime = bp->ut_timefld;
165 * if the terminal line is '~', the machine stopped.
166 * see utmp(5) for more info.
168 if (linep[0] == '~' && !linep[1]) {
169 /* everybody just logged out */
170 for (T = ttylist; T; T = T->next)
171 T->logout = -bp->ut_timefld;
172 currentout = -bp->ut_timefld;
173 crmsg = strncmp(namep, "shutdown",
174 namesz) ? "crash" : "shutdown";
175 if (want(bp, NO)) {
176 ct = fmttime(bp->ut_timefld, fulltime);
177 printf("%-*.*s %-*.*s %-*.*s %s\n",
178 namesz, namesz, namep,
179 linesz, linesz, linep,
180 hostsz, hostsz,
181 gethost(bp, hostp, numeric), ct);
182 if (maxrec != -1 && !--maxrec)
183 return;
185 continue;
188 * if the line is '{' or '|', date got set; see
189 * utmp(5) for more info.
191 if ((linep[0] == '{' || linep[0] == '|') && !linep[1]) {
192 if (want(bp, NO)) {
193 ct = fmttime(bp->ut_timefld, fulltime);
194 printf("%-*.*s %-*.*s %-*.*s %s\n",
195 namesz, namesz, namep,
196 linesz, linesz, linep,
197 hostsz, hostsz,
198 gethost(bp, hostp, numeric),
199 ct);
200 if (maxrec && !--maxrec)
201 return;
203 continue;
205 /* find associated tty */
206 for (T = ttylist;; T = T->next) {
207 if (!T) {
208 /* add new one */
209 T = addtty(linep);
210 break;
212 if (!strncmp(T->tty, linep, LINESIZE))
213 break;
215 if (TYPE(bp) == SIGNATURE)
216 continue;
217 if (namep[0] && want(bp, YES)) {
218 ct = fmttime(bp->ut_timefld, fulltime);
219 printf("%-*.*s %-*.*s %-*.*s %s ",
220 namesz, namesz, namep,
221 linesz, linesz, linep,
222 hostsz, hostsz,
223 gethost(bp, hostp, numeric),
224 ct);
225 if (!T->logout)
226 puts(" still logged in");
227 else {
228 time_t delta; /* time difference */
230 if (T->logout < 0) {
231 T->logout = -T->logout;
232 printf("- %s", crmsg);
234 else
235 printf("- %s",
236 fmttime(T->logout,
237 fulltime | TIMEONLY));
238 delta = T->logout - bp->ut_timefld;
239 if (delta < SECSPERDAY)
240 printf(" (%s)\n",
241 fmttime(delta,
242 fulltime | TIMEONLY | GMT));
243 else
244 printf(" (%lld+%s)\n",
245 (long long)
246 delta / SECSPERDAY,
247 fmttime(delta,
248 fulltime | TIMEONLY | GMT));
250 if (maxrec != -1 && !--maxrec)
251 return;
253 T->logout = bp->ut_timefld;
256 fulltime = 1; /* show full time */
257 crmsg = fmttime(seentime, FULLTIME);
258 if ((ct = strrchr(file, '/')) != NULL)
259 ct++;
260 printf("\n%s begins %s\n", ct ? ct : file, crmsg);
264 * want --
265 * see if want this entry
267 static int
268 want(struct utmp *bp, int check)
270 ARG *step;
272 if (check) {
274 * when uucp and ftp log in over a network, the entry in
275 * the utmp file is the name plus their process id. See
276 * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
278 if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
279 bp->ut_line[3] = '\0';
280 else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
281 bp->ut_line[4] = '\0';
283 if (!arglist)
284 return (YES);
286 for (step = arglist; step; step = step->next)
287 switch(step->type) {
288 case HOST_TYPE:
289 if (!strncasecmp(step->name, bp->ut_host, HOSTSIZE))
290 return (YES);
291 break;
292 case TTY_TYPE:
293 if (!strncmp(step->name, bp->ut_line, LINESIZE))
294 return (YES);
295 break;
296 case USER_TYPE:
297 if (!strncmp(step->name, bp->ut_name, NAMESIZE))
298 return (YES);
299 break;
301 return (NO);
305 * onintr --
306 * on interrupt, we inform the user how far we've gotten
308 static void
309 onintr(int signo)
311 /* FIXME: None of this is allowed in a signal handler */
312 printf("\ninterrupted %s\n", fmttime(seentime, FULLTIME));
313 if (signo == SIGINT) {
314 (void)raise_default_signal(signo);
315 exit(EXIT_FAILURE);
317 (void)fflush(stdout); /* fix required for rsh */