Print this page
2989 Eliminate use of LOGNAME_MAX in ON
1166 useradd have warning with name more 8 chars
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/last/last.c
+++ new/usr/src/cmd/last/last.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 + * Copyright (c) 2013 Gary Mills
24 + *
23 25 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 26 * Use is subject to license terms.
25 27 */
26 28
27 29 /*
28 30 * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
29 31 * All Rights Reserved
30 32 */
31 33
32 34 /*
33 35 * University Copyright- Copyright (c) 1982, 1986, 1988
34 36 * The Regents of the University of California
35 37 * All Rights Reserved
36 38 *
37 39 * University Acknowledgment- Portions of this document are derived from
38 40 * software developed by the University of California, Berkeley, and its
39 41 * contributors.
40 42 */
41 43
42 -#pragma ident "%Z%%M% %I% %E% SMI"
43 -
44 44 /*
45 45 * last
46 46 */
47 47 #include <sys/types.h>
48 48 #include <stdio.h>
49 49 #include <stdlib.h>
50 50 #include <unistd.h>
51 51 #include <strings.h>
52 52 #include <signal.h>
53 53 #include <sys/stat.h>
54 54 #include <pwd.h>
55 55 #include <fcntl.h>
56 56 #include <utmpx.h>
57 57 #include <locale.h>
58 58 #include <ctype.h>
59 59
60 60 /*
61 - * NMAX, LMAX and HMAX are set to these values for now. They
62 - * should be much higher because of the max allowed limit in
63 - * utmpx.h
61 + * Use the full lengths from utmpx for NMAX, LMAX and HMAX .
64 62 */
65 -#define NMAX 8
66 -#define LMAX 12
63 +#define NMAX (sizeof (((struct utmpx *)0)->ut_user))
64 +#define LMAX (sizeof (((struct utmpx *)0)->ut_line))
67 65 #define HMAX (sizeof (((struct utmpx *)0)->ut_host))
66 +
67 +/* Print minimum field widths. */
68 +#define LOGIN_WIDTH 8
69 +#define LINE_WIDTH 12
70 +
68 71 #define SECDAY (24*60*60)
69 72 #define CHUNK_SIZE 256
70 73
71 74 #define lineq(a, b) (strncmp(a, b, LMAX) == 0)
72 75 #define nameq(a, b) (strncmp(a, b, NMAX) == 0)
73 76 #define hosteq(a, b) (strncmp(a, b, HMAX) == 0)
74 77 #define linehostnameq(a, b, c, d) \
75 78 (lineq(a, b)&&hosteq(a+LMAX+1, c)&&nameq(a+LMAX+HMAX+2, d))
76 79
77 80 #define USAGE "usage: last [-n number] [-f filename] [-a ] [name | tty] ...\n"
78 81
79 82 /* Beware: These are set in main() to exclude the executable name. */
80 83 static char **argv;
81 84 static int argc;
82 85 static char **names;
83 86 static int names_num;
84 87
85 88 static struct utmpx buf[128];
86 89
87 90 /*
88 91 * ttnames and logouts are allocated in the blocks of
89 92 * CHUNK_SIZE lines whenever needed. The count of the
90 93 * current size is maintained in the variable "lines"
91 94 * The variable bootxtime is used to hold the time of
92 95 * the last BOOT_TIME
93 96 * All elements of the logouts are initialised to bootxtime
94 97 * everytime the buffer is reallocated.
95 98 */
96 99
97 100 static char **ttnames;
98 101 static time_t *logouts;
99 102 static time_t bootxtime;
100 103 static int lines;
101 104 static char timef[128];
102 105 static char hostf[HMAX + 1];
103 106
104 107 static char *strspl(char *, char *);
105 108 static void onintr(int);
106 109 static void reallocate_buffer();
107 110 static void memory_alloc(int);
108 111 static int want(struct utmpx *, char **, char **);
109 112 static void record_time(time_t *, int *, int, struct utmpx *);
110 113
111 114 int
112 115 main(int ac, char **av)
113 116 {
114 117 int i, j;
115 118 int aflag = 0;
116 119 int fpos; /* current position in time format buffer */
117 120 int chrcnt; /* # of chars formatted by current sprintf */
118 121 int bl, wtmp;
119 122 char *ct;
120 123 char *ut_host;
121 124 char *ut_user;
122 125 struct utmpx *bp;
123 126 time_t otime;
124 127 struct stat stb;
125 128 int print = 0;
126 129 char *crmsg = (char *)0;
127 130 long outrec = 0;
128 131 long maxrec = 0x7fffffffL;
129 132 char *wtmpfile = "/var/adm/wtmpx";
130 133 size_t hostf_len;
131 134
132 135 (void) setlocale(LC_ALL, "");
133 136 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
134 137 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't. */
135 138 #endif
136 139 (void) textdomain(TEXT_DOMAIN);
137 140
138 141 (void) time(&buf[0].ut_xtime);
139 142 ac--, av++;
140 143 argc = ac;
141 144 argv = av;
142 145 names = malloc(argc * sizeof (char *));
143 146 if (names == NULL) {
144 147 perror("last");
145 148 exit(2);
146 149 }
147 150 names_num = 0;
148 151 for (i = 0; i < argc; i++) {
149 152 if (argv[i][0] == '-') {
150 153
151 154 /* -[0-9]* sets max # records to print */
152 155 if (isdigit(argv[i][1])) {
153 156 maxrec = atoi(argv[i]+1);
154 157 continue;
155 158 }
156 159
157 160 for (j = 1; argv[i][j] != '\0'; ++j) {
158 161 switch (argv[i][j]) {
159 162
160 163 /* -f name sets filename of wtmp file */
161 164 case 'f':
162 165 if (argv[i][j+1] != '\0') {
163 166 wtmpfile = &argv[i][j+1];
164 167 } else if (i+1 < argc) {
165 168 wtmpfile = argv[++i];
166 169 } else {
167 170 (void) fprintf(stderr,
168 171 gettext("last: argument to "
169 172 "-f is missing\n"));
170 173 (void) fprintf(stderr,
171 174 gettext(USAGE));
172 175 exit(1);
173 176 }
174 177 goto next_word;
175 178
176 179 /* -n number sets max # records to print */
177 180 case 'n': {
178 181 char *arg;
179 182
180 183 if (argv[i][j+1] != '\0') {
181 184 arg = &argv[i][j+1];
182 185 } else if (i+1 < argc) {
183 186 arg = argv[++i];
184 187 } else {
185 188 (void) fprintf(stderr,
186 189 gettext("last: argument to "
187 190 "-n is missing\n"));
188 191 (void) fprintf(stderr,
189 192 gettext(USAGE));
190 193 exit(1);
191 194 }
192 195
193 196 if (!isdigit(*arg)) {
194 197 (void) fprintf(stderr,
195 198 gettext("last: argument to "
196 199 "-n is not a number\n"));
197 200 (void) fprintf(stderr,
198 201 gettext(USAGE));
199 202 exit(1);
200 203 }
201 204 maxrec = atoi(arg);
202 205 goto next_word;
203 206 }
204 207
205 208 /* -a displays hostname last on the line */
206 209 case 'a':
207 210 aflag++;
208 211 break;
209 212
210 213 default:
211 214 (void) fprintf(stderr, gettext(USAGE));
212 215 exit(1);
213 216 }
214 217 }
215 218
216 219 next_word:
217 220 continue;
218 221 }
219 222
220 223 if (strlen(argv[i]) > 2 || strcmp(argv[i], "~") == 0 ||
221 224 getpwnam(argv[i]) != NULL) {
222 225 /* Not a tty number. */
223 226 names[names_num] = argv[i];
224 227 ++names_num;
225 228 } else {
226 229 /* tty number. Prepend "tty". */
227 230 names[names_num] = strspl("tty", argv[i]);
228 231 ++names_num;
229 232 }
230 233 }
231 234
232 235 wtmp = open(wtmpfile, 0);
233 236 if (wtmp < 0) {
234 237 perror(wtmpfile);
235 238 exit(1);
236 239 }
237 240 (void) fstat(wtmp, &stb);
238 241 bl = (stb.st_size + sizeof (buf)-1) / sizeof (buf);
239 242 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
240 243 (void) signal(SIGINT, onintr);
241 244 (void) signal(SIGQUIT, onintr);
242 245 }
243 246 lines = CHUNK_SIZE;
244 247 ttnames = calloc(lines, sizeof (char *));
245 248 logouts = calloc(lines, sizeof (time_t));
246 249 if (ttnames == NULL || logouts == NULL) {
↓ open down ↓ |
169 lines elided |
↑ open up ↑ |
247 250 (void) fprintf(stderr, gettext("Out of memory \n "));
248 251 exit(2);
249 252 }
250 253 for (bl--; bl >= 0; bl--) {
251 254 (void) lseek(wtmp, (off_t)(bl * sizeof (buf)), 0);
252 255 bp = &buf[read(wtmp, buf, sizeof (buf)) / sizeof (buf[0]) - 1];
253 256 for (; bp >= buf; bp--) {
254 257 if (want(bp, &ut_host, &ut_user)) {
255 258 for (i = 0; i <= lines; i++) {
256 259 if (i == lines)
257 - reallocate_buffer();
260 + reallocate_buffer();
258 261 if (ttnames[i] == NULL) {
259 - memory_alloc(i);
262 + memory_alloc(i);
260 263 /*
261 264 * LMAX+HMAX+NMAX+3 bytes have been
262 265 * allocated for ttnames[i].
263 266 * If bp->ut_line is longer than LMAX,
264 267 * ut_host is longer than HMAX,
265 268 * and ut_user is longer than NMAX,
266 269 * truncate it to fit ttnames[i].
267 270 */
268 271 (void) strlcpy(ttnames[i], bp->ut_line,
269 - LMAX+1);
272 + LMAX+1);
270 273 (void) strlcpy(ttnames[i]+LMAX+1,
271 - ut_host, HMAX+1);
274 + ut_host, HMAX+1);
272 275 (void) strlcpy(ttnames[i]+LMAX+HMAX+2,
273 - ut_user, NMAX+1);
276 + ut_user, NMAX+1);
274 277 record_time(&otime, &print,
275 - i, bp);
278 + i, bp);
276 279 break;
277 280 } else if (linehostnameq(ttnames[i],
278 281 bp->ut_line, ut_host, ut_user)) {
279 282 record_time(&otime,
280 283 &print, i, bp);
281 284 break;
282 285 }
283 286 }
284 287 }
285 288 if (print) {
286 289 if (strncmp(bp->ut_line, "ftp", 3) == 0)
287 290 bp->ut_line[3] = '\0';
288 291 if (strncmp(bp->ut_line, "uucp", 4) == 0)
289 292 bp->ut_line[4] = '\0';
290 293
291 294 ct = ctime(&bp->ut_xtime);
292 295 (void) printf(gettext("%-*.*s %-*.*s "),
293 - NMAX, NMAX, bp->ut_name,
294 - LMAX, LMAX, bp->ut_line);
296 + LOGIN_WIDTH, NMAX, bp->ut_name,
297 + LINE_WIDTH, LMAX, bp->ut_line);
295 298 hostf_len = strlen(bp->ut_host);
296 299 (void) snprintf(hostf, sizeof (hostf),
297 300 "%-*.*s", hostf_len, hostf_len,
298 301 bp->ut_host);
299 302 fpos = snprintf(timef, sizeof (timef),
300 - "%10.10s %5.5s ",
303 + "%10.10s %5.5s ",
301 304 ct, 11 + ct);
302 305 if (!lineq(bp->ut_line, "system boot") &&
303 306 !lineq(bp->ut_line, "system down")) {
304 307 if (otime == 0 &&
305 308 bp->ut_type == USER_PROCESS) {
306 309
307 310 if (fpos < sizeof (timef)) {
308 311 /* timef still has room */
309 312 (void) snprintf(timef + fpos, sizeof (timef) - fpos,
310 - gettext(" still logged in"));
313 + gettext(" still logged in"));
311 314 }
312 315
313 316 } else {
314 317 time_t delta;
315 318 if (otime < 0) {
316 319 otime = -otime;
317 320 /*
318 321 * TRANSLATION_NOTE
319 322 * See other notes on "down"
320 323 * and "- %5.5s".
321 324 * "-" means "until". This
322 325 * is displayed after the
323 326 * starting time as in:
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
324 327 * 16:20 - down
325 328 * You probably don't want to
326 329 * translate this. Should you
327 330 * decide to translate this,
328 331 * translate "- %5.5s" too.
329 332 */
330 333
331 334 if (fpos < sizeof (timef)) {
332 335 /* timef still has room */
333 336 chrcnt = snprintf(timef + fpos, sizeof (timef) - fpos,
334 - gettext("- %s"), crmsg);
337 + gettext("- %s"), crmsg);
335 338 fpos += chrcnt;
336 339 }
337 340
338 341 } else {
339 342
340 343 if (fpos < sizeof (timef)) {
341 344 /* timef still has room */
342 345 chrcnt = snprintf(timef + fpos, sizeof (timef) - fpos,
343 - gettext("- %5.5s"), ctime(&otime) + 11);
346 + gettext("- %5.5s"), ctime(&otime) + 11);
344 347 fpos += chrcnt;
345 348 }
346 349
347 350 }
348 351 delta = otime - bp->ut_xtime;
349 352 if (delta < SECDAY) {
350 353
351 354 if (fpos < sizeof (timef)) {
352 355 /* timef still has room */
353 356 (void) snprintf(timef + fpos, sizeof (timef) - fpos,
354 - gettext(" (%5.5s)"), asctime(gmtime(&delta)) + 11);
357 + gettext(" (%5.5s)"), asctime(gmtime(&delta)) + 11);
355 358 }
356 359
357 360 } else {
358 361
359 362 if (fpos < sizeof (timef)) {
360 363 /* timef still has room */
361 364 (void) snprintf(timef + fpos, sizeof (timef) - fpos,
362 - gettext(" (%ld+%5.5s)"), delta / SECDAY,
365 + gettext(" (%ld+%5.5s)"), delta / SECDAY,
363 366 asctime(gmtime(&delta)) + 11);
364 367 }
365 368
366 369 }
367 370 }
368 371 }
369 372 if (aflag)
370 373 (void) printf("%-35.35s %-.*s\n",
371 374 timef, strlen(hostf), hostf);
372 375 else
373 376 (void) printf("%-16.16s %-.35s\n",
374 377 hostf, timef);
375 378 (void) fflush(stdout);
376 379 if (++outrec >= maxrec)
377 380 exit(0);
378 381 }
379 382 /*
380 383 * when the system is down or crashed.
381 384 */
382 385 if (bp->ut_type == BOOT_TIME) {
383 386 for (i = 0; i < lines; i++)
384 387 logouts[i] = -bp->ut_xtime;
385 388 bootxtime = -bp->ut_xtime;
386 389 /*
387 390 * TRANSLATION_NOTE
388 391 * Translation of this "down " will replace
389 392 * the %s in "- %s". "down" is used instead
390 393 * of the real time session was ended, probably
391 394 * because the session ended by a sudden crash.
392 395 */
393 396 crmsg = gettext("down ");
394 397 }
395 398 print = 0; /* reset the print flag */
396 399 }
397 400 }
398 401 ct = ctime(&buf[0].ut_xtime);
399 402 (void) printf(gettext("\nwtmp begins %10.10s %5.5s \n"), ct, ct + 11);
400 403
401 404 /* free() called to prevent lint warning about names */
402 405 free(names);
403 406
404 407 return (0);
405 408 }
406 409
407 410 static void
408 411 reallocate_buffer()
409 412 {
410 413 int j;
↓ open down ↓ |
38 lines elided |
↑ open up ↑ |
411 414 static char **tmpttnames;
412 415 static time_t *tmplogouts;
413 416
414 417 lines += CHUNK_SIZE;
415 418 tmpttnames = realloc(ttnames, sizeof (char *)*lines);
416 419 tmplogouts = realloc(logouts, sizeof (time_t)*lines);
417 420 if (tmpttnames == NULL || tmplogouts == NULL) {
418 421 (void) fprintf(stderr, gettext("Out of memory \n"));
419 422 exit(2);
420 423 } else {
421 - ttnames = tmpttnames;
422 - logouts = tmplogouts;
424 + ttnames = tmpttnames;
425 + logouts = tmplogouts;
423 426 }
424 427 for (j = lines-CHUNK_SIZE; j < lines; j++) {
425 428 ttnames[j] = NULL;
426 429 logouts[j] = bootxtime;
427 430 }
428 431 }
429 432
430 433 static void
431 434 memory_alloc(int i)
432 435 {
433 436 ttnames[i] = (char *)malloc(LMAX + HMAX + NMAX + 3);
434 437 if (ttnames[i] == NULL) {
435 438 (void) fprintf(stderr, gettext("Out of memory \n "));
436 439 exit(2);
437 440 }
438 441 }
439 442
440 443 static void
441 444 onintr(int signo)
442 445 {
443 446 char *ct;
444 447
445 448 if (signo == SIGQUIT)
446 449 (void) signal(SIGQUIT, (void(*)())onintr);
447 450 ct = ctime(&buf[0].ut_xtime);
448 451 (void) printf(gettext("\ninterrupted %10.10s %5.5s \n"), ct, ct + 11);
449 452 (void) fflush(stdout);
450 453 if (signo == SIGINT)
451 454 exit(1);
452 455 }
453 456
454 457 static int
455 458 want(struct utmpx *bp, char **host, char **user)
456 459 {
457 460 char **name;
458 461 int i;
459 462 char *zerostr = "\0";
460 463
461 464 *host = zerostr; *user = zerostr;
462 465
463 466 /* if ut_line = dtremote for the users who did dtremote login */
464 467 if (strncmp(bp->ut_line, "dtremote", 8) == 0) {
465 468 *host = bp->ut_host;
466 469 *user = bp->ut_user;
467 470 }
468 471 /* if ut_line = dtlocal for the users who did a dtlocal login */
469 472 else if (strncmp(bp->ut_line, "dtlocal", 7) == 0) {
470 473 *host = bp->ut_host;
471 474 *user = bp->ut_user;
472 475 }
473 476 /*
474 477 * Both dtremote and dtlocal can have multiple entries in
475 478 * /var/adm/wtmpx with these values, so the user and host
476 479 * entries are also checked
477 480 */
478 481 if ((bp->ut_type == BOOT_TIME) || (bp->ut_type == DOWN_TIME))
479 482 (void) strcpy(bp->ut_user, "reboot");
480 483
481 484 if (bp->ut_type != USER_PROCESS && bp->ut_type != DEAD_PROCESS &&
482 485 bp->ut_type != BOOT_TIME && bp->ut_type != DOWN_TIME)
483 486 return (0);
484 487
485 488 if (bp->ut_user[0] == '.')
486 489 return (0);
487 490
488 491 if (names_num == 0) {
489 492 if (bp->ut_line[0] != '\0')
490 493 return (1);
491 494 } else {
492 495 name = names;
493 496 for (i = 0; i < names_num; i++, name++) {
494 497 if (nameq(*name, bp->ut_name) ||
495 498 lineq(*name, bp->ut_line) ||
496 499 (lineq(*name, "ftp") &&
497 500 (strncmp(bp->ut_line, "ftp", 3) == 0))) {
498 501 return (1);
499 502 }
500 503 }
501 504 }
502 505 return (0);
503 506 }
504 507
505 508 static char *
506 509 strspl(char *left, char *right)
507 510 {
508 511 size_t ressize = strlen(left) + strlen(right) + 1;
509 512
510 513 char *res = malloc(ressize);
511 514
512 515 if (res == NULL) {
513 516 perror("last");
514 517 exit(2);
515 518 }
516 519 (void) strlcpy(res, left, ressize);
517 520 (void) strlcat(res, right, ressize);
518 521 return (res);
519 522 }
520 523
521 524 static void
522 525 record_time(time_t *otime, int *print, int i, struct utmpx *bp)
523 526 {
524 527 *otime = logouts[i];
525 528 logouts[i] = bp->ut_xtime;
526 529 if ((bp->ut_type == USER_PROCESS && bp->ut_user[0] != '\0') ||
527 530 (bp->ut_type == BOOT_TIME) || (bp->ut_type == DOWN_TIME))
528 531 *print = 1;
529 532 else
530 533 *print = 0;
531 534 }
↓ open down ↓ |
99 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX