X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=login-utils%2Flast.c;h=be744b079198ecf11ba05eed990c5f942bca18c0;hb=aa14d687ac401f9c313190793d657218c0d0405a;hp=78b82ca8fe0bf8f6d20a3047cf582707d2db6248;hpb=c7eb14d3253a4944d317129588a81c96fcab2376;p=thirdparty%2Futil-linux.git diff --git a/login-utils/last.c b/login-utils/last.c index 78b82ca8fe..be744b0791 100644 --- a/login-utils/last.c +++ b/login-utils/last.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -40,6 +40,7 @@ #include #include #include +#include #include "c.h" #include "nls.h" @@ -52,12 +53,6 @@ #include "timeutils.h" #include "monotonic.h" -#if defined(_HAVE_UT_TV) -# define UL_UT_TIME ut_tv.tv_sec -#else -# define UL_UT_TIME ut_time -#endif - #ifndef SHUTDOWN_TIME # define SHUTDOWN_TIME 254 #endif @@ -99,7 +94,7 @@ struct last_control { /* Double linked list of struct utmp's */ struct utmplist { - struct utmp ut; + struct utmpx ut; struct utmplist *next; struct utmplist *prev; }; @@ -150,8 +145,8 @@ static struct last_timefmt timefmts[] = { }, [LAST_TIMEFTM_ISO8601] = { .name = "iso", - .in_len = 24, - .out_len = 26, + .in_len = 25, + .out_len = 27, .in_fmt = LAST_TIMEFTM_ISO8601, .out_fmt = LAST_TIMEFTM_ISO8601 } @@ -163,22 +158,22 @@ static time_t lastdate; /* Last date we've seen */ static time_t currentdate; /* date when we started processing the file */ /* --time-format=option parser */ -static int which_time_format(const char *optarg) +static int which_time_format(const char *s) { size_t i; for (i = 0; i < ARRAY_SIZE(timefmts); i++) { - if (strcmp(timefmts[i].name, optarg) == 0) + if (strcmp(timefmts[i].name, s) == 0) return i; } - errx(EXIT_FAILURE, _("unknown time format: %s"), optarg); + errx(EXIT_FAILURE, _("unknown time format: %s"), s); } /* * Read one utmp entry, return in new format. * Automatically reposition file pointer. */ -static int uread(FILE *fp, struct utmp *u, int *quit, const char *filename) +static int uread(FILE *fp, struct utmpx *u, int *quit, const char *filename) { static int utsize; static char buf[UCHUNKSIZE]; @@ -191,14 +186,14 @@ static int uread(FILE *fp, struct utmp *u, int *quit, const char *filename) /* * Normal read. */ - return fread(u, sizeof(struct utmp), 1, fp); + return fread(u, sizeof(struct utmpx), 1, fp); } if (u == NULL) { /* * Initialize and position. */ - utsize = sizeof(struct utmp); + utsize = sizeof(struct utmpx); fseeko(fp, 0, SEEK_END); fpos = ftello(fp); if (fpos == 0) @@ -222,7 +217,7 @@ static int uread(FILE *fp, struct utmp *u, int *quit, const char *filename) */ bpos -= utsize; if (bpos >= 0) { - memcpy(u, buf + bpos, sizeof(struct utmp)); + memcpy(u, buf + bpos, sizeof(struct utmpx)); return 1; } @@ -258,7 +253,7 @@ static int uread(FILE *fp, struct utmp *u, int *quit, const char *filename) memcpy(tmp, buf + UCHUNKSIZE + bpos, -bpos); bpos += UCHUNKSIZE; - memcpy(u, tmp, sizeof(struct utmp)); + memcpy(u, tmp, sizeof(struct utmpx)); return 1; } @@ -350,10 +345,11 @@ static int time_formatter(int fmt, char *dst, size_t dlen, time_t *when) break; } case LAST_TIMEFTM_CTIME: - ret = snprintf(dst, dlen, "%s", ctime(when)); + snprintf(dst, dlen, "%s", ctime(when)); + ret = rtrim_whitespace((unsigned char *) dst); break; case LAST_TIMEFTM_ISO8601: - ret = strtime_iso(when, ISO_8601_DATE|ISO_8601_TIME|ISO_8601_TIMEZONE, dst, dlen); + ret = strtime_iso(when, ISO_TIMESTAMP_T, dst, dlen); break; default: abort(); @@ -381,14 +377,14 @@ static void trim_trailing_spaces(char *s) /* * Show one line of information on screen */ -static int list(const struct last_control *ctl, struct utmp *p, time_t logout_time, int what) +static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_time, int what) { time_t secs, utmp_time; char logintime[LAST_TIMESTAMP_LEN]; char logouttime[LAST_TIMESTAMP_LEN]; char length[LAST_TIMESTAMP_LEN]; char final[512]; - char utline[UT_LINESIZE+1]; + char utline[sizeof(p->ut_line) + 1]; char domain[256]; char *s; int mins, hours, days; @@ -399,7 +395,7 @@ static int list(const struct last_control *ctl, struct utmp *p, time_t logout_ti * uucp and ftp have special-type entries */ utline[0] = 0; - strncat(utline, p->ut_line, UT_LINESIZE); + strncat(utline, p->ut_line, sizeof(utline) - 1); if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3])) utline[3] = 0; if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4])) @@ -411,7 +407,7 @@ static int list(const struct last_control *ctl, struct utmp *p, time_t logout_ti if (ctl->show) { char **walk; for (walk = ctl->show; *walk; walk++) { - if (strncmp(p->ut_user, *walk, UT_NAMESIZE) == 0 || + if (strncmp(p->ut_user, *walk, sizeof(p->ut_user)) == 0 || strcmp(utline, *walk) == 0 || (strncmp(utline, "tty", 3) == 0 && strcmp(utline + 3, *walk) == 0)) break; @@ -424,7 +420,7 @@ static int list(const struct last_control *ctl, struct utmp *p, time_t logout_ti */ fmt = &timefmts[ctl->time_fmt]; - utmp_time = p->UL_UT_TIME; + utmp_time = p->ut_tv.tv_sec; if (ctl->present) { if (ctl->present < utmp_time) @@ -439,11 +435,16 @@ static int list(const struct last_control *ctl, struct utmp *p, time_t logout_ti errx(EXIT_FAILURE, _("preallocation size exceeded")); /* log-out time */ - secs = logout_time - utmp_time; + secs = logout_time - utmp_time; /* Under strange circumstances, secs < 0 can happen */ mins = (secs / 60) % 60; hours = (secs / 3600) % 24; days = secs / 86400; + strcpy(logouttime, "- "); + if (time_formatter(fmt->out_fmt, logouttime + 2, + sizeof(logouttime) - 2, &logout_time) < 0) + errx(EXIT_FAILURE, _("preallocation size exceeded")); + if (logout_time == currentdate) { if (ctl->time_fmt > LAST_TIMEFTM_SHORT) { sprintf(logouttime, " still running"); @@ -453,9 +454,13 @@ static int list(const struct last_control *ctl, struct utmp *p, time_t logout_ti sprintf(length, "running"); } } else if (days) { - sprintf(length, "(%d+%02d:%02d)", days, hours, mins); + sprintf(length, "(%d+%02d:%02d)", days, abs(hours), abs(mins)); /* hours and mins always shown as positive (w/o minus sign!) even if secs < 0 */ + } else if (hours) { + sprintf(length, " (%02d:%02d)", hours, abs(mins)); /* mins always shown as positive (w/o minus sign!) even if secs < 0 */ + } else if (secs >= 0) { + sprintf(length, " (%02d:%02d)", hours, mins); } else { - sprintf(length, " (%02d:%02d)", hours, mins); + sprintf(length, " (-00:%02d)", abs(mins)); /* mins always shown as positive (w/o minus sign!) even if secs < 0 */ } switch(what) { @@ -492,10 +497,6 @@ static int list(const struct last_control *ctl, struct utmp *p, time_t logout_ti break; case R_NORMAL: case R_REBOOT: - strcpy(logouttime, "- "); - if (time_formatter(fmt->out_fmt, logouttime + 2, - sizeof(logouttime) - 2, &logout_time) < 0) - errx(EXIT_FAILURE, _("preallocation size exceeded")); break; default: abort(); @@ -506,14 +507,9 @@ static int list(const struct last_control *ctl, struct utmp *p, time_t logout_ti */ r = -1; if (ctl->usedns || ctl->useip) - r = dns_lookup(domain, sizeof(domain), ctl->useip, p->ut_addr_v6); - if (r < 0) { - len = UT_HOSTSIZE; - if (len >= (int)sizeof(domain)) len = sizeof(domain) - 1; - domain[0] = 0; - strncat(domain, p->ut_host, len); - } - + r = dns_lookup(domain, sizeof(domain), ctl->useip, (int32_t*)p->ut_addr_v6); + if (r < 0) + mem2strcpy(domain, p->ut_host, sizeof(p->ut_host), sizeof(domain)); if (ctl->showhost) { if (!ctl->altlist) { @@ -561,8 +557,9 @@ static int list(const struct last_control *ctl, struct utmp *p, time_t logout_ti } -static void __attribute__((__noreturn__)) usage(const struct last_control *ctl, FILE *out) +static void __attribute__((__noreturn__)) usage(const struct last_control *ctl) { + FILE *out = stdout; fputs(USAGE_HEADER, out); fprintf(out, _( " %s [options] [...] [...]\n"), program_invocation_short_name); @@ -589,21 +586,21 @@ static void __attribute__((__noreturn__)) usage(const struct last_control *ctl, " notime|short|full|iso\n"), out); fputs(USAGE_SEPARATOR, out); - fputs(USAGE_HELP, out); - fputs(USAGE_VERSION, out); - fprintf(out, USAGE_MAN_TAIL("last(1)")); + printf(USAGE_HELP_OPTIONS(22)); + printf(USAGE_MAN_TAIL("last(1)")); exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } -static int is_phantom(const struct last_control *ctl, struct utmp *ut) +static int is_phantom(const struct last_control *ctl, struct utmpx *ut) { struct passwd *pw; - char path[32]; + char path[sizeof(ut->ut_line) + 16]; int ret = 0; - if (ut->UL_UT_TIME < ctl->boot_time.tv_sec) + if (ut->ut_tv.tv_sec < ctl->boot_time.tv_sec) return 1; + ut->ut_user[__UT_NAMESIZE - 1] = '\0'; pw = getpwnam(ut->ut_user); if (!pw) return 1; @@ -634,9 +631,9 @@ static int is_phantom(const struct last_control *ctl, struct utmp *ut) static void process_wtmp_file(const struct last_control *ctl, const char *filename) { - FILE *fp; /* Filepointer of wtmp file */ + FILE *fp; /* File pointer of wtmp file */ - struct utmp ut; /* Current utmp entry */ + struct utmpx ut; /* Current utmp entry */ struct utmplist *ulist = NULL; /* All entries */ struct utmplist *p; /* Pointer into utmplist */ struct utmplist *next; /* Pointer into utmplist */ @@ -679,7 +676,7 @@ static void process_wtmp_file(const struct last_control *ctl, * Read first structure to capture the time field */ if (uread(fp, &ut, NULL, filename) == 1) - begintime = ut.UL_UT_TIME; + begintime = ut.ut_tv.tv_sec; else { if (fstat(fileno(fp), &st) != 0) err(EXIT_FAILURE, _("stat of %s failed"), filename); @@ -701,16 +698,16 @@ static void process_wtmp_file(const struct last_control *ctl, if (uread(fp, &ut, &quit, filename) != 1) break; - if (ctl->since && ut.UL_UT_TIME < ctl->since) + if (ctl->since && ut.ut_tv.tv_sec < ctl->since) continue; - if (ctl->until && ctl->until < ut.UL_UT_TIME) + if (ctl->until && ctl->until < ut.ut_tv.tv_sec) continue; - lastdate = ut.UL_UT_TIME; + lastdate = ut.ut_tv.tv_sec; if (ctl->lastb) { - quit = list(ctl, &ut, ut.UL_UT_TIME, R_NORMAL); + quit = list(ctl, &ut, ut.ut_tv.tv_sec, R_NORMAL); continue; } @@ -760,7 +757,7 @@ static void process_wtmp_file(const struct last_control *ctl, strcpy(ut.ut_line, "system down"); quit = list(ctl, &ut, lastboot, R_NORMAL); } - lastdown = lastrch = ut.UL_UT_TIME; + lastdown = lastrch = ut.ut_tv.tv_sec; down = 1; break; case OLD_TIME: @@ -775,7 +772,7 @@ static void process_wtmp_file(const struct last_control *ctl, case BOOT_TIME: strcpy(ut.ut_line, "system boot"); quit = list(ctl, &ut, lastdown, R_REBOOT); - lastboot = ut.UL_UT_TIME; + lastboot = ut.ut_tv.tv_sec; down = 1; break; case RUN_LVL: @@ -785,11 +782,11 @@ static void process_wtmp_file(const struct last_control *ctl, quit = list(ctl, &ut, lastrch, R_NORMAL); } if (x == '0' || x == '6') { - lastdown = ut.UL_UT_TIME; + lastdown = ut.ut_tv.tv_sec; down = 1; ut.ut_type = SHUTDOWN_TIME; } - lastrch = ut.UL_UT_TIME; + lastrch = ut.ut_tv.tv_sec; break; case USER_PROCESS: @@ -802,10 +799,10 @@ static void process_wtmp_file(const struct last_control *ctl, for (p = ulist; p; p = next) { next = p->next; if (strncmp(p->ut.ut_line, ut.ut_line, - UT_LINESIZE) == 0) { + sizeof(ut.ut_line)) == 0) { /* Show it */ if (c == 0) { - quit = list(ctl, &ut, p->ut.UL_UT_TIME, R_NORMAL); + quit = list(ctl, &ut, p->ut.ut_tv.tv_sec, R_NORMAL); c = 1; } if (p->next) @@ -831,7 +828,7 @@ static void process_wtmp_file(const struct last_control *ctl, c = whydown; quit = list(ctl, &ut, lastboot, c); } - /* FALLTHRU */ + /* fallthrough */ case DEAD_PROCESS: /* @@ -841,7 +838,7 @@ static void process_wtmp_file(const struct last_control *ctl, if (ut.ut_line[0] == 0) break; p = xmalloc(sizeof(struct utmplist)); - memcpy(&p->ut, &ut, sizeof(struct utmp)); + memcpy(&p->ut, &ut, sizeof(struct utmpx)); p->next = ulist; p->prev = NULL; if (ulist) @@ -852,12 +849,14 @@ static void process_wtmp_file(const struct last_control *ctl, case EMPTY: case INIT_PROCESS: case LOGIN_PROCESS: +#ifdef ACCOUNTING case ACCOUNTING: +#endif /* ignored ut_types */ break; default: - warnx("unrecogized ut_type: %d", ut.ut_type); + warnx("unrecognized ut_type: %d", ut.ut_type); } /* @@ -865,7 +864,7 @@ static void process_wtmp_file(const struct last_control *ctl, * the entire current ulist. */ if (down) { - lastboot = ut.UL_UT_TIME; + lastboot = ut.ut_tv.tv_sec; whydown = (ut.ut_type == SHUTDOWN_TIME) ? R_DOWN : R_CRASH; for (p = ulist; p; p = next) { next = p->next; @@ -876,7 +875,19 @@ static void process_wtmp_file(const struct last_control *ctl, } } - printf(_("\n%s begins %s"), basename(filename), ctime(&begintime)); + if (ctl->time_fmt != LAST_TIMEFTM_NONE) { + struct last_timefmt *fmt; + char timestr[LAST_TIMESTAMP_LEN]; + char *tmp = xstrdup(filename); + + fmt = &timefmts[ctl->time_fmt]; + if (time_formatter(fmt->in_fmt, timestr, + sizeof(timestr), &begintime) < 0) + errx(EXIT_FAILURE, _("preallocation size exceeded")); + printf(_("\n%s begins %s\n"), basename(tmp), timestr); + free(tmp); + } + fclose(fp); for (p = ulist; p; p = next) { @@ -919,7 +930,7 @@ int main(int argc, char **argv) { "time-format", required_argument, NULL, OPT_TIME_FORMAT }, { NULL, 0, NULL, 0 } }; - static const ul_excl_t excl[] = { /* rows and cols in in ASCII order */ + static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ { 'F', OPT_TIME_FORMAT }, /* fulltime, time-format */ { 0 } }; @@ -940,7 +951,7 @@ int main(int argc, char **argv) switch(c) { case 'h': - usage(&ctl, stdout); + usage(&ctl); break; case 'V': printf(UTIL_LINUX_VERSION); @@ -987,10 +998,10 @@ int main(int argc, char **argv) ctl.until = (time_t) (p / 1000000); break; case 'w': - if (ctl.name_len < UT_NAMESIZE) - ctl.name_len = UT_NAMESIZE; - if (ctl.domain_len < UT_HOSTSIZE) - ctl.domain_len = UT_HOSTSIZE; + if (ctl.name_len < sizeof(((struct utmpx *) 0)->ut_user)) + ctl.name_len = sizeof(((struct utmpx *) 0)->ut_user); + if (ctl.domain_len < sizeof(((struct utmpx *) 0)->ut_host)) + ctl.domain_len = sizeof(((struct utmpx *) 0)->ut_host); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': @@ -1000,8 +1011,7 @@ int main(int argc, char **argv) ctl.time_fmt = which_time_format(optarg); break; default: - usage(&ctl, stderr); - break; + errtryhelp(EXIT_FAILURE); } }