View | Details | Raw Unified | Return to bug 27050
Collapse All | Expand All

(-)last.1 (-5 / +75 lines)
Lines 32-38 Link Here
32
.\"     @(#)last.1	8.1 (Berkeley) 6/6/93
32
.\"     @(#)last.1	8.1 (Berkeley) 6/6/93
33
.\" $FreeBSD: src/usr.bin/last/last.1,v 1.8 2001/04/26 06:10:46 dd Exp $
33
.\" $FreeBSD: src/usr.bin/last/last.1,v 1.8 2001/04/26 06:10:46 dd Exp $
34
.\"
34
.\"
35
.Dd June 6, 1993
35
.Dd May 2, 2001
36
.Dt LAST 1
36
.Dt LAST 1
37
.Os BSD 4
37
.Os BSD 4
38
.Sh NAME
38
.Sh NAME
Lines 41-46 Link Here
41
.Sh SYNOPSIS
41
.Sh SYNOPSIS
42
.Nm
42
.Nm
43
.Op Fl Ns Ar n
43
.Op Fl Ns Ar n
44
.Oo
45
.Fl d
46
.Sm off
47
.Op Oo Ar CC Oc Ar YY
48
.Op Ar MM DD
49
.Ar hh mm
50
.Op Ar .SS
51
.Sm on
52
.Oc
44
.Op Fl f Ar file
53
.Op Fl f Ar file
45
.Op Fl h Ar host
54
.Op Fl h Ar host
46
.Op Fl s
55
.Op Fl s
Lines 49-60 Link Here
49
.Op user ...
58
.Op user ...
50
.Sh DESCRIPTION
59
.Sh DESCRIPTION
51
.Nm Last
60
.Nm Last
52
will list the sessions of specified
61
will either list the sessions of specified
53
.Ar users ,
62
.Ar users ,
54
.Ar ttys ,
63
.Ar ttys ,
55
and
64
and
56
.Ar hosts ,
65
.Ar hosts ,
57
in reverse time order.
66
in reverse time order,
67
or list the users logged in at a specified date and time.
58
Each line of output contains
68
Each line of output contains
59
the user name, the tty from which the session was conducted, any
69
the user name, the tty from which the session was conducted, any
60
hostname, the start and stop times for the session, and the duration
70
hostname, the start and stop times for the session, and the duration
Lines 69-74 Link Here
69
Limits the report to
79
Limits the report to
70
.Ar n
80
.Ar n
71
lines.
81
lines.
82
.It Fl d Ar date
83
Specify the snapshot date and time.
84
All users logged in at the snapshot date and time will
85
be reported.
86
This may be used with the
87
.Fl f
88
option to derive the results from stored wtmp files.
89
When this argument is provided, all other options except for
90
.Fl f
91
and
92
.Fl Ar n
93
are ignored.
94
The argument should be in the form
95
.Sm off
96
.Op Oo Ar CC Oc Ar YY
97
.Op Ar MM DD
98
.Ar hh mm
99
.Op Ar .SS
100
.Sm on
101
where each pair of letters represents the following:
102
.Pp
103
.Bl -tag -width Ds -compact -offset indent
104
.It Ar CC
105
The first two digits of the year (the century).
106
.It Ar YY
107
The second two digits of the year.
108
If
109
.Ar YY
110
is specified, but
111
.Ar CC
112
is not, a value for
113
.Ar YY
114
between 69 and 99 results in a
115
.Ar CC
116
value of 19.
117
Otherwise, a
118
.Ar CC
119
value of 20 is used.
120
.It Ar MM
121
Month of the year, from 1 to 12.
122
.It Ar DD
123
Day of the month, from 1 to 31.
124
.It Ar hh
125
Hour of the day, from 0 to 23.
126
.It Ar mm
127
Minute of the hour, from 0 to 59.
128
.It Ar SS
129
Second of the minute, from 0 to 61.
130
.El
131
.Pp
132
If the
133
.Ar CC
134
and
135
.Ar YY
136
letter pairs are not specified, the values default to the current
137
year.
138
If the
139
.Ar SS
140
letter pair is not specified, the value defaults to 0.
72
.It Fl f Ar file
141
.It Fl f Ar file
73
.Nm Last
142
.Nm Last
74
reads the file
143
reads the file
Lines 94-101 Link Here
94
default days, hours and minutes.
163
default days, hours and minutes.
95
.El
164
.El
96
.Pp
165
.Pp
97
If
166
If multiple arguments are given,
98
multiple arguments are given, the information which applies to any of the
167
and a snapshot time is not specified,
168
the information which applies to any of the
99
arguments is printed, e.g.,
169
arguments is printed, e.g.,
100
.Dq Li "last root -t console"
170
.Dq Li "last root -t console"
101
would list all of
171
would list all of
(-)last.c (-68 / +173 lines)
Lines 62-67 Link Here
62
62
63
#define	NO	0				/* false/no */
63
#define	NO	0				/* false/no */
64
#define	YES	1				/* true/yes */
64
#define	YES	1				/* true/yes */
65
#define	ATOI2(ar)	((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
65
66
66
static struct utmp	buf[1024];		/* utmp read buffer */
67
static struct utmp	buf[1024];		/* utmp read buffer */
67
68
Lines 89-99 Link Here
89
static int	sflag = 0;			/* show delta in seconds */
90
static int	sflag = 0;			/* show delta in seconds */
90
static int	width = 5;			/* show seconds in delta */
91
static int	width = 5;			/* show seconds in delta */
91
static int      d_first;
92
static int      d_first;
93
static time_t	snaptime;			/* if != 0, we will only
94
						 * report users logged in
95
						 * at this snapshot time
96
						 */
92
97
93
void	 addarg __P((int, char *));
98
void	 addarg __P((int, char *));
94
void	 hostconv __P((char *));
99
void	 hostconv __P((char *));
95
void	 onintr __P((int));
100
void	 onintr __P((int));
96
char	*ttyconv __P((char *));
101
char	*ttyconv __P((char *));
102
time_t	 dateconv __P((char *));
97
int	 want __P((struct utmp *));
103
int	 want __P((struct utmp *));
98
void	 wtmp __P((void));
104
void	 wtmp __P((void));
99
105
Lines 117-123 Link Here
117
	d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
123
	d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
118
124
119
	maxrec = -1;
125
	maxrec = -1;
120
	while ((ch = getopt(argc, argv, "0123456789f:h:st:w")) != -1)
126
	snaptime = 0;
127
	while ((ch = getopt(argc, argv, "0123456789d:f:h:st:w")) != -1)
121
		switch (ch) {
128
		switch (ch) {
122
		case '0': case '1': case '2': case '3': case '4':
129
		case '0': case '1': case '2': case '3': case '4':
123
		case '5': case '6': case '7': case '8': case '9':
130
		case '5': case '6': case '7': case '8': case '9':
Lines 135-140 Link Here
135
					exit(0);
142
					exit(0);
136
			}
143
			}
137
			break;
144
			break;
145
		case 'd':
146
			snaptime = dateconv(optarg);
147
			break;
138
		case 'f':
148
		case 'f':
139
			file = optarg;
149
			file = optarg;
140
			break;
150
			break;
Lines 189-194 Link Here
189
	char    *crmsg;
199
	char    *crmsg;
190
	char ct[80];
200
	char ct[80];
191
	struct tm *tm;
201
	struct tm *tm;
202
	int	 snapfound = 0;			/* found snapshot entry? */
192
203
193
	LIST_INIT(&ttylist);
204
	LIST_INIT(&ttylist);
194
205
Lines 220-226 Link Here
220
				currentout = -bp->ut_time;
231
				currentout = -bp->ut_time;
221
				crmsg = strncmp(bp->ut_name, "shutdown",
232
				crmsg = strncmp(bp->ut_name, "shutdown",
222
				    UT_NAMESIZE) ? "crash" : "shutdown";
233
				    UT_NAMESIZE) ? "crash" : "shutdown";
