]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/utmp-wtmp.c
tree-wide: drop license boilerplate
[thirdparty/systemd.git] / src / shared / utmp-wtmp.c
index 32996fad36cd711fcf03a12286742bbd35de05cd..314488ab8f2e14d141c8fded87a100de4502f7b9 100644 (file)
@@ -1,35 +1,32 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
   Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <utmpx.h>
 #include <errno.h>
-#include <assert.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <sys/time.h>
 #include <sys/utsname.h>
-#include <fcntl.h>
 #include <unistd.h>
-#include <sys/poll.h>
+#include <utmpx.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "hostname-util.h"
 #include "macro.h"
 #include "path-util.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "time-util.h"
+#include "user-util.h"
+#include "util.h"
 #include "utmp-wtmp.h"
 
 int utmp_get_runlevel(int *runlevel, int *previous) {
@@ -92,8 +89,6 @@ int utmp_get_runlevel(int *runlevel, int *previous) {
 static void init_timestamp(struct utmpx *store, usec_t t) {
         assert(store);
 
-        zero(*store);
-
         if (t <= 0)
                 t = now(CLOCK_REALTIME);
 
@@ -143,7 +138,7 @@ static int write_entry_wtmp(const struct utmpx *store) {
         assert(store);
 
         /* wtmp is a simple append-only file where each entry is
-        simply appended to the end; i.e. basically a log. */
+        simply appended to the end; i.e. basically a log. */
 
         errno = 0;
         updwtmpx(_PATH_WTMPX, store);
@@ -172,7 +167,7 @@ static int write_entry_both(const struct utmpx *store) {
 }
 
 int utmp_put_shutdown(void) {
-        struct utmpx store;
+        struct utmpx store = {};
 
         init_entry(&store, 0);
 
@@ -183,7 +178,7 @@ int utmp_put_shutdown(void) {
 }
 
 int utmp_put_reboot(usec_t t) {
-        struct utmpx store;
+        struct utmpx store = {};
 
         init_entry(&store, t);
 
@@ -205,34 +200,56 @@ _pure_ static const char *sanitize_id(const char *id) {
         return id + l - sizeof(((struct utmpx*) NULL)->ut_id);
 }
 
-int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) {
-        struct utmpx store;
+int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user) {
+        struct utmpx store = {
+                .ut_type = INIT_PROCESS,
+                .ut_pid = pid,
+                .ut_session = sid,
+        };
+        int r;
 
         assert(id);
 
         init_timestamp(&store, 0);
 
-        store.ut_type = INIT_PROCESS;
-        store.ut_pid = pid;
-        store.ut_session = sid;
-
+        /* ut_id needs only be nul-terminated if it is shorter than sizeof(ut_id) */
         strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id));
 
         if (line)
                 strncpy(store.ut_line, basename(line), sizeof(store.ut_line));
 
-        return write_entry_both(&store);
+        r = write_entry_both(&store);
+        if (r < 0)
+                return r;
+
+        if (IN_SET(ut_type, LOGIN_PROCESS, USER_PROCESS)) {
+                store.ut_type = LOGIN_PROCESS;
+                r = write_entry_both(&store);
+                if (r < 0)
+                        return r;
+        }
+
+        if (ut_type == USER_PROCESS) {
+                store.ut_type = USER_PROCESS;
+                strncpy(store.ut_user, user, sizeof(store.ut_user)-1);
+                r = write_entry_both(&store);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
 }
 
 int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
-        struct utmpx lookup, store, store_wtmp, *found;
+        struct utmpx lookup = {
+                .ut_type = INIT_PROCESS /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
+        }, store, store_wtmp, *found;
 
         assert(id);
 
         setutxent();
 
-        zero(lookup);
-        lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
+        /* ut_id needs only be nul-terminated if it is shorter than sizeof(ut_id) */
         strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id));
 
         found = getutxid(&lookup);
@@ -260,7 +277,7 @@ int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
 
 
 int utmp_put_runlevel(int runlevel, int previous) {
-        struct utmpx store;
+        struct utmpx store = {};
         int r;
 
         assert(runlevel > 0);
@@ -300,7 +317,7 @@ static int write_to_terminal(const char *tty, const char *message) {
         assert(tty);
         assert(message);
 
-        fd = open(tty, O_WRONLY|O_NDELAY|O_NOCTTY|O_CLOEXEC);
+        fd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
         if (fd < 0 || !isatty(fd))
                 return -errno;
 
@@ -347,25 +364,38 @@ static int write_to_terminal(const char *tty, const char *message) {
         return 0;
 }
 
-int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) {
-        _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL;
+int utmp_wall(
+        const char *message,
+        const char *username,
+        const char *origin_tty,
+        bool (*match_tty)(const char *tty, void *userdata),
+        void *userdata) {
+
+        _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
         char date[FORMAT_TIMESTAMP_MAX];
         struct utmpx *u;
         int r;
 
         hn = gethostname_malloc();
-        un = getlogname_malloc();
-        if (!hn || !un)
+        if (!hn)
                 return -ENOMEM;
+        if (!username) {
+                un = getlogname_malloc();
+                if (!un)
+                        return -ENOMEM;
+        }
 
-        getttyname_harder(STDIN_FILENO, &tty);
+        if (!origin_tty) {
+                getttyname_harder(STDIN_FILENO, &stdin_tty);
+                origin_tty = stdin_tty;
+        }
 
         if (asprintf(&text,
                      "\a\r\n"
                      "Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
                      "%s\r\n\r\n",
-                     un, hn,
-                     tty ? " on " : "", strempty(tty),
+                     un ?: username, hn,
+                     origin_tty ? " on " : "", strempty(origin_tty),
                      format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)),
                      message) < 0)
                 return -ENOMEM;
@@ -382,7 +412,7 @@ int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) {
                 if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
                         continue;
 
-                /* this access is fine, because strlen("/dev/") << 32 (UT_LINESIZE) */
+                /* this access is fine, because STRLEN("/dev/") << 32 (UT_LINESIZE) */
                 if (path_startswith(u->ut_line, "/dev/"))
                         path = u->ut_line;
                 else {
@@ -392,7 +422,7 @@ int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) {
                         path = buf;
                 }
 
-                if (!match_tty || match_tty(path)) {
+                if (!match_tty || match_tty(path, userdata)) {
                         q = write_to_terminal(path, text);
                         if (q < 0)
                                 r = q;