chiark / gitweb /
71f985345a1579aa1836a9203aa759d83c4152a5
[elogind.git] / src / machine / machined-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 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 <errno.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <pwd.h>
26
27 #include "sd-id128.h"
28 #include "sd-messages.h"
29
30 #include "strv.h"
31 #include "mkdir.h"
32 #include "path-util.h"
33 #include "special.h"
34 #include "fileio-label.h"
35 #include "label.h"
36 #include "utf8.h"
37 #include "unit-name.h"
38 #include "bus-util.h"
39 #include "time-util.h"
40 #include "cgroup-util.h"
41 #include "machined.h"
42
43 static bool valid_machine_name(const char *p) {
44         size_t l;
45
46         if (!filename_is_safe(p))
47                 return false;
48
49         if (!ascii_is_valid(p))
50                 return false;
51
52         l = strlen(p);
53
54         if (l < 1 || l> 64)
55                 return false;
56
57         return true;
58 }
59
60 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
61         _cleanup_free_ char *p = NULL;
62         Manager *m = userdata;
63         Machine *machine;
64         const char *name;
65         int r;
66
67         assert(bus);
68         assert(message);
69         assert(m);
70
71         r = sd_bus_message_read(message, "s", &name);
72         if (r < 0)
73                 return sd_bus_reply_method_errno(bus, message, r, NULL);
74
75         machine = hashmap_get(m->machines, name);
76         if (!machine)
77                 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
78
79         p = machine_bus_path(machine);
80         if (!p)
81                 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
82
83         return sd_bus_reply_method_return(bus, message, "o", p);
84 }
85
86 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata) {
87         _cleanup_free_ char *p = NULL;
88         Manager *m = userdata;
89         Machine *machine = NULL;
90         pid_t pid;
91         int r;
92
93         assert(bus);
94         assert(message);
95         assert(m);
96
97         assert_cc(sizeof(pid_t) == sizeof(uint32_t));
98
99         r = sd_bus_message_read(message, "u", &pid);
100         if (r < 0)
101                 return sd_bus_reply_method_errno(bus, message, r, NULL);
102
103         if (pid == 0) {
104                 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
105                 if (r < 0)
106                         return sd_bus_reply_method_errno(bus, message, r, NULL);
107         }
108
109         r = manager_get_machine_by_pid(m, pid, &machine);
110         if (r < 0)
111                 return sd_bus_reply_method_errno(bus, message, r, NULL);
112         if (!machine)
113                 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_MACHINE_FOR_PID, "PID %lu does not belong to any known machine", (unsigned long) pid);
114
115         p = machine_bus_path(machine);
116         if (!p)
117                 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
118
119         return sd_bus_reply_method_return(bus, message, "o", p);
120 }
121
122 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata) {
123         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
124         Manager *m = userdata;
125         Machine *machine;
126         Iterator i;
127         int r;
128
129         assert(bus);
130         assert(message);
131         assert(m);
132
133         r = sd_bus_message_new_method_return(bus, message, &reply);
134         if (r < 0)
135                 return sd_bus_reply_method_errno(bus, message, r, NULL);
136
137         r = sd_bus_message_open_container(reply, 'a', "(ssso)");
138         if (r < 0)
139                 return sd_bus_reply_method_errno(bus, message, r, NULL);
140
141         HASHMAP_FOREACH(machine, m->machines, i) {
142                 _cleanup_free_ char *p = NULL;
143
144                 p = machine_bus_path(machine);
145                 if (!p)
146                         return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
147
148                 r = sd_bus_message_append(reply, "(ssso)",
149                                           machine->name,
150                                           strempty(machine_class_to_string(machine->class)),
151                                           machine->service,
152                                           p);
153                 if (r < 0)
154                         return sd_bus_reply_method_errno(bus, message, r, NULL);
155         }
156
157         r = sd_bus_message_close_container(reply);
158         if (r < 0)
159                 return sd_bus_reply_method_errno(bus, message, r, NULL);
160
161         return sd_bus_send(bus, reply, NULL);
162 }
163
164 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
165         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
166         const char *name, *service, *class, *root_directory;
167         Manager *manager = userdata;
168         MachineClass c;
169         uint32_t leader;
170         sd_id128_t id;
171         const void *v;
172         Machine *m;
173         size_t n;
174         int r;
175
176         assert(bus);
177         assert(message);
178         assert(manager);
179
180         r = sd_bus_message_read(message, "s", &name);
181         if (r < 0)
182                 return sd_bus_reply_method_errno(bus, message, r, NULL);
183         if (!valid_machine_name(name))
184                 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
185
186         r = sd_bus_message_read_array(message, 'y', &v, &n);
187         if (r < 0)
188                 return sd_bus_reply_method_errno(bus, message, r, NULL);
189         if (n == 0)
190                 id = SD_ID128_NULL;
191         else if (n == 16)
192                 memcpy(&id, v, n);
193         else
194                 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
195
196         r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
197         if (r < 0)
198                 return sd_bus_reply_method_errno(bus, message, r, NULL);
199
200         if (isempty(class))
201                 c = _MACHINE_CLASS_INVALID;
202         else {
203                 c = machine_class_from_string(class);
204                 if (c < 0)
205                         return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
206         }
207
208         if (leader == 1)
209                 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
210
211         if (!isempty(root_directory) && !path_is_absolute(root_directory))
212                 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
213
214         r = sd_bus_message_enter_container(message, 'a', "(sv)");
215         if (r < 0)
216                 return sd_bus_reply_method_errno(bus, message, r, NULL);
217
218         if (leader == 0) {
219                 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
220
221                 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), (pid_t*) &leader);
222                 if (r < 0)
223                         return sd_bus_reply_method_errno(bus, message, r, NULL);
224         }
225
226         if (hashmap_get(manager->machines, name))
227                 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
228
229         r = manager_add_machine(manager, name, &m);
230         if (r < 0)
231                 return sd_bus_reply_method_errno(bus, message, r, NULL);
232
233         m->leader = leader;
234         m->class = c;
235         m->id = id;
236
237         if (!isempty(service)) {
238                 m->service = strdup(service);
239                 if (!m->service) {
240                         r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
241                         goto fail;
242                 }
243         }
244
245         if (!isempty(root_directory)) {
246                 m->root_directory = strdup(root_directory);
247                 if (!m->root_directory) {
248                         r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
249                         goto fail;
250                 }
251         }
252
253         r = machine_start(m, message, &error);
254         if (r < 0) {
255                 r = sd_bus_reply_method_errno(bus, message, r, &error);
256                 goto fail;
257         }
258
259         m->create_message = sd_bus_message_ref(message);
260
261         return 1;
262
263 fail:
264         machine_add_to_gc_queue(m);
265
266         return r;
267 }
268
269 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
270         Manager *m = userdata;
271         Machine *machine;
272         const char *name;
273         int r;
274
275         assert(bus);
276         assert(message);
277         assert(m);
278
279         r = sd_bus_message_read(message, "s", &name);
280         if (r < 0)
281                 return sd_bus_reply_method_errno(bus, message, r, NULL);
282
283         machine = hashmap_get(m->machines, name);
284         if (!machine)
285                 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
286
287         r = machine_stop(machine);
288         if (r < 0)
289                 return sd_bus_reply_method_errno(bus, message, r, NULL);
290
291         return sd_bus_reply_method_return(bus, message, NULL);
292 }
293
294 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
295         Manager *m = userdata;
296         Machine *machine;
297         const char *name;
298         const char *swho;
299         int32_t signo;
300         KillWho who;
301         int r;
302
303         assert(bus);
304         assert(message);
305         assert(m);
306
307         r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
308         if (r < 0)
309                 return sd_bus_reply_method_errno(bus, message, r, NULL);
310
311         if (isempty(swho))
312                 who = KILL_ALL;
313         else {
314                 who = kill_who_from_string(swho);
315                 if (who < 0)
316                         return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
317         }
318
319         if (signo <= 0 || signo >= _NSIG)
320                 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
321
322         machine = hashmap_get(m->machines, name);
323         if (!machine)
324                 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
325
326         r = machine_kill(machine, who, signo);
327         if (r < 0)
328                 return sd_bus_reply_method_errno(bus, message, r, NULL);
329
330         return sd_bus_reply_method_return(bus, message, NULL);
331 }
332
333 const sd_bus_vtable manager_vtable[] = {
334         SD_BUS_VTABLE_START(0),
335         SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, 0),
336         SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, 0),
337         SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, 0),
338         SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
339         SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, 0),
340         SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, 0),
341         SD_BUS_SIGNAL("MachineNew", "so", 0),
342         SD_BUS_SIGNAL("MachineRemoved", "so", 0),
343         SD_BUS_VTABLE_END
344 };
345
346 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
347         const char *path, *result, *unit;
348         Manager *m = userdata;
349         Machine *machine;
350         uint32_t id;
351         int r;
352
353         assert(bus);
354         assert(message);
355         assert(m);
356
357         r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
358         if (r < 0) {
359                 log_error("Failed to parse JobRemoved message: %s", strerror(-r));
360                 return 0;
361         }
362
363         machine = hashmap_get(m->machine_units, unit);
364         if (!machine)
365                 return 0;
366
367         if (streq_ptr(path, machine->scope_job)) {
368                 free(machine->scope_job);
369                 machine->scope_job = NULL;
370
371                 if (machine->started) {
372                         if (streq(result, "done"))
373                                 machine_send_create_reply(machine, NULL);
374                         else {
375                                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
376
377                                 sd_bus_error_setf(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
378
379                                 machine_send_create_reply(machine, &error);
380                         }
381                 } else
382                         machine_save(machine);
383         }
384
385         machine_add_to_gc_queue(machine);
386         return 0;
387 }
388
389 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
390         _cleanup_free_ char *unit = NULL;
391         Manager *m = userdata;
392         Machine *machine;
393         const char *path;
394
395         assert(bus);
396         assert(message);
397         assert(m);
398
399         path = sd_bus_message_get_path(message);
400         if (!path)
401                 return 0;
402
403         unit_name_from_dbus_path(path, &unit);
404         if (!unit)
405                 return 0;
406
407         machine = hashmap_get(m->machine_units, unit);
408         if (machine)
409                 machine_add_to_gc_queue(machine);
410
411         return 0;
412 }
413
414 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
415         const char *path, *unit;
416         Manager *m = userdata;
417         Machine *machine;
418         int r;
419
420         assert(bus);
421         assert(message);
422         assert(m);
423
424         r = sd_bus_message_read(message, "so", &unit, &path);
425         if (r < 0) {
426                 log_error("Failed to parse UnitRemoved message: %s", strerror(-r));
427                 return 0;
428         }
429
430         machine = hashmap_get(m->machine_units, unit);
431         if (machine)
432                 machine_add_to_gc_queue(machine);
433
434         return 0;
435 }
436
437 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata) {
438         Manager *m = userdata;
439         Machine *machine;
440         Iterator i;
441         int b, r;
442
443         assert(bus);
444
445         r = sd_bus_message_read(message, "b", &b);
446         if (r < 0) {
447                 log_error("Failed to parse Reloading message: %s", strerror(-r));
448                 return 0;
449         }
450
451         if (b)
452                 return 0;
453
454         /* systemd finished reloading, let's recheck all our machines */
455         log_debug("System manager has been reloaded, rechecking machines...");
456
457         HASHMAP_FOREACH(machine, m->machines, i)
458                 machine_add_to_gc_queue(machine);
459
460         return 0;
461 }
462
463 int manager_start_scope(
464                 Manager *manager,
465                 const char *scope,
466                 pid_t pid,
467                 const char *slice,
468                 const char *description,
469                 sd_bus_message *more_properties,
470                 sd_bus_error *error,
471                 char **job) {
472
473         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
474         int r;
475
476         assert(manager);
477         assert(scope);
478         assert(pid > 1);
479
480         r = sd_bus_message_new_method_call(
481                         manager->bus,
482                         "org.freedesktop.systemd1",
483                         "/org/freedesktop/systemd1",
484                         "org.freedesktop.systemd1.Manager",
485                         "StartTransientUnit",
486                         &m);
487         if (r < 0)
488                 return r;
489
490         r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
491         if (r < 0)
492                 return r;
493
494         r = sd_bus_message_open_container(m, 'a', "(sv)");
495         if (r < 0)
496                 return r;
497
498         if (!isempty(slice)) {
499                 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
500                 if (r < 0)
501                         return r;
502         }
503
504         if (!isempty(description)) {
505                 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
506                 if (r < 0)
507                         return r;
508         }
509
510         /* cgroup empty notification is not available in containers
511          * currently. To make this less problematic, let's shorten the
512          * stop timeout for machines, so that we don't wait
513          * forever. */
514         r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
515         if (r < 0)
516                 return r;
517
518         r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
519         if (r < 0)
520                 return r;
521
522         if (more_properties) {
523                 r = sd_bus_message_copy(m, more_properties, true);
524                 if (r < 0)
525                         return r;
526         }
527
528         r = sd_bus_message_close_container(m);
529         if (r < 0)
530                 return r;
531
532         r = sd_bus_send_with_reply_and_block(manager->bus, m, 0, error, &reply);
533         if (r < 0)
534                 return r;
535
536         if (job) {
537                 const char *j;
538                 char *copy;
539
540                 r = sd_bus_message_read(reply, "o", &j);
541                 if (r < 0)
542                         return r;
543
544                 copy = strdup(j);
545                 if (!copy)
546                         return -ENOMEM;
547
548                 *job = copy;
549         }
550
551         return 1;
552 }
553
554 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
555         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
556         int r;
557
558         assert(manager);
559         assert(unit);
560
561         r = sd_bus_call_method(
562                         manager->bus,
563                         "org.freedesktop.systemd1",
564                         "/org/freedesktop/systemd1",
565                         "org.freedesktop.systemd1.Manager",
566                         "StopUnit",
567                         error,
568                         &reply,
569                         "ss", unit, "fail");
570         if (r < 0) {
571                 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
572                     sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
573
574                         if (job)
575                                 *job = NULL;
576
577                         sd_bus_error_free(error);
578                         return 0;
579                 }
580
581                 return r;
582         }
583
584         if (job) {
585                 const char *j;
586                 char *copy;
587
588                 r = sd_bus_message_read(reply, "o", &j);
589                 if (r < 0)
590                         return r;
591
592                 copy = strdup(j);
593                 if (!copy)
594                         return -ENOMEM;
595
596                 *job = copy;
597         }
598
599         return 1;
600 }
601
602 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
603         assert(manager);
604         assert(unit);
605
606         return sd_bus_call_method(
607                         manager->bus,
608                         "org.freedesktop.systemd1",
609                         "/org/freedesktop/systemd1",
610                         "org.freedesktop.systemd1.Manager",
611                         "KillUnit",
612                         error,
613                         NULL,
614                         "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
615 }
616
617 int manager_unit_is_active(Manager *manager, const char *unit) {
618         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
619         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
620         _cleanup_free_ char *path = NULL;
621         const char *state;
622         int r;
623
624         assert(manager);
625         assert(unit);
626
627         path = unit_dbus_path_from_name(unit);
628         if (!path)
629                 return -ENOMEM;
630
631         r = sd_bus_get_property(
632                         manager->bus,
633                         "org.freedesktop.systemd1",
634                         path,
635                         "org.freedesktop.systemd1.Unit",
636                         "ActiveState",
637                         &error,
638                         &reply,
639                         "s");
640         if (r < 0) {
641                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
642                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
643                         return true;
644
645                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
646                     sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
647                         return false;
648
649                 return r;
650         }
651
652         r = sd_bus_message_read(reply, "s", &state);
653         if (r < 0)
654                 return -EINVAL;
655
656         return !streq(state, "inactive") && !streq(state, "failed");
657 }
658
659 int manager_job_is_active(Manager *manager, const char *path) {
660         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
661         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
662         int r;
663
664         assert(manager);
665         assert(path);
666
667         r = sd_bus_get_property(
668                         manager->bus,
669                         "org.freedesktop.systemd1",
670                         path,
671                         "org.freedesktop.systemd1.Job",
672                         "State",
673                         &error,
674                         &reply,
675                         "s");
676         if (r < 0) {
677                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
678                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
679                         return true;
680
681                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
682                         return false;
683
684                 return r;
685         }
686
687         /* We don't actually care about the state really. The fact
688          * that we could read the job state is enough for us */
689
690         return true;
691 }
692
693 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
694         _cleanup_free_ char *unit = NULL;
695         Machine *mm;
696         int r;
697
698         assert(m);
699         assert(pid >= 1);
700         assert(machine);
701
702         r = cg_pid_get_unit(pid, &unit);
703         if (r < 0)
704                 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
705         else
706                 mm = hashmap_get(m->machine_units, unit);
707
708         if (!mm)
709                 return 0;
710
711         *machine = mm;
712         return 1;
713 }
714
715 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
716         Machine *machine;
717
718         assert(m);
719         assert(name);
720
721         machine = hashmap_get(m->machines, name);
722         if (!machine) {
723                 machine = machine_new(m, name);
724                 if (!machine)
725                         return -ENOMEM;
726         }
727
728         if (_machine)
729                 *_machine = machine;
730
731         return 0;
732 }