]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - term-utils/wall.c
Make the ways of using output stream consistent in usage()
[thirdparty/util-linux.git] / term-utils / wall.c
index 803a02976e5d79b360d9fce88146a3ccac0f0f91..a3fe7d29a6a79be5b1e8e1d0a7016d128630f51e 100644 (file)
 #include <sys/types.h>
 #include <grp.h>
 
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+# include <systemd/sd-login.h>
+# include <systemd/sd-daemon.h>
+#endif
+
 #include "nls.h"
 #include "xalloc.h"
 #include "strutils.h"
 #include "pathnames.h"
 #include "carefulputc.h"
 #include "c.h"
+#include "cctype.h"
 #include "fileutils.h"
 #include "closestream.h"
+#include "timeutils.h"
+#include "pwdutils.h"
 
 #define        TERM_WIDTH      79
 #define        WRITE_TIME_OUT  300             /* in seconds */
@@ -93,8 +101,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -n, --nobanner          do not print banner, works only for root\n"), out);
        fputs(_(" -t, --timeout <timeout> write timeout in seconds\n"), out);
        fputs(USAGE_SEPARATOR, out);
-       fputs(USAGE_HELP, out);
-       fputs(USAGE_VERSION, out);
+       fprintf(out, USAGE_HELP_OPTIONS(25));
        fprintf(out, USAGE_MAN_TAIL("wall(1)"));
 
        exit(EXIT_SUCCESS);
@@ -112,26 +119,26 @@ struct group_workspace {
 #endif
 };
 
-static gid_t get_group_gid(const char *optarg)
+static gid_t get_group_gid(const char *group)
 {
        struct group *gr;
        gid_t gid;
 
-       if ((gr = getgrnam(optarg)))
+       if ((gr = getgrnam(group)))
                return gr->gr_gid;
 
-       gid = strtou32_or_err(optarg, _("invalid group argument"));
+       gid = strtou32_or_err(group, _("invalid group argument"));
        if (!getgrgid(gid))
-               errx(EXIT_FAILURE, _("%s: unknown gid"), optarg);
+               errx(EXIT_FAILURE, _("%s: unknown gid"), group);
 
        return gid;
 }
 
