* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
static char sccsid
[] = "@(#)last.c 5.4 (Berkeley) %G%";
#define MAXTTYS 200 /* max ttys last can handle */
#define SECDAY (24*60*60) /* seconds in a day */
#define NO 0 /* false/no */
#define YES 1 /* true/yes */
static struct utmp buf
[500]; /* utmp read buffer */
#define HMAX sizeof(buf[0].ut_host) /* size of utmp host field */
#define LMAX sizeof(buf[0].ut_line) /* size of utmp tty field */
#define NMAX sizeof(buf[0].ut_name) /* size of utmp name field */
#define lineq(a,b) (!strncmp(a,b,LMAX))
#define nameq(a,b) (!strncmp(a,b,NMAX))
#define hosteq(a,b) (!strncmp(a,b,HMAX))
long logout
; /* log out time */
char tty
[LMAX
+ 1]; /* terminal name */
static TTYS tab
[MAXTTYS
+ 1]; /* tty table */
static char **sargs
; /* start of selections args */
register struct utmp
*bp
; /* current structure */
register TTYS
*T
; /* table entry */
register long maxrec
= -1; /* records to display */
register int indx
; /* array offsets */
struct stat stb
; /* stat of file for size */
long delta
, /* time difference */
int bl
, /* reads to do */
wtmp
, /* wtmp file descriptor */
char *ct
, /* ctime return */
*crmsg
, /* crash message */
*file
, /* user specified file */
*asctime(), *ctime(), *strspl();
for (--argc
,sargs
= argv
= ++argv
,indx
= 0;indx
< argc
;++indx
) {
if (argv
[indx
][0] == '-' && isdigit(argv
[indx
][1])) {
if ((maxrec
= atol(argv
[indx
] + 1)) <= 0) {
fputs("last: bad line count value.\n",stderr
);
if (!strncmp(argv
[indx
],"-f",2)) {
else if (++indx
== argc
) {
fputs("last: option requires an argument -- f\n",stderr
);
if (strlen(argv
[indx
]) > 2)
if (!strcmp(argv
[indx
],"~"))
if (getpwnam(argv
[indx
]))
argv
[indx
] = strspl(argv
[indx
]);
if ((wtmp
= open(file
,O_RDONLY
,0)) < 0 || fstat(wtmp
,&stb
) == -1) {
bl
= (stb
.st_size
+ sizeof(buf
) - 1) / sizeof(buf
);
tab
[MAXTTYS
].logout
= -1; /* end flag value */
if (lseek(wtmp
,(long)(bl
* sizeof(buf
)),L_SET
) == -1 || (bytes
= read(wtmp
,(char *)buf
,sizeof(buf
))) == -1) {
for (bp
= &buf
[bytes
/ sizeof(buf
[0]) - 1];bp
>= buf
;--bp
) {
if (lineq(bp
->ut_line
,"~")) {
* if the name is empty and the terminal
* line is '~', it's a shutdown of some
* sort; see utmp(5) for more info.
for (T
= tab
;T
->logout
!= -1;++T
)
T
->logout
= -bp
->ut_time
;
crmsg
= nameq(bp
->ut_name
,"shutdown") ? "down " : "crash";
strcpy(bp
->ut_name
,"reboot");
ct
= ctime(&bp
->ut_time
);
printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s \n",NMAX
,NMAX
,bp
->ut_name
,LMAX
,LMAX
,bp
->ut_line
,HMAX
,HMAX
,bp
->ut_host
,ct
,ct
+ 11);
if (maxrec
!= -1 && !--maxrec
)
bcopy(bp
->ut_line
,T
->tty
,LMAX
);
if (lineq(T
->tty
,bp
->ut_line
))
if ((++T
)->logout
== -1) {
fputs("last: too many terminals.\n",stderr
);
if (bp
->ut_name
[0] && want(bp
,YES
)) {
ct
= ctime(&bp
->ut_time
);
printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ",NMAX
,NMAX
,bp
->ut_name
,LMAX
,LMAX
,bp
->ut_line
,HMAX
,HMAX
,bp
->ut_host
,ct
,ct
+ 11);
puts(" still logged in");
printf("- %5.5s",ctime(&T
->logout
)+11);
delta
= T
->logout
- bp
->ut_time
;
printf(" (%5.5s)\n",asctime(gmtime(&delta
))+11);
printf(" (%ld+%5.5s)\n",delta
/ SECDAY
,asctime(gmtime(&delta
))+11);
if (maxrec
!= -1 && !--maxrec
)
ct
= ctime(&buf
[0].ut_time
);
printf("\nwtmp begins %10.10s %5.5s \n",ct
,ct
+ 11);
ct
= ctime(&buf
[0].ut_time
);
printf("\ninterrupted %10.10s %5.5s \n",ct
,ct
+ 11);
fflush(stdout
); /* fix required for rsh */
register struct utmp
*bp
;
* when uucp and ftp log in over a network, the entry in the
* utmp file is the name plus their process id. See etc/ftpd.c
* and usr.bin/uucp/uucpd.c for more information.
if (!strncmp(bp
->ut_line
,"ftp",3))
else if (!strncmp(bp
->ut_line
,"uucp",4))
for (indx
= sargs
;*indx
;++indx
)
if (nameq(*indx
,bp
->ut_name
) || lineq(*indx
,bp
->ut_line
))
if (!(res
= malloc((u_int
)(4 + strlen(str
))))) {
fputs("last: malloc failure.\n",stderr
);