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