-static struct group_workspace *init_group_workspace(const char *optarg)
+static struct group_workspace *init_group_workspace(const char *group)
 {
        struct group_workspace *buf = xmalloc(sizeof(struct group_workspace));
 
-       buf->requested_group = get_group_gid(optarg);
+       buf->requested_group = get_group_gid(group);
        buf->ngroups = sysconf(_SC_NGROUPS_MAX) + 1;  /* room for the primary gid */
        buf->groups = xcalloc(sizeof(*buf->groups), buf->ngroups);
 
@@ -203,7 +210,7 @@ int main(int argc, char **argv)
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       atexit(close_stdout);
+       close_stdout_atexit();
 
        while ((ch = getopt_long(argc, argv, "nt:g:Vh", longopts, NULL)) != -1) {
                switch (ch) {
@@ -221,9 +228,9 @@ int main(int argc, char **argv)
                case 'g':
                        group_buf = init_group_workspace(optarg);
                        break;
+
                case 'V':
-                       printf(UTIL_LINUX_VERSION);
-                       exit(EXIT_SUCCESS);
+                       print_version(EXIT_SUCCESS);
                case 'h':
                        usage();
                default:
@@ -244,128 +251,95 @@ int main(int argc, char **argv)
 
        iov.iov_base = mbuf;
        iov.iov_len = mbufsize;
-       while((utmpptr = getutxent())) {
-               if (!utmpptr->ut_user[0])
-                       continue;
-#ifdef USER_PROCESS
-               if (utmpptr->ut_type != USER_PROCESS)
-                       continue;
-#endif
-               /* Joey Hess reports that use-sessreg in /etc/X11/wdm/
-                  produces ut_line entries like :0, and a write
-                  to /dev/:0 fails. */
-               if (utmpptr->ut_line[0] == ':')
-                       continue;
-
-               if (group_buf && !is_gr_member(utmpptr->ut_user, group_buf))
-                       continue;
-
-               xstrncpy(line, utmpptr->ut_line, sizeof(utmpptr->ut_line));
-               if ((p = ttymsg(&iov, 1, line, timeout)) != NULL)
-                       warnx("%s", p);
-       }
-       endutxent();
-       free(mbuf);
-       free_group_workspace(group_buf);
-       exit(EXIT_SUCCESS);
-}
 
-struct buffer {
-       size_t  sz;
-       size_t  used;
-       char    *data;
-};
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+       if (sd_booted() > 0) {
+               char **sessions_list;
+               int sessions;
 
-static void buf_enlarge(struct buffer *bs, size_t len)
-{
-       if (bs->sz == 0 || len > bs->sz - bs->used) {
-               bs->sz += len < 128 ? 128 : len;
-               bs->data = xrealloc(bs->data, bs->sz);
-       }
-}
+               sessions = sd_get_sessions(&sessions_list);
+               if (sessions < 0)
+                       errx(EXIT_FAILURE, _("error getting sessions: %s"),
+                               strerror(-sessions));
 
-static void buf_puts(struct buffer *bs, const char *s)
-{
-       size_t len = strlen(s);
+               for (int i = 0; i < sessions; i++) {
+                       char *name, *tty;
+                       int r;
 
-       buf_enlarge(bs, len + 1);
-       memcpy(bs->data + bs->used, s, len + 1);
-       bs->used += len;
-}
+                       if ((r = sd_session_get_username(sessions_list[i], &name)) < 0)
+                               errx(EXIT_FAILURE, _("get user name failed: %s"), strerror (-r));
 
-static void buf_printf(struct buffer *bs, const char *fmt, ...)
-{
-       int rc;
-       va_list ap;
-       size_t limit;
-
-       buf_enlarge(bs, 0);     /* default size */
-       limit = bs->sz - bs->used;
-
-       va_start(ap, fmt);
-       rc = vsnprintf(bs->data + bs->used, limit, fmt, ap);
-       va_end(ap);
-
-       if (rc >= 0 && (size_t) rc >= limit) {  /* not enough, enlarge */
-               buf_enlarge(bs, (size_t)rc + 1);
-               limit = bs->sz - bs->used;
-               va_start(ap, fmt);
-               rc = vsnprintf(bs->data  + bs->used, limit, fmt, ap);
-               va_end(ap);
-       }
+                       if (!(group_buf && !is_gr_member(name, group_buf))) {
+                               if (sd_session_get_tty(sessions_list[i], &tty) >= 0) {
+                                       if ((p = ttymsg(&iov, 1, tty, timeout)) != NULL)
+                                               warnx("%s", p);
 
-       if (rc > 0)
-               bs->used += rc;
-}
+                                       free(tty);
+                               }
+                       }
+                       free(name);
+                       free(sessions_list[i]);
+               }
+               free(sessions_list);
+       } else
+#endif
+       {
+               while ((utmpptr = getutxent())) {
+                       if (!utmpptr->ut_user[0])
+                               continue;
+#ifdef USER_PROCESS
+                       if (utmpptr->ut_type != USER_PROCESS)
+                               continue;
+#endif
+                       /* Joey Hess reports that use-sessreg in /etc/X11/wdm/ produces
+                        * ut_line entries like :0, and a write to /dev/:0 fails.
+                        *
+                        * It also seems that some login manager may produce empty ut_line.
+                        */
+                       if (!*utmpptr->ut_line || *utmpptr->ut_line == ':')
+                               continue;
 
-static void buf_putc_careful(struct buffer *bs, int c)
-{
-       if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n') {
-               buf_enlarge(bs, 1);
-               bs->data[bs->used++] = c;
-       } else if (!isascii(c))
-               buf_printf(bs, "\\%3o", (unsigned char)c);
-       else {
-               char tmp[] = { '^', c ^ 0x40, '\0' };
-               buf_puts(bs, tmp);
+                       if (group_buf && !is_gr_member(utmpptr->ut_user, group_buf))
+                               continue;
+
+                       mem2strcpy(line, utmpptr->ut_line, sizeof(utmpptr->ut_line), sizeof(line));
+                       if ((p = ttymsg(&iov, 1, line, timeout)) != NULL)
+                               warnx("%s", p);
+               }
+               endutxent();
        }
+
+       free(mbuf);
+       free_group_workspace(group_buf);
+       exit(EXIT_SUCCESS);
 }
 
 static char *makemsg(char *fname, char **mvec, int mvecsz,
                     size_t *mbufsize, int print_banner)
 {
-       struct buffer _bs = {.used = 0}, *bs = &_bs;
-       register int ch, cnt;
-       char *p, *lbuf;
-       long line_max;
-
-       line_max = sysconf(_SC_LINE_MAX);
-       if (line_max <= 0)
-               line_max = 512;
-
-       lbuf = xmalloc(line_max);
+       char *lbuf, *retbuf;
+       FILE * fs = open_memstream(&retbuf, mbufsize);
+       size_t lbuflen = 512;
+       lbuf = xmalloc(lbuflen);
 
        if (print_banner == TRUE) {
                char *hostname = xgethostname();
-               char *whom, *where, *date;
-               struct passwd *pw;
+               char *whom, *where, date[CTIME_BUFSIZ];
                time_t now;
 
-               if (!(whom = getlogin()) || !*whom)
-                       whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
+               whom = xgetlogin();
                if (!whom) {
-                       whom = "someone";
+                       whom = "<someone>";
                        warn(_("cannot get passwd uid"));
                }
                where = ttyname(STDOUT_FILENO);
                if (!where) {
                        where = "somewhere";
-                       warn(_("cannot get tty name"));
                } else if (strncmp(where, "/dev/", 5) == 0)
                        where += 5;
 
                time(&now);
-               date = xstrdup(ctime(&now));
+               ctime_r(&now, date);
                date[strlen(date) - 1] = '\0';
 
                /*
@@ -377,16 +351,15 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
                 */
                /* snprintf is not always available, but the sprintf's here
                   will not overflow as long as %d takes at most 100 chars */
-               buf_printf(bs, "\r%*s\r\n", TERM_WIDTH, " ");
+               fprintf(fs, "\r%*s\r\n", TERM_WIDTH, " ");
 
-               snprintf(lbuf, line_max,
+               snprintf(lbuf, lbuflen,
                                _("Broadcast message from %s@%s (%s) (%s):"),
                                whom, hostname, where, date);
-               buf_printf(bs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf);
+               fprintf(fs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf);
                free(hostname);
-               free(date);
        }
-       buf_printf(bs, "%*s\r\n", TERM_WIDTH, " ");
+       fprintf(fs, "%*s\r\n", TERM_WIDTH, " ");
 
         if (mvec) {
                /*
@@ -395,11 +368,11 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
                int i;
 
                for (i = 0; i < mvecsz; i++) {
-                       buf_puts(bs, mvec[i]);
+                       fputs(mvec[i], fs);
                        if (i < mvecsz - 1)
-                               buf_puts(bs, " ");
+                               fputc(' ', fs);
                }
-               buf_puts(bs, "\r\n");
+               fputs("\r\n", fs);
        } else {
                /*
                 * read message from <file>
@@ -424,26 +397,13 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
                /*
                 * Read message from stdin.
                 */
-               while (fgets(lbuf, line_max, stdin)) {
-                       for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
-                               if (cnt == TERM_WIDTH || ch == '\n') {
-                                       for (; cnt < TERM_WIDTH; ++cnt)
-                                               buf_puts(bs, " ");
-                                       buf_puts(bs, "\r\n");
-                                       cnt = 0;
-                               }
-                               if (ch == '\t')
-                                       cnt += (7 - (cnt % 8));
-                               if (ch != '\n')
-                                       buf_putc_careful(bs, ch);
-                       }
-               }
+               while (getline(&lbuf, &lbuflen, stdin) >= 0)
+                       fputs_careful(lbuf, fs, '^', true, TERM_WIDTH);
        }
-       buf_printf(bs, "%*s\r\n", TERM_WIDTH, " ");
+       fprintf(fs, "%*s\r\n", TERM_WIDTH, " ");
 
        free(lbuf);
 
-       bs->data[bs->used] = '\0';      /* be paranoid */
-       *mbufsize = bs->used;
-       return bs->data;
+       fclose(fs);
+       return retbuf;
 }