2
* Copyright 1989 - 1994, Julianne Frances Haugh
2
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
3
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
4
* Copyright (c) 2000 - 2006, Tomasz Kłoczko
5
* Copyright (c) 2007 - 2009, Nicolas François
3
6
* All rights reserved.
5
8
* Redistribution and use in source and binary forms, with or without
10
13
* 2. Redistributions in binary form must reproduce the above copyright
11
14
* notice, this list of conditions and the following disclaimer in the
12
15
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of Julianne F. Haugh nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
* 3. The name of the copyright holders or contributors may not be used to
17
* endorse or promote products derived from this software without
18
* specific prior written permission.
17
* THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
33
#include <config.h>
32
#ident "$Id: lastlog.c 1751 2008-02-03 16:28:03Z nekral-guest $"
35
#ident "$Id: lastlog.c 2502 2009-03-13 22:20:20Z nekral-guest $"
34
37
#include <getopt.h>
35
38
#include <lastlog.h>
38
41
#include <sys/stat.h>
39
42
#include <sys/types.h>
41
45
#include "defines.h"
42
46
#include "prototypes.h"
44
49
* Needed for MkLinux DR1/2/2.1 - J.
46
51
#ifndef LASTLOG_FILE
47
52
#define LASTLOG_FILE "/var/log/lastlog"
52
58
static FILE *lastlogfile; /* lastlog file stream */
53
static long umin; /* if uflg, only display users with uid >= umin */
54
static long umax; /* if uflg, only display users with uid <= umax */
59
static unsigned long umin; /* if uflg and has_umin, only display users with uid >= umin */
60
static bool has_umin = false;
61
static unsigned long umax; /* if uflg and has_umax, only display users with uid <= umax */
62
static bool has_umax = false;
55
63
static int days; /* number of days to consider for print command */
56
64
static time_t seconds; /* that number of days in seconds */
57
65
static int inverse_days; /* number of days to consider for print command */
58
66
static time_t inverse_seconds; /* that number of days in seconds */
61
static int uflg = 0; /* print only an user of range of users */
62
static int tflg = 0; /* print is restricted to most recent days */
63
static int bflg = 0; /* print excludes most recent days */
64
static struct lastlog lastlog; /* scratch structure to play with ... */
67
static struct stat statbuf; /* fstat buffer for file size */
70
static bool uflg = false; /* print only an user of range of users */
71
static bool tflg = false; /* print is restricted to most recent days */
72
static bool bflg = false; /* print excludes most recent days */
65
73
static struct passwd *pwent;
67
75
#define NOW (time ((time_t *) 0))
82
90
static void print_one (const struct passwd *pw)
92
static bool once = false;
89
99
#ifdef HAVE_STRFTIME
108
offset = pw->pw_uid * sizeof (ll);
110
if (offset <= (statbuf.st_size - sizeof (ll))) {
111
/* fseeko errors are not really relevant for us. */
112
assert ( fseeko (lastlogfile, offset, SEEK_SET) == 0 );
113
/* lastlog is a sparse file. Even if no entries were
114
* entered for this user, which should be able to get the
115
* empty entry in this case.
117
if (fread ((char *) &ll, sizeof (ll), 1, lastlogfile) != 1) {
119
_("lastlog: Failed to get the entry for UID %d\n"),
124
/* Outsize of the lastlog file.
125
* Behave as if there were a missing entry (same behavior
126
* as if we were reading an non existing entry in the
127
* sparse lastlog file).
129
memzero (&ll, sizeof (ll));
132
/* Filter out entries that do not match with the -t or -b options */
133
if (tflg && ((NOW - ll.ll_time) > seconds)) {
137
if (bflg && ((NOW - ll.ll_time) < inverse_seconds)) {
141
/* Print the header only once */
97
143
#ifdef HAVE_LL_HOST
98
144
puts (_("Username Port From Latest"));
100
146
puts (_("Username Port Latest"));
104
ll_time = lastlog.ll_time;
151
ll_time = ll.ll_time;
105
152
tm = localtime (&ll_time);
106
153
#ifdef HAVE_STRFTIME
107
154
strftime (ptime, sizeof (ptime), "%a %b %e %H:%M:%S %z %Y", tm);
114
if (lastlog.ll_time == (time_t) 0)
161
if (ll.ll_time == (time_t) 0) {
115
162
cp = _("**Never logged in**\0");
117
165
#ifdef HAVE_LL_HOST
118
printf ("%-16s %-8.8s %-16.16s %s\n", pw->pw_name,
119
lastlog.ll_line, lastlog.ll_host, cp);
166
printf ("%-16s %-8.8s %-16.16s %s\n",
167
pw->pw_name, ll.ll_line, ll.ll_host, cp);
121
printf ("%-16s\t%-8.8s %s\n", pw->pw_name, lastlog.ll_line, cp);
169
printf ("%-16s\t%-8.8s %s\n",
170
pw->pw_name, ll.ll_line, cp);
125
174
static void print (void)
131
while ((pwent = getpwent ())) {
132
user = pwent->pw_uid;
134
((umin != -1 && user < (uid_t)umin) ||
135
(umax != -1 && user > (uid_t)umax)))
137
offset = user * sizeof lastlog;
139
fseeko (lastlogfile, offset, SEEK_SET);
140
if (fread ((char *) &lastlog, sizeof lastlog, 1,
144
if (tflg && NOW - lastlog.ll_time > seconds)
147
if (bflg && NOW - lastlog.ll_time < inverse_seconds)
176
if (uflg && has_umin && has_umax && (umin == umax)) {
177
print_one (getpwuid ((uid_t)umin));
180
while ( (pwent = getpwent ()) != NULL ) {
182
&& ( (has_umin && (pwent->pw_uid < (uid_t)umin))
183
|| (has_umax && (pwent->pw_uid > (uid_t)umax)))) {
154
192
int main (int argc, char **argv)
156
setlocale (LC_ALL, "");
157
bindtextdomain (PACKAGE, LOCALEDIR);
158
textdomain (PACKAGE);
194
(void) setlocale (LC_ALL, "");
195
(void) bindtextdomain (PACKAGE, LOCALEDIR);
196
(void) textdomain (PACKAGE);
167
205
{NULL, 0, NULL, '\0'}
171
getopt_long (argc, argv, "ht:b:u:", longopts,
208
while ((c = getopt_long (argc, argv, "ht:b:u:", longopts,
178
days = atoi (optarg);
179
seconds = days * DAY;
215
days = atoi (optarg); /* FIXME */
216
seconds = (time_t) days * DAY;
183
inverse_days = atoi (optarg);
184
inverse_seconds = inverse_days * DAY;
220
inverse_days = atoi (optarg); /* FIXME */
221
inverse_seconds = (time_t) inverse_days * DAY;
192
229
* - a numerical login ID
193
230
* - a range (-x, x-, x-y)
196
pwent = xgetpwnam (optarg);
233
/* local, no need for xgetpwnam */
234
pwent = getpwnam (optarg);
197
235
if (NULL != pwent) {
198
umin = pwent->pw_uid;
236
umin = (unsigned long) pwent->pw_uid;
203
user = strtol(optarg, &endptr, 10);
204
if (*optarg != '\0' && *endptr == '\0') {
214
} else if (endptr[0] == '-' && endptr[1] == '\0') {
218
} else if (*endptr == '-') {
219
/* <userid>-<userid> */
221
umax = atol(endptr+1);
241
if (getrange (optarg,
243
&umax, &has_umax) == 0) {
224
_("Unknown user or range: %s\n"),
245
_("lastlog: Unknown user or range: %s\n"),