summaryrefslogtreecommitdiff
path: root/src/shared/utmp-wtmp.c
diff options
context:
space:
mode:
authorSven Eden <yamakuzure@gmx.net>2017-03-14 11:30:17 +0100
committerSven Eden <yamakuzure@gmx.net>2017-03-14 12:12:32 +0100
commit3d1092eab0f4a5c771225c78072a7b6eccb82849 (patch)
tree2b1603e5a0aa1e7e42f4bb9bbcac73bfac46e63d /src/shared/utmp-wtmp.c
parentd76bb3c179b7a32b109e39aa87ff09c8f5a8c178 (diff)
Major cleanup of all leftovers after rebasing on master.
The patching of elogind in several steps with only partly rebasing on a common commit with upstream, left the tree in a state, that was unmergeable with master. By rebasing on master and manually cleaning up all commits, this merge is now possible. However, this process left some orphans, that are cleanup now.
Diffstat (limited to 'src/shared/utmp-wtmp.c')
-rw-r--r--src/shared/utmp-wtmp.c408
1 files changed, 0 insertions, 408 deletions
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
deleted file mode 100644
index 6fa9a3d7a..000000000
--- a/src/shared/utmp-wtmp.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <string.h>
-#include <sys/utsname.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <poll.h>
-
-#include "macro.h"
-#include "path-util.h"
-#include "terminal-util.h"
-#include "hostname-util.h"
-#include "utmp-wtmp.h"
-
-int utmp_get_runlevel(int *runlevel, int *previous) {
- struct utmpx *found, lookup = { .ut_type = RUN_LVL };
- int r;
- const char *e;
-
- assert(runlevel);
-
- /* If these values are set in the environment this takes
- * precedence. Presumably, sysvinit does this to work around a
- * race condition that would otherwise exist where we'd always
- * go to disk and hence might read runlevel data that might be
- * very new and does not apply to the current script being
- * executed. */
-
- e = getenv("RUNLEVEL");
- if (e && e[0] > 0) {
- *runlevel = e[0];
-
- if (previous) {
- /* $PREVLEVEL seems to be an Upstart thing */
-
- e = getenv("PREVLEVEL");
- if (e && e[0] > 0)
- *previous = e[0];
- else
- *previous = 0;
- }
-
- return 0;
- }
-
- if (utmpxname(_PATH_UTMPX) < 0)
- return -errno;
-
- setutxent();
-
- found = getutxid(&lookup);
- if (!found)
- r = -errno;
- else {
- int a, b;
-
- a = found->ut_pid & 0xFF;
- b = (found->ut_pid >> 8) & 0xFF;
-
- *runlevel = a;
- if (previous)
- *previous = b;
-
- r = 0;
- }
-
- endutxent();
-
- return r;
-}
-
-static void init_timestamp(struct utmpx *store, usec_t t) {
- assert(store);
-
- if (t <= 0)
- t = now(CLOCK_REALTIME);
-
- store->ut_tv.tv_sec = t / USEC_PER_SEC;
- store->ut_tv.tv_usec = t % USEC_PER_SEC;
-}
-
-static void init_entry(struct utmpx *store, usec_t t) {
- struct utsname uts = {};
-
- assert(store);
-
- init_timestamp(store, t);
-
- if (uname(&uts) >= 0)
- strncpy(store->ut_host, uts.release, sizeof(store->ut_host));
-
- strncpy(store->ut_line, "~", sizeof(store->ut_line)); /* or ~~ ? */
- strncpy(store->ut_id, "~~", sizeof(store->ut_id));
-}
-
-static int write_entry_utmp(const struct utmpx *store) {
- int r;
-
- assert(store);
-
- /* utmp is similar to wtmp, but there is only one entry for
- * each entry type resp. user; i.e. basically a key/value
- * table. */
-
- if (utmpxname(_PATH_UTMPX) < 0)
- return -errno;
-
- setutxent();
-
- if (!pututxline(store))
- r = -errno;
- else
- r = 0;
-
- endutxent();
-
- return r;
-}
-
-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. */
-
- errno = 0;
- updwtmpx(_PATH_WTMPX, store);
- return -errno;
-}
-
-static int write_utmp_wtmp(const struct utmpx *store_utmp, const struct utmpx *store_wtmp) {
- int r, s;
-
- r = write_entry_utmp(store_utmp);
- s = write_entry_wtmp(store_wtmp);
-
- if (r >= 0)
- r = s;
-
- /* If utmp/wtmp have been disabled, that's a good thing, hence
- * ignore the errors */
- if (r == -ENOENT)
- r = 0;
-
- return r;
-}
-
-static int write_entry_both(const struct utmpx *store) {
- return write_utmp_wtmp(store, store);
-}
-
-int utmp_put_shutdown(void) {
- struct utmpx store = {};
-
- init_entry(&store, 0);
-
- store.ut_type = RUN_LVL;
- strncpy(store.ut_user, "shutdown", sizeof(store.ut_user));
-
- return write_entry_both(&store);
-}
-
-int utmp_put_reboot(usec_t t) {
- struct utmpx store = {};
-
- init_entry(&store, t);
-
- store.ut_type = BOOT_TIME;
- strncpy(store.ut_user, "reboot", sizeof(store.ut_user));
-
- return write_entry_both(&store);
-}
-
-_pure_ static const char *sanitize_id(const char *id) {
- size_t l;
-
- assert(id);
- l = strlen(id);
-
- if (l <= sizeof(((struct utmpx*) NULL)->ut_id))
- return 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 = {
- .ut_type = INIT_PROCESS,
- .ut_pid = pid,
- .ut_session = sid,
- };
-
- assert(id);
-
- init_timestamp(&store, 0);
-
- /* 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);
-}
-
-int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
- struct utmpx lookup = {
- .ut_type = INIT_PROCESS /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
- }, store, store_wtmp, *found;
-
- assert(id);
-
- setutxent();
-
- /* 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);
- if (!found)
- return 0;
-
- if (found->ut_pid != pid)
- return 0;
-
- memcpy(&store, found, sizeof(store));
- store.ut_type = DEAD_PROCESS;
- store.ut_exit.e_termination = code;
- store.ut_exit.e_exit = status;
-
- zero(store.ut_user);
- zero(store.ut_host);
- zero(store.ut_tv);
-
- memcpy(&store_wtmp, &store, sizeof(store_wtmp));
- /* wtmp wants the current time */
- init_timestamp(&store_wtmp, 0);
-
- return write_utmp_wtmp(&store, &store_wtmp);
-}
-
-
-int utmp_put_runlevel(int runlevel, int previous) {
- struct utmpx store = {};
- int r;
-
- assert(runlevel > 0);
-
- if (previous <= 0) {
- /* Find the old runlevel automatically */
-
- r = utmp_get_runlevel(&previous, NULL);
- if (r < 0) {
- if (r != -ESRCH)
- return r;
-
- previous = 0;
- }
- }
-
- if (previous == runlevel)
- return 0;
-
- init_entry(&store, 0);
-
- store.ut_type = RUN_LVL;
- store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8);
- strncpy(store.ut_user, "runlevel", sizeof(store.ut_user));
-
- return write_entry_both(&store);
-}
-
-#define TIMEOUT_MSEC 50
-
-static int write_to_terminal(const char *tty, const char *message) {
- _cleanup_close_ int fd = -1;
- const char *p;
- size_t left;
- usec_t end;
-
- assert(tty);
- assert(message);
-
- fd = open(tty, O_WRONLY|O_NDELAY|O_NOCTTY|O_CLOEXEC);
- if (fd < 0 || !isatty(fd))
- return -errno;
-
- p = message;
- left = strlen(message);
-
- end = now(CLOCK_MONOTONIC) + TIMEOUT_MSEC*USEC_PER_MSEC;
-
- while (left > 0) {
- ssize_t n;
- struct pollfd pollfd = {
- .fd = fd,
- .events = POLLOUT,
- };
- usec_t t;
- int k;
-
- t = now(CLOCK_MONOTONIC);
-
- if (t >= end)
- return -ETIME;
-
- k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC);
- if (k < 0)
- return -errno;
-
- if (k == 0)
- return -ETIME;
-
- n = write(fd, p, left);
- if (n < 0) {
- if (errno == EAGAIN)
- continue;
-
- return -errno;
- }
-
- assert((size_t) n <= left);
-
- p += n;
- left -= n;
- }
-
- return 0;
-}
-
-int utmp_wall(const char *message, const char *username, bool (*match_tty)(const char *tty)) {
- _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL;
- char date[FORMAT_TIMESTAMP_MAX];
- struct utmpx *u;
- int r;
-
- hn = gethostname_malloc();
- if (!hn)
- return -ENOMEM;
- if (!username) {
- un = getlogname_malloc();
- if (!un)
- return -ENOMEM;
- }
-
- getttyname_harder(STDIN_FILENO, &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 ?: username, hn,
- tty ? " on " : "", strempty(tty),
- format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)),
- message) < 0)
- return -ENOMEM;
-
- setutxent();
-
- r = 0;
-
- while ((u = getutxent())) {
- _cleanup_free_ char *buf = NULL;
- const char *path;
- int q;
-
- if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
- continue;
-
- /* this access is fine, because strlen("/dev/") << 32 (UT_LINESIZE) */
- if (path_startswith(u->ut_line, "/dev/"))
- path = u->ut_line;
- else {
- if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0)
- return -ENOMEM;
-
- path = buf;
- }
-
- if (!match_tty || match_tty(path)) {
- q = write_to_terminal(path, text);
- if (q < 0)
- r = q;
- }
- }
-
- return r;
-}