chiark / gitweb /
logind: add infrastructure to keep track of machines, and move to slices
[elogind.git] / src / login / user-sessions.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
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
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
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
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <unistd.h>
24 #include <errno.h>
25
26 #include "log.h"
27 #include "util.h"
28 #include "cgroup-util.h"
29 #include "fileio.h"
30
31 static int kill_all_users(void) {
32         _cleanup_closedir_ DIR *d = NULL;
33         struct dirent *de;
34         int r = 0;
35
36         d = opendir("/run/systemd/users");
37         if (!d) {
38                 if (errno == ENOENT)
39                         return 0;
40
41                 log_error("Failed to open /run/systemd/users: %m");
42                 return -errno;
43         }
44
45         FOREACH_DIRENT(de, d, return -errno) {
46                 _cleanup_free_ char *cgroup = NULL;
47                 char *a;
48                 int k;
49
50                 if (!dirent_is_file(de))
51                         continue;
52
53                 a = strappenda("/run/systemd/users/", de->d_name);
54
55                 k = parse_env_file(a, NEWLINE, "CGROUP", &cgroup, NULL);
56                 if (k < 0) {
57                         if (k != -ENOENT) {
58                                 log_error("Failed to read user data: %s", strerror(-k));
59                                 r = k;
60                         }
61
62                         continue;
63                 }
64
65                 if (!cgroup) {
66                         log_error("User data did not contain cgroup field.");
67                         r = -ENOENT;
68                         continue;
69                 }
70
71                 k = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, cgroup, true);
72                 if (k < 0) {
73                         log_error("Failed to kill cgroup %s: %s", cgroup, strerror(-k));
74                         r = k;
75                 }
76         }
77
78         return r;
79 }
80
81 static int kill_all_sessions(void) {
82         _cleanup_closedir_ DIR *d = NULL;
83         struct dirent *de;
84         int r = 0;
85
86         d = opendir("/run/systemd/sessions");
87         if (!d) {
88                 if (errno == ENOENT)
89                         return 0;
90
91                 log_error("Failed to open /run/systemd/sessions: %m");
92                 return -errno;
93         }
94
95         FOREACH_DIRENT(de, d, return -errno) {
96                 _cleanup_free_ char *cgroup = NULL;
97                 char *a;
98                 int k;
99
100                 if (!dirent_is_file(de))
101                         continue;
102
103                 a = strappenda("/run/systemd/sessions/", de->d_name);
104
105                 k = parse_env_file(a, NEWLINE, "CGROUP", &cgroup, NULL);
106                 if (k < 0) {
107                         if (k != -ENOENT) {
108                                 log_error("Failed to read session data: %s", strerror(-k));
109                                 r = k;
110                         }
111
112                         continue;
113                 }
114
115                 if (!cgroup) {
116                         log_error("Session data did not contain cgroup field.");
117                         r = -ENOENT;
118                         continue;
119                 }
120
121                 k = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, cgroup, true);
122                 if (k < 0) {
123                         log_error("Failed to kill cgroup %s: %s", cgroup, strerror(-k));
124                         r = k;
125                 }
126         }
127
128         return r;
129 }
130
131 int main(int argc, char*argv[]) {
132         int ret = EXIT_FAILURE;
133
134         if (argc != 2) {
135                 log_error("This program requires one argument.");
136                 return EXIT_FAILURE;
137         }
138
139         log_set_target(LOG_TARGET_AUTO);
140         log_parse_environment();
141         log_open();
142
143         umask(0022);
144
145         if (streq(argv[1], "start")) {
146                 int q = 0, r = 0;
147
148                 if (unlink("/run/nologin") < 0 && errno != ENOENT) {
149                         log_error("Failed to remove /run/nologin file: %m");
150                         r = -errno;
151                 }
152
153                 if (unlink("/etc/nologin") < 0 && errno != ENOENT) {
154
155                         /* If the file doesn't exist and /etc simply
156                          * was read-only (in which case unlink()
157                          * returns EROFS even if the file doesn't
158                          * exist), don't complain */
159
160                         if (errno != EROFS || access("/etc/nologin", F_OK) >= 0) {
161                                 log_error("Failed to remove /etc/nologin file: %m");
162                                 q = -errno;
163                         }
164                 }
165
166                 if (r < 0 || q < 0)
167                         goto finish;
168
169         } else if (streq(argv[1], "stop")) {
170                 int r, q;
171
172                 r = write_string_file_atomic("/run/nologin", "System is going down.");
173                 if (r < 0)
174                         log_error("Failed to create /run/nologin: %s", strerror(-r));
175
176                 q = kill_all_users();
177                 if (q < 0 && r >= 0)
178                         r = q;
179
180                 q = kill_all_sessions();
181                 if (q < 0 && r >= 0)
182                         r = q;
183
184         } else {
185                 log_error("Unknown verb %s.", argv[1]);
186                 goto finish;
187         }
188
189         ret = EXIT_SUCCESS;
190
191 finish:
192         return ret;
193 }