]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/lastlogin/lastlogin.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / usr.sbin / lastlogin / lastlogin.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 1996 John M. Vinopal
5  * Copyright (c) 2018 Philip Paeps
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed for the NetBSD Project
19  *      by John M. Vinopal.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __RCSID("$FreeBSD$");
39 __RCSID("$NetBSD: lastlogin.c,v 1.4 1998/02/03 04:45:35 perry Exp $");
40 #endif
41
42 #include <err.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48 #include <utmpx.h>
49
50 #include <libxo/xo.h>
51
52         int     main(int, char **);
53 static  void    output(struct utmpx *);
54 static  void    usage(void);
55 static int      utcmp_user(const void *, const void *);
56
57 static int      order = 1;
58 static const char *file = NULL;
59 static int      (*utcmp)(const void *, const void *) = utcmp_user;
60
61 static int
62 utcmp_user(const void *u1, const void *u2)
63 {
64
65         return (order * strcmp(((const struct utmpx *)u1)->ut_user,
66             ((const struct utmpx *)u2)->ut_user));
67 }
68
69 static int
70 utcmp_time(const void *u1, const void *u2)
71 {
72         time_t t1, t2;
73
74         t1 = ((const struct utmpx *)u1)->ut_tv.tv_sec;
75         t2 = ((const struct utmpx *)u2)->ut_tv.tv_sec;
76         return (t1 < t2 ? order : t1 > t2 ? -order : 0);
77 }
78
79 int
80 main(int argc, char *argv[])
81 {
82         int     ch, i, ulistsize;
83         struct utmpx *u, *ulist;
84
85         argc = xo_parse_args(argc, argv);
86         if (argc < 0)
87                 exit(1);
88
89         while ((ch = getopt(argc, argv, "f:rt")) != -1) {
90                 switch (ch) {
91                 case 'f':
92                         file = optarg;
93                         break;
94                 case 'r':
95                         order = -1;
96                         break;
97                 case 't':
98                         utcmp = utcmp_time;
99                         break;
100                 default:
101                         usage();
102                 }
103         }
104         argc -= optind;
105         argv += optind;
106
107         xo_open_container("lastlogin-information");
108         xo_open_list("lastlogin");
109
110         if (argc > 0) {
111                 /* Process usernames given on the command line. */
112                 for (i = 0; i < argc; i++) {
113                         if (setutxdb(UTXDB_LASTLOGIN, file) != 0)
114                                 xo_err(1, "failed to open lastlog database");
115                         if ((u = getutxuser(argv[i])) == NULL) {
116                                 xo_warnx("user '%s' not found", argv[i]);
117                                 continue;
118                         }
119                         output(u);
120                         endutxent();
121                 }
122         } else {
123                 /* Read all lastlog entries, looking for active ones. */
124                 if (setutxdb(UTXDB_LASTLOGIN, file) != 0)
125                         xo_err(1, "failed to open lastlog database");
126                 ulist = NULL;
127                 ulistsize = 0;
128                 while ((u = getutxent()) != NULL) {
129                         if (u->ut_type != USER_PROCESS)
130                                 continue;
131                         if ((ulistsize % 16) == 0) {
132                                 ulist = realloc(ulist,
133                                     (ulistsize + 16) * sizeof(struct utmpx));
134                                 if (ulist == NULL)
135                                         xo_err(1, "malloc");
136                         }
137                         ulist[ulistsize++] = *u;
138                 }
139                 endutxent();
140
141                 qsort(ulist, ulistsize, sizeof(struct utmpx), utcmp);
142                 for (i = 0; i < ulistsize; i++)
143                         output(&ulist[i]);
144         }
145
146         xo_close_list("lastlogin");
147         xo_close_container("lastlogin-information");
148         xo_finish();
149
150         exit(0);
151 }
152
153 /* Duplicate the output of last(1) */
154 static void
155 output(struct utmpx *u)
156 {
157         time_t t = u->ut_tv.tv_sec;
158
159         xo_open_instance("lastlogin");
160         xo_emit("{:user/%-10s/%s} {:tty/%-8s/%s} {:from/%-22.22s/%s}",
161                 u->ut_user, u->ut_line, u->ut_host);
162         xo_attr("seconds", "%lu", (unsigned long)t);
163         xo_emit(" {:login-time/%.24s/%.24s}\n", ctime(&t));
164         xo_close_instance("lastlogin");
165 }
166
167 static void
168 usage(void)
169 {
170         xo_error("usage: lastlogin [-f file] [-rt] [user ...]\n");
171         xo_finish();
172         exit(1);
173 }