223
				if (want(bp)) {
234
				/*
235
				 * if we're in snapshot mode, we want to
236
				 * exit if this shutdown/reboot appears
237
				 * while we we are tracking the active
238
				 * range
239
				 */
240
				if (snaptime && snapfound)
241
					return;
242
				/*
243
				 * don't print shutdown/reboot entries
244
				 * unless flagged for 
245
				 */ 
246
				if (!snaptime && want(bp)) {
224
					tm = localtime(&bp->ut_time);
247
					tm = localtime(&bp->ut_time);
225
					(void) strftime(ct, sizeof(ct),
248
					(void) strftime(ct, sizeof(ct),
226
						     d_first ? "%a %e %b %R" :
249
						     d_first ? "%a %e %b %R" :
Lines 243-249 Link Here
243
			 */
266
			 */
244
			if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|')
267
			if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|')
245
			    && !bp->ut_line[1]) {
268
			    && !bp->ut_line[1]) {
246
				if (want(bp)) {
269
				if (want(bp) && !snaptime) {
247
					tm = localtime(&bp->ut_time);
270
					tm = localtime(&bp->ut_time);
248
					(void) strftime(ct, sizeof(ct),
271
					(void) strftime(ct, sizeof(ct),
249
						     d_first ? "%a %e %b %R" :
272
						     d_first ? "%a %e %b %R" :
Lines 259-335 Link Here
259
				}
282
				}
260
				continue;
283
				continue;
261
			}
284
			}
262
			if (bp->ut_name[0] == '\0' || want(bp)) {
285
			/* find associated tty */
263
				/* find associated tty */
286
			LIST_FOREACH(tt, &ttylist, list)
264
				LIST_FOREACH(tt, &ttylist, list)
287
			    if (!strncmp(tt->tty, bp->ut_line, UT_LINESIZE))
265
					if (!strncmp(tt->tty, bp->ut_line, UT_LINESIZE))
288
				    break;
266
						break;
289
			
267
290
			if (tt == NULL) {
268
				if (tt == NULL) {
291
				/* add new one */
269
					/* add new one */
292
				tt = malloc(sizeof(struct ttytab));
270
					tt = malloc(sizeof(struct ttytab));
293
				if (tt == NULL)
271
					if (tt == NULL)
294
					err(1, "malloc failure");
272
						err(1, "malloc failure");
295
				tt->logout = currentout;
273
					tt->logout = currentout;
296
				strncpy(tt->tty, bp->ut_line, UT_LINESIZE);
274
					strncpy(tt->tty, bp->ut_line, UT_LINESIZE);
297
				LIST_INSERT_HEAD(&ttylist, tt, list);
275
					LIST_INSERT_HEAD(&ttylist, tt, list);
298
			}
276
				}
299
			
277
300
			/*
278
				if (bp->ut_name[0]) {
301
			 * print record if not in snapshot mode and wanted
279
					/*
302
			 * or in snapshot mode and in snapshot range
280
					 * when uucp and ftp log in over a network, the entry in
303
			 */
281
					 * the utmp file is the name plus their process id.  See
304
			if (bp->ut_name[0] && (want(bp) ||
282
					 * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
305
			    (bp->ut_time < snaptime &&
283
					 */
306
				(tt->logout > snaptime || tt->logout < 1)))) {
284
					if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
307
				snapfound = 1;
285
						bp->ut_line[3] = '\0';
308
				/*
286
					else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
309
				 * when uucp and ftp log in over a network, the entry in
287
						bp->ut_line[4] = '\0';
310
				 * the utmp file is the name plus their process id.  See
288
					tm = localtime(&bp->ut_time);
311
				 * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
289
					(void) strftime(ct, sizeof(ct),
312
				 */
290
						     d_first ? "%a %e %b %R" :
313
				if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
291
							       "%a %b %e %R",
314
					bp->ut_line[3] = '\0';
292
						     tm);
315
				else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
293
					printf("%-*.*s %-*.*s %-*.*s %s ",
316
					bp->ut_line[4] = '\0';
294
					    UT_NAMESIZE, UT_NAMESIZE, bp->ut_name,
317
				tm = localtime(&bp->ut_time);
295
					    UT_LINESIZE, UT_LINESIZE, bp->ut_line,
318
				(void) strftime(ct, sizeof(ct),
296
					    UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host,
319
				    d_first ? "%a %e %b %R" :
297
					    ct);
320
				    "%a %b %e %R",
298
					if (!tt->logout)
321
				    tm);
299
						puts("  still logged in");
322
				printf("%-*.*s %-*.*s %-*.*s %s ",
323
				    UT_NAMESIZE, UT_NAMESIZE, bp->ut_name,
324
				    UT_LINESIZE, UT_LINESIZE, bp->ut_line,
325
				    UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host,
326
				    ct);
327
				if (!tt->logout)
328
					puts("  still logged in");
329
				else {
330
					if (tt->logout < 0) {
331
						tt->logout = -tt->logout;
332
						printf("- %s", crmsg);
333
					}
300
					else {
334
					else {
301
						if (tt->logout < 0) {
335
						tm = localtime(&tt->logout);
302
							tt->logout = -tt->logout;
336
						(void) strftime(ct, sizeof(ct), "%R", tm);
303
							printf("- %s", crmsg);
337
						printf("- %s", ct);
304
						}
338
					}
305
						else {
339
					delta = tt->logout - bp->ut_time;
306
							tm = localtime(&tt->logout);
340
					if ( sflag ) {
307
							(void) strftime(ct, sizeof(ct), "%R", tm);
341
						printf("  (%8lu)\n", 
308
							printf("- %s", ct);
342
						    delta);
309
						}
343
					} else {
310
						delta = tt->logout - bp->ut_time;
344
						tm = gmtime(&delta);
311
						if ( sflag ) {
345
						(void) strftime(ct, sizeof(ct),
312
							printf("  (%8lu)\n", 
346
						    width >= 8 ? "%T" : "%R",
313
								delta);
347
						    tm);
314
						} else {
348
						if (delta < 86400)
315
						    tm = gmtime(&delta);
316
						    (void) strftime(ct, sizeof(ct),
317
						     width >= 8 ? "%T" : "%R",
318
						     tm);
319
						    if (delta < 86400)
320
							printf("  (%s)\n", ct);
349
							printf("  (%s)\n", ct);
321
						    else
350
						else
322
							printf(" (%ld+%s)\n",
351
							printf(" (%ld+%s)\n",
323
							    delta / 86400,  ct);
352
							    delta / 86400,  ct);
324
						}
325
					}
353
					}
326
					LIST_REMOVE(tt, list);
327
					free(tt);
328
					if (maxrec != -1 && !--maxrec)
329
						return;
330
				} else {
331
					tt->logout = bp->ut_time;
332
				}
354
				}
355
				LIST_REMOVE(tt, list);
356
				free(tt);
357
				if (maxrec != -1 && !--maxrec)
358
					return;
359
			} else {
360
				tt->logout = bp->ut_time;
333
			}
361
			}
334
		}
362
		}
