chiark / gitweb /
Close stdin, stdout and stderr on daemonizing
[elogind.git] / src / login / elogind.c
1 /***
2   This file is part of elogind.
3
4   Copyright 2017 Sven Eden
5
6   elogind is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   elogind is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with elogind; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20
21 #include "bus-util.h"
22 #include "cgroup.h"
23 #include "elogind.h"
24 #include "fd-util.h"
25 #include "fileio.h"
26 #include "fs-util.h"
27 #include "mount-setup.h"
28 #include "parse-util.h"
29 #include "process-util.h"
30 #include "signal-util.h"
31 #include "socket-util.h"
32 #include "stdio-util.h"
33 #include "string-util.h"
34 #include "strv.h"
35 #include "umask-util.h"
36
37
38 #define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024)
39 #ifndef ELOGIND_PID_FILE
40 #  define ELOGIND_PID_FILE "/run/elogind.pid"
41 #endif // ELOGIND_PID_FILE
42
43
44 static int elogind_signal_handler(sd_event_source *s,
45                                    const struct signalfd_siginfo *si,
46                                    void *userdata) {
47         Manager *m = userdata;
48         int r;
49
50         log_warning("Received signal %u [%s]", si->ssi_signo,
51                     signal_to_string(si->ssi_signo));
52
53         r = sd_event_get_state(m->event);
54
55         if (r != SD_EVENT_FINISHED)
56                 sd_event_exit(m->event, si->ssi_signo);
57
58         return 0;
59 }
60
61
62 static void remove_pid_file(void) {
63         if (access(ELOGIND_PID_FILE, F_OK) == 0)
64                 unlink_noerrno(ELOGIND_PID_FILE);
65 }
66
67
68 static void write_pid_file(void) {
69         char c[DECIMAL_STR_MAX(pid_t) + 2];
70         pid_t pid;
71         int   r;
72
73         pid = getpid_cached();
74
75         xsprintf(c, PID_FMT "\n", pid);
76
77         r = write_string_file(ELOGIND_PID_FILE, c,
78                               WRITE_STRING_FILE_CREATE |
79                               WRITE_STRING_FILE_VERIFY_ON_FAILURE);
80         if (r < 0)
81                 log_error_errno(-r, "Failed to write PID file %s: %m",
82                                 ELOGIND_PID_FILE);
83
84         /* Make sure the PID file gets cleaned up on exit! */
85         atexit(remove_pid_file);
86 }
87
88
89 /** daemonize elogind by double forking.
90   * The grand child returns 0.
91   * The parent and child return their forks PID.
92   * On error, a value < 0 is returned.
93 **/
94 static int elogind_daemonize(void) {
95         pid_t child;
96         pid_t grandchild;
97         pid_t SID;
98         int r;
99
100 #ifdef ENABLE_DEBUG_ELOGIND
101         log_notice("Double forking elogind");
102         log_notice("Parent PID     : %5d", getpid_cached());
103         log_notice("Parent SID     : %5d", getsid(getpid_cached()));
104 #endif // ENABLE_DEBUG_ELOGIND
105
106         child = fork();
107
108         if (child < 0)
109                 return log_error_errno(errno, "Failed to fork: %m");
110
111         if (child) {
112                 /* Wait for the child to terminate, so the decoupling
113                  * is guaranteed to succeed.
114                  */
115                 r = wait_for_terminate_and_warn("elogind control child", child, true);
116                 if (r < 0)
117                         return r;
118                 return child;
119         }
120
121 #ifdef ENABLE_DEBUG_ELOGIND
122         log_notice("Child PID      : %5d", getpid_cached());
123         log_notice("Child SID      : %5d", getsid(getpid_cached()));
124 #endif // ENABLE_DEBUG_ELOGIND
125
126         /* The first child has to become a new session leader. */
127         close_all_fds(NULL, 0);
128
129         /* close_all_fds() does not close 0,1,2 */
130         close(0);
131         close(1);
132         close(2);
133
134         SID = setsid();
135         if ((pid_t)-1 == SID)
136                 return log_error_errno(errno, "Failed to create new SID: %m");
137
138 #ifdef ENABLE_DEBUG_ELOGIND
139         log_notice("Child new SID  : %5d", getsid(getpid_cached()));
140 #endif // ENABLE_DEBUG_ELOGIND
141
142         umask(0022);
143
144         /* Now the grandchild, the true daemon, can be created. */
145         grandchild = fork();
146
147         if (grandchild < 0)
148                 return log_error_errno(errno, "Failed to double fork: %m");
149
150         if (grandchild)
151                 /* Exit immediately! */
152                 return grandchild;
153
154         close_all_fds(NULL, 0);
155         umask(0022);
156
157 #ifdef ENABLE_DEBUG_ELOGIND
158         log_notice("Grand child PID: %5d", getpid_cached());
159         log_notice("Grand child SID: %5d", getsid(getpid_cached()));
160 #endif // ENABLE_DEBUG_ELOGIND
161
162         /* Take care of our PID-file now */
163         write_pid_file();
164
165         return 0;
166 }
167
168
169 /// Simple tool to see, if elogind is already running
170 static pid_t elogind_is_already_running(bool need_pid_file) {
171         _cleanup_free_ char *s = NULL;
172         pid_t pid;
173         int r;
174
175         r = read_one_line_file(ELOGIND_PID_FILE, &s);
176
177         if (r < 0)
178                 goto we_are_alone;
179
180         r = safe_atoi32(s, &pid);
181
182         if (r < 0)
183                 goto we_are_alone;
184
185         if ( (pid != getpid_cached()) && pid_is_alive(pid))
186                 return pid;
187
188 we_are_alone:
189
190         /* Take care of our PID-file now.
191            If the user is going to fork elogind, the PID file
192            will be overwritten. */
193         if (need_pid_file)
194                 write_pid_file();
195
196         return 0;
197 }
198
199
200 static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
201         Manager *m = userdata;
202         char buf[PATH_MAX+1];
203         ssize_t n;
204
205         n = recv(fd, buf, sizeof(buf), 0);
206         if (n < 0)
207                 return log_error_errno(errno, "Failed to read cgroups agent message: %m");
208         if (n == 0) {
209                 log_error("Got zero-length cgroups agent message, ignoring.");
210                 return 0;
211         }
212         if ((size_t) n >= sizeof(buf)) {
213                 log_error("Got overly long cgroups agent message, ignoring.");
214                 return 0;
215         }
216
217         if (memchr(buf, 0, n)) {
218                 log_error("Got cgroups agent message with embedded NUL byte, ignoring.");
219                 return 0;
220         }
221         buf[n] = 0;
222
223         manager_notify_cgroup_empty(m, buf);
224
225         return 0;
226 }
227
228
229 /// Add-On for manager_connect_bus()
230 /// Original: src/core/manager.c:manager_setup_cgroups_agent()
231 int elogind_setup_cgroups_agent(Manager *m) {
232
233         static const union sockaddr_union sa = {
234                 .un.sun_family = AF_UNIX,
235                 .un.sun_path = "/run/systemd/cgroups-agent",
236         };
237         int r = 0;
238
239         /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering
240          * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and
241          * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on
242          * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number
243          * of D-Bus connections may be queued until the kernel will start dropping further incoming connections,
244          * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX
245          * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and
246          * we thus won't lose messages.
247          *
248          * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen
249          * to it. The system instance hence listens on this special socket, but the user instances listen on the system
250          * bus for these messages. */
251
252         if (m->test_run_flags)
253                 return 0;
254
255         if (!MANAGER_IS_SYSTEM(m))
256                 return 0;
257
258         r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
259         if (r < 0)
260                 return log_error_errno(r, "Failed to determine whether unified cgroups hierarchy is used: %m");
261         if (r > 0) /* We don't need this anymore on the unified hierarchy */
262                 return 0;
263
264         if (m->cgroups_agent_fd < 0) {
265                 _cleanup_close_ int fd = -1;
266
267                 /* First free all secondary fields */
268                 m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
269
270                 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
271                 if (fd < 0)
272                         return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m");
273
274                 fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE);
275
276                 (void) unlink(sa.un.sun_path);
277
278                 /* Only allow root to connect to this socket */
279                 RUN_WITH_UMASK(0077)
280                         r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
281                 if (r < 0)
282                         return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
283
284                 m->cgroups_agent_fd = fd;
285                 fd = -1;
286         }
287
288         if (!m->cgroups_agent_event_source) {
289                 r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m);
290                 if (r < 0)
291                         return log_error_errno(r, "Failed to allocate cgroups agent event source: %m");
292
293                 /* Process cgroups notifications early, but after having processed service notification messages or
294                  * SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification,
295                  * and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of
296                  * cgroup inotify for the unified cgroup stuff. */
297                 r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5);
298                 if (r < 0)
299                         return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m");
300
301                 (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent");
302         }
303
304         return 0;
305 }
306
307
308 /** Extra functionality at startup, exclusive to elogind
309   * return < 0 on error, exit with failure.
310   * return = 0 on success, continue normal operation.
311   * return > 0 if elogind is already running or forked, exit with success.
312 **/
313 int elogind_startup(int argc, char *argv[]) {
314         bool  daemonize = false;
315         pid_t pid;
316         int   r         = 0;
317         bool  show_help = false;
318         bool  wrong_arg = false;
319
320         /* add a -h/--help and a -d/--daemon argument. */
321         if ( (argc == 2) && argv[1] && strlen(argv[1]) ) {
322                 if ( streq(argv[1], "-D") || streq(argv[1], "--daemon") )
323                         daemonize = true;
324                 else if ( streq(argv[1], "-h") || streq(argv[1], "--help") ) {
325                         show_help = true;
326                         r = 1;
327                 } else
328                         wrong_arg = true;
329         } else if (argc > 2)
330                 wrong_arg = true;
331
332         /* Note: At this point, the logging is not initialized, so we can not
333                  use log_debug_elogind(). */
334 #ifdef ENABLE_DEBUG_ELOGIND
335         log_notice("elogind startup: Daemonize: %s, Show Help: %s, Wrong arg: %s",
336                 daemonize ? "True" : "False",
337                 show_help ? "True" : "False",
338                 wrong_arg ? "True" : "False");
339 #endif // ENABLE_DEBUG_ELOGIND
340
341         /* try to get some meaningful output in case of an error */
342         if (wrong_arg) {
343                 log_error("Unknown arguments");
344                 show_help = true;
345                 r = -EINVAL;
346         }
347         if (show_help) {
348                 log_info("%s [<-D|--daemon>|<-h|--help>]", basename(argv[0]));
349                 return r;
350         }
351
352         /* Do not continue if elogind is already running */
353         pid = elogind_is_already_running(!daemonize);
354         if (pid) {
355                 log_error("elogind is already running as PID " PID_FMT, pid);
356                 return pid;
357         }
358
359         /* elogind allows to be daemonized using one argument "-D" / "--daemon" */
360         if (daemonize)
361                 r = elogind_daemonize();
362
363         return r;
364 }
365
366
367 /// Add-On for manager_free()
368 void elogind_manager_free(Manager* m) {
369
370         manager_shutdown_cgroup(m, true);
371
372         sd_event_source_unref(m->cgroups_agent_event_source);
373
374         safe_close(m->cgroups_agent_fd);
375
376         strv_free(m->suspend_mode);
377         strv_free(m->suspend_state);
378         strv_free(m->hibernate_mode);
379         strv_free(m->hibernate_state);
380         strv_free(m->hybrid_sleep_mode);
381         strv_free(m->hybrid_sleep_state);
382 }
383
384
385 /// Add-On for manager_new()
386 int elogind_manager_new(Manager* m) {
387         int r = 0;
388
389         m->cgroups_agent_fd = -1;
390         m->pin_cgroupfs_fd  = -1;
391         m->test_run_flags   = 0;
392
393         /* Init sleep modes and states */
394         m->suspend_mode       = NULL;
395         m->suspend_state      = NULL;
396         m->hibernate_mode     = NULL;
397         m->hibernate_state    = NULL;
398         m->hybrid_sleep_mode  = NULL;
399         m->hybrid_sleep_state = NULL;
400
401         /* If elogind should be its own controller, mount its cgroup */
402         if (streq(SYSTEMD_CGROUP_CONTROLLER, "_elogind")) {
403                 m->is_system = true;
404                 r = mount_setup(true);
405         } else
406                 m->is_system = false;
407
408         /* Make cgroups */
409         if (r > -1)
410                 r = manager_setup_cgroup(m);
411
412         return r;
413 }
414
415
416 /// Add-On for manager_reset_config()
417 void elogind_manager_reset_config(Manager* m) {
418
419 #ifdef ENABLE_DEBUG_ELOGIND
420         int dbg_cnt;
421 #endif // ENABLE_DEBUG_ELOGIND
422
423         /* Set default Sleep config if not already set by logind.conf */
424         if (!m->suspend_state)
425                 m->suspend_state = strv_new("mem", "standby", "freeze", NULL);
426         if (!m->hibernate_mode)
427                 m->hibernate_mode = strv_new("platform", "shutdown", NULL);
428         if (!m->hibernate_state)
429                 m->hibernate_state = strv_new("disk", NULL);
430         if (!m->hybrid_sleep_mode)
431                 m->hybrid_sleep_mode = strv_new("suspend", "platform", "shutdown", NULL);
432         if (!m->hybrid_sleep_state)
433                 m->hybrid_sleep_state = strv_new("disk", NULL);
434
435 #ifdef ENABLE_DEBUG_ELOGIND
436         dbg_cnt = -1;
437         while (m->suspend_mode && m->suspend_mode[++dbg_cnt])
438                 log_debug_elogind("suspend_mode[%d] = %s",
439                                   dbg_cnt, m->suspend_mode[dbg_cnt]);
440         dbg_cnt = -1;
441         while (m->suspend_state[++dbg_cnt])
442                 log_debug_elogind("suspend_state[%d] = %s",
443                                   dbg_cnt, m->suspend_state[dbg_cnt]);
444         dbg_cnt = -1;
445         while (m->hibernate_mode[++dbg_cnt])
446                 log_debug_elogind("hibernate_mode[%d] = %s",
447                                   dbg_cnt, m->hibernate_mode[dbg_cnt]);
448         dbg_cnt = -1;
449         while (m->hibernate_state[++dbg_cnt])
450                 log_debug_elogind("hibernate_state[%d] = %s",
451                                   dbg_cnt, m->hibernate_state[dbg_cnt]);
452         dbg_cnt = -1;
453         while (m->hybrid_sleep_mode[++dbg_cnt])
454                 log_debug_elogind("hybrid_sleep_mode[%d] = %s",
455                                   dbg_cnt, m->hybrid_sleep_mode[dbg_cnt]);
456         dbg_cnt = -1;
457         while (m->hybrid_sleep_state[++dbg_cnt])
458                 log_debug_elogind("hybrid_sleep_state[%d] = %s",
459                                   dbg_cnt, m->hybrid_sleep_state[dbg_cnt]);
460 #endif // ENABLE_DEBUG_ELOGIND
461 }
462
463
464 /// Add-On for manager_startup()
465 int elogind_manager_startup(Manager *m) {
466         int r;
467
468         assert(m);
469
470         assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, -1) >= 0);
471         r = sd_event_add_signal(m->event, NULL, SIGINT, elogind_signal_handler, m);
472         if (r < 0)
473                 return log_error_errno(r, "Failed to register SIGINT handler: %m");
474
475         assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGQUIT, -1) >= 0);
476         r = sd_event_add_signal(m->event, NULL, SIGQUIT, elogind_signal_handler, m);
477         if (r < 0)
478                 return log_error_errno(r, "Failed to register SIGQUIT handler: %m");
479
480         assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGTERM, -1) >= 0);
481         r = sd_event_add_signal(m->event, NULL, SIGTERM, elogind_signal_handler, m);
482         if (r < 0)
483                 return log_error_errno(r, "Failed to register SIGTERM handler: %m");
484
485         return 0;
486 }