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