chiark / gitweb /
udev-builtin-blkid: remove dead code
[elogind.git] / src / dbus1-generator / dbus1-generator.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 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 "util.h"
23 #include "conf-parser.h"
24 #include "special.h"
25 #include "mkdir.h"
26 #include "bus-util.h"
27 #include "bus-internal.h"
28 #include "unit-name.h"
29 #include "cgroup-util.h"
30
31 static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp";
32
33 static int create_dbus_files(
34                 const char *path,
35                 const char *name,
36                 const char *service,
37                 const char *exec,
38                 const char *user,
39                 const char *type) {
40
41         _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL;
42         _cleanup_fclose_ FILE *f = NULL;
43
44         assert(path);
45         assert(name);
46         assert(service || exec);
47
48         if (!service) {
49                 _cleanup_free_ char *a = NULL;
50
51                 s = strjoin("dbus-", name, ".service", NULL);
52                 if (!s)
53                         return log_oom();
54
55                 a = strjoin(arg_dest_late, "/", s, NULL);
56                 if (!a)
57                         return log_oom();
58
59                 f = fopen(a, "wxe");
60                 if (!f) {
61                         log_error("Failed to create %s: %m", a);
62                         return -errno;
63                 }
64
65                 fprintf(f,
66                         "# Automatically generated by systemd-dbus1-generator\n\n"
67                         "[Unit]\n"
68                         "SourcePath=%s\n"
69                         "Description=DBUS1: %s\n"
70                         "Documentation=man:systemd-dbus1-generator(8)\n\n"
71                         "[Service]\n"
72                         "ExecStart=%s\n"
73                         "Type=dbus\n"
74                         "BusName=%s\n",
75                         path,
76                         name,
77                         exec,
78                         name);
79
80                 if (user)
81                         fprintf(f, "User=%s\n", user);
82
83
84                 if (type) {
85                         fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
86
87                         if (streq(type, "system"))
88                                 fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_PATH "\n");
89                         else if (streq(type, "session")) {
90                                 char *run;
91
92                                 run = getenv("XDG_RUNTIME_DIR");
93                                 if (!run) {
94                                         log_error("XDG_RUNTIME_DIR not set.");
95                                         return -EINVAL;
96                                 }
97
98                                 fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT "\n",
99                                         (unsigned long) getuid(), run);
100                         }
101                 }
102
103                 fflush(f);
104                 if (ferror(f)) {
105                         log_error("Failed to write %s: %m", a);
106                         return -errno;
107                 }
108
109                 service = s;
110         }
111
112         b = strjoin(arg_dest_late, "/", name, ".busname", NULL);
113         if (!b)
114                 return log_oom();
115
116         f = fopen(b, "wxe");
117         if (!f) {
118                 log_error("Failed to create %s: %m", b);
119                 return -errno;
120         }
121
122         fprintf(f,
123                 "# Automatically generated by systemd-dbus1-generator\n\n"
124                 "[Unit]\n"
125                 "SourcePath=%s\n"
126                 "Description=DBUS1: %s\n"
127                 "Documentation=man:systemd-dbus1-generator(8)\n\n"
128                 "[BusName]\n"
129                 "Name=%s\n"
130                 "Service=%s\n",
131                 path,
132                 name,
133                 name,
134                 service);
135
136         fflush(f);
137         if (ferror(f)) {
138                 log_error("Failed to write %s: %m", b);
139                 return -errno;
140         }
141
142         lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
143         if (!lnk)
144                 return log_oom();
145
146         mkdir_parents_label(lnk, 0755);
147         if (symlink(b, lnk)) {
148                 log_error("Failed to create symlink %s: %m", lnk);
149                 return -errno;
150         }
151
152         return 0;
153 }
154
155 static int add_dbus(const char *path, const char *fname, const char *type) {
156         _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL;
157
158         ConfigTableItem table[] = {
159                 { "D-BUS Service", "Name", config_parse_string, 0, &name },
160                 { "D-BUS Service", "Exec", config_parse_string, 0, &exec },
161                 { "D-BUS Service", "User", config_parse_string, 0, &user },
162                 { "D-BUS Service", "SystemdService", config_parse_string, 0, &service },
163         };
164
165         _cleanup_fclose_ FILE *f = NULL;
166         _cleanup_free_ char *p = NULL;
167         int r;
168
169         assert(path);
170         assert(fname);
171
172         p = strjoin(path, "/", fname, NULL);
173         if (!p)
174                 return log_oom();
175
176         f = fopen(p, "re");
177         if (!f) {
178                 if (errno == -ENOENT)
179                         return 0;
180
181                 log_error("Failed to read %s: %m", p);
182                 return -errno;
183         }
184
185         r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL);
186         if (r < 0)
187                 return r;
188
189         if (!name) {
190                 log_warning("Activation file %s lacks name setting, ignoring.", p);
191                 return 0;
192         }
193
194         if (!service_name_is_valid(name)) {
195                 log_warning("Bus service name %s is not valid, ignoring.", name);
196                 return 0;
197         }
198
199         if (streq(name, "org.freedesktop.systemd1")) {
200                 log_debug("Skipping %s, identified as systemd.", p);
201                 return 0;
202         }
203
204         if (service) {
205                 if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
206                         log_warning("Unit name %s is not valid, ignoring.", service);
207                         return 0;
208                 }
209                 if (!endswith(service, ".service")) {
210                         log_warning("Bus names can only activate services, ignoring %s.", p);
211                         return 0;
212                 }
213         } else {
214                 if (streq(exec, "/bin/false") || !exec) {
215                         log_warning("Neither service name nor binary path specified, ignoring %s.", p);
216                         return 0;
217                 }
218
219                 if (exec[0] != '/') {
220                         log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
221                         return 0;
222                 }
223         }
224
225         return create_dbus_files(p, name, service, exec, user, type);
226 }
227
228 static int parse_dbus_fragments(const char *path, const char *type) {
229         _cleanup_closedir_ DIR *d = NULL;
230         struct dirent *de;
231         int r;
232
233         assert(path);
234         assert(type);
235
236         d = opendir(path);
237         if (!d) {
238                 if (errno == -ENOENT)
239                         return 0;
240
241                 log_error("Failed to enumerate D-Bus activated services: %m");
242                 return -errno;
243         }
244
245         r = 0;
246         FOREACH_DIRENT(de, d, goto fail) {
247                 int q;
248
249                 if (!endswith(de->d_name, ".service"))
250                         continue;
251
252                 q = add_dbus(path, de->d_name, type);
253                 if (q < 0)
254                         r = q;
255         }
256
257         return r;
258
259 fail:
260         log_error("Failed to read D-Bus services directory: %m");
261         return -errno;
262 }
263
264 static int link_busnames_target(const char *units) {
265         const char *f, *t;
266
267         f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET);
268         t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
269
270         mkdir_parents_label(t, 0755);
271         if (symlink(f, t) < 0) {
272                 log_error("Failed to create symlink %s: %m", t);
273                 return -errno;
274         }
275
276         return 0;
277 }
278
279 static int link_compatibility(const char *units) {
280         const char *f, *t;
281
282         f = strappenda(units, "/systemd-bus-proxyd.socket");
283         t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
284         mkdir_parents_label(t, 0755);
285         if (symlink(f, t) < 0) {
286                 log_error("Failed to create symlink %s: %m", t);
287                 return -errno;
288         }
289
290         f = strappenda(units, "/systemd-bus-proxyd.socket");
291         t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
292         mkdir_parents_label(t, 0755);
293         if (symlink(f, t) < 0) {
294                 log_error("Failed to create symlink %s: %m", t);
295                 return -errno;
296         }
297
298         t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
299         if (symlink("/dev/null", t) < 0) {
300                 log_error("Failed to mask %s: %m", t);
301                 return -errno;
302         }
303
304         return 0;
305 }
306
307 int main(int argc, char *argv[]) {
308         const char *path, *type, *units;
309         int r, q;
310
311         if (argc > 1 && argc != 4) {
312                 log_error("This program takes three or no arguments.");
313                 return EXIT_FAILURE;
314         }
315
316         if (argc > 1) {
317                 arg_dest = argv[1];
318                 arg_dest_late = argv[3];
319         }
320
321         log_set_target(LOG_TARGET_SAFE);
322         log_parse_environment();
323         log_open();
324
325         umask(0022);
326
327         if (access("/dev/kdbus/control", F_OK) < 0)
328                 return 0;
329
330         r = cg_pid_get_owner_uid(0, NULL);
331         if (r >= 0) {
332                 path = "/usr/share/dbus-1/services";
333                 type = "session";
334                 units = USER_DATA_UNIT_PATH;
335         } else if (r == -ENOENT) {
336                 path = "/usr/share/dbus-1/system-services";
337                 type = "system";
338                 units = SYSTEM_DATA_UNIT_PATH;
339         } else {
340                 log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
341                 return r;
342         }
343
344         r = parse_dbus_fragments(path, type);
345
346         /* FIXME: One day this should just be pulled in statically from basic.target */
347         q = link_busnames_target(units);
348         if (q < 0)
349                 r = q;
350
351         q = link_compatibility(units);
352         if (q < 0)
353                 r = q;
354
355         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
356 }