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