]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - login-utils/lslogins.c
misc: consolidate smartcols error messages
[thirdparty/util-linux.git] / login-utils / lslogins.c
index 65129658d06636940567555cb2f336a52dbdf18d..ab04c10bb2214f738feed77219ce4ae6deec4e70 100644 (file)
@@ -31,7 +31,7 @@
 #include <shadow.h>
 #include <paths.h>
 #include <time.h>
-#include <utmp.h>
+#include <utmpx.h>
 #include <signal.h>
 #include <err.h>
 #include <limits.h>
@@ -56,6 +56,7 @@
 #include "pathnames.h"
 #include "logindefs.h"
 #include "procutils.h"
+#include "timeutils.h"
 
 /*
  * column description
@@ -242,10 +243,10 @@ static const struct lslogins_coldesc coldescs[] =
 };
 
 struct lslogins_control {
-       struct utmp *wtmp;
+       struct utmpx *wtmp;
        size_t wtmp_size;
 
-       struct utmp *btmp;
+       struct utmpx *btmp;
        size_t btmp_size;
 
        void *usertree;
@@ -293,22 +294,6 @@ static inline size_t err_columns_index(size_t arysz, size_t idx)
 #define add_column(ary, n, id) \
                ((ary)[ err_columns_index(ARRAY_SIZE(ary), (n)) ] = (id))
 
-static struct timeval now;
-
-static int date_is_today(time_t t)
-{
-       if (now.tv_sec == 0)
-               gettimeofday(&now, NULL);
-       return t / (3600 * 24) == now.tv_sec / (3600 * 24);
-}
-
-static int date_is_thisyear(time_t t)
-{
-       if (now.tv_sec == 0)
-               gettimeofday(&now, NULL);
-       return t / (3600 * 24 * 365) == now.tv_sec / (3600 * 24 * 365);
-}
-
 static int column_name_to_id(const char *name, size_t namesz)
 {
        size_t i;
@@ -323,37 +308,44 @@ static int column_name_to_id(const char *name, size_t namesz)
        return -1;
 }
 
+static struct timeval now;
+
 static char *make_time(int mode, time_t time)
 {
-       char *s;
-       struct tm tm;
+       int rc = 0;
        char buf[64] = {0};
 
-       localtime_r(&time, &tm);
-
        switch(mode) {
        case TIME_FULL:
+       {
+               char *s;
+               struct tm tm;
+               localtime_r(&time, &tm);
+
                asctime_r(&tm, buf);
                if (*(s = buf + strlen(buf) - 1) == '\n')
                        *s = '\0';
+               rc = 0;
                break;
+       }
        case TIME_SHORT:
-               if (date_is_today(time))
-                       strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
-               else if (date_is_thisyear(time))
-                       strftime(buf, sizeof(buf), "%b%d/%H:%M", &tm);
-               else
-                       strftime(buf, sizeof(buf), "%Y-%b%d", &tm);
+               rc = strtime_short(&time, &now, UL_SHORTTIME_THISYEAR_HHMM,
+                               buf, sizeof(buf));
                break;
        case TIME_ISO:
-               strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm);
+               rc = strtime_iso(&time, ISO_8601_DATE|ISO_8601_TIME|ISO_8601_TIMEZONE,
+                                  buf, sizeof(buf));
                break;
        case TIME_ISO_SHORT:
-               strftime(buf, sizeof(buf), "%Y-%m-%d", &tm);
+               rc = strtime_iso(&time, ISO_8601_DATE, buf, sizeof(buf));
                break;
        default:
                errx(EXIT_FAILURE, _("unsupported time type"));
        }
+
+       if (rc)
+                errx(EXIT_FAILURE, _("failed to compose time string"));
+
        return xstrdup(buf);
 }
 
@@ -397,7 +389,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;
@@ -418,19 +410,17 @@ again:
        return res;
 }
 
-static struct utmp *get_last_wtmp(struct lslogins_control *ctl, const char *username)
+static struct utmpx *get_last_wtmp(struct lslogins_control *ctl, const char *username)
 {
        size_t n = 0;
-       size_t len;
 
        if (!username)
                return NULL;
 
-       len = strlen(username);
        n = ctl->wtmp_size - 1;
        do {
                if (!strncmp(username, ctl->wtmp[n].ut_user,
-                   len < UT_NAMESIZE ? len : UT_NAMESIZE))
+                            sizeof(ctl->wtmp[0].ut_user)))
                        return ctl->wtmp + n;
        } while (n--);
        return NULL;
@@ -455,40 +445,38 @@ static int require_btmp(void)
        return 0;
 }
 
-static struct utmp *get_last_btmp(struct lslogins_control *ctl, const char *username)
+static struct utmpx *get_last_btmp(struct lslogins_control *ctl, const char *username)
 {
        size_t n = 0;
-       size_t len;
 
        if (!username)
                return NULL;
 
-       len = strlen(username);
        n = ctl->btmp_size - 1;
        do {
                if (!strncmp(username, ctl->btmp[n].ut_user,
-                   len < UT_NAMESIZE ? len : UT_NAMESIZE))
+                            sizeof(ctl->wtmp[0].ut_user)))
                        return ctl->btmp + n;
        }while (n--);
        return NULL;
 
 }
 
-static int read_utmp(char const *file, size_t *nents, struct utmp **res)
+static int read_utmp(char const *file, size_t *nents, struct utmpx **res)
 {
        size_t n_read = 0, n_alloc = 0;
-       struct utmp *utmp = NULL, *u;
+       struct utmpx *utmp = NULL, *u;
 
-       if (utmpname(file) < 0)
+       if (utmpxname(file) < 0)
                return -errno;
 
-       setutent();
+       setutxent();
        errno = 0;
 
-       while ((u = getutent()) != NULL) {
+       while ((u = getutxent()) != NULL) {
                if (n_read == n_alloc) {
                        n_alloc += 32;
-                       utmp = xrealloc(utmp, n_alloc * sizeof (struct utmp));
+                       utmp = xrealloc(utmp, n_alloc * sizeof (struct utmpx));
                }
                utmp[n_read++] = *u;
        }
@@ -497,7 +485,7 @@ static int read_utmp(char const *file, size_t *nents, struct utmp **res)
                return -errno;
        }
 
-       endutent();
+       endutxent();
 
        *nents = n_read;
        *res = utmp;
@@ -528,21 +516,24 @@ static int parse_btmp(struct lslogins_control *ctl, char *path)
 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)
@@ -552,6 +543,7 @@ static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd)
 
        if (*len)
                (*list)[n] = (*list)[--(*len)];
+
        return 0;
 }
 
@@ -575,7 +567,7 @@ static int valid_pwd(const char *str)
        const char *p;
 
        for (p = str; p && *p; p++)
-               if (!isalnum((unsigned int) *p))
+               if (!isalnum((unsigned char) *p))
                        return 0;
        return p > str ? 1 : 0;
 }
@@ -586,7 +578,7 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c
        struct passwd *pwd;
        struct group *grp;
        struct spwd *shadow;
-       struct utmp *user_wtmp = NULL, *user_btmp = NULL;
+       struct utmpx *user_wtmp = NULL, *user_btmp = NULL;
        int n = 0;
        time_t time;
        uid_t uid;
@@ -770,14 +762,6 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c
        return user;
 }
 
-/* some UNIX implementations set errno iff a passwd/grp/...
- * entry was not found. The original UNIX logins(1) utility always
- * ignores invalid login/group names, so we're going to as well.*/
-#define IS_REAL_ERRNO(e) !((e) == ENOENT || (e) == ESRCH || \
-               (e) == EBADF || (e) == EPERM || (e) == EAGAIN)
-
-/* get a definitive list of users we want info about... */
-
 static int str_to_uint(char *s, unsigned int *ul)
 {
        char *end;
@@ -789,6 +773,7 @@ static int str_to_uint(char *s, unsigned int *ul)
        return 1;
 }
 
