]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/swap.c
sd-bus: properly translate high-level attach flags into kdbus attach flags
[thirdparty/systemd.git] / src / core / swap.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
07b0b134
ML
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
5430f7f2
LP
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
07b0b134
ML
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
5430f7f2 16 Lesser General Public License for more details.
07b0b134 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
07b0b134
ML
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <limits.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <sys/epoll.h>
27#include <sys/stat.h>
28#include <sys/swap.h>
e04aad61 29#include <libudev.h>
07b0b134
ML
30
31#include "unit.h"
32#include "swap.h"
33#include "load-fragment.h"
34#include "load-dropin.h"
35#include "unit-name.h"
36#include "dbus-swap.h"
514f4ef5 37#include "special.h"
8a0867d6 38#include "bus-errors.h"
9a57c629 39#include "exit-status.h"
f6a6225e 40#include "def.h"
9eb977db 41#include "path-util.h"
a5c3034f 42#include "virt.h"
5bcb0f2b 43#include "udev-util.h"
07b0b134
ML
44
45static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
46 [SWAP_DEAD] = UNIT_INACTIVE,
e04aad61 47 [SWAP_ACTIVATING] = UNIT_ACTIVATING,
5bcb0f2b 48 [SWAP_ACTIVATING_DONE] = UNIT_ACTIVE,
07b0b134 49 [SWAP_ACTIVE] = UNIT_ACTIVE,
e04aad61
LP
50 [SWAP_DEACTIVATING] = UNIT_DEACTIVATING,
51 [SWAP_ACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
52 [SWAP_ACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
53 [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
54 [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
fdf20a31 55 [SWAP_FAILED] = UNIT_FAILED
07b0b134
ML
56};
57
718db961
LP
58static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
59static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
60
e04aad61 61static void swap_unset_proc_swaps(Swap *s) {
9670d583
LP
62 assert(s);
63
64 if (!s->from_proc_swaps)
65 return;
66
67 free(s->parameters_proc_swaps.what);
68 s->parameters_proc_swaps.what = NULL;
69
70 s->from_proc_swaps = false;
71}
72
73static int swap_set_devnode(Swap *s, const char *devnode) {
df326b84 74 Hashmap *swaps;
5bcb0f2b 75 Swap *first;
9670d583 76 int r;
e04aad61
LP
77
78 assert(s);
79
9670d583
LP
80 r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, string_hash_func, string_compare_func);
81 if (r < 0)
82 return r;
e04aad61 83
9670d583 84 swaps = UNIT(s)->manager->swaps_by_devnode;
e04aad61 85
9670d583
LP
86 if (s->devnode) {
87 first = hashmap_get(swaps, s->devnode);
e04aad61 88
9670d583
LP
89 LIST_REMOVE(same_devnode, first, s);
90 if (first)
91 hashmap_replace(swaps, first->devnode, first);
92 else
93 hashmap_remove(swaps, s->devnode);
5bcb0f2b 94
9670d583
LP
95 free(s->devnode);
96 s->devnode = NULL;
97 }
98
99 if (devnode) {
100 s->devnode = strdup(devnode);
101 if (!s->devnode)
102 return -ENOMEM;
103
104 first = hashmap_get(swaps, s->devnode);
105 LIST_PREPEND(same_devnode, first, s);
106
107 return hashmap_replace(swaps, first->devnode, first);
108 }
109
110 return 0;
e04aad61
LP
111}
112
f6cebb3b 113static void swap_init(Unit *u) {
6e620bec
LP
114 Swap *s = SWAP(u);
115
116 assert(s);
1124fe6f 117 assert(UNIT(s)->load_state == UNIT_STUB);
6e620bec 118
1f19a534 119 s->timeout_usec = u->manager->default_timeout_start_usec;
e04aad61
LP
120
121 exec_context_init(&s->exec_context);
ac155bb8
MS
122 s->exec_context.std_output = u->manager->default_std_output;
123 s->exec_context.std_error = u->manager->default_std_error;
4819ff03 124 kill_context_init(&s->kill_context);
4ad49000 125 cgroup_context_init(&s->cgroup_context);
e04aad61 126
085afe36
LP
127 unit_cgroup_context_init_defaults(u, &s->cgroup_context);
128
6b1dc2bd 129 s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1;
e04aad61 130
e1770af8 131 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
c8f4d764 132
5bcb0f2b 133 u->ignore_on_isolate = true;
e04aad61
LP
134}
135
136static void swap_unwatch_control_pid(Swap *s) {
137 assert(s);
138
139 if (s->control_pid <= 0)
140 return;
141
142 unit_unwatch_pid(UNIT(s), s->control_pid);
143 s->control_pid = 0;
6e620bec
LP
144}
145
4e85aff4
LP
146static void swap_done(Unit *u) {
147 Swap *s = SWAP(u);
07b0b134 148
4e85aff4 149 assert(s);
07b0b134 150
e04aad61 151 swap_unset_proc_swaps(s);
9670d583 152 swap_set_devnode(s, NULL);
e04aad61 153
4e85aff4 154 free(s->what);
e04aad61
LP
155 s->what = NULL;
156
4e85aff4 157 free(s->parameters_fragment.what);
6b1dc2bd 158 s->parameters_fragment.what = NULL;
e04aad61 159
613b411c
LP
160 cgroup_context_done(&s->cgroup_context);
161 exec_context_done(&s->exec_context);
162 s->exec_runtime = exec_runtime_unref(s->exec_runtime);
e04aad61
LP
163 exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
164 s->control_command = NULL;
165
166 swap_unwatch_control_pid(s);
167
718db961
LP
168 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
169}
170
171static int swap_arm_timer(Swap *s) {
172 int r;
173
174 assert(s);
175
176 if (s->timeout_usec <= 0) {
177 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
178 return 0;
179 }
180
181 if (s->timer_event_source) {
182 r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec);
183 if (r < 0)
184 return r;
185
186 return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
187 }
188
151b9b96 189 return sd_event_add_monotonic(UNIT(s)->manager->event, &s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec, 0, swap_dispatch_timer, s);
07b0b134
ML
190}
191
173a8d04
LP
192static int swap_add_device_links(Swap *s) {
193 SwapParameters *p;
194
195 assert(s);
196
197 if (!s->what)
198 return 0;
199
200 if (s->from_fragment)
201 p = &s->parameters_fragment;
173a8d04
LP
202 else
203 return 0;
204
cfcfd4ae 205 if (is_device_path(s->what))
5bcb0f2b 206 return unit_add_node_link(UNIT(s), s->what, !p->noauto && UNIT(s)->manager->running_as == SYSTEMD_SYSTEM);
cfcfd4ae
LP
207 else
208 /* File based swap devices need to be ordered after
2b93b027 209 * systemd-remount-fs.service, since they might need a
cfcfd4ae 210 * writable file system. */
2b93b027 211 return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true);
173a8d04
LP
212}
213
2edd4434 214static int swap_add_default_dependencies(Swap *s) {
64347fc2 215 bool nofail = false, noauto = false;
2edd4434
LP
216 int r;
217
218 assert(s);
219
67445f4e 220 if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
6b1dc2bd 221 return 0;
2edd4434 222
c0387ebf
LP
223 if (detect_container(NULL) > 0)
224 return 0;
225
6b1dc2bd
LP
226 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
227 if (r < 0)
228 return r;
2edd4434 229
64347fc2
TG
230 if (s->from_fragment) {
231 SwapParameters *p = &s->parameters_fragment;
232
233 nofail = p->nofail;
234 noauto = p->noauto;
235 }
236
237 if (!noauto) {
4e82fe52 238 if (nofail)
5bcb0f2b 239 r = unit_add_dependency_by_name_inverse(UNIT(s), UNIT_WANTS, SPECIAL_SWAP_TARGET, NULL, true);
4e82fe52 240 else
5bcb0f2b 241 r = unit_add_two_dependencies_by_name_inverse(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SWAP_TARGET, NULL, true);
64347fc2
TG
242 if (r < 0)
243 return r;
244 }
245
2edd4434
LP
246 return 0;
247}
248
4e85aff4
LP
249static int swap_verify(Swap *s) {
250 bool b;
7fd1b19b 251 _cleanup_free_ char *e = NULL;
4e85aff4 252
1124fe6f 253 if (UNIT(s)->load_state != UNIT_LOADED)
5bcb0f2b 254 return 0;
4e85aff4 255
170ca19e 256 e = unit_name_from_path(s->what, ".swap");
5bcb0f2b 257 if (!e)
170ca19e 258 return log_oom();
4e85aff4
LP
259
260 b = unit_has_name(UNIT(s), e);
4e85aff4 261 if (!b) {
5bcb0f2b 262 log_error_unit(UNIT(s)->id, "%s: Value of \"What\" and unit name do not match, not loading.", UNIT(s)->id);
4e85aff4
LP
263 return -EINVAL;
264 }
265
4819ff03 266 if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
5bcb0f2b 267 log_error_unit(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.", UNIT(s)->id);
e04aad61
LP
268 return -EINVAL;
269 }
270
4e85aff4
LP
271 return 0;
272}
273
9670d583
LP
274static int swap_load_devnode(Swap *s) {
275 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
276 struct stat st;
277 const char *p;
278
279 assert(s);
280
281 if (stat(s->what, &st) < 0 || !S_ISBLK(st.st_mode))
282 return 0;
283
284 d = udev_device_new_from_devnum(UNIT(s)->manager->udev, 'b', st.st_rdev);
285 if (!d)
286 return 0;
287
288 p = udev_device_get_devnode(d);
289 if (!p)
290 return 0;
291
292 return swap_set_devnode(s, p);
293}
294
07b0b134
ML
295static int swap_load(Unit *u) {
296 int r;
297 Swap *s = SWAP(u);
298
299 assert(s);
ac155bb8 300 assert(u->load_state == UNIT_STUB);
07b0b134
ML
301
302 /* Load a .swap file */
646134dc
ZJS
303 r = unit_load_fragment_and_dropin_optional(u);
304 if (r < 0)
07b0b134
ML
305 return r;
306
ac155bb8 307 if (u->load_state == UNIT_LOADED) {
646134dc
ZJS
308 r = unit_add_exec_dependencies(u, &s->exec_context);
309 if (r < 0)
27abbe82 310 return r;
4e85aff4 311
1124fe6f 312 if (UNIT(s)->fragment_path)
4e85aff4
LP
313 s->from_fragment = true;
314
315 if (!s->what) {
316 if (s->parameters_fragment.what)
317 s->what = strdup(s->parameters_fragment.what);
4e85aff4
LP
318 else if (s->parameters_proc_swaps.what)
319 s->what = strdup(s->parameters_proc_swaps.what);
320 else
ac155bb8 321 s->what = unit_name_to_path(u->id);
4e85aff4
LP
322
323 if (!s->what)
07b0b134 324 return -ENOMEM;
4e85aff4 325 }
07b0b134
ML
326
327 path_kill_slashes(s->what);
328
5bcb0f2b
LP
329 if (!UNIT(s)->description) {
330 r = unit_set_description(u, s->what);
331 if (r < 0)
4e85aff4 332 return r;
5bcb0f2b 333 }
4e85aff4 334
a57f7e2c 335 r = unit_require_mounts_for(UNIT(s), s->what);
646134dc 336 if (r < 0)
07b0b134
ML
337 return r;
338
a57f7e2c 339 r = swap_add_device_links(s);
646134dc 340 if (r < 0)
6e2ef85b 341 return r;
07b0b134 342
9670d583
LP
343 r = swap_load_devnode(s);
344 if (r < 0)
345 return r;
346
a016b922
LP
347 r = unit_add_default_slice(u);
348 if (r < 0)
349 return r;
350
646134dc
ZJS
351 if (UNIT(s)->default_dependencies) {
352 r = swap_add_default_dependencies(s);
353 if (r < 0)
2edd4434 354 return r;
646134dc 355 }
e06c73cc 356
085afe36 357 r = unit_exec_context_patch_defaults(u, &s->exec_context);
e06c73cc
LP
358 if (r < 0)
359 return r;
07b0b134
ML
360 }
361
362 return swap_verify(s);
363}
364
6b1dc2bd 365static int swap_add_one(
4e85aff4
LP
366 Manager *m,
367 const char *what,
e04aad61 368 const char *what_proc_swaps,
4e85aff4
LP
369 int priority,
370 bool noauto,
173a8d04 371 bool nofail,
e04aad61
LP
372 bool set_flags) {
373
7fd1b19b 374 _cleanup_free_ char *e = NULL;
2c7c6144 375 bool delete = false;
5bcb0f2b 376 Unit *u = NULL;
07b0b134 377 int r;
4e85aff4
LP
378 SwapParameters *p;
379
380 assert(m);
381 assert(what);
6b1dc2bd 382 assert(what_proc_swaps);
07b0b134 383
7d17cfbc
MS
384 e = unit_name_from_path(what, ".swap");
385 if (!e)
170ca19e 386 return log_oom();
07b0b134 387
e04aad61
LP
388 u = manager_get_unit(m, e);
389
6b1dc2bd 390 if (u &&
e04aad61
LP
391 SWAP(u)->from_proc_swaps &&
392 !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
393 return -EEXIST;
4e85aff4
LP
394
395 if (!u) {
07b0b134
ML
396 delete = true;
397
7d17cfbc 398 u = unit_new(m, sizeof(Swap));
170ca19e
ZJS
399 if (!u)
400 return log_oom();
e04aad61 401
7d17cfbc
MS
402 r = unit_add_name(u, e);
403 if (r < 0)
e04aad61
LP
404 goto fail;
405
7d17cfbc
MS
406 SWAP(u)->what = strdup(what);
407 if (!SWAP(u)->what) {
646134dc 408 r = log_oom();
e04aad61
LP
409 goto fail;
410 }
411
412 unit_add_to_load_queue(u);
4e85aff4
LP
413 } else
414 delete = false;
07b0b134 415
6b1dc2bd 416 p = &SWAP(u)->parameters_proc_swaps;
07b0b134 417
6b1dc2bd 418 if (!p->what) {
5bcb0f2b
LP
419 p->what = strdup(what_proc_swaps);
420 if (!p->what) {
421 r = -ENOMEM;
6b1dc2bd
LP
422 goto fail;
423 }
6b1dc2bd 424 }
e04aad61 425
6b1dc2bd
LP
426 if (set_flags) {
427 SWAP(u)->is_active = true;
428 SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
4e85aff4 429 }
07b0b134 430
6b1dc2bd
LP
431 SWAP(u)->from_proc_swaps = true;
432
4e85aff4
LP
433 p->priority = priority;
434 p->noauto = noauto;
173a8d04 435 p->nofail = nofail;
07b0b134 436
4e85aff4 437 unit_add_to_dbus_queue(u);
07b0b134 438
07b0b134
ML
439 return 0;
440
441fail:
66870f90 442 log_warning_unit(e, "Failed to load swap unit: %s", strerror(-r));
e04aad61 443
4e85aff4 444 if (delete && u)
07b0b134
ML
445 unit_free(u);
446
4e85aff4 447 return r;
07b0b134
ML
448}
449
e04aad61 450static int swap_process_new_swap(Manager *m, const char *device, int prio, bool set_flags) {
5bcb0f2b
LP
451 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
452 struct udev_list_entry *item = NULL, *first = NULL;
453 const char *dn;
e04aad61 454 struct stat st;
5bcb0f2b 455 int r;
e04aad61
LP
456
457 assert(m);
458
5bcb0f2b
LP
459 r = swap_add_one(m, device, device, prio, false, false, set_flags);
460 if (r < 0)
461 return r;
e04aad61 462
5bcb0f2b
LP
463 /* If this is a block device, then let's add duplicates for
464 * all other names of this block device */
465 if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode))
466 return 0;
e04aad61 467
5bcb0f2b
LP
468 d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev);
469 if (!d)
470 return 0;
e04aad61 471
5bcb0f2b
LP
472 /* Add the main device node */
473 dn = udev_device_get_devnode(d);
474 if (dn && !streq(dn, device))
475 swap_add_one(m, dn, device, prio, false, false, set_flags);
e04aad61 476
5bcb0f2b
LP
477 /* Add additional units for all symlinks */
478 first = udev_device_get_devlinks_list_entry(d);
479 udev_list_entry_foreach(item, first) {
480 const char *p;
e04aad61 481
5bcb0f2b
LP
482 /* Don't bother with the /dev/block links */
483 p = udev_list_entry_get_name(item);
e04aad61 484
5bcb0f2b
LP
485 if (streq(p, device))
486 continue;
e04aad61 487
5bcb0f2b
LP
488 if (path_startswith(p, "/dev/block/"))
489 continue;
e04aad61 490
5bcb0f2b
LP
491 if (stat(p, &st) >= 0)
492 if (!S_ISBLK(st.st_mode) ||
493 st.st_rdev != udev_device_get_devnum(d))
494 continue;
e04aad61 495
5bcb0f2b 496 swap_add_one(m, p, device, prio, false, false, set_flags);
e04aad61
LP
497 }
498
e04aad61
LP
499 return r;
500}
501
07b0b134
ML
502static void swap_set_state(Swap *s, SwapState state) {
503 SwapState old_state;
e04aad61 504
07b0b134
ML
505 assert(s);
506
507 old_state = s->state;
508 s->state = state;
509
e04aad61
LP
510 if (state != SWAP_ACTIVATING &&
511 state != SWAP_ACTIVATING_SIGTERM &&
512 state != SWAP_ACTIVATING_SIGKILL &&
5bcb0f2b 513 state != SWAP_ACTIVATING_DONE &&
e04aad61
LP
514 state != SWAP_DEACTIVATING &&
515 state != SWAP_DEACTIVATING_SIGTERM &&
516 state != SWAP_DEACTIVATING_SIGKILL) {
718db961 517 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
e04aad61
LP
518 swap_unwatch_control_pid(s);
519 s->control_command = NULL;
520 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
521 }
522
07b0b134 523 if (state != old_state)
66870f90
ZJS
524 log_debug_unit(UNIT(s)->id,
525 "%s changed %s -> %s",
526 UNIT(s)->id,
527 swap_state_to_string(old_state),
528 swap_state_to_string(state));
07b0b134 529
5bcb0f2b 530 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
07b0b134
ML
531}
532
533static int swap_coldplug(Unit *u) {
534 Swap *s = SWAP(u);
535 SwapState new_state = SWAP_DEAD;
e04aad61 536 int r;
07b0b134
ML
537
538 assert(s);
539 assert(s->state == SWAP_DEAD);
540
541 if (s->deserialized_state != s->state)
542 new_state = s->deserialized_state;
4e85aff4 543 else if (s->from_proc_swaps)
07b0b134
ML
544 new_state = SWAP_ACTIVE;
545
5bcb0f2b
LP
546 if (new_state == s->state)
547 return 0;
e04aad61 548
5bcb0f2b
LP
549 if (new_state == SWAP_ACTIVATING ||
550 new_state == SWAP_ACTIVATING_SIGTERM ||
551 new_state == SWAP_ACTIVATING_SIGKILL ||
552 new_state == SWAP_ACTIVATING_DONE ||
553 new_state == SWAP_DEACTIVATING ||
554 new_state == SWAP_DEACTIVATING_SIGTERM ||
555 new_state == SWAP_DEACTIVATING_SIGKILL) {
e04aad61 556
5bcb0f2b
LP
557 if (s->control_pid <= 0)
558 return -EBADMSG;
e04aad61 559
5bcb0f2b
LP
560 r = unit_watch_pid(UNIT(s), s->control_pid);
561 if (r < 0)
562 return r;
e04aad61 563
5bcb0f2b
LP
564 r = swap_arm_timer(s);
565 if (r < 0)
566 return r;
e04aad61 567 }
07b0b134 568
5bcb0f2b 569 swap_set_state(s, new_state);
07b0b134
ML
570 return 0;
571}
572
573static void swap_dump(Unit *u, FILE *f, const char *prefix) {
574 Swap *s = SWAP(u);
4e85aff4 575 SwapParameters *p;
07b0b134
ML
576
577 assert(s);
4e85aff4
LP
578 assert(f);
579
580 if (s->from_proc_swaps)
581 p = &s->parameters_proc_swaps;
582 else if (s->from_fragment)
583 p = &s->parameters_fragment;
b6bfc7bb
LP
584 else
585 p = NULL;
07b0b134
ML
586
587 fprintf(f,
4e85aff4 588 "%sSwap State: %s\n"
e1770af8 589 "%sResult: %s\n"
07b0b134 590 "%sWhat: %s\n"
4e85aff4
LP
591 "%sFrom /proc/swaps: %s\n"
592 "%sFrom fragment: %s\n",
07b0b134 593 prefix, swap_state_to_string(s->state),
e1770af8 594 prefix, swap_result_to_string(s->result),
07b0b134 595 prefix, s->what,
4e85aff4
LP
596 prefix, yes_no(s->from_proc_swaps),
597 prefix, yes_no(s->from_fragment));
e04aad61 598
9670d583
LP
599 if (s->devnode)
600 fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode);
601
b6bfc7bb
LP
602 if (p)
603 fprintf(f,
604 "%sPriority: %i\n"
605 "%sNoAuto: %s\n"
606 "%sNoFail: %s\n",
607 prefix, p->priority,
608 prefix, yes_no(p->noauto),
609 prefix, yes_no(p->nofail));
610
e04aad61
LP
611 if (s->control_pid > 0)
612 fprintf(f,
613 "%sControl PID: %lu\n",
614 prefix, (unsigned long) s->control_pid);
615
616 exec_context_dump(&s->exec_context, f, prefix);
4819ff03 617 kill_context_dump(&s->kill_context, f, prefix);
e04aad61
LP
618}
619
620static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
621 pid_t pid;
622 int r;
623
624 assert(s);
625 assert(c);
626 assert(_pid);
627
4ad49000
LP
628 unit_realize_cgroup(UNIT(s));
629
613b411c
LP
630 r = unit_setup_exec_runtime(UNIT(s));
631 if (r < 0)
632 goto fail;
633
718db961 634 r = swap_arm_timer(s);
646134dc 635 if (r < 0)
e04aad61
LP
636 goto fail;
637
646134dc
ZJS
638 r = exec_spawn(c,
639 NULL,
640 &s->exec_context,
641 NULL, 0,
642 UNIT(s)->manager->environment,
643 true,
644 true,
645 true,
646 UNIT(s)->manager->confirm_spawn,
13b84ec7 647 UNIT(s)->manager->cgroup_supported,
4ad49000 648 UNIT(s)->cgroup_path,
e66cf1a3 649 manager_get_runtime_prefix(UNIT(s)->manager),
646134dc 650 UNIT(s)->id,
09812eb7 651 0,
646134dc 652 NULL,
613b411c 653 s->exec_runtime,
646134dc
ZJS
654 &pid);
655 if (r < 0)
e04aad61
LP
656 goto fail;
657
646134dc
ZJS
658 r = unit_watch_pid(UNIT(s), pid);
659 if (r < 0)
e04aad61
LP
660 /* FIXME: we need to do something here */
661 goto fail;
662
663 *_pid = pid;
664
665 return 0;
666
667fail:
718db961 668 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
e04aad61
LP
669
670 return r;
07b0b134
ML
671}
672
e1770af8 673static void swap_enter_dead(Swap *s, SwapResult f) {
07b0b134
ML
674 assert(s);
675
e1770af8
LP
676 if (f != SWAP_SUCCESS)
677 s->result = f;
e04aad61 678
613b411c
LP
679 exec_runtime_destroy(s->exec_runtime);
680 s->exec_runtime = exec_runtime_unref(s->exec_runtime);
681
e66cf1a3
LP
682 exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
683
e1770af8 684 swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
07b0b134
ML
685}
686
e1770af8 687static void swap_enter_active(Swap *s, SwapResult f) {
e04aad61
LP
688 assert(s);
689
e1770af8
LP
690 if (f != SWAP_SUCCESS)
691 s->result = f;
e04aad61
LP
692
693 swap_set_state(s, SWAP_ACTIVE);
694}
695
e1770af8 696static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
07b0b134
ML
697 int r;
698
699 assert(s);
e04aad61 700
e1770af8
LP
701 if (f != SWAP_SUCCESS)
702 s->result = f;
e04aad61 703
cd2086fe
LP
704 r = unit_kill_context(
705 UNIT(s),
706 &s->kill_context,
707 state != SWAP_ACTIVATING_SIGTERM && state != SWAP_DEACTIVATING_SIGTERM,
708 -1,
709 s->control_pid,
710 false);
711 if (r < 0)
712 goto fail;
e04aad61 713
cd2086fe 714 if (r > 0) {
718db961 715 r = swap_arm_timer(s);
646134dc 716 if (r < 0)
e04aad61
LP
717 goto fail;
718
719 swap_set_state(s, state);
ac84d1fb
LP
720 } else if (state == SWAP_ACTIVATING_SIGTERM)
721 swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_SUCCESS);
722 else if (state == SWAP_DEACTIVATING_SIGTERM)
723 swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_SUCCESS);
724 else
e1770af8 725 swap_enter_dead(s, SWAP_SUCCESS);
e04aad61
LP
726
727 return;
728
729fail:
66870f90
ZJS
730 log_warning_unit(UNIT(s)->id,
731 "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
e04aad61 732
e1770af8 733 swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
e04aad61
LP
734}
735
736static void swap_enter_activating(Swap *s) {
737 int r, priority;
738
739 assert(s);
740
741 s->control_command_id = SWAP_EXEC_ACTIVATE;
742 s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
07b0b134 743
4e85aff4
LP
744 if (s->from_fragment)
745 priority = s->parameters_fragment.priority;
e04aad61
LP
746 else
747 priority = -1;
4e85aff4 748
e04aad61 749 if (priority >= 0) {
5bcb0f2b 750 char p[DECIMAL_STR_MAX(int)];
07b0b134 751
5bcb0f2b 752 sprintf(p, "%i", priority);
07b0b134 753
e04aad61
LP
754 r = exec_command_set(
755 s->control_command,
756 "/sbin/swapon",
757 "-p",
758 p,
759 s->what,
760 NULL);
761 } else
762 r = exec_command_set(
763 s->control_command,
764 "/sbin/swapon",
765 s->what,
766 NULL);
767
768 if (r < 0)
769 goto fail;
770
771 swap_unwatch_control_pid(s);
772
646134dc
ZJS
773 r = swap_spawn(s, s->control_command, &s->control_pid);
774 if (r < 0)
e04aad61
LP
775 goto fail;
776
777 swap_set_state(s, SWAP_ACTIVATING);
778
779 return;
780
781fail:
66870f90
ZJS
782 log_warning_unit(UNIT(s)->id,
783 "%s failed to run 'swapon' task: %s",
784 UNIT(s)->id, strerror(-r));
e1770af8 785 swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
e04aad61
LP
786}
787
e1770af8 788static void swap_enter_deactivating(Swap *s) {
e04aad61
LP
789 int r;
790
791 assert(s);
792
e04aad61
LP
793 s->control_command_id = SWAP_EXEC_DEACTIVATE;
794 s->control_command = s->exec_command + SWAP_EXEC_DEACTIVATE;
795
646134dc 796 r = exec_command_set(s->control_command,
e04aad61
LP
797 "/sbin/swapoff",
798 s->what,
646134dc
ZJS
799 NULL);
800 if (r < 0)
e04aad61
LP
801 goto fail;
802
803 swap_unwatch_control_pid(s);
804
646134dc
ZJS
805 r = swap_spawn(s, s->control_command, &s->control_pid);
806 if (r < 0)
e04aad61
LP
807 goto fail;
808
809 swap_set_state(s, SWAP_DEACTIVATING);
810
811 return;
812
813fail:
66870f90
ZJS
814 log_warning_unit(UNIT(s)->id,
815 "%s failed to run 'swapoff' task: %s",
816 UNIT(s)->id, strerror(-r));
e1770af8 817 swap_enter_active(s, SWAP_FAILURE_RESOURCES);
e04aad61
LP
818}
819
820static int swap_start(Unit *u) {
821 Swap *s = SWAP(u);
822
823 assert(s);
824
825 /* We cannot fulfill this request right now, try again later
826 * please! */
827
828 if (s->state == SWAP_DEACTIVATING ||
829 s->state == SWAP_DEACTIVATING_SIGTERM ||
830 s->state == SWAP_DEACTIVATING_SIGKILL ||
831 s->state == SWAP_ACTIVATING_SIGTERM ||
832 s->state == SWAP_ACTIVATING_SIGKILL)
833 return -EAGAIN;
834
835 if (s->state == SWAP_ACTIVATING)
836 return 0;
837
838 assert(s->state == SWAP_DEAD || s->state == SWAP_FAILED);
839
a5c3034f
LP
840 if (detect_container(NULL) > 0)
841 return -EPERM;
842
e1770af8 843 s->result = SWAP_SUCCESS;
e04aad61 844 swap_enter_activating(s);
07b0b134
ML
845 return 0;
846}
847
848static int swap_stop(Unit *u) {
849 Swap *s = SWAP(u);
07b0b134
ML
850
851 assert(s);
852
e04aad61
LP
853 if (s->state == SWAP_DEACTIVATING ||
854 s->state == SWAP_DEACTIVATING_SIGTERM ||
855 s->state == SWAP_DEACTIVATING_SIGKILL ||
856 s->state == SWAP_ACTIVATING_SIGTERM ||
857 s->state == SWAP_ACTIVATING_SIGKILL)
858 return 0;
07b0b134 859
e04aad61 860 assert(s->state == SWAP_ACTIVATING ||
5bcb0f2b 861 s->state == SWAP_ACTIVATING_DONE ||
e04aad61 862 s->state == SWAP_ACTIVE);
07b0b134 863
a5c3034f
LP
864 if (detect_container(NULL) > 0)
865 return -EPERM;
866
e1770af8 867 swap_enter_deactivating(s);
07b0b134
ML
868 return 0;
869}
870
871static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
872 Swap *s = SWAP(u);
873
874 assert(s);
875 assert(f);
876 assert(fds);
877
878 unit_serialize_item(u, f, "state", swap_state_to_string(s->state));
e1770af8 879 unit_serialize_item(u, f, "result", swap_result_to_string(s->result));
e04aad61
LP
880
881 if (s->control_pid > 0)
882 unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid);
883
884 if (s->control_command_id >= 0)
885 unit_serialize_item(u, f, "control-command", swap_exec_command_to_string(s->control_command_id));
07b0b134
ML
886
887 return 0;
888}
889
890static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
891 Swap *s = SWAP(u);
892
893 assert(s);
894 assert(fds);
895
896 if (streq(key, "state")) {
897 SwapState state;
898
646134dc
ZJS
899 state = swap_state_from_string(value);
900 if (state < 0)
66870f90 901 log_debug_unit(u->id, "Failed to parse state value %s", value);
07b0b134
ML
902 else
903 s->deserialized_state = state;
e1770af8
LP
904 } else if (streq(key, "result")) {
905 SwapResult f;
906
907 f = swap_result_from_string(value);
908 if (f < 0)
66870f90 909 log_debug_unit(u->id, "Failed to parse result value %s", value);
e1770af8
LP
910 else if (f != SWAP_SUCCESS)
911 s->result = f;
e04aad61
LP
912 } else if (streq(key, "control-pid")) {
913 pid_t pid;
914
915 if (parse_pid(value, &pid) < 0)
66870f90 916 log_debug_unit(u->id, "Failed to parse control-pid value %s", value);
e04aad61
LP
917 else
918 s->control_pid = pid;
919
920 } else if (streq(key, "control-command")) {
921 SwapExecCommand id;
922
646134dc
ZJS
923 id = swap_exec_command_from_string(value);
924 if (id < 0)
66870f90 925 log_debug_unit(u->id, "Failed to parse exec-command value %s", value);
e04aad61
LP
926 else {
927 s->control_command_id = id;
928 s->control_command = s->exec_command + id;
929 }
07b0b134 930 } else
66870f90 931 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
07b0b134
ML
932
933 return 0;
934}
935
44a6b1b6 936_pure_ static UnitActiveState swap_active_state(Unit *u) {
07b0b134
ML
937 assert(u);
938
939 return state_translation_table[SWAP(u)->state];
940}
941
44a6b1b6 942_pure_ static const char *swap_sub_state_to_string(Unit *u) {
07b0b134
ML
943 assert(u);
944
945 return swap_state_to_string(SWAP(u)->state);
946}
947
44a6b1b6 948_pure_ static bool swap_check_gc(Unit *u) {
07b0b134
ML
949 Swap *s = SWAP(u);
950
951 assert(s);
952
6b1dc2bd 953 return s->from_proc_swaps;
07b0b134
ML
954}
955
e04aad61
LP
956static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
957 Swap *s = SWAP(u);
e1770af8 958 SwapResult f;
e04aad61
LP
959
960 assert(s);
961 assert(pid >= 0);
962
963 if (pid != s->control_pid)
964 return;
965
966 s->control_pid = 0;
967
96342de6 968 if (is_clean_exit(code, status, NULL))
e1770af8
LP
969 f = SWAP_SUCCESS;
970 else if (code == CLD_EXITED)
971 f = SWAP_FAILURE_EXIT_CODE;
972 else if (code == CLD_KILLED)
973 f = SWAP_FAILURE_SIGNAL;
974 else if (code == CLD_DUMPED)
975 f = SWAP_FAILURE_CORE_DUMP;
976 else
977 assert_not_reached("Unknown code");
978
979 if (f != SWAP_SUCCESS)
980 s->result = f;
e04aad61
LP
981
982 if (s->control_command) {
6ea832a2 983 exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
e1770af8 984
e04aad61
LP
985 s->control_command = NULL;
986 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
987 }
988
66870f90
ZJS
989 log_full_unit(f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
990 u->id,
991 "%s swap process exited, code=%s status=%i",
992 u->id, sigchld_code_to_string(code), status);
e04aad61
LP
993
994 switch (s->state) {
995
996 case SWAP_ACTIVATING:
5bcb0f2b 997 case SWAP_ACTIVATING_DONE:
e04aad61
LP
998 case SWAP_ACTIVATING_SIGTERM:
999 case SWAP_ACTIVATING_SIGKILL:
1000
e1770af8
LP
1001 if (f == SWAP_SUCCESS)
1002 swap_enter_active(s, f);
e04aad61 1003 else
e1770af8 1004 swap_enter_dead(s, f);
e04aad61
LP
1005 break;
1006
1007 case SWAP_DEACTIVATING:
1008 case SWAP_DEACTIVATING_SIGKILL:
1009 case SWAP_DEACTIVATING_SIGTERM:
1010
7bb01eff 1011 swap_enter_dead(s, f);
e04aad61
LP
1012 break;
1013
1014 default:
1015 assert_not_reached("Uh, control process died at wrong time.");
1016 }
1017
1018 /* Notify clients about changed exit status */
1019 unit_add_to_dbus_queue(u);
e04aad61
LP
1020}
1021
718db961
LP
1022static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
1023 Swap *s = SWAP(userdata);
e04aad61
LP
1024
1025 assert(s);
718db961 1026 assert(s->timer_event_source == source);
e04aad61
LP
1027
1028 switch (s->state) {
1029
1030 case SWAP_ACTIVATING:
5bcb0f2b 1031 case SWAP_ACTIVATING_DONE:
718db961 1032 log_warning_unit(UNIT(s)->id, "%s activation timed out. Stopping.", UNIT(s)->id);
e1770af8 1033 swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
e04aad61
LP
1034 break;
1035
1036 case SWAP_DEACTIVATING:
718db961 1037 log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Stopping.", UNIT(s)->id);
e1770af8 1038 swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
e04aad61
LP
1039 break;
1040
1041 case SWAP_ACTIVATING_SIGTERM:
4819ff03 1042 if (s->kill_context.send_sigkill) {
718db961 1043 log_warning_unit(UNIT(s)->id, "%s activation timed out. Killing.", UNIT(s)->id);
e1770af8 1044 swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
ba035df2 1045 } else {
718db961 1046 log_warning_unit(UNIT(s)->id, "%s activation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
e1770af8 1047 swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
ba035df2 1048 }
e04aad61
LP
1049 break;
1050
1051 case SWAP_DEACTIVATING_SIGTERM:
4819ff03 1052 if (s->kill_context.send_sigkill) {
718db961 1053 log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Killing.", UNIT(s)->id);
e1770af8 1054 swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
ba035df2 1055 } else {
718db961 1056 log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
e1770af8 1057 swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
ba035df2 1058 }
e04aad61
LP
1059 break;
1060
1061 case SWAP_ACTIVATING_SIGKILL:
1062 case SWAP_DEACTIVATING_SIGKILL:
718db961 1063 log_warning_unit(UNIT(s)->id, "%s swap process still around after SIGKILL. Ignoring.", UNIT(s)->id);
e1770af8 1064 swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
e04aad61
LP
1065 break;
1066
1067 default:
1068 assert_not_reached("Timeout at wrong time.");
1069 }
718db961
LP
1070
1071 return 0;
e04aad61
LP
1072}
1073
1074static int swap_load_proc_swaps(Manager *m, bool set_flags) {
1075 unsigned i;
1076 int r = 0;
1077
1078 assert(m);
1079
07b0b134 1080 rewind(m->proc_swaps);
bab45044 1081
4e85aff4 1082 (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n");
07b0b134 1083
e04aad61 1084 for (i = 1;; i++) {
9fb3675e 1085 _cleanup_free_ char *dev = NULL, *d = NULL;
07b0b134
ML
1086 int prio = 0, k;
1087
646134dc
ZJS
1088 k = fscanf(m->proc_swaps,
1089 "%ms " /* device/file */
1090 "%*s " /* type of swap */
1091 "%*s " /* swap size */
1092 "%*s " /* used */
1093 "%i\n", /* priority */
1094 &dev, &prio);
1095 if (k != 2) {
07b0b134 1096 if (k == EOF)
4e85aff4 1097 break;
07b0b134 1098
646134dc 1099 log_warning("Failed to parse /proc/swaps:%u", i);
e04aad61 1100 continue;
07b0b134 1101 }
07b0b134 1102
4e85aff4 1103 d = cunescape(dev);
4e85aff4
LP
1104 if (!d)
1105 return -ENOMEM;
1106
e04aad61 1107 k = swap_process_new_swap(m, d, prio, set_flags);
07b0b134 1108 if (k < 0)
e04aad61 1109 r = k;
07b0b134
ML
1110 }
1111
e04aad61
LP
1112 return r;
1113}
1114
718db961
LP
1115static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
1116 Manager *m = userdata;
595ed347 1117 Unit *u;
4e434314
LP
1118 int r;
1119
1120 assert(m);
718db961 1121 assert(revents & EPOLLPRI);
4e434314 1122
646134dc
ZJS
1123 r = swap_load_proc_swaps(m, true);
1124 if (r < 0) {
e04aad61
LP
1125 log_error("Failed to reread /proc/swaps: %s", strerror(-r));
1126
1127 /* Reset flags, just in case, for late calls */
595ed347
MS
1128 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
1129 Swap *swap = SWAP(u);
e04aad61
LP
1130
1131 swap->is_active = swap->just_activated = false;
1132 }
1133
1134 return 0;
1135 }
1136
1137 manager_dispatch_load_queue(m);
1138
595ed347
MS
1139 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
1140 Swap *swap = SWAP(u);
e04aad61
LP
1141
1142 if (!swap->is_active) {
1143 /* This has just been deactivated */
1144
e04aad61
LP
1145 swap_unset_proc_swaps(swap);
1146
1147 switch (swap->state) {
1148
1149 case SWAP_ACTIVE:
e1770af8 1150 swap_enter_dead(swap, SWAP_SUCCESS);
e04aad61
LP
1151 break;
1152
1153 default:
5bcb0f2b 1154 /* Fire again */
e04aad61
LP
1155 swap_set_state(swap, swap->state);
1156 break;
1157 }
1158
1159 } else if (swap->just_activated) {
1160
1161 /* New swap entry */
1162
1163 switch (swap->state) {
1164
1165 case SWAP_DEAD:
1166 case SWAP_FAILED:
e1770af8 1167 swap_enter_active(swap, SWAP_SUCCESS);
e04aad61
LP
1168 break;
1169
5bcb0f2b
LP
1170 case SWAP_ACTIVATING:
1171 swap_set_state(swap, SWAP_ACTIVATING_DONE);
1172 break;
1173
e04aad61
LP
1174 default:
1175 /* Nothing really changed, but let's
1176 * issue an notification call
1177 * nonetheless, in case somebody is
1178 * waiting for this. */
1179 swap_set_state(swap, swap->state);
1180 break;
1181 }
1182 }
1183
1184 /* Reset the flags for later calls */
1185 swap->is_active = swap->just_activated = false;
1186 }
1187
1188 return 1;
1189}
1190
1191static Unit *swap_following(Unit *u) {
1192 Swap *s = SWAP(u);
1193 Swap *other, *first = NULL;
1194
1195 assert(s);
1196
9670d583 1197 if (streq_ptr(s->what, s->devnode))
e04aad61
LP
1198 return NULL;
1199
1200 /* Make everybody follow the unit that's named after the swap
1201 * device in the kernel */
1202
9670d583
LP
1203 LIST_FOREACH_AFTER(same_devnode, other, s)
1204 if (streq_ptr(other->what, other->devnode))
e04aad61
LP
1205 return UNIT(other);
1206
9670d583
LP
1207 LIST_FOREACH_BEFORE(same_devnode, other, s) {
1208 if (streq_ptr(other->what, other->devnode))
e04aad61
LP
1209 return UNIT(other);
1210
1211 first = other;
1212 }
1213
1214 return UNIT(first);
07b0b134
ML
1215}
1216
6210e7fc 1217static int swap_following_set(Unit *u, Set **_set) {
5bcb0f2b 1218 Swap *s = SWAP(u), *other;
6210e7fc
LP
1219 Set *set;
1220 int r;
1221
1222 assert(s);
1223 assert(_set);
1224
9670d583 1225 if (LIST_JUST_US(same_devnode, s)) {
6210e7fc
LP
1226 *_set = NULL;
1227 return 0;
1228 }
1229
5bcb0f2b
LP
1230 set = set_new(NULL, NULL);
1231 if (!set)
6210e7fc
LP
1232 return -ENOMEM;
1233
9670d583 1234 LIST_FOREACH_AFTER(same_devnode, other, s) {
5bcb0f2b
LP
1235 r = set_put(set, other);
1236 if (r < 0)
6210e7fc 1237 goto fail;
5bcb0f2b 1238 }
6210e7fc 1239
9670d583 1240 LIST_FOREACH_BEFORE(same_devnode, other, s) {
5bcb0f2b
LP
1241 r = set_put(set, other);
1242 if (r < 0)
6210e7fc 1243 goto fail;
5bcb0f2b 1244 }
6210e7fc
LP
1245
1246 *_set = set;
1247 return 1;
1248
1249fail:
1250 set_free(set);
1251 return r;
1252}
1253
07b0b134
ML
1254static void swap_shutdown(Manager *m) {
1255 assert(m);
1256
718db961
LP
1257 m->swap_event_source = sd_event_source_unref(m->swap_event_source);
1258
07b0b134
ML
1259 if (m->proc_swaps) {
1260 fclose(m->proc_swaps);
1261 m->proc_swaps = NULL;
1262 }
e04aad61 1263
9670d583
LP
1264 hashmap_free(m->swaps_by_devnode);
1265 m->swaps_by_devnode = NULL;
07b0b134
ML
1266}
1267
07b0b134
ML
1268static int swap_enumerate(Manager *m) {
1269 int r;
9670d583 1270
07b0b134
ML
1271 assert(m);
1272
4e434314 1273 if (!m->proc_swaps) {
646134dc
ZJS
1274 m->proc_swaps = fopen("/proc/swaps", "re");
1275 if (!m->proc_swaps)
718db961 1276 return errno == ENOENT ? 0 : -errno;
4e434314 1277
151b9b96 1278 r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m);
718db961 1279 if (r < 0)
29083707
LP
1280 goto fail;
1281
1282 /* Dispatch this before we dispatch SIGCHLD, so that
1283 * we always get the events from /proc/swaps before
1284 * the SIGCHLD of /sbin/swapon. */
1285 r = sd_event_source_set_priority(m->swap_event_source, -10);
1286 if (r < 0)
718db961 1287 goto fail;
4e434314
LP
1288 }
1289
646134dc
ZJS
1290 r = swap_load_proc_swaps(m, false);
1291 if (r < 0)
718db961
LP
1292 goto fail;
1293
1294 return 0;
07b0b134 1295
718db961
LP
1296fail:
1297 swap_shutdown(m);
07b0b134
ML
1298 return r;
1299}
1300
9670d583
LP
1301int swap_process_new_device(Manager *m, struct udev_device *dev) {
1302 struct udev_list_entry *item = NULL, *first = NULL;
1303 _cleanup_free_ char *e = NULL;
1304 const char *dn;
1305 Swap *s;
1306 int r = 0;
1307
1308 assert(m);
1309 assert(dev);
1310
1311 dn = udev_device_get_devnode(dev);
1312 if (!dn)
1313 return 0;
1314
1315 e = unit_name_from_path(dn, ".swap");
1316 if (!e)
1317 return -ENOMEM;
1318
1319 s = hashmap_get(m->units, e);
1320 if (s)
1321 r = swap_set_devnode(s, dn);
1322
1323 first = udev_device_get_devlinks_list_entry(dev);
1324 udev_list_entry_foreach(item, first) {
1325 _cleanup_free_ char *n = NULL;
1326
1327 n = unit_name_from_path(udev_list_entry_get_name(item), ".swap");
1328 if (!n)
1329 return -ENOMEM;
1330
1331 s = hashmap_get(m->units, n);
1332 if (s) {
1333 int q;
1334
1335 q = swap_set_devnode(s, dn);
1336 if (q < 0)
1337 r = q;
1338 }
1339 }
1340
1341 return r;
1342}
1343
1344int swap_process_removed_device(Manager *m, struct udev_device *dev) {
9670d583
LP
1345 const char *dn;
1346 int r = 0;
1347 Swap *s;
1348
1349 dn = udev_device_get_devnode(dev);
1350 if (!dn)
1351 return 0;
1352
1353 while ((s = hashmap_get(m->swaps_by_devnode, dn))) {
1354 int q;
1355
1356 q = swap_set_devnode(s, NULL);
1357 if (q < 0)
1358 r = q;
1359 }
1360
1361 return r;
1362}
1363
fdf20a31 1364static void swap_reset_failed(Unit *u) {
5632e374
LP
1365 Swap *s = SWAP(u);
1366
1367 assert(s);
1368
fdf20a31 1369 if (s->state == SWAP_FAILED)
5632e374 1370 swap_set_state(s, SWAP_DEAD);
e04aad61 1371
e1770af8 1372 s->result = SWAP_SUCCESS;
5632e374
LP
1373}
1374
718db961 1375static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
814cc562 1376 return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error);
8a0867d6
LP
1377}
1378
68db7a3b
ZJS
1379static int swap_get_timeout(Unit *u, uint64_t *timeout) {
1380 Swap *s = SWAP(u);
1381 int r;
1382
1383 if (!s->timer_event_source)
1384 return 0;
1385
1386 r = sd_event_source_get_time(s->timer_event_source, timeout);
1387 if (r < 0)
1388 return r;
1389
1390 return 1;
1391}
1392
5632e374
LP
1393static const char* const swap_state_table[_SWAP_STATE_MAX] = {
1394 [SWAP_DEAD] = "dead",
e04aad61 1395 [SWAP_ACTIVATING] = "activating",
5bcb0f2b 1396 [SWAP_ACTIVATING_DONE] = "activating-done",
5632e374 1397 [SWAP_ACTIVE] = "active",
e04aad61
LP
1398 [SWAP_DEACTIVATING] = "deactivating",
1399 [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
1400 [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
1401 [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
1402 [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
fdf20a31 1403 [SWAP_FAILED] = "failed"
5632e374
LP
1404};
1405
1406DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
1407
e04aad61
LP
1408static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
1409 [SWAP_EXEC_ACTIVATE] = "ExecActivate",
1410 [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
1411};
1412
1413DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand);
1414
e1770af8
LP
1415static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
1416 [SWAP_SUCCESS] = "success",
1417 [SWAP_FAILURE_RESOURCES] = "resources",
1418 [SWAP_FAILURE_TIMEOUT] = "timeout",
1419 [SWAP_FAILURE_EXIT_CODE] = "exit-code",
1420 [SWAP_FAILURE_SIGNAL] = "signal",
1421 [SWAP_FAILURE_CORE_DUMP] = "core-dump"
1422};
1423
1424DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
1425
07b0b134 1426const UnitVTable swap_vtable = {
7d17cfbc 1427 .object_size = sizeof(Swap),
718db961
LP
1428 .exec_context_offset = offsetof(Swap, exec_context),
1429 .cgroup_context_offset = offsetof(Swap, cgroup_context),
1430 .kill_context_offset = offsetof(Swap, kill_context),
613b411c 1431 .exec_runtime_offset = offsetof(Swap, exec_runtime),
3ef63c31 1432
f975e971
LP
1433 .sections =
1434 "Unit\0"
1435 "Swap\0"
1436 "Install\0",
4ad49000 1437 .private_section = "Swap",
71645aca 1438
e04aad61 1439 .no_alias = true,
07b0b134
ML
1440 .no_instances = true,
1441
4e85aff4 1442 .init = swap_init,
07b0b134 1443 .load = swap_load,
6e620bec 1444 .done = swap_done,
07b0b134
ML
1445
1446 .coldplug = swap_coldplug,
1447
1448 .dump = swap_dump,
1449
1450 .start = swap_start,
1451 .stop = swap_stop,
1452
8a0867d6
LP
1453 .kill = swap_kill,
1454
68db7a3b
ZJS
1455 .get_timeout = swap_get_timeout,
1456
07b0b134
ML
1457 .serialize = swap_serialize,
1458 .deserialize_item = swap_deserialize_item,
1459
1460 .active_state = swap_active_state,
1461 .sub_state_to_string = swap_sub_state_to_string,
1462
1463 .check_gc = swap_check_gc,
1464
e04aad61 1465 .sigchld_event = swap_sigchld_event,
e04aad61
LP
1466
1467 .reset_failed = swap_reset_failed,
1468
c4e2ceae 1469 .bus_interface = "org.freedesktop.systemd1.Swap",
718db961 1470 .bus_vtable = bus_swap_vtable,
74c964d3
LP
1471 .bus_set_property = bus_swap_set_property,
1472 .bus_commit_properties = bus_swap_commit_properties,
07b0b134 1473
e04aad61 1474 .following = swap_following,
6210e7fc 1475 .following_set = swap_following_set,
5632e374 1476
6e620bec 1477 .enumerate = swap_enumerate,
c6918296
MS
1478 .shutdown = swap_shutdown,
1479
1480 .status_message_formats = {
1481 .starting_stopping = {
1482 [0] = "Activating swap %s...",
1483 [1] = "Deactivating swap %s...",
1484 },
1485 .finished_start_job = {
1486 [JOB_DONE] = "Activated swap %s.",
1487 [JOB_FAILED] = "Failed to activate swap %s.",
1488 [JOB_DEPENDENCY] = "Dependency failed for %s.",
1489 [JOB_TIMEOUT] = "Timed out activating swap %s.",
1490 },
1491 .finished_stop_job = {
1492 [JOB_DONE] = "Deactivated swap %s.",
1493 [JOB_FAILED] = "Failed deactivating swap %s.",
1494 [JOB_TIMEOUT] = "Timed out deactivating swap %s.",
1495 },
1496 },
07b0b134 1497};