diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h --- util-linux-2.23.2/include/pathnames.h.kzak 2016-03-16 15:17:42.648298525 +0100 +++ util-linux-2.23.2/include/pathnames.h 2016-03-16 15:18:13.769055345 +0100 @@ -36,6 +36,7 @@ #endif #define _PATH_MOTDFILE "/etc/motd" #define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_VAR_NOLOGIN "/var/run/nologin" #define _PATH_LOGIN "/bin/login" #define _PATH_INITTAB "/etc/inittab" diff -up util-linux-2.23.2/login-utils/lslogins.1.kzak util-linux-2.23.2/login-utils/lslogins.1 --- util-linux-2.23.2/login-utils/lslogins.1.kzak 2016-03-16 15:17:42.639298595 +0100 +++ util-linux-2.23.2/login-utils/lslogins.1 2016-03-16 15:18:13.769055345 +0100 @@ -5,7 +5,10 @@ lslogins \- display information about known users in the system .SH SYNOPSIS .B lslogins -[\fIoptions\fR] [\fB-s\fR|\fB-u\fR[=\fIUID\fR]] [\fB-g \fIgroups\fR] [\fB-l \fIlogins\fR] +[options] +.RB [ \-s | \-u [ =\fIUID ]] +.RB [ \-g " \fIgroups\fR]" +.RB [ \-l " \fIlogins\fR]" .SH DESCRIPTION .PP Examine the wtmp and btmp logs, /etc/shadow (if necessary) and /etc/passwd @@ -17,7 +20,7 @@ Mandatory arguments to long options are .TP \fB\-a\fR, \fB\-\-acc\-expiration\fR Display data about the date of last password change and the account expiration -date (see \fBshadow\fR(5) for more info). (Requires root priviliges.) +date (see \fBshadow\fR(5) for more info). (Requires root privileges.) .TP \fB\-\-btmp\-file \fIpath\fP Alternate path for btmp. @@ -31,7 +34,7 @@ Output data in the format of NAME=VALUE. \fB\-f\fR, \fB\-\-failed\fR Display data about the users' last failed login attempts. .TP -\fB\-G\fR, \fB\-\-groups\-info\fR +\fB\-G\fR, \fB\-\-supp\-groups\fR Show information about groups. .TP \fB\-g\fR, \fB\-\-groups\fR=\fIgroups\fR @@ -48,9 +51,6 @@ Display data containing information abou Only show data of users with a login specified in \fIlogins\fR (user names or user IDS). More than one login may be specified; the list has to be comma-separated. .TP -\fB\-m\fR, \fB\-\-supp\-groups\fR -Show supplementary groups. -.TP \fB\-n\fR, \fB\-\-newline\fR Display each piece of information on a separate line. .TP @@ -71,21 +71,21 @@ Display information related to login by \fB\-r\fR, \fB\-\-raw\fR Raw output (no columnation). .TP -\fB\-s\fR, \fB\-\-system\-accs\fR[=\fIthreshold\fR] +\fB\-s\fR, \fB\-\-system\-accs\fR Show system accounts. These are by default all accounts with a UID below 1000 -(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID -threshold can also be specified explicitly (necessary for some distributions that -allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). +(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). +This hardcoded default maybe overwritten by parameters SYS_UID_MIN and SYS_UID_MAX in +the file /etc/login.defs. .TP -\fB\-\-time-format\fR \fItype\fP +\fB\-\-time\-format\fR \fItype\fP Display dates in short, full or iso format. The default is short, this time format is designed to be space efficient and human readable. .TP -\fB\-u\fR, \fB\-\-user\-accs\fR[=\fIthreshold\fR] +\fB\-u\fR, \fB\-\-user\-accs\fR Show user accounts. These are by default all accounts with UID above 1000 -(inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID -threshold can also be specified explicitly (necessary for some distributions that -allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). +(inclusive), with the exception of either nobody or nfsnobody (UID 65534). +This hardcoded default maybe overwritten by parameters UID_MIN and UID_MAX in +the file /etc/login.defs. .TP \fB\-V\fR, \fB\-\-version\fR Display version information and exit. diff -up util-linux-2.23.2/login-utils/lslogins.c.kzak util-linux-2.23.2/login-utils/lslogins.c --- util-linux-2.23.2/login-utils/lslogins.c.kzak 2016-03-16 15:17:42.639298595 +0100 +++ util-linux-2.23.2/login-utils/lslogins.c 2016-03-16 15:22:49.845899268 +0100 @@ -144,6 +144,7 @@ enum { TIME_SHORT, TIME_FULL, TIME_ISO, + TIME_ISO_SHORT, }; /* @@ -350,6 +351,9 @@ static char *make_time(int mode, time_t case TIME_ISO: strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm); break; + case TIME_ISO_SHORT: + strftime(buf, sizeof(buf), "%Y-%m-%d", &tm); + break; default: errx(EXIT_FAILURE, _("unsupported time type")); } @@ -396,7 +400,7 @@ again: x = snprintf(p, len, "%s,", grp->gr_name); } - if (x < 0 || (size_t) x + 1 > len) { + if (x < 0 || (size_t) x >= len) { size_t cur = p - res; maxlen *= 2; @@ -496,21 +500,24 @@ static int parse_btmp(struct lslogins_co static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd) { size_t n = 0; + int ngroups = 0; *len = 0; *list = NULL; /* first let's get a supp. group count */ - getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len); - if (!*len) + getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups); + if (!ngroups) return -1; - *list = xcalloc(1, *len * sizeof(gid_t)); + *list = xcalloc(1, ngroups * sizeof(gid_t)); /* now for the actual list of GIDs */ - if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len)) + if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups)) return -1; + *len = (size_t) ngroups; + /* getgroups also returns the user's primary GID - dispose of it */ while (n < *len) { if ((*list)[n] == pwd->pw_gid) @@ -520,6 +527,7 @@ static int get_sgroups(gid_t **list, siz if (*len) (*list)[n] = (*list)[--(*len)]; + return 0; } @@ -685,8 +693,8 @@ static struct lslogins_user *get_user_in if (strstr(pwd->pw_shell, "nologin")) user->nologin = 1; else if (pwd->pw_uid) - user->nologin = access("/etc/nologin", F_OK) == 0 || - access("/var/run/nologin", F_OK) == 0; + user->nologin = access(_PATH_NOLOGIN, F_OK) == 0 || + access(_PATH_VAR_NOLOGIN, F_OK) == 0; break; case COL_PWD_WARN: if (shadow && shadow->sp_warn >= 0) @@ -694,7 +702,8 @@ static struct lslogins_user *get_user_in break; case COL_PWD_EXPIR: if (shadow && shadow->sp_expire >= 0) - user->pwd_expire = make_time(TIME_SHORT, + user->pwd_expire = make_time(ctl->time_mode == TIME_ISO ? + TIME_ISO_SHORT : ctl->time_mode, shadow->sp_expire * 86400); break; case COL_PWD_CTIME: @@ -702,7 +711,8 @@ static struct lslogins_user *get_user_in * (especially in non-GMT timezones) would only serve * to confuse */ if (shadow) - user->pwd_ctime = make_time(TIME_SHORT, + user->pwd_ctime = make_time(ctl->time_mode == TIME_ISO ? + TIME_ISO_SHORT : ctl->time_mode, shadow->sp_lstchg * 86400); break; case COL_PWD_CTIME_MIN: @@ -852,7 +862,7 @@ static int get_user(struct lslogins_cont const char *username) { *user = get_user_info(ctl, username); - if (!*user && errno) + if (!*user) if (IS_REAL_ERRNO(errno)) return -1; return 0; @@ -887,33 +897,33 @@ static int create_usertree(struct lslogi static struct libscols_table *setup_table(struct lslogins_control *ctl) { - struct libscols_table *tb = scols_new_table(); + struct libscols_table *table = scols_new_table(); int n = 0; - if (!tb) + if (!table) errx(EXIT_FAILURE, _("failed to initialize output table")); if (ctl->noheadings) - scols_table_enable_noheadings(tb, 1); + scols_table_enable_noheadings(table, 1); switch(outmode) { case OUT_COLON: - scols_table_enable_raw(tb, 1); - scols_table_set_column_separator(tb, ":"); + scols_table_enable_raw(table, 1); + scols_table_set_column_separator(table, ":"); break; case OUT_NEWLINE: - scols_table_set_column_separator(tb, "\n"); + scols_table_set_column_separator(table, "\n"); /* fallthrough */ case OUT_EXPORT: - scols_table_enable_export(tb, 1); + scols_table_enable_export(table, 1); break; case OUT_NUL: - scols_table_set_line_separator(tb, "\0"); + scols_table_set_line_separator(table, "\0"); /* fallthrough */ case OUT_RAW: - scols_table_enable_raw(tb, 1); + scols_table_enable_raw(table, 1); break; case OUT_PRETTY: - scols_table_enable_noheadings(tb, 1); + scols_table_enable_noheadings(table, 1); default: break; } @@ -924,7 +934,7 @@ static struct libscols_table *setup_tabl if (ctl->notrunc) flags &= ~SCOLS_FL_TRUNC; - if (!scols_table_new_column(tb, + if (!scols_table_new_column(table, coldescs[columns[n]].name, coldescs[columns[n]].whint, flags)) @@ -932,9 +942,9 @@ static struct libscols_table *setup_tabl ++n; } - return tb; + return table; fail: - scols_unref_table(tb); + scols_unref_table(table); return NULL; } @@ -1050,10 +1060,10 @@ static void fill_table(const void *u, co return; } #ifdef HAVE_LIBSYSTEMD -static void print_journal_tail(const char *journal_path, uid_t uid, size_t len) +static void print_journal_tail(const char *journal_path, uid_t uid, size_t len, int time_mode) { sd_journal *j; - char *match, *buf; + char *match, *timestamp; uint64_t x; time_t t; const char *identifier, *pid, *message; @@ -1064,7 +1074,6 @@ static void print_journal_tail(const cha else sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); - buf = xmalloc(sizeof(char) * 16); xasprintf(&match, "_UID=%d", uid); sd_journal_add_match(j, match, 0); @@ -1074,37 +1083,35 @@ static void print_journal_tail(const cha do { if (0 > sd_journal_get_data(j, "SYSLOG_IDENTIFIER", (const void **) &identifier, &identifier_len)) - return; + goto done; if (0 > sd_journal_get_data(j, "_PID", (const void **) &pid, &pid_len)) - return; + goto done; if (0 > sd_journal_get_data(j, "MESSAGE", (const void **) &message, &message_len)) - return; + goto done; sd_journal_get_realtime_usec(j, &x); t = x / 1000000; - strftime(buf, 16, "%b %d %H:%M:%S", localtime(&t)); - - fprintf(stdout, "%s", buf); - + timestamp = make_time(time_mode, t); + /* Get rid of journal entry field identifiers */ identifier = strchr(identifier, '=') + 1; - pid = strchr(pid, '=') + 1 ; + pid = strchr(pid, '=') + 1; message = strchr(message, '=') + 1; - fprintf(stdout, " %s", identifier); - fprintf(stdout, "[%s]:", pid); - fprintf(stdout, "%s\n", message); + fprintf(stdout, "%s %s[%s]: %s\n", timestamp, identifier, pid, + message); + free(timestamp); } while (sd_journal_next(j)); - free(buf); +done: free(match); sd_journal_flush_matches(j); sd_journal_close(j); } #endif -static int print_pretty(struct libscols_table *tb) +static int print_pretty(struct libscols_table *table) { struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD); struct libscols_column *col; @@ -1113,8 +1120,8 @@ static int print_pretty(struct libscols_ const char *hstr, *dstr; int n = 0; - ln = scols_table_get_line(tb, 0); - while (!scols_table_next_column(tb, itr, &col)) { + ln = scols_table_get_line(table, 0); + while (!scols_table_next_column(table, itr, &col)) { data = scols_line_get_cell(ln, n); @@ -1142,7 +1149,7 @@ static int print_user_table(struct lslog print_pretty(tb); #ifdef HAVE_LIBSYSTEMD fprintf(stdout, _("\nLast logs:\n")); - print_journal_tail(ctl->journal_path, ctl->uid, 3); + print_journal_tail(ctl->journal_path, ctl->uid, 3, ctl->time_mode); fputc('\n', stdout); #endif } else @@ -1175,16 +1182,25 @@ static void free_user(void *f) free(u); } -struct lslogins_timefmt { - const char *name; - int val; -}; +static int parse_time_mode(const char *optarg) +{ + struct lslogins_timefmt { + const char *name; + const int val; + }; + static const struct lslogins_timefmt timefmts[] = { + {"iso", TIME_ISO}, + {"full", TIME_FULL}, + {"short", TIME_SHORT}, + }; + size_t i; -static struct lslogins_timefmt timefmts[] = { - { "short", TIME_SHORT }, - { "full", TIME_FULL }, - { "iso", TIME_ISO }, -}; + for (i = 0; i < ARRAY_SIZE(timefmts); i++) { + if (strcmp(timefmts[i].name, optarg) == 0) + return timefmts[i].val; + } + errx(EXIT_FAILURE, _("unknown time format: %s"), optarg); +} static void __attribute__((__noreturn__)) usage(FILE *out) { @@ -1193,16 +1209,18 @@ static void __attribute__((__noreturn__) fputs(USAGE_HEADER, out); fprintf(out, _(" %s [options]\n"), program_invocation_short_name); + fputs(USAGE_SEPARATOR, out); + fputs(_("Display information about known users in the system.\n"), out); + fputs(USAGE_OPTIONS, out); fputs(_(" -a, --acc-expiration display info about passwords expiration\n"), out); fputs(_(" -c, --colon-separate display data in a format similar to /etc/passwd\n"), out); fputs(_(" -e, --export display in an export-able output format\n"), out); fputs(_(" -f, --failed display data about the users' last failed logins\n"), out); - fputs(_(" -G, --groups-info display information about groups\n"), out); + fputs(_(" -G, --supp-groups display information about groups\n"), out); fputs(_(" -g, --groups= display users belonging to a group in \n"), out); fputs(_(" -L, --last show info about the users' last login sessions\n"), out); fputs(_(" -l, --logins= display only users from \n"), out); - fputs(_(" -m, --supp-groups display supplementary groups as well\n"), out); fputs(_(" -n, --newline display each piece of information on a new line\n"), out); fputs(_(" --noheadings don't print headings\n"), out); fputs(_(" --notruncate don't truncate output\n"), out); @@ -1226,7 +1244,7 @@ static void __attribute__((__noreturn__) fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); - fprintf(out, _("\nFor more details see lslogins(1).\n")); + fprintf(out, USAGE_MAN_TAIL("lslogins(1)")); exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } @@ -1241,8 +1259,7 @@ int main(int argc, char *argv[]) /* long only options. */ enum { - OPT_VER = CHAR_MAX + 1, - OPT_WTMP, + OPT_WTMP = CHAR_MAX + 1, OPT_BTMP, OPT_NOTRUNC, OPT_NOHEAD, @@ -1300,7 +1317,7 @@ int main(int argc, char *argv[]) add_column(columns, ncolumns++, COL_UID); add_column(columns, ncolumns++, COL_USER); - while ((c = getopt_long(argc, argv, "acfGg:hLl:no:prsuVxzZ", + while ((c = getopt_long(argc, argv, "acefGg:hLl:no:prsuVzZ", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -1394,18 +1411,7 @@ int main(int argc, char *argv[]) ctl->noheadings = 1; break; case OPT_TIME_FMT: - { - size_t i; - - for (i = 0; i < ARRAY_SIZE(timefmts); i++) { - if (strcmp(timefmts[i].name, optarg) == 0) { - ctl->time_mode = timefmts[i].val; - break; - } - } - if (ctl->time_mode == TIME_INVALID) - usage(stderr); - } + ctl->time_mode = parse_time_mode(optarg); break; case 'V': printf(UTIL_LINUX_VERSION); @@ -1433,7 +1439,7 @@ int main(int argc, char *argv[]) logins = argv[optind]; outmode = OUT_PRETTY; } else if (argc != optind) - usage(stderr); + errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users.")); scols_init_debug(0);