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