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