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