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