1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 //#include "alloc-util.h"
32 #include "bus-error.h"
33 //#include "bus-util.h"
34 //#include "format-util.h"
37 #include "process-util.h"
38 //#include "special.h"
40 //#include "unit-name.h"
42 #include "utmp-wtmp.h"
44 /// Additional includes needed by elogind
45 #include "string-util.h"
46 #include "time-util.h"
47 #include "update-utmp.h"
48 typedef struct Context {
55 #if 0 /// UNNEEDED by elogind
56 static usec_t get_startup_time(Context *c) {
57 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
63 r = sd_bus_get_property_trivial(
65 "org.freedesktop.systemd1",
66 "/org/freedesktop/systemd1",
67 "org.freedesktop.systemd1.Manager",
72 log_error_errno(r, "Failed to get timestamp: %s", bus_error_message(&error, r));
79 static int get_current_runlevel(Context *c) {
84 /* The first target of this list that is active or has
85 * a job scheduled wins. We prefer runlevels 5 and 3
86 * here over the others, since these are the main
87 * runlevels used on Fedora. It might make sense to
88 * change the order on some distributions. */
89 { '5', SPECIAL_GRAPHICAL_TARGET },
90 { '3', SPECIAL_MULTI_USER_TARGET },
91 { '1', SPECIAL_RESCUE_TARGET },
94 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
100 for (i = 0; i < ELEMENTSOF(table); i++) {
101 _cleanup_free_ char *state = NULL, *path = NULL;
103 path = unit_dbus_path_from_name(table[i].special);
107 r = sd_bus_get_property_string(
109 "org.freedesktop.systemd1",
111 "org.freedesktop.systemd1.Unit",
116 return log_warning_errno(r, "Failed to get state: %s", bus_error_message(&error, r));
118 if (STR_IN_SET(state, "active", "reloading"))
119 return table[i].runlevel;
126 static int on_reboot(Context *c) {
132 /* We finished start-up, so let's write the utmp
133 * record and send the audit msg */
136 if (c->audit_fd >= 0)
137 if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
139 r = log_error_errno(errno, "Failed to send audit message: %m");
143 #if 0 /// systemd hasn't started the system, so elogind always uses NOW()
144 /* If this call fails it will return 0, which
145 * utmp_put_reboot() will then fix to the current time */
146 t = get_startup_time(c);
148 t = now(CLOCK_REALTIME);
151 q = utmp_put_reboot(t);
153 log_error_errno(q, "Failed to write utmp record: %m");
160 static int on_shutdown(Context *c) {
165 /* We started shut-down, so let's write the utmp
166 * record and send the audit msg */
169 if (c->audit_fd >= 0)
170 if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
172 r = log_error_errno(errno, "Failed to send audit message: %m");
176 q = utmp_put_shutdown();
178 log_error_errno(q, "Failed to write utmp record: %m");
185 #if 0 /// UNNEEDED by elogind
186 static int on_runlevel(Context *c) {
187 int r = 0, q, previous, runlevel;
191 /* We finished changing runlevel, so let's write the
192 * utmp record and send the audit msg */
194 /* First, get last runlevel */
195 q = utmp_get_runlevel(&previous, NULL);
198 if (!IN_SET(q, -ESRCH, -ENOENT))
199 return log_error_errno(q, "Failed to get current runlevel: %m");
204 /* Secondly, get new runlevel */
205 runlevel = get_current_runlevel(c);
210 if (previous == runlevel)
214 if (c->audit_fd >= 0) {
215 _cleanup_free_ char *s = NULL;
217 if (asprintf(&s, "old-level=%c new-level=%c",
218 previous > 0 ? previous : 'N',
219 runlevel > 0 ? runlevel : 'N') < 0)
222 if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 && errno != EPERM)
223 r = log_error_errno(errno, "Failed to send audit message: %m");
227 q = utmp_put_runlevel(runlevel, previous);
228 if (q < 0 && !IN_SET(q, -ESRCH, -ENOENT)) {
229 log_error_errno(q, "Failed to write utmp record: %m");
237 #if 0 /// elogind needs this to be a callable function
238 int main(int argc, char *argv[]) {
240 void update_utmp(int argc, char* argv[]) {
247 #if 0 /// UNNEEDED by elogind
250 if (getppid() != 1) {
251 log_error("This program should be invoked by init only.");
256 log_error("This program requires one argument.");
260 log_set_target(LOG_TARGET_AUTO);
261 log_parse_environment();
271 /* If the kernel lacks netlink or audit support,
272 * don't worry about it. */
273 c.audit_fd = audit_open();
274 if (c.audit_fd < 0 && !IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT))
275 log_error_errno(errno, "Failed to connect to audit log: %m");
277 #if 0 /// UNNEEDED by elogind
278 r = bus_connect_system_systemd(&c.bus);
280 log_error_errno(r, "Failed to get D-Bus connection: %m");
285 log_debug("systemd-update-utmp running as pid "PID_FMT, getpid_cached());
287 if (streq(argv[1], "reboot"))
289 else if (streq(argv[1], "shutdown"))
291 else if (streq(argv[1], "runlevel"))
294 log_error("Unknown command %s", argv[1]);
298 log_debug("systemd-update-utmp stopped as pid "PID_FMT, getpid_cached());
302 if (streq(argv[1], "reboot"))
304 else if (streq(argv[1], "shutdown"))
305 (void)on_shutdown(&c);
309 audit_close(c.audit_fd);
312 #if 0 /// UNNEEDED by elogind
313 sd_bus_flush_close_unref(c.bus);
315 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;