want.c revision 1.3 1 /* $NetBSD: want.c,v 1.3 2004/11/11 00:54:23 christos 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. 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.
18 *
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.
30 */
31 static struct utmp *buf;
32
33 static void onintr(int);
34 static int want(struct utmp *, int);
35 static const char *gethost(struct utmp *, int);
36
37 static const char *
38 gethost(struct utmp* ut, int numeric)
39 {
40 #if FIRSTVALID == 0
41 return numeric ? "" : ut->ut_host;
42 #else
43 if (numeric) {
44 static char buf[512];
45 const char *p;
46 struct sockaddr_storage *ss = &ut->ut_ss;
47 void *a;
48 switch (ss->ss_family) {
49 default:
50 (void)snprintf(buf, sizeof(buf), "%d: unknown family",
51 ss->ss_family);
52 return buf;
53 case 0: /* reboot etc. entries */
54 return "";
55 case AF_INET:
56 a = &((struct sockaddr_in *)(void *)ss)->sin_addr;
57 break;
58 case AF_INET6:
59 a = &((struct sockaddr_in6 *)(void *)ss)->sin6_addr;
60 break;
61 }
62 if ((p = inet_ntop(ss->ss_family, a, buf, ss->ss_len)) != NULL)
63 return p;
64 (void)snprintf(buf, sizeof(buf), "%s", strerror(errno));
65 return buf;
66 } else
67 return ut->ut_host;
68 #endif
69 }
70
71 /*
72 * wtmp --
73 * read through the wtmp file
74 */
75 void
76 wtmp(const char *file, int namesz, int linesz, int hostsz, int numeric)
77 {
78 struct utmp *bp; /* current structure */
79 TTY *T; /* tty list entry */
80 struct stat stb; /* stat of file for sz */
81 time_t delta; /* time difference */
82 off_t bl;
83 int bytes, wfd;
84 char *ct, *crmsg;
85 size_t len = sizeof(*buf) * MAXUTMP;
86
87 if ((buf = malloc(len)) == NULL)
88 err(1, "Cannot allocate utmp buffer");
89
90 crmsg = NULL;
91
92 if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1)
93 err(1, "%s", file);
94 bl = (stb.st_size + len - 1) / len;
95
96 buf[FIRSTVALID].ut_timefld = time(NULL);
97 (void)signal(SIGINT, onintr);
98 (void)signal(SIGQUIT, onintr);
99
100 while (--bl >= 0) {
101 if (lseek(wfd, bl * len, SEEK_SET) == -1 ||
102 (bytes = read(wfd, buf, len)) == -1)
103 err(1, "%s", file);
104 for (bp = &buf[bytes / sizeof(*buf) - 1]; bp >= buf; --bp) {
105 /*
106 * if the terminal line is '~', the machine stopped.
107 * see utmp(5) for more info.
108 */
109 if (bp->ut_line[0] == '~' && !bp->ut_line[1]) {
110 /* everybody just logged out */
111 for (T = ttylist; T; T = T->next)
112 T->logout = -bp->ut_timefld;
113 currentout = -bp->ut_timefld;
114 crmsg = strncmp(bp->ut_name, "shutdown",
115 namesz) ? "crash" : "shutdown";
116 if (want(bp, NO)) {
117 ct = fmttime(bp->ut_timefld, fulltime);
118 printf("%-*.*s %-*.*s %-*.*s %s\n",
119 namesz, namesz, bp->ut_name,
120 linesz, linesz, bp->ut_line,
121 hostsz, hostsz,
122 gethost(bp, numeric), ct);
123 if (maxrec != -1 && !--maxrec)
124 return;
125 }
126 continue;
127 }
128 /*
129 * if the line is '{' or '|', date got set; see
130 * utmp(5) for more info.
131 */
132 if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|')
133 && !bp->ut_line[1]) {
134 if (want(bp, NO)) {
135 ct = fmttime(bp->ut_timefld, fulltime);
136 printf("%-*.*s %-*.*s %-*.*s %s\n",
137 namesz, namesz,
138 bp->ut_name,
139 linesz, linesz,
140 bp->ut_line,
141 hostsz, hostsz,
142 gethost(bp, numeric),
143 ct);
144 if (maxrec && !--maxrec)
145 return;
146 }
147 continue;
148 }
149 /* find associated tty */
150 for (T = ttylist;; T = T->next) {
151 if (!T) {
152 /* add new one */
153 T = addtty(bp->ut_line);
154 break;
155 }
156 if (!strncmp(T->tty, bp->ut_line, LINESIZE))
157 break;
158 }
159 if (TYPE(bp) == SIGNATURE)
160 continue;
161 if (bp->ut_name[0] && want(bp, YES)) {
162 ct = fmttime(bp->ut_timefld, fulltime);
163 printf("%-*.*s %-*.*s %-*.*s %s ",
164 namesz, namesz, bp->ut_name,
165 linesz, linesz, bp->ut_line,
166 hostsz, hostsz,
167 gethost(bp, numeric),
168 ct);
169 if (!T->logout)
170 puts(" still logged in");
171 else {
172 if (T->logout < 0) {
173 T->logout = -T->logout;
174 printf("- %s", crmsg);
175 }
176 else
177 printf("- %s",
178 fmttime(T->logout,
179 fulltime | TIMEONLY));
180 delta = T->logout - bp->ut_timefld;
181 if (delta < SECSPERDAY)
182 printf(" (%s)\n",
183 fmttime(delta,
184 fulltime | TIMEONLY | GMT));
185 else
186 printf(" (%ld+%s)\n",
187 delta / SECSPERDAY,
188 fmttime(delta,
189 fulltime | TIMEONLY | GMT));
190 }
191 if (maxrec != -1 && !--maxrec)
192 return;
193 }
194 T->logout = bp->ut_timefld;
195 }
196 }
197 fulltime = 1; /* show full time */
198 crmsg = fmttime(buf[FIRSTVALID].ut_timefld, FULLTIME);
199 if ((ct = strrchr(file, '/')) != NULL)
200 ct++;
201 printf("\n%s begins %s\n", ct ? ct : file, crmsg);
202 }
203
204 /*
205 * want --
206 * see if want this entry
207 */
208 static int
209 want(struct utmp *bp, int check)
210 {
211 ARG *step;
212
213 if (check) {
214 /*
215 * when uucp and ftp log in over a network, the entry in
216 * the utmp file is the name plus their process id. See
217 * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
218 */
219 if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
220 bp->ut_line[3] = '\0';
221 else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
222 bp->ut_line[4] = '\0';
223 }
224 if (!arglist)
225 return (YES);
226
227 for (step = arglist; step; step = step->next)
228 switch(step->type) {
229 case HOST_TYPE:
230 if (!strncasecmp(step->name, bp->ut_host, HOSTSIZE))
231 return (YES);
232 break;
233 case TTY_TYPE:
234 if (!strncmp(step->name, bp->ut_line, LINESIZE))
235 return (YES);
236 break;
237 case USER_TYPE:
238 if (!strncmp(step->name, bp->ut_name, NAMESIZE))
239 return (YES);
240 break;
241 }
242 return (NO);
243 }
244
245 /*
246 * onintr --
247 * on interrupt, we inform the user how far we've gotten
248 */
249 static void
250 onintr(int signo)
251 {
252
253 printf("\ninterrupted %s\n", fmttime(buf[FIRSTVALID].ut_timefld,
254 FULLTIME));
255 if (signo == SIGINT)
256 exit(1);
257 (void)fflush(stdout); /* fix required for rsh */
258 }
259