summaryrefslogtreecommitdiffstats
path: root/login-utils/lslogins.c
diff options
context:
space:
mode:
authorOndrej Oprala2014-04-22 15:38:27 +0200
committerKarel Zak2014-05-15 13:55:59 +0200
commitdd7760a8c108d8d538b4fb1ca7a46f44d719ca3d (patch)
treeacabfbeaab2a7a0337c3c3802d8aefcfe2fb5cd5 /login-utils/lslogins.c
parentlslogins: add functionality (diff)
downloadkernel-qcow2-util-linux-dd7760a8c108d8d538b4fb1ca7a46f44d719ca3d.tar.gz
kernel-qcow2-util-linux-dd7760a8c108d8d538b4fb1ca7a46f44d719ca3d.tar.xz
kernel-qcow2-util-linux-dd7760a8c108d8d538b4fb1ca7a46f44d719ca3d.zip
lslogins: store users in a tree
Signed-off-by: Ondrej Oprala <ooprala@redhat.com>
Diffstat (limited to 'login-utils/lslogins.c')
-rw-r--r--login-utils/lslogins.c360
1 files changed, 190 insertions, 170 deletions
diff --git a/login-utils/lslogins.c b/login-utils/lslogins.c
index 657a408ab..abea2a4b6 100644
--- a/login-utils/lslogins.c
+++ b/login-utils/lslogins.c
@@ -35,6 +35,8 @@
#include <err.h>
#include <limits.h>
+#include <search.h>
+
#include <libsmartcols.h>
#ifdef HAVE_LIBSELINUX
#include <selinux/selinux.h>
@@ -61,14 +63,20 @@ struct lslogins_coldesc {
double whint; /* width hint */
};
-static struct list_head userlist;
+void *usertree;
+int (*cmp_fn) (const void *a, const void *b);
/* the most uber of flags */
static int uberflag;
+FILE *PWDFILE;
+FILE *GRPFILE;
struct utmp *wtmp, *btmp;
size_t wtmp_size, btmp_size;
int want_wtmp, want_btmp;
+struct libscols_table *tb;
+
+char *PASSWD_PATH = _PATH_PASSWD;
#define UL_UID_MIN "1000"
#define UL_UID_MAX "60000"
#define UL_SYS_UID_MIN "201"
@@ -129,7 +137,6 @@ struct lslogins_user {
char *pwd_status;
int hushed;
- struct list_head ulist;
};
/*
* flags
@@ -202,6 +209,9 @@ static struct lslogins_coldesc coldescs[] =
[COL_SELINUX] = { "CONTEXT", N_("the user's security context"), 0.4 },
};
+int columns[ARRAY_SIZE(coldescs)];
+int ncolumns;
+
static int
column_name_to_id(const char *name, size_t namesz)
{
@@ -252,7 +262,7 @@ static void __attribute__((__noreturn__)) usage(FILE *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, --more Display secondary groups as well\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(_(" -r, --raw Display the raw table\n"), out);
@@ -262,6 +272,10 @@ 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(_("--path-passwd Set an alternate path for passwd\n"), out);
+ fputs(_("--path-shadow Set an alternate path for shadow\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(USAGE_HELP, out);
fputs(USAGE_VERSION, out);
@@ -406,28 +420,17 @@ static struct utmp *get_recent_btmp(const char *username)
}
-static int parse_wtmp(void)
+static int parse_utmp(char *path)
{
int rc = 0;
- rc = read_utmp(_PATH_WTMP, &wtmp_size, &wtmp);
+ rc = read_utmp(path, &wtmp_size, &wtmp);
if (rc < 0 && errno != EACCES)
err(EXIT_FAILURE, "%s: %s", _PATH_WTMP, strerror(errno));
return rc;
return rc;
}
-static int parse_btmp(void)
-{
- int rc = 0;
-
- rc = read_utmp(_PATH_BTMP, &btmp_size, &btmp);
- if (rc < 0 && errno != EACCES)
- err(EXIT_FAILURE, "%s: %s", _PATH_BTMP, strerror(errno));
- return rc;
-
- return rc;
-}
static int get_sgroups(int *len, gid_t **list, struct passwd *pwd)
{
@@ -478,10 +481,9 @@ static struct lslogins_user *get_user_info(const char *username, const int *colu
errno = ENOMEM;
return NULL;
}
- INIT_LIST_HEAD(&user->ulist);
errno = 0;
- pwd = username ? getpwnam(username) : getpwent();
+ pwd = username ? getpwnam(username) : fgetpwent(PWDFILE);
if (!pwd)
return NULL;
@@ -723,26 +725,25 @@ static int get_user(struct lslogins_user **user,
return 0;
}
-static int user_in_list(struct list_head *head, char *uname)
+static void *user_in_tree(void **rootp, struct lslogins_user *u)
{
- struct list_head *p;
- list_for_each(p, head) {
- if (!strcmp(uname, list_entry(p, struct lslogins_user, ulist)->login))
- return 1;
- }
- return 0;
+ void *rc;
+ rc = tfind(u, rootp, cmp_fn);
+ if (!rc)
+ tdelete(u, rootp, cmp_fn);
+ return rc;
}
-static int create_userlist(char *logins, char *groups, const int *const columns, const int ncolumns)
+static int create_usertree(char *logins, char *groups, const int *const columns, const int ncolumns)
{
char *username, *gname;
- struct lslogins_user *user = NULL;
+ struct lslogins_user *user = NULL, tmpuser;
struct group *grp;
int n = 0;
if (!logins && !groups) {
while ((user = get_next_user(columns, ncolumns)))
- list_add(&user->ulist, &userlist);
+ tsearch(user, &usertree, cmp_fn);
HANDLE_ERROR(errno);
}
@@ -752,7 +753,7 @@ static int create_userlist(char *logins, char *groups, const int *const columns,
if (get_user(&user, username, columns, ncolumns))
return -1;
if (user) /* otherwise an invalid user name has probably been given */
- list_add(&user->ulist, &userlist);
+ tsearch(user, &usertree, cmp_fn);
}
}
if (groups) {
@@ -766,36 +767,30 @@ static int create_userlist(char *logins, char *groups, const int *const columns,
}
while ((username = grp->gr_mem[n++])) {
-
- if (!user_in_list(&userlist, username)) {
+ tmpuser.login = username;
+ if (!user_in_tree(&usertree, &tmpuser)) {
if (get_user(&user, username, columns, ncolumns))
return -1;
if (user) /* otherwise an invalid user name has probably been given */
- list_add(&user->ulist, &userlist);
+ tsearch(user, &usertree, cmp_fn);
}
}
}
}
return 0;
}
-static int cmp_uname(struct list_head *a, struct list_head *b, void *data __attribute__((unused)))
-{
- return strcmp(list_entry(a,struct lslogins_user,ulist)->login,
- list_entry(b,struct lslogins_user,ulist)->login);
-}
-static int cmp_uid(struct list_head *a, struct list_head *b, void *data __attribute__((unused)))
+static int cmp_uname(const void *a, const void *b)
{
- return bcmp(&list_entry(a,struct lslogins_user,ulist)->uid,
- &list_entry(b,struct lslogins_user,ulist)->uid,
- sizeof(uid_t));
+ return strcmp(((struct lslogins_user *)a)->login,
+ ((struct lslogins_user *)b)->login);
}
-static void sort_userlist(void)
+static int cmp_uid(const void *a, const void *b)
{
- if (uberflag & F_SORT)
- list_sort(&userlist,cmp_uname, NULL);
- else
- list_sort(&userlist,cmp_uid, NULL);
+ uid_t x = ((struct lslogins_user *)a)->uid;
+ uid_t z = ((struct lslogins_user *)b)->uid;
+ return x > z ? 1 : (x < z ? -1 : 0);
}
+
static struct libscols_table *setup_table(const int *const columns, const int ncolumns)
{
struct libscols_table *tb = scols_new_table();
@@ -836,149 +831,155 @@ fail:
scols_unref_table(tb);
return NULL;
}
-
-static int print_user_table(const int *const columns, const int ncolumns)
+static void fill_table(const void *u, const VISIT which, const int depth __attribute__((unused)))
{
- int n;
- struct list_head *p;
- struct libscols_table *tb;
struct libscols_line *ln;
- struct lslogins_user *user;
-
- tb = setup_table(columns, ncolumns);
- if (!tb)
- return -1;
+ struct lslogins_user *user = *(struct lslogins_user **)u;
+ int n = 0;
- sort_userlist();
+ if ((which == preorder) || (which == endorder))
+ return;
- list_for_each(p, &userlist) {
- user = list_entry(p, struct lslogins_user, ulist);
- n = 0;
- ln = scols_table_new_line(tb, NULL);
- while (n < ncolumns) {
- switch (columns[n]) {
- case COL_LOGIN:
- if (scols_line_set_data(ln, n, user->login))
- goto fail;
- break;
- case COL_UID:
- {
- char *str_uid = uidtostr(user->uid);
- if (!str_uid || scols_line_set_data(ln, n, str_uid))
- goto fail;
- break;
- }
- case COL_NOPASSWD:
- if (scols_line_set_data(ln, n, status[user->nopasswd]))
- goto fail;
- break;
- case COL_NOLOGIN:
- if (scols_line_set_data(ln, n, status[user->nologin]))
- goto fail;
- break;
- case COL_LOCKED:
- if (scols_line_set_data(ln, n, status[user->locked]))
- goto fail;
- break;
- case COL_PGRP:
- if (scols_line_set_data(ln, n, user->group))
- goto fail;
- break;
- case COL_PGID:
- {
- char *str_gid = gidtostr(user->gid);
- if (!str_gid || scols_line_set_data(ln, n, str_gid))
- goto fail;
- break;
- }
- case COL_SGRPS:
- if (scols_line_set_data(ln, n, user->sgroups))
- goto fail;
- break;
- case COL_HOME:
- if (scols_line_set_data(ln, n, user->homedir))
- goto fail;
- break;
- case COL_SHELL:
- if (scols_line_set_data(ln, n, user->shell))
- goto fail;
- break;
- case COL_FULLNAME:
- if (scols_line_set_data(ln, n, user->gecos))
- goto fail;
- break;
- case COL_LAST_LOGIN:
- if (scols_line_set_data(ln, n, user->last_login))
- goto fail;
- break;
- case COL_LAST_TTY:
- if (scols_line_set_data(ln, n, user->last_tty))
- goto fail;
- break;
- case COL_LAST_HOSTNAME:
- if (scols_line_set_data(ln, n, user->last_hostname))
- goto fail;
- break;
- case COL_FAILED_LOGIN:
- if (scols_line_set_data(ln, n, user->failed_login))
- goto fail;
- break;
- case COL_FAILED_TTY:
- if (scols_line_set_data(ln, n, user->failed_tty))
+ ln = scols_table_new_line(tb, NULL);
+ while (n < ncolumns) {
+ switch (columns[n]) {
+ case COL_LOGIN:
+ if (scols_line_set_data(ln, n, user->login))
+ goto fail;
+ break;
+ case COL_UID:
+ {
+ char *str_uid = uidtostr(user->uid);
+ if (!str_uid || scols_line_set_data(ln, n, str_uid))
goto fail;
break;
- case COL_HUSH_STATUS:
- if (scols_line_set_data(ln, n, status[user->hushed]))
+ }
+ case COL_NOPASSWD:
+ if (scols_line_set_data(ln, n, status[user->nopasswd]))
+ goto fail;
+ break;
+ case COL_NOLOGIN:
+ if (scols_line_set_data(ln, n, status[user->nologin]))
+ goto fail;
+ break;
+ case COL_LOCKED:
+ if (scols_line_set_data(ln, n, status[user->locked]))
+ goto fail;
+ break;
+ case COL_PGRP:
+ if (scols_line_set_data(ln, n, user->group))
+ goto fail;
+ break;
+ case COL_PGID:
+ {
+ char *str_gid = gidtostr(user->gid);
+ if (!str_gid || scols_line_set_data(ln, n, str_gid))
goto fail;
break;
+ }
+ case COL_SGRPS:
+ if (scols_line_set_data(ln, n, user->sgroups))
+ goto fail;
+ break;
+ case COL_HOME:
+ if (scols_line_set_data(ln, n, user->homedir))
+ goto fail;
+ break;
+ case COL_SHELL:
+ if (scols_line_set_data(ln, n, user->shell))
+ goto fail;
+ break;
+ case COL_FULLNAME:
+ if (scols_line_set_data(ln, n, user->gecos))
+ goto fail;
+ break;
+ case COL_LAST_LOGIN:
+ if (scols_line_set_data(ln, n, user->last_login))
+ goto fail;
+ break;
+ case COL_LAST_TTY:
+ if (scols_line_set_data(ln, n, user->last_tty))
+ goto fail;
+ break;
+ case COL_LAST_HOSTNAME:
+ if (scols_line_set_data(ln, n, user->last_hostname))
+ goto fail;
+ break;
+ case COL_FAILED_LOGIN:
+ if (scols_line_set_data(ln, n, user->failed_login))
+ goto fail;
+ break;
+ case COL_FAILED_TTY:
+ if (scols_line_set_data(ln, n, user->failed_tty))
+ goto fail;
+ break;
+ case COL_HUSH_STATUS:
+ if (scols_line_set_data(ln, n, status[user->hushed]))
+ goto fail;
+ break;
#define PWD_TIME(S,L,T) strftime((S),(L), "%a %b %d %Y", (T))
- case COL_PWD_EXPIR:
- if (scols_line_set_data(ln, n, user->pwd_expir))
- goto fail;
- break;
- case COL_PWD_CTIME:
- if (scols_line_set_data(ln, n, user->pwd_ctime))
- goto fail;
- break;
- case COL_PWD_CTIME_MIN:
- if (scols_line_set_data(ln, n, user->pwd_ctime_min))
- goto fail;
- break;
- case COL_PWD_CTIME_MAX:
- if (scols_line_set_data(ln, n, user->pwd_ctime_max))
- goto fail;
- break;
+ case COL_PWD_EXPIR:
+ if (scols_line_set_data(ln, n, user->pwd_expir))
+ goto fail;
+ break;
+ case COL_PWD_CTIME:
+ if (scols_line_set_data(ln, n, user->pwd_ctime))
+ goto fail;
+ break;
+ case COL_PWD_CTIME_MIN:
+ if (scols_line_set_data(ln, n, user->pwd_ctime_min))
+ goto fail;
+ break;
+ case COL_PWD_CTIME_MAX:
+ if (scols_line_set_data(ln, n, user->pwd_ctime_max))
+ goto fail;
+ break;
#ifdef HAVE_LIBSELINUX
- case COL_SELINUX:
- if (scols_line_set_data(ln, n, user->context))
- goto fail;
- break;
+ case COL_SELINUX:
+ if (scols_line_set_data(ln, n, user->context))
+ goto fail;
+ break;
#endif
- default:
- /* something went very wrong here */
- err(EXIT_FAILURE, "fatal: unknown error");
- }
- ++n;
+ default:
+ /* something went very wrong here */
+ err(EXIT_FAILURE, "fatal: unknown error");
}
+ ++n;
}
+ return;
+fail:
+ exit(1);
+}
+static int print_user_table(void)
+{
+ tb = setup_table(columns, ncolumns);
+ if (!tb)
+ return -1;
+
+ twalk(usertree, fill_table);
scols_print_table(tb);
scols_unref_table(tb);
return 0;
-fail:
- return -1;
}
-
+static void free_user(void *u)
+{
+ free(u);
+}
int main(int argc, char *argv[])
{
int c;
- int columns[ARRAY_SIZE(coldescs)], ncolumns = 0;
char *logins = NULL, *groups = NULL;
+ char *path_wtmp = _PATH_WTMP, *path_btmp = _PATH_BTMP;
/* long only options. */
enum {
OPT_LAST = CHAR_MAX + 1,
OPT_VER,
+ OPT_WTMP,
+ OPT_BTMP,
+ OPT_PASSWD,
+ OPT_SHADOW,
};
static const struct option longopts[] = {
{ "acc-expiration", no_argument, 0, 'a' },
@@ -988,17 +989,21 @@ int main(int argc, char *argv[])
{ "groups", required_argument, 0, 'g' },
{ "help", no_argument, 0, 'h' },
{ "logins", required_argument, 0, 'l' },
- { "more", no_argument, 0, 'm' },
+ { "supp-groups", no_argument, 0, 'm' },
{ "newline", no_argument, 0, 'n' },
{ "output", required_argument, 0, 'o' },
{ "last", no_argument, 0, OPT_LAST },
{ "raw", no_argument, 0, 'r' },
- { "sys-accs", no_argument, 0, 's' },
- { "sort", no_argument, 0, 't' },
+ { "system-accs", no_argument, 0, 's' },
+ { "sort-by-name", no_argument, 0, 't' },
{ "user-accs", no_argument, 0, 'u' },
{ "version", no_argument, 0, OPT_VER },
{ "extra", no_argument, 0, 'x' },
{ "print0", no_argument, 0, 'z' },
+ { "path-wtmp", required_argument, 0, OPT_WTMP },
+ { "path-btmp", required_argument, 0, OPT_BTMP },
+ { "path-passwd", required_argument, 0, OPT_PASSWD },
+ { "path-shadow", required_argument, 0, OPT_SHADOW },
#ifdef HAVE_LIBSELINUX
{ "context", no_argument, 0, 'Z' },
#endif
@@ -1016,6 +1021,8 @@ int main(int argc, char *argv[])
textdomain(PACKAGE);
atexit(close_stdout);
+ cmp_fn = cmp_uid;
+
while ((c = getopt_long(argc, argv, "acefg:hl:mno:rstuxzZ",
longopts, NULL)) != -1) {
@@ -1077,6 +1084,7 @@ int main(int argc, char *argv[])
uberflag |= F_SYSAC;
break;
case 't':
+ cmp_fn = cmp_uname;
uberflag |= F_SORT;
break;
case 'u':
@@ -1094,6 +1102,17 @@ int main(int argc, char *argv[])
case 'z':
outmode = out_nul;
break;
+ case OPT_WTMP:
+ path_wtmp = optarg;
+ break;
+ case OPT_BTMP:
+ path_btmp = optarg;
+ break;
+ case OPT_PASSWD:
+ PASSWD_PATH = optarg;
+ break;
+ case OPT_SHADOW:
+ break;
case 'Z':
#ifdef HAVE_LIBSELINUX
if (0 < is_selinux_enabled())
@@ -1156,15 +1175,16 @@ int main(int argc, char *argv[])
}
if (want_wtmp)
- parse_wtmp();
+ parse_utmp(path_wtmp);
if (want_btmp)
- parse_btmp();
+ parse_utmp(path_btmp);
- INIT_LIST_HEAD(&userlist);
- if (create_userlist(logins, groups, columns, ncolumns))
+ PWDFILE = fopen(PASSWD_PATH,"r");
+ if (create_usertree(logins, groups, columns, ncolumns))
return EXIT_FAILURE;
- print_user_table(columns, ncolumns);
+ print_user_table();
+ tdestroy(usertree, free_user);
return EXIT_SUCCESS;
}