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