1 --- last.c 2001-09-26 12:59:46.000000000 +0200
2 +++ ../../sysvinit-2.86.ds1/src/last.c 2004-07-30 14:16:26.000000000 +0200
5 * Author: Miquel van Smoorenburg, miquels@cistron.nl
7 - * Version: @(#)last 2.79 13-Jun-2001 miquels@cistron.nl
8 + * Version: @(#)last 2.85 30-Jul-2004 miquels@cistron.nl
10 * This file is part of the sysvinit suite,
11 - * Copyright 1991-2001 Miquel van Smoorenburg.
12 + * Copyright 1991-2004 Miquel van Smoorenburg.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
17 # define SHUTDOWN_TIME 254
20 -char *Version = "@(#) last 2.79 11-Sep-2000 miquels";
21 +char *Version = "@(#) last 2.85 31-Apr-2004 miquels";
23 #define CHOP_DOMAIN 0 /* Define to chop off local domainname. */
24 #define NEW_UTMP 1 /* Fancy & fast utmp read code. */
26 * Initialize and position.
28 utsize = oldfmt ? sizeof(uto) : sizeof(struct utmp);
29 - fseek(fp, 0L, SEEK_END);
31 + fseeko(fp, 0, SEEK_END);
35 o = ((fpos - 1) / UCHUNKSIZE) * UCHUNKSIZE;
36 - if (fseek(fp, o, SEEK_SET) < 0) {
37 + if (fseeko(fp, o, SEEK_SET) < 0) {
38 fprintf(stderr, "%s: seek failed!\n", progname);
42 + bpos = (int)(fpos - o);
43 if (fread(buf, bpos, 1, fp) != 1) {
44 fprintf(stderr, "%s: read failed!\n", progname);
47 * Copy whatever is left in the buffer.
49 memcpy(tmp + (-bpos), buf, utsize + bpos);
50 - if (fseek(fp, fpos, SEEK_SET) < 0) {
51 + if (fseeko(fp, fpos, SEEK_SET) < 0) {
56 int uread(FILE *fp, struct utmp *u, int *quit)
63 r = oldfmt ? sizeof(struct oldutmp) : sizeof(struct utmp);
64 - fseek(fp, -1L * r, SEEK_END);
65 + fseek(fp, -1 * r, SEEK_END);
70 r = fread(u, sizeof(struct utmp), 1, fp);
72 - if (fseek(fp, -2L * sizeof(struct utmp), SEEK_CUR) < 0)
73 + if (fseeko(fp, -2 * sizeof(struct utmp), SEEK_CUR) < 0)
78 r = fread(&uto, sizeof(struct oldutmp), 1, fp);
80 - if (fseek(fp, -2L * sizeof(struct oldutmp), SEEK_CUR) < 0)
81 + if (fseeko(fp, -2 * sizeof(struct oldutmp), SEEK_CUR) < 0)
87 * Lookup a host with DNS.
89 -int dns_lookup(char *result, int size, char *org, unsigned int ip)
90 +int dns_lookup(char *result, int size, int useip, int32_t *a)
95 - * Try to catch illegal IP numbers
97 - if (ip == 0 || (int)ip == -1 || (ip >> 24) == 0 || (ip & 255) == 0) {
98 - if (size > UT_HOSTSIZE) size = UT_HOSTSIZE+1;
99 - strncpy(result, org, size - 1);
100 - result[size-1] = 0;
104 - if ((h = gethostbyaddr((char *)&ip, 4, AF_INET)) == NULL) {
105 - strncpy(result, inet_ntoa(*(struct in_addr *)&ip), size);
106 - result[size-1] = 0;
108 + struct sockaddr_in sin;
109 + struct sockaddr_in6 sin6;
110 + struct sockaddr *sa;
112 + unsigned int topnibble;
115 + flags = useip ? NI_NUMERICHOST : 0;
118 + * IPv4 or IPv6 ? We use 2 heuristics:
119 + * 1. Current IPv6 range uses 2000-3fff. Outside of
120 + * that is illegal and must be IPv4.
121 + * 2. If last 3 bytes are 0, must be IPv4
122 + * 3. If IPv6 in IPv4, handle as IPv4
126 + if (a[0] == 0 && a[1] == 0 && a[2] == htonl (0xffff))
128 + topnibble = ntohl((unsigned int)a[0]) >> 28;
129 + if (topnibble < 2 || topnibble > 3 || mapped ||
130 + (a[1] == 0 && a[2] == 0 && a[3] == 0)) {
132 + sin.sin_family = AF_INET;
134 + sin.sin_addr.s_addr = mapped ? a[3] : a[0];
135 + sa = (struct sockaddr *)&sin;
136 + salen = sizeof(sin);
139 + memset(&sin6, 0, sizeof(sin6));
140 + sin6.sin6_family = AF_INET6;
141 + sin6.sin6_port = 0;
142 + memcpy(sin6.sin6_addr.s6_addr, a, 16);
143 + sa = (struct sockaddr *)&sin6;
144 + salen = sizeof(sin6);
146 - strncpy(result, h->h_name, size-1);
147 - result[size-1] = 0;
150 + return getnameinfo(sa, salen, result, size, NULL, 0, flags);
154 @@ -330,22 +349,22 @@
156 int list(struct utmp *p, time_t t, int what)
159 - char logintime[32];
160 - char logouttime[32];
163 - char utline[UT_LINESIZE+1];
166 - int mins, hours, days;
169 + char logintime[32];
170 + char logouttime[32];
173 + char utline[UT_LINESIZE+1];
176 + int mins, hours, days;
180 * uucp and ftp have special-type entries
182 - strncpy(utline, p->ut_line, UT_LINESIZE);
183 - utline[UT_LINESIZE - 1] = 0;
185 + strncat(utline, p->ut_line, UT_LINESIZE);
186 if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3]))
188 if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4]))
189 @@ -412,14 +431,14 @@
191 * Look up host with DNS if needed.
194 - dns_lookup(domain, sizeof(domain), p->ut_host, p->ut_addr);
196 - in.s_addr = p->ut_addr;
197 - strcpy(domain, inet_ntoa(in));
199 - strncpy(domain, p->ut_host, UT_HOSTSIZE);
200 - domain[UT_HOSTSIZE-1] = 0;
202 + if (usedns || useip)
203 + r = dns_lookup(domain, sizeof(domain), useip, p->ut_addr_v6);
206 + if (len >= sizeof(domain)) len = sizeof(domain) - 1;
208 + strncat(domain, p->ut_host, len);
212 @@ -472,10 +491,48 @@
215 fprintf(stderr, "Usage: %s [-num | -n num] [-f file] "
216 + "[-t YYYYMMDDHHMMSS] "
217 "[-R] [-x] [-o] [username..] [tty..]\n", s);
221 +time_t parsetm(char *ts)
223 + struct tm u = {0}, origu;
226 + if (sscanf(ts, "%4d%2d%2d%2d%2d%2d", &u.tm_year,
227 + &u.tm_mon, &u.tm_mday, &u.tm_hour, &u.tm_min,
237 + if ((tm = mktime(&u)) == (time_t)-1)
241 + * Unfortunately mktime() is much more forgiving than
242 + * it should be. For example, it'll gladly accept
243 + * "30" as a valid month number. This behavior is by
244 + * design, but we don't like it, so we want to detect
247 + if (u.tm_year != origu.tm_year ||
248 + u.tm_mon != origu.tm_mon ||
249 + u.tm_mday != origu.tm_mday ||
250 + u.tm_hour != origu.tm_hour ||
251 + u.tm_min != origu.tm_min ||
252 + u.tm_sec != origu.tm_sec)
258 int main(int argc, char **argv)
260 FILE *fp; /* Filepointer of wtmp file */
261 @@ -499,10 +556,12 @@
262 int extended = 0; /* Lots of info. */
263 char *altufile = NULL;/* Alternate wtmp */
265 + time_t until = 0; /* at what time to stop parsing the file */
267 progname = mybasename(argv[0]);
269 /* Process the arguments. */
270 - while((c = getopt(argc, argv, "f:n:Rxadio0123456789")) != EOF)
271 + while((c = getopt(argc, argv, "f:n:Rxadiot:0123456789")) != EOF)
280 + if ((until = parsetm(optarg)) == (time_t)-1) {
281 + fprintf(stderr, "%s: Invalid time value \"%s\"\n",
286 case '0': case '1': case '2': case '3': case '4':
287 case '5': case '6': case '7': case '8': case '9':
288 maxrecs = 10*maxrecs + c - '0';
290 if (uread(fp, &ut, &quit) != 1)
293 + if (until && until < ut.ut_time)
296 if (memcmp(&ut, &oldut, sizeof(struct utmp)) == 0) continue;
297 memcpy(&oldut, &ut, sizeof(struct utmp));
298 lastdate = ut.ut_time;