summaryrefslogtreecommitdiffstats
path: root/login-utils
diff options
context:
space:
mode:
authorOndrej Oprala2014-04-29 13:40:32 +0200
committerKarel Zak2014-05-15 13:55:59 +0200
commitc77108b86787cb99b110c3ebabd746052101410a (patch)
tree6f9a4d143aa22a943db96c143eab7bf1852302a2 /login-utils
parentlslogins: also add readutmp.c (diff)
downloadkernel-qcow2-util-linux-c77108b86787cb99b110c3ebabd746052101410a.tar.gz
kernel-qcow2-util-linux-c77108b86787cb99b110c3ebabd746052101410a.tar.xz
kernel-qcow2-util-linux-c77108b86787cb99b110c3ebabd746052101410a.zip
lslogins: pretty printing and extended -l,-g
Diffstat (limited to 'login-utils')
-rw-r--r--login-utils/lslogins.128
-rw-r--r--login-utils/lslogins.c187
2 files changed, 147 insertions, 68 deletions
diff --git a/login-utils/lslogins.1 b/login-utils/lslogins.1
index a961efea4..2075cc494 100644
--- a/login-utils/lslogins.1
+++ b/login-utils/lslogins.1
@@ -54,7 +54,7 @@ Show users without a password.
\fB\-r\fR, \fB\-\-raw\fR
Raw output (no columnation).
.TP
-\fB\-s\fR, \fB\-\-sys\-accs\fR[=\fIUID\fR]
+\fB\-s\fR, \fB\-\-sys\-accs\fR
Show system accounts. These are by the default all accounts with UID below 1000 (non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID
treshold can also be specified explicitly (necessary for some distributions that allocate UIDs
starting from 100, 500 - or an entirely different value - rather than 1000).
@@ -62,7 +62,7 @@ starting from 100, 500 - or an entirely different value - rather than 1000).
\fB\-t\fR, \fB\-\-sort\fR
Sort by user name, rather than UID.
.TP
-\fB\-u\fR, \fB\-\-user\-accs\fR[=\fIUID\fR]
+\fB\-u\fR, \fB\-\-user\-accs\fR
Show user accounts. These are by the default all accounts with UID above 1000 (inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID
treshold can also be specified explicitly (necessary for some distributions that allocate UIDs
starting from 100, 500 - or an entirely different value - rather than 1000).
@@ -82,20 +82,20 @@ Display help information and exit.
Display version information and exit.
-
-Note that switches -a and -x require root priviliges. Otherwise their fields will state <unknown> for each entry.
+Note that the default UID tresholds are read from /etc/login.defs.
+Note that switches -a and -x require root priviliges. Otherwise their fields will state "-" for each entry.
.sp
-.SH COLORS
-Implicit coloring can be disabled as follows:
-.RS
-
-.br
-.BI "touch /etc/terminal-colors.d/lslogins.disable"
-.br
+.\".SH COLORS
+.\"Implicit coloring can be disabled as follows:
+.\".RS
-.RE
-For more details see
-.BR terminal-colors.d (5).
+.\".br
+.\".BI "touch /etc/terminal-colors.d/lslogins.disable"
+.\".br
+.\"
+.\".RE
+.\"For more details see
+.\".BR terminal-colors.d (5).
.SH EXIT STATUS
.TP
0
diff --git a/login-utils/lslogins.c b/login-utils/lslogins.c
index 0f8ed6e5e..d0fe35321 100644
--- a/login-utils/lslogins.c
+++ b/login-utils/lslogins.c
@@ -59,16 +59,18 @@
struct lslogins_coldesc {
const char *name;
const char *help;
+ const char *pretty_name;
double whint; /* width hint */
+ long flag;
};
static int lslogins_flag;
-#define UL_UID_MIN "1000"
-#define UL_UID_MAX "60000"
-#define UL_SYS_UID_MIN "201"
-#define UL_SYS_UID_MAX "999"
+#define UL_UID_MIN 1000
+#define UL_UID_MAX 60000
+#define UL_SYS_UID_MIN 201
+#define UL_SYS_UID_MAX 999
/* we use the value of outmode to determine
* appropriate flags for the libsmartcols table
@@ -85,6 +87,7 @@ enum {
out_newline,
out_raw,
out_nul,
+ out_pretty,
};
struct lslogins_user {
@@ -148,7 +151,7 @@ enum {
COL_SGRPS,
COL_HOME,
COL_SHELL,
- COL_FULLNAME,
+ COL_GECOS,
COL_LAST_LOGIN,
COL_LAST_TTY,
COL_LAST_HOSTNAME,
@@ -168,28 +171,28 @@ enum {
static const char *const status[] = { "0", "1", "-" };
static struct lslogins_coldesc coldescs[] =
{
- [COL_LOGIN] = { "LOGIN", N_("user/system login"), 0.2 },
- [COL_UID] = { "UID", N_("user UID"), 0.05 },
- [COL_NOPASSWD] = { "NOPASSWD", N_("account has a password?"), 1 },
- [COL_NOLOGIN] = { "NOLOGIN", N_("account has a password?"), 1 },
- [COL_LOCKED] = { "LOCKED", N_("account has a password?"), 1 },
- [COL_PGRP] = { "GRP", N_("primary group name"), 0.2 },
- [COL_PGID] = { "GID", N_("primary group GID"), 0.05 },
- [COL_SGRPS] = { "SEC_GRPS", N_("secondary group names and GIDs"), 0.5 },
- [COL_HOME] = { "HOMEDIR", N_("home directory"), 0.3 },
- [COL_SHELL] = { "SHELL", N_("login shell"), 0.1 },
- [COL_FULLNAME] = { "FULLNAME", N_("full user name"), 0.3 },
- [COL_LAST_LOGIN] = { "LAST_LOGIN", N_("date of last login"), 24 },
- [COL_LAST_TTY] = { "LAST_TTY", N_("last tty used"), 0.05 },
- [COL_LAST_HOSTNAME] = { "LAST_HOSTNAME", N_("hostname during the last session"), 0.2},
- [COL_FAILED_LOGIN] = { "FAILED_LOGIN", N_("date of last failed login"), 24 },
- [COL_FAILED_TTY] = { "FAILED_TTY", N_("where did the login fail?"), 0.05 },
- [COL_HUSH_STATUS] = { "HUSHED", N_("User's hush settings"), 1 },
- [COL_PWD_WARN] = { "PWD_WARN", N_("password warn interval"), 24 },
- [COL_PWD_CTIME] = { "PWD_CHANGE", N_("date of last password change"), 24 },
- [COL_PWD_CTIME_MIN] = { "PWD_MIN", N_("number of days required between changes"), 24 },
- [COL_PWD_CTIME_MAX] = { "PWD_MAX", N_("max number of days a password may remain unchanged"), 24 },
- [COL_SELINUX] = { "CONTEXT", N_("the user's security context"), 0.4 },
+ [COL_LOGIN] = { "LOGIN", N_("user/system login"), "Login", 0.2, SCOLS_FL_NOEXTREMES },
+ [COL_UID] = { "UID", N_("user UID"), "UID", 0.05, SCOLS_FL_RIGHT},
+ [COL_NOPASSWD] = { "NOPASSWD", N_("account has a password?"), "No password", 1 },
+ [COL_NOLOGIN] = { "NOLOGIN", N_("account has a password?"), "No login", 1 },
+ [COL_LOCKED] = { "LOCKED", N_("account has a password?"), "Locked", 1 },
+ [COL_PGRP] = { "GROUPS", N_("primary group name"), "Primary group", 0.2 },
+ [COL_PGID] = { "GID", N_("primary group GID"), "GID", 0.05, SCOLS_FL_RIGHT },
+ [COL_SGRPS] = { "SUPP-GROUPS", N_("secondary group names and GIDs"), "Secondary groups", 0.5 },
+ [COL_HOME] = { "HOMEDIR", N_("home directory"), "Home directory", 0.3 },
+ [COL_SHELL] = { "SHELL", N_("login shell"), "Shell", 0.1 },
+ [COL_GECOS] = { "GECOS", N_("full user name"), "Comment field", 0.3, SCOLS_FL_TRUNC },
+ [COL_LAST_LOGIN] = { "LAST-LOGIN", N_("date of last login"), "Last login", 24 },
+ [COL_LAST_TTY] = { "LAST-TTY", N_("last tty used"), "Last terminal", 0.05 },
+ [COL_LAST_HOSTNAME] = { "LAST-HOSTNAME", N_("hostname during the last session"), "Last hostname", 0.2},
+ [COL_FAILED_LOGIN] = { "FAILED-LOGIN", N_("date of last failed login"), "Failed login", 24 },
+ [COL_FAILED_TTY] = { "FAILED-TTY", N_("where did the login fail?"), "Failed login terminal", 0.05 },
+ [COL_HUSH_STATUS] = { "HUSHED", N_("User's hush settings"), "Hushed", 1 },
+ [COL_PWD_WARN] = { "PWD-WARN", N_("password warn interval"), "Days to passwd warning", 24 },
+ [COL_PWD_CTIME] = { "PWD-CHANGE", N_("date of last password change"), "Password changed", 24 },
+ [COL_PWD_CTIME_MIN] = { "PWD-MIN", N_("number of days required between changes"), "Minimal change time", 24 },
+ [COL_PWD_CTIME_MAX] = { "PWD-MAX", N_("max number of days a password may remain unchanged"), "Maximal change time", 24 },
+ [COL_SELINUX] = { "CONTEXT", N_("the user's security context"), "Selinux context", 0.4 },
};
struct lslogins_control {
@@ -211,6 +214,8 @@ struct lslogins_control {
char **ulist;
size_t ulsiz;
+
+ int sel_enabled;
};
/* these have to remain global since there's no other
* reasonable way to pass them for each call of fill_table()
@@ -263,12 +268,13 @@ static void __attribute__((__noreturn__)) usage(FILE *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 last users' failed logins\n"), out);
- fputs(_(" -g, --groups=<GROUPS> Display users belonging to a group in GROUPS\n"), out);
- fputs(_(" -l, --logins=<LOGINS> Display only users from LOGINS\n"), out);
+ fputs(_(" -g, --groups=<groups> Display users belonging to a group in GROUPS\n"), out);
+ fputs(_(" -l, --logins=<logins> Display only users from LOGINS\n"), out);
fputs(_(" --last Show info about the users' last login sessions\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(_(" -o, --output[=<LIST>] Define the columns to output\n"), out);
+ fputs(_(" --notrunc Don't truncate output\n"), out);
+ fputs(_(" -o, --output[=<list>] Define the columns to output\n"), out);
fputs(_(" -r, --raw Display the raw table\n"), out);
fputs(_(" -s, --system-accs Display system accounts\n"), out);
fputs(_(" -t, --sort Sort output by login instead of UID\n"), out);
@@ -276,8 +282,8 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
fputs(_(" -x, --extra Display extra information\n"), out);
fputs(_(" -z, --print0 Delimit user entries with a nul character\n"), out);
fputs(_(" -Z, --context Display the users' security context\n"), out);
- fputs(_(" --path-wtmp Set an alternate path for wtmp\n"), out);
- fputs(_(" --path-btmp Set an alternate path for btmp\n"), out);
+ fputs(_(" --wtmp-file Set an alternate path for wtmp\n"), out);
+ fputs(_(" --btmp-file Set an alternate path for btmp\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(USAGE_HELP, out);
fputs(USAGE_VERSION, out);
@@ -575,7 +581,7 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c
gid_t *list = NULL;
if (get_sgroups(&n, &list, pwd))
- err(1, NULL, strerror(errno));
+ err(1, NULL);
user->sgroups = build_sgroups_string(n, list);
@@ -589,7 +595,7 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c
case COL_SHELL:
user->shell = xstrdup(pwd->pw_shell);
break;
- case COL_FULLNAME:
+ case COL_GECOS:
user->gecos = xstrdup(pwd->pw_gecos);
break;
case COL_LAST_LOGIN:
@@ -741,12 +747,26 @@ static void *user_in_tree(void **rootp, struct lslogins_user *u)
*/
/* get a definitive list of users we want info about... */
+
+static int str_to_uint(char *s, unsigned int *ul)
+{
+ char *end;
+ if (!s || !*s)
+ return -1;
+ *ul = strtoul(s, &end, 0);
+ if (!*end)
+ return 0;
+ return 1;
+}
static int get_ulist(struct lslogins_control *ctl, char *logins, char *groups)
{
char *u, *g;
size_t i = 0, n = 0, *arsiz;
struct group *grp;
+ struct passwd *pwd;
char ***ar;
+ uid_t uid;
+ gid_t gid;
ar = &ctl->ulist;
arsiz = &ctl->ulsiz;
@@ -758,6 +778,13 @@ static int get_ulist(struct lslogins_control *ctl, char *logins, char *groups)
while ((u = strtok(logins, ","))) {
logins = NULL;
+ /* user specified by UID? */
+ if (!str_to_uint(u, &uid)) {
+ pwd = getpwuid(uid);
+ if (!pwd)
+ continue;
+ u = pwd->pw_name;
+ }
(*ar)[i++] = xstrdup(u);
if (i == *arsiz)
@@ -768,7 +795,12 @@ static int get_ulist(struct lslogins_control *ctl, char *logins, char *groups)
while ((g = strtok(groups, ","))) {
groups = NULL;
- grp = getgrnam(g);
+ /* user specified by GID? */
+ if (!str_to_uint(g, &gid))
+ grp = getgrgid(gid);
+ else
+ grp = getgrnam(g);
+
if (!grp)
continue;
@@ -877,13 +909,15 @@ static struct libscols_table *setup_table(void)
case out_raw:
scols_table_enable_raw(tb, 1);
break;
+ case out_pretty:
+ scols_table_enable_noheadings(tb, 1);
default:
break;
}
while (n < ncolumns) {
if (!scols_table_new_column(tb, coldescs[columns[n]].name,
- coldescs[columns[n]].whint, 0))
+ coldescs[columns[n]].whint, coldescs[columns[n]].flag))
goto fail;
++n;
}
@@ -954,7 +988,7 @@ static void fill_table(const void *u, const VISIT which, const int depth __attri
if (scols_line_set_data(ln, n, user->shell))
goto fail;
break;
- case COL_FULLNAME:
+ case COL_GECOS:
if (scols_line_set_data(ln, n, user->gecos))
goto fail;
break;
@@ -1014,7 +1048,31 @@ static void fill_table(const void *u, const VISIT which, const int depth __attri
fail:
exit(1);
}
+static int print_pretty(struct libscols_table *tb)
+{
+ struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
+ struct libscols_column *col;
+ struct libscols_cell *data;
+ struct libscols_line *ln;
+ const char *hstr, *dstr;
+ int n = 0;
+
+ ln = scols_table_get_line(tb, 0);
+ while (!scols_table_next_column(tb, itr, &col)) {
+
+ data = scols_line_get_cell(ln, n);
+ hstr = coldescs[columns[n]].pretty_name;
+ dstr = scols_cell_get_data(data);
+
+ printf("%s:%*c%-36s\n", hstr, 26 - (int)strlen(hstr), ' ', dstr);
+ ++n;
+ }
+
+ scols_free_iter(itr);
+ return 0;
+
+}
static int print_user_table(struct lslogins_control *ctl)
{
tb = setup_table();
@@ -1022,7 +1080,10 @@ static int print_user_table(struct lslogins_control *ctl)
return -1;
twalk(ctl->usertree, fill_table);
- scols_print_table(tb);
+ if (outmode == out_pretty)
+ print_pretty(tb);
+ else
+ scols_print_table(tb);
return 0;
}
@@ -1064,6 +1125,7 @@ int main(int argc, char *argv[])
OPT_VER,
OPT_WTMP,
OPT_BTMP,
+ OPT_NOTRUNC,
};
static const struct option longopts[] = {
@@ -1076,6 +1138,7 @@ int main(int argc, char *argv[])
{ "logins", required_argument, 0, 'l' },
{ "supp-groups", no_argument, 0, 'm' },
{ "newline", no_argument, 0, 'n' },
+ { "notruncate", no_argument, 0, OPT_NOTRUNC },
{ "output", required_argument, 0, 'o' },
{ "last", no_argument, 0, OPT_LAST },
{ "raw", no_argument, 0, 'r' },
@@ -1088,8 +1151,8 @@ int main(int argc, char *argv[])
/* TODO: find a reasonable way to do this for passwd/group/shadow,
* as libc itself doesn't supply any way to get a specific
* entry from a user-specified file */
- { "path-wtmp", required_argument, 0, OPT_WTMP },
- { "path-btmp", required_argument, 0, OPT_BTMP },
+ { "wtmp-file", required_argument, 0, OPT_WTMP },
+ { "btmp-file", required_argument, 0, OPT_BTMP },
#ifdef HAVE_LIBSELINUX
{ "context", no_argument, 0, 'Z' },
#endif
@@ -1159,8 +1222,8 @@ int main(int argc, char *argv[])
lslogins_flag |= F_LAST;
break;
case 's':
- ctl->SYS_UID_MIN = strtoul(getlogindefs_str("SYS_UID_MIN", UL_SYS_UID_MIN), NULL, 0);
- ctl->SYS_UID_MAX = strtoul(getlogindefs_str("SYS_UID_MAX", UL_SYS_UID_MAX), NULL, 0);
+ ctl->SYS_UID_MIN = getlogindefs_num("SYS_UID_MIN", UL_SYS_UID_MIN);
+ ctl->SYS_UID_MAX = getlogindefs_num("SYS_UID_MAX", UL_SYS_UID_MAX);
lslogins_flag |= F_SYSAC;
break;
case 't':
@@ -1168,8 +1231,8 @@ int main(int argc, char *argv[])
lslogins_flag |= F_SORT;
break;
case 'u':
- ctl->UID_MIN = strtoul(getlogindefs_str("UID_MIN", UL_UID_MIN), NULL, 0);
- ctl->UID_MAX = strtoul(getlogindefs_str("UID_MAX", UL_UID_MAX), NULL, 0);
+ ctl->UID_MIN = getlogindefs_num("UID_MIN", UL_UID_MIN);
+ ctl->UID_MAX = getlogindefs_num("UID_MAX", UL_UID_MAX);
lslogins_flag |= F_USRAC;
break;
case OPT_VER:
@@ -1188,19 +1251,28 @@ int main(int argc, char *argv[])
case OPT_BTMP:
path_btmp = optarg;
break;
+ case OPT_NOTRUNC:
+ coldescs[COL_GECOS].flag = 0;
+ break;
case 'Z':
#ifdef HAVE_LIBSELINUX
- if (0 < is_selinux_enabled())
- lslogins_flag |= F_SELINUX;
- else
+ lslogins_flag |= F_SELINUX;
+ ctl->sel_enabled = is_selinux_enabled();
+ if (ctl->sel_enabled == -1)
+ exit(1);
#endif
- err(0, "warning: --context only works on a system with SELinux enabled");
break;
default:
usage(stderr);
}
}
- if (argc != optind)
+ if (argc - optind == 1) {
+ if (strchr(argv[optind], ','))
+ err(EXIT_FAILURE, "%s", "Only one user may be specified. Use -l for multiple users");
+ logins = argv[optind];
+ outmode = out_pretty;
+ }
+ else if (argc != optind)
usage(stderr);
/* lslogins -u -s == lslogins */
@@ -1208,11 +1280,19 @@ int main(int argc, char *argv[])
lslogins_flag &= ~(F_USRAC | F_SYSAC);
if (!ncolumns) {
- columns[ncolumns++] = COL_LOGIN;
- columns[ncolumns++] = COL_UID;
+ if (lslogins_flag & F_SORT) {
+ columns[ncolumns++] = COL_LOGIN;
+ columns[ncolumns++] = COL_UID;
+ }
+ else {
+ columns[ncolumns++] = COL_UID;
+ columns[ncolumns++] = COL_LOGIN;
+ }
columns[ncolumns++] = COL_PGRP;
columns[ncolumns++] = COL_PGID;
- columns[ncolumns++] = COL_FULLNAME;
+ columns[ncolumns++] = COL_LAST_LOGIN;
+
+ want_wtmp = 1;
if (lslogins_flag & F_NOPWD) {
columns[ncolumns++] = COL_NOPASSWD;
@@ -1225,10 +1305,8 @@ int main(int argc, char *argv[])
columns[ncolumns++] = COL_PWD_WARN;
}
if (lslogins_flag & F_LAST) {
- columns[ncolumns++] = COL_LAST_LOGIN;
columns[ncolumns++] = COL_LAST_TTY;
columns[ncolumns++] = COL_LAST_HOSTNAME;
- want_wtmp = 1;
}
if (lslogins_flag & F_FAIL) {
columns[ncolumns++] = COL_FAILED_LOGIN;
@@ -1244,6 +1322,7 @@ int main(int argc, char *argv[])
columns[ncolumns++] = COL_HUSH_STATUS;
columns[ncolumns++] = COL_PWD_CTIME_MIN;
columns[ncolumns++] = COL_PWD_CTIME_MAX;
+ columns[ncolumns++] = COL_GECOS;
}
if (lslogins_flag & F_SELINUX)
columns[ncolumns++] = COL_SELINUX;