chiark / gitweb /
systemd-fsck: always connect to systemd-fsckd
[elogind.git] / src / machine / machine.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 <string.h>
23 #include <unistd.h>
24 #include <errno.h>
25
26 #include "sd-messages.h"
27
28 #include "util.h"
29 #include "mkdir.h"
30 #include "hashmap.h"
31 #include "strv.h"
32 #include "fileio.h"
33 #include "special.h"
34 #include "unit-name.h"
35 #include "bus-util.h"
36 #include "bus-error.h"
37 #include "machine.h"
38 #include "machine-dbus.h"
39
40 Machine* machine_new(Manager *manager, const char *name) {
41         Machine *m;
42
43         assert(manager);
44         assert(name);
45
46         m = new0(Machine, 1);
47         if (!m)
48                 return NULL;
49
50         m->name = strdup(name);
51         if (!m->name)
52                 goto fail;
53
54         m->state_file = strappend("/run/systemd/machines/", m->name);
55         if (!m->state_file)
56                 goto fail;
57
58         if (hashmap_put(manager->machines, m->name, m) < 0)
59                 goto fail;
60
61         m->class = _MACHINE_CLASS_INVALID;
62         m->manager = manager;
63
64         return m;
65
66 fail:
67         free(m->state_file);
68         free(m->name);
69         free(m);
70
71         return NULL;
72 }
73
74 void machine_free(Machine *m) {
75         assert(m);
76
77         while (m->operations)
78                 machine_operation_unref(m->operations);
79
80         if (m->in_gc_queue)
81                 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
82
83         if (m->unit) {
84                 hashmap_remove(m->manager->machine_units, m->unit);
85                 free(m->unit);
86         }
87
88         free(m->scope_job);
89
90         hashmap_remove(m->manager->machines, m->name);
91
92         if (m->leader > 0)
93                 hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
94
95         sd_bus_message_unref(m->create_message);
96
97         free(m->name);
98         free(m->state_file);
99         free(m->service);
100         free(m->root_directory);
101         free(m->netif);
102         free(m);
103 }
104
105 int machine_save(Machine *m) {
106         _cleanup_free_ char *temp_path = NULL;
107         _cleanup_fclose_ FILE *f = NULL;
108         int r;
109
110         assert(m);
111         assert(m->state_file);
112
113         if (!m->started)
114                 return 0;
115
116         r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
117         if (r < 0)
118                 goto finish;
119
120         r = fopen_temporary(m->state_file, &f, &temp_path);
121         if (r < 0)
122                 goto finish;
123
124         fchmod(fileno(f), 0644);
125
126         fprintf(f,
127                 "# This is private data. Do not parse.\n"
128                 "NAME=%s\n",
129                 m->name);
130
131         if (m->unit) {
132                 _cleanup_free_ char *escaped;
133
134                 escaped = cescape(m->unit);
135                 if (!escaped) {
136                         r = -ENOMEM;
137                         goto finish;
138                 }
139
140                 fprintf(f, "SCOPE=%s\n", escaped); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
141         }
142
143         if (m->scope_job)
144                 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
145
146         if (m->service) {
147                 _cleanup_free_ char *escaped;
148
149                 escaped = cescape(m->service);
150                 if (!escaped) {
151                         r = -ENOMEM;
152                         goto finish;
153                 }
154                 fprintf(f, "SERVICE=%s\n", escaped);
155         }
156
157         if (m->root_directory) {
158                 _cleanup_free_ char *escaped;
159
160                 escaped = cescape(m->root_directory);
161                 if (!escaped) {
162                         r = -ENOMEM;
163                         goto finish;
164                 }
165                 fprintf(f, "ROOT=%s\n", escaped);
166         }
167
168         if (!sd_id128_equal(m->id, SD_ID128_NULL))
169                 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
170
171         if (m->leader != 0)
172                 fprintf(f, "LEADER="PID_FMT"\n", m->leader);
173
174         if (m->class != _MACHINE_CLASS_INVALID)
175                 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
176
177         if (dual_timestamp_is_set(&m->timestamp))
178                 fprintf(f,
179                         "REALTIME="USEC_FMT"\n"
180                         "MONOTONIC="USEC_FMT"\n",
181                         m->timestamp.realtime,
182                         m->timestamp.monotonic);
183
184         if (m->n_netif > 0) {
185                 unsigned i;
186
187                 fputs("NETIF=", f);
188
189                 for (i = 0; i < m->n_netif; i++) {
190                         if (i != 0)
191                                 fputc(' ', f);
192
193                         fprintf(f, "%i", m->netif[i]);
194                 }
195
196                 fputc('\n', f);
197         }
198
199         r = fflush_and_check(f);
200         if (r < 0)
201                 goto finish;
202
203         if (rename(temp_path, m->state_file) < 0) {
204                 r = -errno;
205                 goto finish;
206         }
207
208         free(temp_path);
209         temp_path = NULL;
210
211         if (m->unit) {
212                 char *sl;
213
214                 /* Create a symlink from the unit name to the machine
215                  * name, so that we can quickly find the machine for
216                  * each given unit */
217                 sl = strjoina("/run/systemd/machines/unit:", m->unit);
218                 symlink(m->name, sl);
219         }
220
221 finish:
222         if (temp_path)
223                 unlink(temp_path);
224
225         if (r < 0)
226                 log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
227
228         return r;
229 }
230
231 static void machine_unlink(Machine *m) {
232         assert(m);
233
234         if (m->unit) {
235
236                 char *sl;
237
238                 sl = strjoina("/run/systemd/machines/unit:", m->unit);
239                 unlink(sl);
240         }
241
242         if (m->state_file)
243                 unlink(m->state_file);
244 }
245
246 int machine_load(Machine *m) {
247         _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
248         int r;
249
250         assert(m);
251
252         r = parse_env_file(m->state_file, NEWLINE,
253                            "SCOPE",     &m->unit,
254                            "SCOPE_JOB", &m->scope_job,
255                            "SERVICE",   &m->service,
256                            "ROOT",      &m->root_directory,
257                            "ID",        &id,
258                            "LEADER",    &leader,
259                            "CLASS",     &class,
260                            "REALTIME",  &realtime,
261                            "MONOTONIC", &monotonic,
262                            "NETIF",     &netif,
263                            NULL);
264         if (r < 0) {
265                 if (r == -ENOENT)
266                         return 0;
267
268                 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
269         }
270
271         if (id)
272                 sd_id128_from_string(id, &m->id);
273
274         if (leader)
275                 parse_pid(leader, &m->leader);
276
277         if (class) {
278                 MachineClass c;
279
280                 c = machine_class_from_string(class);
281                 if (c >= 0)
282                         m->class = c;
283         }
284
285         if (realtime) {
286                 unsigned long long l;
287                 if (sscanf(realtime, "%llu", &l) > 0)
288                         m->timestamp.realtime = l;
289         }
290
291         if (monotonic) {
292                 unsigned long long l;
293                 if (sscanf(monotonic, "%llu", &l) > 0)
294                         m->timestamp.monotonic = l;
295         }
296
297         if (netif) {
298                 size_t l, allocated = 0, nr = 0;
299                 const char *word, *state;
300                 int *ni = NULL;
301
302                 FOREACH_WORD(word, l, netif, state) {
303                         char buf[l+1];
304                         int ifi;
305
306                         *(char*) (mempcpy(buf, word, l)) = 0;
307
308                         if (safe_atoi(buf, &ifi) < 0)
309                                 continue;
310                         if (ifi <= 0)
311                                 continue;
312
313                         if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
314                                 free(ni);
315                                 return log_oom();
316                         }
317
318                         ni[nr++] = ifi;
319                 }
320
321                 free(m->netif);
322                 m->netif = ni;
323                 m->n_netif = nr;
324         }
325
326         return r;
327 }
328
329 static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
330         int r = 0;
331
332         assert(m);
333
334         if (!m->unit) {
335                 _cleanup_free_ char *escaped = NULL;
336                 char *scope, *description, *job = NULL;
337
338                 escaped = unit_name_escape(m->name);
339                 if (!escaped)
340                         return log_oom();
341
342                 scope = strjoin("machine-", escaped, ".scope", NULL);
343                 if (!scope)
344                         return log_oom();
345
346                 description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
347
348                 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
349                 if (r < 0) {
350                         log_error("Failed to start machine scope: %s", bus_error_message(error, r));
351                         free(scope);
352                         return r;
353                 } else {
354                         m->unit = scope;
355
356                         free(m->scope_job);
357                         m->scope_job = job;
358                 }
359         }
360
361         if (m->unit)
362                 hashmap_put(m->manager->machine_units, m->unit, m);
363
364         return r;
365 }
366
367 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
368         int r;
369
370         assert(m);
371
372         if (m->started)
373                 return 0;
374
375         r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
376         if (r < 0)
377                 return r;
378
379         /* Create cgroup */
380         r = machine_start_scope(m, properties, error);
381         if (r < 0)
382                 return r;
383
384         log_struct(LOG_INFO,
385                    LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START),
386                    "NAME=%s", m->name,
387                    "LEADER="PID_FMT, m->leader,
388                    LOG_MESSAGE("New machine %s.", m->name),
389                    NULL);
390
391         if (!dual_timestamp_is_set(&m->timestamp))
392                 dual_timestamp_get(&m->timestamp);
393
394         m->started = true;
395
396         /* Save new machine data */
397         machine_save(m);
398
399         machine_send_signal(m, true);
400
401         return 0;
402 }
403
404 static int machine_stop_scope(Machine *m) {
405         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
406         char *job = NULL;
407         int r;
408
409         assert(m);
410
411         if (!m->unit)
412                 return 0;
413
414         r = manager_stop_unit(m->manager, m->unit, &error, &job);
415         if (r < 0) {
416                 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
417                 return r;
418         }
419
420         free(m->scope_job);
421         m->scope_job = job;
422
423         return 0;
424 }
425
426 int machine_stop(Machine *m) {
427         int r = 0, k;
428         assert(m);
429
430         if (m->started)
431                 log_struct(LOG_INFO,
432                            LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
433                            "NAME=%s", m->name,
434                            "LEADER="PID_FMT, m->leader,
435                            LOG_MESSAGE("Machine %s terminated.", m->name),
436                            NULL);
437
438         /* Kill cgroup */
439         k = machine_stop_scope(m);
440         if (k < 0)
441                 r = k;
442
443         machine_unlink(m);
444         machine_add_to_gc_queue(m);
445
446         if (m->started)
447                 machine_send_signal(m, false);
448
449         m->started = false;
450
451         return r;
452 }
453
454 bool machine_check_gc(Machine *m, bool drop_not_started) {
455         assert(m);
456
457         if (drop_not_started && !m->started)
458                 return false;
459
460         if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
461                 return true;
462
463         if (m->unit && manager_unit_is_active(m->manager, m->unit))
464                 return true;
465
466         return false;
467 }
468
469 void machine_add_to_gc_queue(Machine *m) {
470         assert(m);
471
472         if (m->in_gc_queue)
473                 return;
474
475         LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
476         m->in_gc_queue = true;
477 }
478
479 MachineState machine_get_state(Machine *s) {
480         assert(s);
481
482         if (s->scope_job)
483                 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
484
485         return MACHINE_RUNNING;
486 }
487
488 int machine_kill(Machine *m, KillWho who, int signo) {
489         assert(m);
490
491         if (!m->unit)
492                 return -ESRCH;
493
494         if (who == KILL_LEADER) {
495                 /* If we shall simply kill the leader, do so directly */
496
497                 if (kill(m->leader, signo) < 0)
498                         return -errno;
499
500                 return 0;
501         }
502
503         /* Otherwise make PID 1 do it for us, for the entire cgroup */
504         return manager_kill_unit(m->manager, m->unit, signo, NULL);
505 }
506
507 MachineOperation *machine_operation_unref(MachineOperation *o) {
508         if (!o)
509                 return NULL;
510
511         sd_event_source_unref(o->event_source);
512
513         safe_close(o->errno_fd);
514
515         if (o->pid > 1)
516                 (void) kill(o->pid, SIGKILL);
517
518         sd_bus_message_unref(o->message);
519
520         if (o->machine) {
521                 LIST_REMOVE(operations, o->machine->operations, o);
522                 o->machine->n_operations--;
523         }
524
525         free(o);
526         return NULL;
527 }
528
529 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
530         [MACHINE_CONTAINER] = "container",
531         [MACHINE_VM] = "vm"
532 };
533
534 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
535
536 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
537         [MACHINE_OPENING] = "opening",
538         [MACHINE_RUNNING] = "running",
539         [MACHINE_CLOSING] = "closing"
540 };
541
542 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
543
544 static const char* const kill_who_table[_KILL_WHO_MAX] = {
545         [KILL_LEADER] = "leader",
546         [KILL_ALL] = "all"
547 };
548
549 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);