335
	}
363
	}
Lines 348-353 Link Here
348
{
376
{
349
	ARG *step;
377
	ARG *step;
350
378
379
	if (snaptime)
380
		return (NO);
381
351
	if (!arglist)
382
	if (!arglist)
352
		return (YES);
383
		return (YES);
353
384
Lines 444-449 Link Here
444
		return (arg + 5);
475
		return (arg + 5);
445
	return (arg);
476
	return (arg);
446
}
477
}
478
479
/*
480
 * dateconv --
481
 * 	Convert the snapshot time in command line given in the format
482
 * 	[[CC]YY]MMDDhhmm[.SS]] to a time_t.
483
 * 	Derived from atime_arg1() in usr.bin/touch/touch.c
484
 */
485
time_t
486
dateconv(arg)
487
        char *arg;
488
{
489
        time_t timet;
490
        struct tm *t;
491
        int yearset;
492
        char *p;
493
494
        /* Start with the current time. */
495
        if (time(&timet) < 0)
496
                err(1, "time");
497
        if ((t = localtime(&timet)) == NULL)
498
                err(1, "localtime");
499
500
        /* [[CC]YY]MMDDhhmm[.SS] */
501
        if ((p = strchr(arg, '.')) == NULL)
502
                t->tm_sec = 0; 		/* Seconds defaults to 0. */
503
        else {
504
                if (strlen(p + 1) != 2)
505
                        goto terr;
506
                *p++ = '\0';
507
                t->tm_sec = ATOI2(p);
508
        }
509
510
        yearset = 0;
511
        switch (strlen(arg)) {
512
        case 12:                	/* CCYYMMDDhhmm */
513
                t->tm_year = ATOI2(arg);
514
                t->tm_year *= 100;
515
                yearset = 1;
516
                /* FALLTHOUGH */
517
        case 10:                	/* YYMMDDhhmm */
518
                if (yearset) {
519
                        yearset = ATOI2(arg);
520
                        t->tm_year += yearset;
521
                } else {
522
                        yearset = ATOI2(arg);
523
                        if (yearset < 69)
524
                                t->tm_year = yearset + 2000;
525
                        else
526
                                t->tm_year = yearset + 1900;
527
                }
528
                t->tm_year -= 1900;     /* Convert to UNIX time. */
529
                /* FALLTHROUGH */
530
        case 8:				/* MMDDhhmm */
531
                t->tm_mon = ATOI2(arg);
532
                --t->tm_mon;    	/* Convert from 01-12 to 00-11 */
533
                t->tm_mday = ATOI2(arg);
534
                t->tm_hour = ATOI2(arg);
535
                t->tm_min = ATOI2(arg);
536
                break;
537
        case 4:				/* hhmm */
538
                t->tm_hour = ATOI2(arg);
539
                t->tm_min = ATOI2(arg);
540
                break;
541
        default:
542
                goto terr;
543
        }
544
        t->tm_isdst = -1;       	/* Figure out DST. */
545
        timet = mktime(t);
546
        if (timet == -1)
547
terr:           errx(1,
548
        "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
549
        return timet;
550
}
551
447
552
448
/*
553
/*
449
 * onintr --
554
 * onintr --

Return to bug 27050