1/* See LICENSE file for copyright and license details. */
2
3
4#include <errno.h>
5#include <paths.h>
6#include <pwd.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <time.h>
11#include <utmp.h>
12
13#include "text.h"
14#include "util.h"
15
16#define PASSWD "/etc/passwd"
17
18static FILE *last;
19
20static void
21lastlog(char *user)
22{
23 struct passwd *pwd;
24 struct lastlog ll;
25 time_t lltime;
26
27 errno = 0;
28 if ((pwd = getpwnam(user)) == NULL) {
29 if (errno)
30 weprintf("getpwnam %s:", user);
31 else
32 weprintf("unknown user: %s\n", user);
33 return;
34 }
35
36 fseek(last, pwd->pw_uid * sizeof(struct lastlog), 0);
37 fread(&ll, sizeof(struct lastlog), 1, last);
38
39 if (ferror(last))
40 eprintf("%s: read error:", _PATH_LASTLOG);
41
42 /* on glibc `ll_time' can be an int32_t with compat32
43 * avoid compiler warning when calling ctime() */
44 lltime = ll.ll_time;
45 printf("%-8.8s %-8.8s %-16.16s %s",
46 user, ll.ll_line, ll.ll_host, ctime(&lltime));
47}
48
49// ?man lastlog: report recent logins
50// ?man display the most recent login times of users
51int
52main(int argc, char **argv)
53{
54 FILE *fp;
55 char *line = NULL, *p;
56 size_t sz = 0;
57
58 if ((last = fopen(_PATH_LASTLOG, "r")) == NULL)
59 eprintf("fopen %s:", _PATH_LASTLOG);
60
61 if (argc > 1) {
62 while (*++argv)
63 lastlog(*argv);
64 } else {
65 if ((fp = fopen(PASSWD, "r")) == NULL)
66 eprintf("fopen %s:", PASSWD);
67 while (agetline(&line, &sz, fp) != -1) {
68 if ((p = strchr(line, ':')) == NULL)
69 eprintf("invalid passwd entry\n");
70 *p = '\0';
71 lastlog(line);
72 }
73 if (fclose(fp))
74 eprintf("fclose %s:", PASSWD);
75 free(line);
76 }
77
78 if (fclose(last))
79 eprintf("fclose %s:", _PATH_LASTLOG);
80
81 return 0;
82}