]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/update-utmp/update-utmp.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / update-utmp / update-utmp.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4927fcae
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
4927fcae
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
4927fcae 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
4927fcae
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <assert.h>
23#include <errno.h>
24#include <string.h>
4927fcae
LP
25#include <sys/types.h>
26#include <unistd.h>
27
830f6caa
LP
28#ifdef HAVE_AUDIT
29#include <libaudit.h>
30#endif
31
89456fce
TG
32#include "sd-bus.h"
33
4927fcae
LP
34#include "log.h"
35#include "macro.h"
36#include "util.h"
37#include "special.h"
38#include "utmp-wtmp.h"
89456fce
TG
39#include "bus-util.h"
40#include "bus-error.h"
e7fb33ff 41#include "unit-name.h"
4927fcae
LP
42
43typedef struct Context {
89456fce 44 sd_bus *bus;
4927fcae
LP
45#ifdef HAVE_AUDIT
46 int audit_fd;
47#endif
48} Context;
49
50static usec_t get_startup_time(Context *c) {
89456fce 51 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
47c649b5 52 usec_t t = 0;
89456fce 53 int r;
4927fcae 54
4927fcae
LP
55 assert(c);
56
47c649b5 57 r = sd_bus_get_property_trivial(
436ddded
SP
58 c->bus,
59 "org.freedesktop.systemd1",
60 "/org/freedesktop/systemd1",
89456fce 61 "org.freedesktop.systemd1.Manager",
47c649b5
LP
62 "UserspaceTimestamp",
63 &error,
64 't', &t);
89456fce
TG
65 if (r < 0) {
66 log_error("Failed to get timestamp: %s", bus_error_message(&error, -r));
47c649b5 67 return 0;
4927fcae
LP
68 }
69
4927fcae
LP
70 return t;
71}
72
73static int get_current_runlevel(Context *c) {
74 static const struct {
75 const int runlevel;
76 const char *special;
77 } table[] = {
78 /* The first target of this list that is active or has
ee2083d5
LP
79 * a job scheduled wins. We prefer runlevels 5 and 3
80 * here over the others, since these are the main
81 * runlevels used on Fedora. It might make sense to
82 * change the order on some distributions. */
4927fcae 83 { '5', SPECIAL_RUNLEVEL5_TARGET },
4927fcae 84 { '3', SPECIAL_RUNLEVEL3_TARGET },
3006982d 85 { '4', SPECIAL_RUNLEVEL4_TARGET },
4927fcae 86 { '2', SPECIAL_RUNLEVEL2_TARGET },
3f92e4b4 87 { '1', SPECIAL_RESCUE_TARGET },
4927fcae 88 };
4927fcae 89
89456fce
TG
90 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
91 int r;
4927fcae 92 unsigned i;
4927fcae
LP
93
94 assert(c);
95
4927fcae 96 for (i = 0; i < ELEMENTSOF(table); i++) {
e7fb33ff 97 _cleanup_free_ char *state = NULL, *path = NULL;
4927fcae 98
e7fb33ff
LP
99 path = unit_dbus_path_from_name(table[i].special);
100 if (!path)
101 return log_oom();
89456fce 102
47c649b5 103 r = sd_bus_get_property_string(
436ddded
SP
104 c->bus,
105 "org.freedesktop.systemd1",
106 path,
47c649b5
LP
107 "org.freedesktop.systemd1.Unit",
108 "ActiveState",
89456fce 109 &error,
47c649b5 110 &state);
89456fce 111 if (r < 0) {
47c649b5 112 log_warning("Failed to get state: %s", bus_error_message(&error, -r));
89456fce 113 return r;
4927fcae
LP
114 }
115
4927fcae 116 if (streq(state, "active") || streq(state, "reloading"))
89456fce 117 return table[i].runlevel;
4927fcae
LP
118 }
119
89456fce 120 return 0;
4927fcae
LP
121}
122
123static int on_reboot(Context *c) {
124 int r = 0, q;
125 usec_t t;
126
127 assert(c);
128
129 /* We finished start-up, so let's write the utmp
130 * record and send the audit msg */
131
132#ifdef HAVE_AUDIT
133 if (c->audit_fd >= 0)
0aa281df 134 if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
44785992 135 errno != EPERM) {
56f64d95 136 log_error_errno(errno, "Failed to send audit message: %m");
4927fcae
LP
137 r = -errno;
138 }
139#endif
140
141 /* If this call fails it will return 0, which
142 * utmp_put_reboot() will then fix to the current time */
143 t = get_startup_time(c);
144
1cea22a5
LP
145 q = utmp_put_reboot(t);
146 if (q < 0) {
da927ba9 147 log_error_errno(q, "Failed to write utmp record: %m");
4927fcae
LP
148 r = q;
149 }
150
151 return r;
152}
153
154static int on_shutdown(Context *c) {
155 int r = 0, q;
156
157 assert(c);
158
159 /* We started shut-down, so let's write the utmp
160 * record and send the audit msg */
161
162#ifdef HAVE_AUDIT
163 if (c->audit_fd >= 0)
0aa281df 164 if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
44785992 165 errno != EPERM) {
56f64d95 166 log_error_errno(errno, "Failed to send audit message: %m");
4927fcae
LP
167 r = -errno;
168 }
169#endif
170
1cea22a5
LP
171 q = utmp_put_shutdown();
172 if (q < 0) {
da927ba9 173 log_error_errno(q, "Failed to write utmp record: %m");
4927fcae
LP
174 r = q;
175 }
176
177 return r;
178}
179
180static int on_runlevel(Context *c) {
181 int r = 0, q, previous, runlevel;
182
183 assert(c);
184
185 /* We finished changing runlevel, so let's write the
186 * utmp record and send the audit msg */
187
188 /* First, get last runlevel */
1cea22a5 189 q = utmp_get_runlevel(&previous, NULL);
4927fcae 190
e7fb33ff 191 if (q < 0) {
f647962d
MS
192 if (q != -ESRCH && q != -ENOENT)
193 return log_error_errno(q, "Failed to get current runlevel: %m");
4927fcae 194
4927fcae
LP
195 previous = 0;
196 }
197
830f6caa 198 /* Secondly, get new runlevel */
1cea22a5 199 runlevel = get_current_runlevel(c);
e7fb33ff 200
1cea22a5 201 if (runlevel < 0)
4927fcae
LP
202 return runlevel;
203
204 if (previous == runlevel)
205 return 0;
206
207#ifdef HAVE_AUDIT
208 if (c->audit_fd >= 0) {
1cea22a5 209 _cleanup_free_ char *s = NULL;
4927fcae 210
cd6d0a45
LP
211 if (asprintf(&s, "old-level=%c new-level=%c",
212 previous > 0 ? previous : 'N',
213 runlevel > 0 ? runlevel : 'N') < 0)
1cea22a5 214 return log_oom();
4927fcae 215
0aa281df 216 if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
44785992 217 errno != EPERM) {
56f64d95 218 log_error_errno(errno, "Failed to send audit message: %m");
4927fcae
LP
219 r = -errno;
220 }
4927fcae
LP
221 }
222#endif
223
1cea22a5
LP
224 q = utmp_put_runlevel(runlevel, previous);
225 if (q < 0 && q != -ESRCH && q != -ENOENT) {
da927ba9 226 log_error_errno(q, "Failed to write utmp record: %m");
1cea22a5 227 r = q;
4927fcae
LP
228 }
229
230 return r;
231}
232
233int main(int argc, char *argv[]) {
1cea22a5 234 Context c = {
4927fcae 235#ifdef HAVE_AUDIT
1cea22a5 236 .audit_fd = -1
4927fcae 237#endif
1cea22a5
LP
238 };
239 int r;
4927fcae 240
cd6d0a45
LP
241 if (getppid() != 1) {
242 log_error("This program should be invoked by init only.");
22f4096c 243 return EXIT_FAILURE;
cd6d0a45 244 }
4927fcae
LP
245
246 if (argc != 2) {
247 log_error("This program requires one argument.");
22f4096c 248 return EXIT_FAILURE;
4927fcae
LP
249 }
250
4cfa2c99 251 log_set_target(LOG_TARGET_AUTO);
4927fcae 252 log_parse_environment();
2396fb04 253 log_open();
4927fcae 254
4c12626c
LP
255 umask(0022);
256
4927fcae 257#ifdef HAVE_AUDIT
1cea22a5
LP
258 /* If the kernel lacks netlink or audit support,
259 * don't worry about it. */
260 c.audit_fd = audit_open();
261 if (c.audit_fd < 0 && errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
56f64d95 262 log_error_errno(errno, "Failed to connect to audit log: %m");
4927fcae 263#endif
0f8bd8de 264 r = bus_open_system_systemd(&c.bus);
89456fce 265 if (r < 0) {
da927ba9 266 log_error_errno(r, "Failed to get D-Bus connection: %m");
4927fcae
LP
267 r = -EIO;
268 goto finish;
269 }
270
de0671ee 271 log_debug("systemd-update-utmp running as pid "PID_FMT, getpid());
4927fcae
LP
272
273 if (streq(argv[1], "reboot"))
274 r = on_reboot(&c);
275 else if (streq(argv[1], "shutdown"))
276 r = on_shutdown(&c);
277 else if (streq(argv[1], "runlevel"))
278 r = on_runlevel(&c);
279 else {
280 log_error("Unknown command %s", argv[1]);
281 r = -EINVAL;
282 }
283
de0671ee 284 log_debug("systemd-update-utmp stopped as pid "PID_FMT, getpid());
4927fcae 285
cd6d0a45 286finish:
4927fcae
LP
287#ifdef HAVE_AUDIT
288 if (c.audit_fd >= 0)
289 audit_close(c.audit_fd);
290#endif
291
89456fce
TG
292 if (c.bus)
293 sd_bus_unref(c.bus);
4927fcae 294
22f4096c 295 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
4927fcae 296}