]>
git.cameronkatri.com Git - apple_cmds.git/blob - adv_cmds/last/last.c
2 * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
4 * Copyright (c) 1987, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * The NEXTSTEP Software License Agreement specifies the terms
8 * and conditions for redistribution.
10 * @(#)last.c 8.2 (Berkeley) 4/2/94
15 static const char copyright
[] =
16 "@(#) Copyright (c) 1987, 1993, 1994\n\
17 The Regents of the University of California. All rights reserved.\n";
20 #include <sys/param.h>
36 #define NO 0 /* false/no */
37 #define YES 1 /* true/yes */
39 static const struct utmpx
*prev
; /* previous utmpx structure */
41 /* values from utmp.h, used for print formatting */
42 #define UT_NAMESIZE 8 /* old utmp.h value */
44 #define UT_HOSTSIZE 16
47 const char *name
; /* argument */
51 int type
; /* type of arg */
52 struct arg
*next
; /* linked list pointer */
54 ARG
*arglist
; /* head of linked list */
56 typedef struct ttytab
{
57 long logout
; /* log out time */
58 char id
[_UTX_IDSIZE
]; /* terminal id */
60 struct ttytab
*next
; /* linked list pointer */
62 TTY
*ttylist
; /* head of linked list */
64 static const char *crmsg
; /* cause of last reboot */
65 static long currentout
, /* current logout value */
66 maxrec
; /* records to display */
69 void addarg
__P((int, const char *));
70 TTY
*addtty
__P((const char *, pid_t
));
71 void hostconv
__P((const char *));
72 void onintr
__P((int));
73 const char *ttyconv
__P((const char *));
74 int want
__P((struct utmpx
*, int));
75 void wtmp
__P((void));
88 if ((p
= strrchr(myname
, '/')) != NULL
)
91 while ((ch
= getopt(argc
, argv
, "0123456789f:h:t:")) != EOF
)
93 case '0': case '1': case '2': case '3': case '4':
94 case '5': case '6': case '7': case '8': case '9':
96 * kludge: last was originally designed to take
97 * a number after a dash.
100 p
= argv
[optind
- 1];
101 if (p
[0] == '-' && p
[1] == ch
&& !p
[2])
104 maxrec
= atol(argv
[optind
] + 1);
111 addarg(HOST_TYPE
, optarg
);
114 addarg(TTY_TYPE
, ttyconv(optarg
));
117 warnx("-f is unsupported");
121 (void)fprintf(stderr
,
122 "usage: last [-#] [-t tty] [-h hostname] [user ...]\n");
128 for (argv
+= optind
; *argv
; ++argv
) {
129 #define COMPATIBILITY
131 /* code to allow "last p5" to work */
132 addarg(TTY_TYPE
, ttyconv(*argv
));
134 addarg(USER_TYPE
, *argv
);
143 * read through the wtmp file
150 struct utmpx
*bp
; /* current structure */
151 TTY
*T
; /* tty list entry */
152 long delta
; /* time difference */
156 (void)signal(SIGINT
, onintr
);
157 (void)signal(SIGQUIT
, onintr
);
159 setutxent_wtmp(0); /* zero means reverse chronological order */
160 while ((bp
= getutxent_wtmp()) != NULL
) {
162 switch(bp
->ut_type
) {
165 /* everybody just logged out */
166 for (T
= ttylist
; T
; T
= T
->next
)
167 T
->logout
= -bp
->ut_tv
.tv_sec
;
168 currentout
= -bp
->ut_tv
.tv_sec
;
169 crmsg
= bp
->ut_type
== BOOT_TIME
? "crash" : "shutdown";
171 ct
= ctime(&bp
->ut_tv
.tv_sec
);
172 printf("%-*s %-*s %-*.*s %10.10s %5.5s \n",
173 UT_NAMESIZE
, bp
->ut_type
== BOOT_TIME
? "reboot" : "shutdown",
175 UT_HOSTSIZE
, _UTX_HOSTSIZE
,
176 bp
->ut_host
, ct
, ct
+ 11);
177 if (maxrec
!= -1 && !--maxrec
)
184 ct
= ctime(&bp
->ut_tv
.tv_sec
);
185 printf("%-*s %-*s %-*.*s %10.10s %5.5s \n",
187 UT_LINESIZE
, bp
->ut_type
== OLD_TIME
? "|" : "{",
188 UT_HOSTSIZE
, _UTX_HOSTSIZE
, bp
->ut_host
,
190 if (maxrec
&& !--maxrec
)
196 /* find associated tty */
197 for (T
= ttylist
;; T
= T
->next
) {
200 T
= addtty(bp
->ut_id
, bp
->ut_pid
);
203 if (!memcmp(T
->id
, bp
->ut_id
, _UTX_IDSIZE
) && T
->pid
== bp
->ut_pid
)
206 if (bp
->ut_type
!= DEAD_PROCESS
&& want(bp
, YES
)) {
207 ct
= ctime(&bp
->ut_tv
.tv_sec
);
208 printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ",
209 UT_NAMESIZE
, _UTX_USERSIZE
, bp
->ut_user
,
210 UT_LINESIZE
, _UTX_LINESIZE
, bp
->ut_line
,
211 UT_HOSTSIZE
, _UTX_HOSTSIZE
, bp
->ut_host
,
214 puts(" still logged in");
217 T
->logout
= -T
->logout
;
218 printf("- %s", crmsg
);
222 ctime(&T
->logout
)+11);
223 delta
= T
->logout
- bp
->ut_tv
.tv_sec
;
224 if (delta
< SECSPERDAY
)
226 asctime(gmtime(&delta
))+11);
228 printf(" (%ld+%5.5s)\n",
230 asctime(gmtime(&delta
))+11);
232 if (maxrec
!= -1 && !--maxrec
)
235 T
->logout
= bp
->ut_tv
.tv_sec
;
240 ct
= ctime(prev
? &prev
->ut_tv
.tv_sec
: &now
);
241 printf("\nwtmp begins %10.10s %5.5s \n", ct
, ct
+ 11);
246 * see if want this entry
258 for (step
= arglist
; step
; step
= step
->next
)
261 if (!strncasecmp(step
->name
, bp
->ut_host
, _UTX_HOSTSIZE
))
266 char *line
= bp
->ut_line
;
269 * when uucp and ftp log in over a network, the entry in
270 * the utmpx file is the name plus their process id. See
271 * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
273 if (!strncmp(line
, "ftp", sizeof("ftp") - 1))
275 else if (!strncmp(line
, "uucp", sizeof("uucp") - 1))
278 if (!strncmp(step
->name
, line
, _UTX_LINESIZE
))
283 if (bp
->ut_type
== BOOT_TIME
&& !strncmp(step
->name
, "reboot", _UTX_USERSIZE
))
285 if (bp
->ut_type
== SHUTDOWN_TIME
&& !strncmp(step
->name
, "shutdown", _UTX_USERSIZE
))
287 if (!strncmp(step
->name
, bp
->ut_user
, _UTX_USERSIZE
))
296 * add an entry to a linked list of arguments
305 if (!(cur
= (ARG
*)malloc((u_int
)sizeof(ARG
))))
306 err(1, "malloc failure");
315 * add an entry to a linked list of ttys
324 if (!(cur
= (TTY
*)malloc((u_int
)sizeof(TTY
))))
325 err(1, "malloc failure");
327 cur
->logout
= currentout
;
328 memmove(cur
->id
, id
, _UTX_IDSIZE
);
330 return (ttylist
= cur
);
335 * convert the hostname to search pattern; if the supplied host name
336 * has a domain attached that is the same as the current domain, rip
337 * off the domain suffix since that's what login(1) does.
343 static int first
= 1;
344 static char *hostdot
, name
[MAXHOSTNAMELEN
];
347 if (!(argdot
= strchr(arg
, '.')))
351 if (gethostname(name
, sizeof(name
)))
352 err(1, "gethostname");
353 hostdot
= strchr(name
, '.');
355 if (hostdot
&& !strcasecmp(hostdot
, argdot
))
361 * convert tty to correct name.
369 int len
= strlen(arg
);
372 * kludge -- we assume that most tty's end with
373 * a two character suffix.
376 kludge
= 8; /* either 6 for "ttyxx" or 8 for "console"; use largest */
378 * kludge -- we assume cloning ptys names are "ttys" followed by
379 * more than one digit
381 else if (len
> 2 && *arg
== 's') {
382 const char *cp
= arg
+ 1;
383 while(*cp
&& isdigit(*cp
))
386 kludge
= len
+ sizeof("tty");
389 if (!(mval
= malloc(kludge
)))
390 err(1, "malloc failure");
391 if (!strcmp(arg
, "co"))
392 (void)strcpy(mval
, "console");
394 (void)strcpy(mval
, "tty");
395 (void)strcpy(mval
+ sizeof("tty") - 1, arg
);
399 if (!strncmp(arg
, _PATH_DEV
, sizeof(_PATH_DEV
) - 1))
400 return (arg
+ sizeof(_PATH_DEV
) - 1);
406 * on interrupt, we inform the user how far we've gotten
414 ct
= ctime(prev
? &prev
->ut_tv
.tv_sec
: &now
);
415 printf("\ninterrupted %10.10s %5.5s \n", ct
, ct
+ 11);
418 (void)fflush(stdout
); /* fix required for rsh */