+/* get a definitive list of users we want info about... */
 static int get_ulist(struct lslogins_control *ctl, char *logins, char *groups)
 {
        char *u, *g;
@@ -826,7 +811,7 @@ static int get_ulist(struct lslogins_control *ctl, char *logins, char *groups)
        }
 
        if (groups) {
-               /* FIXME: this might lead to duplicit entries, although not visible
+               /* FIXME: this might lead to duplicate entries, although not visible
                 * in output, crunching a user's info multiple times is very redundant */
                while ((g = strtok(groups, ","))) {
                        n = 0;
@@ -882,13 +867,18 @@ static struct lslogins_user *get_next_user(struct lslogins_control *ctl)
        return u;
 }
 
+/* some UNIX implementations set errno iff a passwd/grp/...
+ * entry was not found. The original UNIX logins(1) utility always
+ * ignores invalid login/group names, so we're going to as well.*/
+#define IS_REAL_ERRNO(e) !((e) == ENOENT || (e) == ESRCH || \
+               (e) == EBADF || (e) == EPERM || (e) == EAGAIN)
+
 static int get_user(struct lslogins_control *ctl, struct lslogins_user **user,
                    const char *username)
 {
        *user = get_user_info(ctl, username);
-       if (!*user)
-               if (IS_REAL_ERRNO(errno))
-                       return -1;
+       if (!*user && IS_REAL_ERRNO(errno))
+               return -1;
        return 0;
 }
 
@@ -925,7 +915,7 @@ static struct libscols_table *setup_table(struct lslogins_control *ctl)
        int n = 0;
 
        if (!table)
-               errx(EXIT_FAILURE, _("failed to initialize output table"));
+               err(EXIT_FAILURE, _("failed to allocate output table"));
        if (ctl->noheadings)
                scols_table_enable_noheadings(table, 1);
 
@@ -982,6 +972,9 @@ static void fill_table(const void *u, const VISIT which, const int depth __attri
                return;
 
        ln = scols_table_new_line(tb, NULL);
+       if (!ln)
+               err(EXIT_FAILURE, _("failed to allocate output line"));
+
        while (n < ncolumns) {
                int rc = 0;
 
@@ -1077,8 +1070,8 @@ static void fill_table(const void *u, const VISIT which, const int depth __attri
                        err(EXIT_FAILURE, _("internal error: unknown column"));
                }
 
-               if (rc != 0)
-                       err(EXIT_FAILURE, _("failed to set data"));
+               if (rc)
+                       err(EXIT_FAILURE, _("failed to add output data"));
                ++n;
        }
        return;
@@ -1206,7 +1199,7 @@ static void free_user(void *f)
        free(u);
 }
 
-static int parse_time_mode(const char *optarg)
+static int parse_time_mode(const char *s)
 {
        struct lslogins_timefmt {
                const char *name;
@@ -1220,10 +1213,10 @@ static int parse_time_mode(const char *optarg)
        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 timefmts[i].val;
        }
-       errx(EXIT_FAILURE, _("unknown time format: %s"), optarg);
+       errx(EXIT_FAILURE, _("unknown time format: %s"), s);
 }
 
 static void __attribute__((__noreturn__)) usage(FILE *out)
@@ -1453,7 +1446,7 @@ int main(int argc, char *argv[])
                        break;
                }
                default:
-                       usage(stderr);
+                       errtryhelp(EXIT_FAILURE);
                }
        }