From 68657ea2e7dd0998f933183b14714d461d2d261e Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Fri, 16 May 2014 11:14:32 +0200 Subject: lslogins: improve supplementary groups code, add SUPP-GIDS * don't build list, but directly create a string * don't mix IDs and group names on output * add SUPP-GIDS to print only IDs Signed-off-by: Karel Zak --- login-utils/lslogins.c | 153 ++++++++++++++++++------------------------------- 1 file changed, 55 insertions(+), 98 deletions(-) (limited to 'login-utils/lslogins.c') diff --git a/login-utils/lslogins.c b/login-utils/lslogins.c index 2ea0980da..e0c47f27c 100644 --- a/login-utils/lslogins.c +++ b/login-utils/lslogins.c @@ -101,7 +101,8 @@ struct lslogins_user { int nologin; int locked; - char *sgroups; + gid_t *sgroups; + size_t nsgroups; char *pwd_ctime; char *pwd_warn; @@ -162,6 +163,7 @@ enum { COL_PGRP, COL_PGID, COL_SGRPS, + COL_SGIDS, COL_HOME, COL_SHELL, COL_GECOS, @@ -197,13 +199,14 @@ static const char *const status[] = { static struct lslogins_coldesc coldescs[] = { [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_UID] = { "UID", N_("user ID"), "UID", 0.05, SCOLS_FL_RIGHT}, [COL_NOPASSWD] = { "NOPASSWD", N_("account has a password?"), "No password", 1, SCOLS_FL_RIGHT }, [COL_NOLOGIN] = { "NOLOGIN", N_("account has a password?"), "No login", 1, SCOLS_FL_RIGHT }, [COL_LOCKED] = { "LOCKED", N_("account has a password?"), "Locked", 1, SCOLS_FL_RIGHT }, [COL_PGRP] = { "GROUP", 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_PGID] = { "GID", N_("primary group ID"), "GID", 0.05, SCOLS_FL_RIGHT }, + [COL_SGRPS] = { "SUPP-GROUPS", N_("supplementary group names"), "Supplementary groups", 0.1 }, + [COL_SGIDS] = { "SUPP-GIDS", N_("supplementary group IDs"), "Supplementary group IDs", 0.1 }, [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 }, @@ -347,11 +350,6 @@ static void __attribute__((__noreturn__)) usage(FILE *out) exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } -struct lslogins_sgroups { - char *gid; - char *uname; - struct lslogins_sgroups *next; -}; static char *uidtostr(uid_t uid) { @@ -367,93 +365,49 @@ static char *gidtostr(gid_t gid) return str_gid; } -static struct lslogins_sgroups *build_sgroups_list(int len, gid_t *list, int *slen) +static char *build_sgroups_string(gid_t *sgroups, size_t nsgroups, int want_names) { - int n = 0; - struct lslogins_sgroups *sgrps, *retgrps; - struct group *grp; - char *buf = NULL; - - if (!len || !list) - return NULL; + size_t n = 0, maxlen, len; + char *res, *p; - *slen = 0; + len = maxlen = nsgroups * 10; + res = p = xmalloc(maxlen); - retgrps = sgrps = xcalloc(1, sizeof(struct lslogins_sgroups)); - while (n < len) { - if (sgrps->next) - sgrps = sgrps->next; - /* TODO: rewrite */ - sgrps->gid = gidtostr(list[n]); - - grp = getgrgid(list[n]); - if (!grp) { - free(retgrps); - return NULL; + while (n < nsgroups) { + int x; +again: + if (!want_names) + x = snprintf(p, len, "%u,", sgroups[n]); + else { + struct group *grp = getgrgid(sgroups[n]); + if (!grp) { + free(res); + return NULL; + } + x = snprintf(p, len, "%s,", grp->gr_name); } - sgrps->uname = xstrdup(grp->gr_name); - *slen += strlen(sgrps->gid) + strlen(sgrps->uname); + if (x < 0 || (size_t) x + 1 > len) { + size_t cur = p - res; - sgrps->next = xcalloc(1, sizeof(struct lslogins_sgroups)); + maxlen *= 2; + res = xrealloc(res, maxlen); + p = res + cur; + len = maxlen - cur; + goto again; + } + len -= x; + p += x; ++n; } - /* space for a pair of parentheses for each gname + (n - 1) commas in between */ - *slen += 3 * n - 1; - - free(buf); - free(sgrps->next); - sgrps->next = NULL; + if (p > res) + *(p - 1) = '\0'; - return retgrps; -} - -static void free_sgroups_list(struct lslogins_sgroups *sgrps) -{ - struct lslogins_sgroups *tmp; - - if (!sgrps) - return; - - tmp = sgrps->next; - while (tmp) { - free(sgrps->gid); - free(sgrps->uname); - free(sgrps); - sgrps = tmp; - tmp = tmp->next; - } + return res; } -static char *build_sgroups_string(int len, gid_t *list) -{ - char *ret = NULL, *slist; - int slen, prlen; - struct lslogins_sgroups *sgrps; - - sgrps = build_sgroups_list(len, list, &slen); - - if (!sgrps) - return NULL; - - ret = slist = xcalloc(1, sizeof(char) * (slen + 1)); - - while (sgrps->next) { - prlen = sprintf(slist, "%s(%s),", sgrps->gid, sgrps->uname); - if (prlen < 0) { - free_sgroups_list(sgrps); - return NULL; - } - slist += prlen; - sgrps = sgrps->next; - } - prlen = sprintf(slist, "%s(%s)", sgrps->gid, sgrps->uname); - - free_sgroups_list(sgrps); - return ret; -} static struct utmp *get_last_wtmp(struct lslogins_control *ctl, const char *username) { @@ -511,22 +465,22 @@ static int parse_btmp(struct lslogins_control *ctl, char *path) err(EXIT_FAILURE, "%s", path); return rc; } -static int get_sgroups(int *len, gid_t **list, struct passwd *pwd) +static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd) { - int n = 0; + size_t n = 0; *len = 0; *list = NULL; /* first let's get a supp. group count */ - getgrouplist(pwd->pw_name, pwd->pw_gid, *list, len); + getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len); if (!*len) return -1; *list = xcalloc(1, *len * sizeof(gid_t)); /* now for the actual list of GIDs */ - if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, len)) + if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len)) return -1; /* getgroups also returns the user's primary GID - dispose of it */ @@ -623,16 +577,10 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c user->gid = pwd->pw_gid; break; case COL_SGRPS: - { - int n = 0; - gid_t *list = NULL; - - if (get_sgroups(&n, &list, pwd)) - err(1, NULL); - - user->sgroups = build_sgroups_string(n, list); - break; - } + case COL_SGIDS: + if (get_sgroups(&user->sgroups, &user->nsgroups, pwd)) + err(EXIT_FAILURE, _("failed to get supplementary groups")); + break; case COL_HOME: user->homedir = xstrdup(pwd->pw_dir); break; @@ -981,7 +929,16 @@ static void fill_table(const void *u, const VISIT which, const int depth __attri rc = scols_line_refer_data(ln, n, gidtostr(user->gid)); break; case COL_SGRPS: - rc = scols_line_set_data(ln, n, user->sgroups); + rc = scols_line_refer_data(ln, n, + build_sgroups_string(user->sgroups, + user->nsgroups, + TRUE)); + break; + case COL_SGIDS: + rc = scols_line_refer_data(ln, n, + build_sgroups_string(user->sgroups, + user->nsgroups, + FALSE)); break; case COL_HOME: rc = scols_line_set_data(ln, n, user->homedir); -- cgit v1.2.3-55-g7522