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