]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/mount.c
readahead: minor code style fixes
[thirdparty/systemd.git] / src / core / mount.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5cb5a6ff 2
a7334b09
LP
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
a7334b09
LP
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.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
5cb5a6ff 22#include <errno.h>
b08d03ff
LP
23#include <stdio.h>
24#include <mntent.h>
ef734fd6 25#include <sys/epoll.h>
e537352b 26#include <signal.h>
5cb5a6ff 27
87f0e418 28#include "unit.h"
5cb5a6ff
LP
29#include "mount.h"
30#include "load-fragment.h"
5cb5a6ff 31#include "load-dropin.h"
b08d03ff 32#include "log.h"
e537352b 33#include "strv.h"
49e942b2 34#include "mkdir.h"
9eb977db 35#include "path-util.h"
e537352b 36#include "mount-setup.h"
9e2f7c11 37#include "unit-name.h"
4139c1b2 38#include "dbus-mount.h"
514f4ef5 39#include "special.h"
8a0867d6 40#include "bus-errors.h"
9a57c629 41#include "exit-status.h"
f6a6225e 42#include "def.h"
5cb5a6ff 43
f50e0a01
LP
44static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
45 [MOUNT_DEAD] = UNIT_INACTIVE,
46 [MOUNT_MOUNTING] = UNIT_ACTIVATING,
e537352b 47 [MOUNT_MOUNTING_DONE] = UNIT_ACTIVE,
f50e0a01 48 [MOUNT_MOUNTED] = UNIT_ACTIVE,
032ff4af 49 [MOUNT_REMOUNTING] = UNIT_RELOADING,
f50e0a01 50 [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
e537352b
LP
51 [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING,
52 [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING,
032ff4af
LP
53 [MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING,
54 [MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING,
e537352b
LP
55 [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
56 [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING,
fdf20a31 57 [MOUNT_FAILED] = UNIT_FAILED
f50e0a01 58};
5cb5a6ff 59
a16e1123
LP
60static void mount_init(Unit *u) {
61 Mount *m = MOUNT(u);
5cb5a6ff 62
a16e1123 63 assert(u);
ac155bb8 64 assert(u->load_state == UNIT_STUB);
a16e1123
LP
65
66 m->timeout_usec = DEFAULT_TIMEOUT_USEC;
3e5235b0
LP
67 m->directory_mode = 0755;
68
c3686083 69 exec_context_init(&m->exec_context);
d893269d 70
6b1dc2bd
LP
71 if (unit_has_name(u, "-.mount")) {
72 /* Don't allow start/stop for root directory */
73 UNIT(m)->refuse_manual_start = true;
74 UNIT(m)->refuse_manual_stop = true;
75 } else {
76 /* The stdio/kmsg bridge socket is on /, in order to avoid a
77 * dep loop, don't use kmsg logging for -.mount */
ac155bb8
MS
78 m->exec_context.std_output = u->manager->default_std_output;
79 m->exec_context.std_error = u->manager->default_std_error;
f6cebb3b 80 }
c3686083 81
a16e1123
LP
82 /* We need to make sure that /bin/mount is always called in
83 * the same process group as us, so that the autofs kernel
84 * side doesn't send us another mount request while we are
85 * already trying to comply its last one. */
74922904 86 m->exec_context.same_pgrp = true;
8d567588 87
a16e1123
LP
88 m->timer_watch.type = WATCH_INVALID;
89
90 m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
c8f4d764 91
1124fe6f 92 UNIT(m)->ignore_on_isolate = true;
8d567588
LP
93}
94
a16e1123 95static void mount_unwatch_control_pid(Mount *m) {
5e94833f
LP
96 assert(m);
97
98 if (m->control_pid <= 0)
99 return;
100
101 unit_unwatch_pid(UNIT(m), m->control_pid);
102 m->control_pid = 0;
103}
104
e537352b
LP
105static void mount_parameters_done(MountParameters *p) {
106 assert(p);
107
108 free(p->what);
109 free(p->options);
110 free(p->fstype);
111
112 p->what = p->options = p->fstype = NULL;
113}
114
87f0e418 115static void mount_done(Unit *u) {
ef734fd6 116 Mount *m = MOUNT(u);
034c6ed7 117
ef734fd6 118 assert(m);
034c6ed7 119
e537352b
LP
120 free(m->where);
121 m->where = NULL;
f50e0a01 122
e537352b
LP
123 mount_parameters_done(&m->parameters_proc_self_mountinfo);
124 mount_parameters_done(&m->parameters_fragment);
ef734fd6 125
e537352b
LP
126 exec_context_done(&m->exec_context);
127 exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
128 m->control_command = NULL;
f50e0a01 129
a16e1123 130 mount_unwatch_control_pid(m);
f50e0a01 131
e537352b 132 unit_unwatch_timer(u, &m->timer_watch);
f50e0a01
LP
133}
134
6b1dc2bd 135static MountParameters* get_mount_parameters_fragment(Mount *m) {
cb39ed3f
LP
136 assert(m);
137
138 if (m->from_fragment)
139 return &m->parameters_fragment;
cb39ed3f
LP
140
141 return NULL;
142}
143
144static MountParameters* get_mount_parameters(Mount *m) {
145 assert(m);
146
147 if (m->from_proc_self_mountinfo)
148 return &m->parameters_proc_self_mountinfo;
149
6b1dc2bd 150 return get_mount_parameters_fragment(m);
cb39ed3f
LP
151}
152
6e2ef85b 153static int mount_add_mount_links(Mount *m) {
ac155bb8 154 Unit *other;
b08d03ff 155 int r;
5c78d8e2 156 MountParameters *pm;
b08d03ff 157
6e2ef85b 158 assert(m);
b08d03ff 159
6b1dc2bd 160 pm = get_mount_parameters_fragment(m);
5c78d8e2 161
6e2ef85b
LP
162 /* Adds in links to other mount points that might lie below or
163 * above us in the hierarchy */
e537352b 164
1124fe6f 165 LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_MOUNT]) {
595ed347 166 Mount *n = MOUNT(other);
5c78d8e2 167 MountParameters *pn;
07b0b134 168
6e2ef85b
LP
169 if (n == m)
170 continue;
b08d03ff 171
1124fe6f 172 if (UNIT(n)->load_state != UNIT_LOADED)
6e2ef85b 173 continue;
b08d03ff 174
6b1dc2bd 175 pn = get_mount_parameters_fragment(n);
5c78d8e2 176
6e2ef85b 177 if (path_startswith(m->where, n->where)) {
b08d03ff 178
6e2ef85b
LP
179 if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
180 return r;
b08d03ff 181
cb39ed3f 182 if (pn)
6e2ef85b
LP
183 if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
184 return r;
b08d03ff 185
6e2ef85b 186 } else if (path_startswith(n->where, m->where)) {
b08d03ff 187
5c78d8e2
LP
188 if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
189 return r;
190
cb39ed3f 191 if (pm)
5c78d8e2
LP
192 if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
193 return r;
194
9631c090 195 } else if (pm && pm->what && path_startswith(pm->what, n->where)) {
5c78d8e2
LP
196
197 if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
6e2ef85b
LP
198 return r;
199
cb39ed3f
LP
200 if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
201 return r;
5c78d8e2 202
9631c090 203 } else if (pn && pn->what && path_startswith(pn->what, m->where)) {
5c78d8e2
LP
204
205 if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
206 return r;
207
cb39ed3f
LP
208 if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
209 return r;
6e2ef85b
LP
210 }
211 }
b08d03ff
LP
212
213 return 0;
214}
215
6e2ef85b 216static int mount_add_swap_links(Mount *m) {
ac155bb8 217 Unit *other;
b08d03ff
LP
218 int r;
219
6e2ef85b 220 assert(m);
b08d03ff 221
1124fe6f 222 LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SWAP])
595ed347 223 if ((r = swap_add_one_mount_link(SWAP(other), m)) < 0)
6e2ef85b 224 return r;
b08d03ff 225
6e2ef85b
LP
226 return 0;
227}
b08d03ff 228
01f78473 229static int mount_add_path_links(Mount *m) {
ac155bb8 230 Unit *other;
01f78473
LP
231 int r;
232
233 assert(m);
234
1124fe6f 235 LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_PATH])
595ed347 236 if ((r = path_add_one_mount_link(PATH(other), m)) < 0)
01f78473
LP
237 return r;
238
239 return 0;
240}
241
6e2ef85b 242static int mount_add_automount_links(Mount *m) {
ac155bb8 243 Unit *other;
6e2ef85b 244 int r;
e537352b 245
6e2ef85b 246 assert(m);
b08d03ff 247
1124fe6f 248 LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_AUTOMOUNT])
595ed347 249 if ((r = automount_add_one_mount_link(AUTOMOUNT(other), m)) < 0)
6e2ef85b 250 return r;
b08d03ff 251
6e2ef85b
LP
252 return 0;
253}
b08d03ff 254
6e2ef85b 255static int mount_add_socket_links(Mount *m) {
ac155bb8 256 Unit *other;
6e2ef85b 257 int r;
b08d03ff 258
6e2ef85b 259 assert(m);
b08d03ff 260
1124fe6f 261 LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SOCKET])
595ed347 262 if ((r = socket_add_one_mount_link(SOCKET(other), m)) < 0)
6e2ef85b 263 return r;
b08d03ff
LP
264
265 return 0;
266}
267
7c8fa05c
LP
268static int mount_add_requires_mounts_links(Mount *m) {
269 Unit *other;
270 int r;
271
272 assert(m);
273
274 LIST_FOREACH(has_requires_mounts_for, other, UNIT(m)->manager->has_requires_mounts_for) {
275 r = unit_add_one_mount_link(other, m);
276 if (r < 0)
277 return r;
278 }
279
280 return 0;
281}
282
07b0b134 283static char* mount_test_option(const char *haystack, const char *needle) {
e537352b
LP
284 struct mntent me;
285
286 assert(needle);
287
288 /* Like glibc's hasmntopt(), but works on a string, not a
289 * struct mntent */
290
291 if (!haystack)
6a39419f 292 return NULL;
e537352b
LP
293
294 zero(me);
295 me.mnt_opts = (char*) haystack;
296
07b0b134 297 return hasmntopt(&me, needle);
e537352b
LP
298}
299
cb39ed3f
LP
300static bool mount_is_network(MountParameters *p) {
301 assert(p);
302
303 if (mount_test_option(p->options, "_netdev"))
304 return true;
305
306 if (p->fstype && fstype_is_network(p->fstype))
307 return true;
308
309 return false;
310}
311
312static bool mount_is_bind(MountParameters *p) {
313 assert(p);
314
315 if (mount_test_option(p->options, "bind"))
316 return true;
317
318 if (p->fstype && streq(p->fstype, "bind"))
319 return true;
320
321 return false;
322}
323
324static bool needs_quota(MountParameters *p) {
325 assert(p);
326
327 if (mount_is_network(p))
328 return false;
329
330 if (mount_is_bind(p))
331 return false;
332
333 return mount_test_option(p->options, "usrquota") ||
d3354f66
LP
334 mount_test_option(p->options, "grpquota") ||
335 mount_test_option(p->options, "quota") ||
336 mount_test_option(p->options, "usrjquota") ||
337 mount_test_option(p->options, "grpjquota");
cb39ed3f
LP
338}
339
173a8d04
LP
340static int mount_add_device_links(Mount *m) {
341 MountParameters *p;
9fff8a1f 342 int r;
173a8d04
LP
343
344 assert(m);
345
6b1dc2bd
LP
346 p = get_mount_parameters_fragment(m);
347 if (!p)
173a8d04
LP
348 return 0;
349
9fff8a1f 350 if (!p->what)
173a8d04 351 return 0;
5c78d8e2 352
155da457 353 if (!mount_is_bind(p) &&
6b1dc2bd
LP
354 !path_equal(m->where, "/")) {
355 r = unit_add_node_link(UNIT(m), p->what, false);
356 if (r < 0)
9fff8a1f
LP
357 return r;
358 }
359
491ad5dc 360 if (p->passno > 0 &&
ff2e0f05 361 !mount_is_bind(p) &&
6b1dc2bd
LP
362 !path_equal(m->where, "/") &&
363 UNIT(m)->manager->running_as == MANAGER_SYSTEM) {
9fff8a1f
LP
364 char *name;
365 Unit *fsck;
366 /* Let's add in the fsck service */
173a8d04 367
a9e1f5ec 368 /* aka SPECIAL_FSCK_SERVICE */
6b1dc2bd
LP
369 name = unit_name_from_path_instance("fsck", p->what, ".service");
370 if (!name)
9fff8a1f
LP
371 return -ENOMEM;
372
6b1dc2bd
LP
373 r = manager_load_unit_prepare(UNIT(m)->manager, name, NULL, NULL, &fsck);
374 if (r < 0) {
9fff8a1f
LP
375 log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
376 free(name);
377 return r;
378 }
9fff8a1f
LP
379 free(name);
380
381 SERVICE(fsck)->fsck_passno = p->passno;
382
6b1dc2bd
LP
383 r = unit_add_two_dependencies(UNIT(m), UNIT_AFTER, UNIT_REQUIRES, fsck, true);
384 if (r < 0)
9fff8a1f
LP
385 return r;
386 }
387
388 return 0;
173a8d04
LP
389}
390
6b1dc2bd
LP
391static int mount_add_quota_links(Mount *m) {
392 int r;
393 MountParameters *p;
394
395 assert(m);
396
397 if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
398 return 0;
399
400 p = get_mount_parameters_fragment(m);
401 if (!p)
402 return 0;
403
404 if (!needs_quota(p))
405 return 0;
406
407 r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true);
408 if (r < 0)
409 return r;
410
411 r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true);
412 if (r < 0)
413 return r;
414
415 return 0;
416}
417
2edd4434
LP
418static int mount_add_default_dependencies(Mount *m) {
419 int r;
9ddc4a26 420 MountParameters *p;
6b1dc2bd 421 const char *after;
2edd4434
LP
422
423 assert(m);
424
1124fe6f 425 if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
9ddc4a26 426 return 0;
cb39ed3f 427
6b1dc2bd
LP
428 p = get_mount_parameters_fragment(m);
429 if (!p)
430 return 0;
2edd4434 431
6b1dc2bd
LP
432 if (path_equal(m->where, "/"))
433 return 0;
434
435 if (mount_is_network(p))
436 after = SPECIAL_REMOTE_FS_PRE_TARGET;
437 else
438 after = SPECIAL_LOCAL_FS_PRE_TARGET;
439
440 r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, after, NULL, true);
441 if (r < 0)
442 return r;
443
444 r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
445 if (r < 0)
446 return r;
2edd4434
LP
447
448 return 0;
449}
450
f4c05147 451static int mount_fix_timeouts(Mount *m) {
8024c3a7
LP
452 MountParameters *p;
453 const char *timeout = NULL;
454 Unit *other;
455 Iterator i;
456 usec_t u;
f4c05147
LP
457 char *t;
458 int r;
8024c3a7
LP
459
460 assert(m);
461
6b1dc2bd
LP
462 p = get_mount_parameters_fragment(m);
463 if (!p)
f4c05147 464 return 0;
8024c3a7
LP
465
466 /* Allow configuration how long we wait for a device that
467 * backs a mount point to show up. This is useful to support
468 * endless device timeouts for devices that show up only after
469 * user input, like crypto devices. */
470
471 if ((timeout = mount_test_option(p->options, "comment=systemd.device-timeout")))
472 timeout += 31;
92a39ae1 473 else if ((timeout = mount_test_option(p->options, "x-systemd.device-timeout")))
8024c3a7
LP
474 timeout += 25;
475 else
f4c05147
LP
476 return 0;
477
478 t = strndup(timeout, strcspn(timeout, ",;" WHITESPACE));
479 if (!t)
480 return -ENOMEM;
8024c3a7 481
f4c05147
LP
482 r = parse_usec(t, &u);
483 free(t);
484
485 if (r < 0) {
8024c3a7 486 log_warning("Failed to parse timeout for %s, ignoring: %s", m->where, timeout);
f4c05147 487 return r;
8024c3a7
LP
488 }
489
1124fe6f 490 SET_FOREACH(other, UNIT(m)->dependencies[UNIT_AFTER], i) {
ac155bb8 491 if (other->type != UNIT_DEVICE)
8024c3a7
LP
492 continue;
493
ac155bb8 494 other->job_timeout = u;
8024c3a7 495 }
f4c05147
LP
496
497 return 0;
8024c3a7
LP
498}
499
8d567588
LP
500static int mount_verify(Mount *m) {
501 bool b;
502 char *e;
503 assert(m);
504
1124fe6f 505 if (UNIT(m)->load_state != UNIT_LOADED)
8d567588
LP
506 return 0;
507
6b1dc2bd 508 if (!m->from_fragment && !m->from_proc_self_mountinfo)
8cbef760
LP
509 return -ENOENT;
510
a16e1123 511 if (!(e = unit_name_from_path(m->where, ".mount")))
8d567588
LP
512 return -ENOMEM;
513
514 b = unit_has_name(UNIT(m), e);
515 free(e);
516
517 if (!b) {
1124fe6f 518 log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(m)->id);
8d567588
LP
519 return -EINVAL;
520 }
521
33ff02c9
LP
522 if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
523 log_error("Cannot create mount unit for API file system %s. Refusing.", m->where);
524 return -EINVAL;
525 }
526
1124fe6f
MS
527 if (UNIT(m)->fragment_path && !m->parameters_fragment.what) {
528 log_error("%s's What setting is missing. Refusing.", UNIT(m)->id);
4e85aff4
LP
529 return -EBADMSG;
530 }
531
2e22afe9 532 if (m->exec_context.pam_name && m->exec_context.kill_mode != KILL_CONTROL_GROUP) {
1124fe6f 533 log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(m)->id);
4d0e5dbd
LP
534 return -EINVAL;
535 }
536
8d567588
LP
537 return 0;
538}
539
e537352b
LP
540static int mount_load(Unit *u) {
541 Mount *m = MOUNT(u);
542 int r;
543
544 assert(u);
ac155bb8 545 assert(u->load_state == UNIT_STUB);
e537352b
LP
546
547 if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
548 return r;
549
550 /* This is a new unit? Then let's add in some extras */
ac155bb8 551 if (u->load_state == UNIT_LOADED) {
27abbe82
LP
552 if ((r = unit_add_exec_dependencies(u, &m->exec_context)) < 0)
553 return r;
554
1124fe6f 555 if (UNIT(m)->fragment_path)
4e85aff4 556 m->from_fragment = true;
e537352b 557
a16e1123 558 if (!m->where)
ac155bb8 559 if (!(m->where = unit_name_to_path(u->id)))
a16e1123
LP
560 return -ENOMEM;
561
562 path_kill_slashes(m->where);
563
1124fe6f 564 if (!UNIT(m)->description)
4e85aff4
LP
565 if ((r = unit_set_description(u, m->where)) < 0)
566 return r;
e537352b 567
173a8d04
LP
568 if ((r = mount_add_device_links(m)) < 0)
569 return r;
6e2ef85b
LP
570
571 if ((r = mount_add_mount_links(m)) < 0)
572 return r;
573
574 if ((r = mount_add_socket_links(m)) < 0)
575 return r;
576
577 if ((r = mount_add_swap_links(m)) < 0)
e537352b
LP
578 return r;
579
01f78473
LP
580 if ((r = mount_add_path_links(m)) < 0)
581 return r;
582
7c8fa05c
LP
583 r = mount_add_requires_mounts_links(m);
584 if (r < 0)
585 return r;
586
6e2ef85b 587 if ((r = mount_add_automount_links(m)) < 0)
e537352b
LP
588 return r;
589
6b1dc2bd
LP
590 r = mount_add_quota_links(m);
591 if (r < 0)
e537352b 592 return r;
4e67ddd6 593
6b1dc2bd 594 if (UNIT(m)->default_dependencies)
2edd4434 595 if ((r = mount_add_default_dependencies(m)) < 0)
4e67ddd6 596 return r;
8024c3a7 597
155da457
LP
598 if ((r = unit_add_default_cgroups(u)) < 0)
599 return r;
600
8024c3a7 601 mount_fix_timeouts(m);
e537352b
LP
602 }
603
8d567588 604 return mount_verify(m);
e537352b
LP
605}
606
a16e1123
LP
607static int mount_notify_automount(Mount *m, int status) {
608 Unit *p;
609 int r;
57020a3a 610 Iterator i;
a16e1123
LP
611
612 assert(m);
613
1124fe6f 614 SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
ac155bb8 615 if (p->type == UNIT_AUTOMOUNT) {
57020a3a
LP
616 r = automount_send_ready(AUTOMOUNT(p), status);
617 if (r < 0)
618 return r;
619 }
a16e1123 620
57020a3a 621 return 0;
a16e1123
LP
622}
623
e537352b
LP
624static void mount_set_state(Mount *m, MountState state) {
625 MountState old_state;
626 assert(m);
627
628 old_state = m->state;
629 m->state = state;
630
631 if (state != MOUNT_MOUNTING &&
632 state != MOUNT_MOUNTING_DONE &&
633 state != MOUNT_REMOUNTING &&
634 state != MOUNT_UNMOUNTING &&
635 state != MOUNT_MOUNTING_SIGTERM &&
636 state != MOUNT_MOUNTING_SIGKILL &&
637 state != MOUNT_UNMOUNTING_SIGTERM &&
638 state != MOUNT_UNMOUNTING_SIGKILL &&
639 state != MOUNT_REMOUNTING_SIGTERM &&
640 state != MOUNT_REMOUNTING_SIGKILL) {
641 unit_unwatch_timer(UNIT(m), &m->timer_watch);
a16e1123 642 mount_unwatch_control_pid(m);
e537352b 643 m->control_command = NULL;
a16e1123 644 m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
e537352b
LP
645 }
646
8d567588
LP
647 if (state == MOUNT_MOUNTED ||
648 state == MOUNT_REMOUNTING)
649 mount_notify_automount(m, 0);
650 else if (state == MOUNT_DEAD ||
651 state == MOUNT_UNMOUNTING ||
652 state == MOUNT_MOUNTING_SIGTERM ||
653 state == MOUNT_MOUNTING_SIGKILL ||
654 state == MOUNT_REMOUNTING_SIGTERM ||
655 state == MOUNT_REMOUNTING_SIGKILL ||
656 state == MOUNT_UNMOUNTING_SIGTERM ||
657 state == MOUNT_UNMOUNTING_SIGKILL ||
fdf20a31 658 state == MOUNT_FAILED)
8d567588
LP
659 mount_notify_automount(m, -ENODEV);
660
e537352b 661 if (state != old_state)
40d50879 662 log_debug("%s changed %s -> %s",
1124fe6f 663 UNIT(m)->id,
a16e1123
LP
664 mount_state_to_string(old_state),
665 mount_state_to_string(state));
e537352b 666
9d2f5178
LP
667 unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
668 m->reload_result = MOUNT_SUCCESS;
e537352b
LP
669}
670
671static int mount_coldplug(Unit *u) {
672 Mount *m = MOUNT(u);
a16e1123
LP
673 MountState new_state = MOUNT_DEAD;
674 int r;
e537352b
LP
675
676 assert(m);
677 assert(m->state == MOUNT_DEAD);
678
a16e1123
LP
679 if (m->deserialized_state != m->state)
680 new_state = m->deserialized_state;
681 else if (m->from_proc_self_mountinfo)
682 new_state = MOUNT_MOUNTED;
e537352b 683
a16e1123 684 if (new_state != m->state) {
e537352b 685
a16e1123
LP
686 if (new_state == MOUNT_MOUNTING ||
687 new_state == MOUNT_MOUNTING_DONE ||
688 new_state == MOUNT_REMOUNTING ||
689 new_state == MOUNT_UNMOUNTING ||
690 new_state == MOUNT_MOUNTING_SIGTERM ||
691 new_state == MOUNT_MOUNTING_SIGKILL ||
692 new_state == MOUNT_UNMOUNTING_SIGTERM ||
693 new_state == MOUNT_UNMOUNTING_SIGKILL ||
694 new_state == MOUNT_REMOUNTING_SIGTERM ||
695 new_state == MOUNT_REMOUNTING_SIGKILL) {
e537352b 696
a16e1123
LP
697 if (m->control_pid <= 0)
698 return -EBADMSG;
e537352b 699
a16e1123
LP
700 if ((r = unit_watch_pid(UNIT(m), m->control_pid)) < 0)
701 return r;
e537352b 702
a16e1123
LP
703 if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
704 return r;
705 }
e537352b 706
a16e1123
LP
707 mount_set_state(m, new_state);
708 }
e537352b
LP
709
710 return 0;
e537352b
LP
711}
712
713static void mount_dump(Unit *u, FILE *f, const char *prefix) {
714 Mount *m = MOUNT(u);
715 MountParameters *p;
716
717 assert(m);
718 assert(f);
719
cb39ed3f 720 p = get_mount_parameters(m);
e537352b
LP
721
722 fprintf(f,
723 "%sMount State: %s\n"
81a5c6d0 724 "%sResult: %s\n"
e537352b
LP
725 "%sWhere: %s\n"
726 "%sWhat: %s\n"
727 "%sFile System Type: %s\n"
728 "%sOptions: %s\n"
e537352b
LP
729 "%sFrom /proc/self/mountinfo: %s\n"
730 "%sFrom fragment: %s\n"
3e5235b0 731 "%sDirectoryMode: %04o\n",
a16e1123 732 prefix, mount_state_to_string(m->state),
81a5c6d0 733 prefix, mount_result_to_string(m->result),
e537352b
LP
734 prefix, m->where,
735 prefix, strna(p->what),
736 prefix, strna(p->fstype),
737 prefix, strna(p->options),
e537352b
LP
738 prefix, yes_no(m->from_proc_self_mountinfo),
739 prefix, yes_no(m->from_fragment),
3e5235b0 740 prefix, m->directory_mode);
e537352b
LP
741
742 if (m->control_pid > 0)
743 fprintf(f,
bb00e604
LP
744 "%sControl PID: %lu\n",
745 prefix, (unsigned long) m->control_pid);
e537352b
LP
746
747 exec_context_dump(&m->exec_context, f, prefix);
748}
749
a16e1123
LP
750static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
751 pid_t pid;
752 int r;
753
754 assert(m);
755 assert(c);
756 assert(_pid);
757
758 if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
759 goto fail;
760
761 if ((r = exec_spawn(c,
762 NULL,
763 &m->exec_context,
764 NULL, 0,
1124fe6f 765 UNIT(m)->manager->environment,
a16e1123
LP
766 true,
767 true,
1e3ad081 768 true,
1124fe6f
MS
769 UNIT(m)->manager->confirm_spawn,
770 UNIT(m)->cgroup_bondings,
771 UNIT(m)->cgroup_attributes,
ecedd90f 772 NULL,
f2b68789 773 NULL,
a16e1123
LP
774 &pid)) < 0)
775 goto fail;
776
777 if ((r = unit_watch_pid(UNIT(m), pid)) < 0)
778 /* FIXME: we need to do something here */
779 goto fail;
780
781 *_pid = pid;
782
783 return 0;
784
785fail:
786 unit_unwatch_timer(UNIT(m), &m->timer_watch);
787
788 return r;
789}
790
9d2f5178 791static void mount_enter_dead(Mount *m, MountResult f) {
e537352b
LP
792 assert(m);
793
9d2f5178
LP
794 if (f != MOUNT_SUCCESS)
795 m->result = f;
e537352b 796
9d2f5178 797 mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
e537352b
LP
798}
799
9d2f5178 800static void mount_enter_mounted(Mount *m, MountResult f) {
80876c20
LP
801 assert(m);
802
9d2f5178
LP
803 if (f != MOUNT_SUCCESS)
804 m->result = f;
80876c20
LP
805
806 mount_set_state(m, MOUNT_MOUNTED);
807}
808
9d2f5178 809static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
e537352b 810 int r;
ca949c9d
LP
811 Set *pid_set = NULL;
812 bool wait_for_exit = false;
e537352b
LP
813
814 assert(m);
815
9d2f5178
LP
816 if (f != MOUNT_SUCCESS)
817 m->result = f;
e537352b 818
2e22afe9 819 if (m->exec_context.kill_mode != KILL_NONE) {
80876c20
LP
820 int sig = (state == MOUNT_MOUNTING_SIGTERM ||
821 state == MOUNT_UNMOUNTING_SIGTERM ||
2e22afe9 822 state == MOUNT_REMOUNTING_SIGTERM) ? m->exec_context.kill_signal : SIGKILL;
e537352b 823
ca949c9d 824 if (m->control_pid > 0) {
cd25cce9 825 if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH)
e537352b 826
ca949c9d
LP
827 log_warning("Failed to kill control process %li: %m", (long) m->control_pid);
828 else
829 wait_for_exit = true;
e537352b
LP
830 }
831
ca949c9d 832 if (m->exec_context.kill_mode == KILL_CONTROL_GROUP) {
2e22afe9 833
ca949c9d
LP
834 if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
835 r = -ENOMEM;
e537352b
LP
836 goto fail;
837 }
ca949c9d
LP
838
839 /* Exclude the control pid from being killed via the cgroup */
840 if (m->control_pid > 0)
841 if ((r = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0)
842 goto fail;
843
88f3e0c9 844 r = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, sig, true, false, pid_set, NULL);
ecedd90f 845 if (r < 0) {
ca949c9d
LP
846 if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
847 log_warning("Failed to kill control group: %s", strerror(-r));
848 } else if (r > 0)
849 wait_for_exit = true;
850
851 set_free(pid_set);
da19d5c1 852 pid_set = NULL;
ca949c9d 853 }
e537352b
LP
854 }
855
ca949c9d 856 if (wait_for_exit) {
80876c20
LP
857 if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
858 goto fail;
e537352b 859
80876c20
LP
860 mount_set_state(m, state);
861 } else if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
9d2f5178 862 mount_enter_mounted(m, MOUNT_SUCCESS);
80876c20 863 else
9d2f5178 864 mount_enter_dead(m, MOUNT_SUCCESS);
e537352b
LP
865
866 return;
867
868fail:
1124fe6f 869 log_warning("%s failed to kill processes: %s", UNIT(m)->id, strerror(-r));
e537352b 870
80876c20 871 if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
9d2f5178 872 mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
80876c20 873 else
9d2f5178 874 mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
ca949c9d
LP
875
876 if (pid_set)
877 set_free(pid_set);
e537352b
LP
878}
879
9d2f5178 880static void mount_enter_unmounting(Mount *m) {
e537352b
LP
881 int r;
882
883 assert(m);
884
a16e1123
LP
885 m->control_command_id = MOUNT_EXEC_UNMOUNT;
886 m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
e537352b
LP
887
888 if ((r = exec_command_set(
a16e1123 889 m->control_command,
e537352b
LP
890 "/bin/umount",
891 m->where,
892 NULL)) < 0)
893 goto fail;
894
a16e1123 895 mount_unwatch_control_pid(m);
5e94833f 896
a16e1123 897 if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
e537352b
LP
898 goto fail;
899
900 mount_set_state(m, MOUNT_UNMOUNTING);
901
902 return;
903
904fail:
1124fe6f 905 log_warning("%s failed to run 'umount' task: %s", UNIT(m)->id, strerror(-r));
9d2f5178 906 mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
e537352b
LP
907}
908
8d567588 909static void mount_enter_mounting(Mount *m) {
e537352b 910 int r;
cb39ed3f 911 MountParameters *p;
e537352b
LP
912
913 assert(m);
914
a16e1123
LP
915 m->control_command_id = MOUNT_EXEC_MOUNT;
916 m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
e537352b 917
d2e54fae 918 mkdir_p_label(m->where, m->directory_mode);
3e5235b0 919
cb39ed3f 920 /* Create the source directory for bind-mounts if needed */
6b1dc2bd 921 p = get_mount_parameters_fragment(m);
cb39ed3f 922 if (p && mount_is_bind(p))
d2e54fae 923 mkdir_p_label(p->what, m->directory_mode);
2b583ce6 924
e537352b
LP
925 if (m->from_fragment)
926 r = exec_command_set(
a16e1123 927 m->control_command,
e537352b
LP
928 "/bin/mount",
929 m->parameters_fragment.what,
930 m->where,
40b8a332 931 "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto",
8d567588 932 m->parameters_fragment.options ? "-o" : NULL, m->parameters_fragment.options,
e537352b 933 NULL);
e537352b
LP
934 else
935 r = -ENOENT;
936
937 if (r < 0)
938 goto fail;
939
a16e1123 940 mount_unwatch_control_pid(m);
5e94833f 941
a16e1123 942 if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
e537352b
LP
943 goto fail;
944
945 mount_set_state(m, MOUNT_MOUNTING);
946
947 return;
948
949fail:
1124fe6f 950 log_warning("%s failed to run 'mount' task: %s", UNIT(m)->id, strerror(-r));
9d2f5178 951 mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
e537352b
LP
952}
953
8d567588 954static void mount_enter_mounting_done(Mount *m) {
e537352b
LP
955 assert(m);
956
e537352b
LP
957 mount_set_state(m, MOUNT_MOUNTING_DONE);
958}
959
9d2f5178 960static void mount_enter_remounting(Mount *m) {
e537352b
LP
961 int r;
962
963 assert(m);
964
a16e1123
LP
965 m->control_command_id = MOUNT_EXEC_REMOUNT;
966 m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
e537352b
LP
967
968 if (m->from_fragment) {
969 char *buf = NULL;
970 const char *o;
971
972 if (m->parameters_fragment.options) {
973 if (!(buf = strappend("remount,", m->parameters_fragment.options))) {
974 r = -ENOMEM;
975 goto fail;
976 }
977
978 o = buf;
979 } else
980 o = "remount";
981
982 r = exec_command_set(
a16e1123 983 m->control_command,
e537352b
LP
984 "/bin/mount",
985 m->parameters_fragment.what,
986 m->where,
40b8a332 987 "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto",
e537352b
LP
988 "-o", o,
989 NULL);
990
991 free(buf);
6b1dc2bd 992 } else
e537352b
LP
993 r = -ENOENT;
994
60b912f6 995 if (r < 0)
e537352b 996 goto fail;
e537352b 997
a16e1123 998 mount_unwatch_control_pid(m);
5e94833f 999
a16e1123 1000 if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
e537352b
LP
1001 goto fail;
1002
1003 mount_set_state(m, MOUNT_REMOUNTING);
1004
1005 return;
1006
1007fail:
1124fe6f 1008 log_warning("%s failed to run 'remount' task: %s", UNIT(m)->id, strerror(-r));
9d2f5178
LP
1009 m->reload_result = MOUNT_FAILURE_RESOURCES;
1010 mount_enter_mounted(m, MOUNT_SUCCESS);
e537352b
LP
1011}
1012
1013static int mount_start(Unit *u) {
1014 Mount *m = MOUNT(u);
1015
1016 assert(m);
1017
1018 /* We cannot fulfill this request right now, try again later
1019 * please! */
1020 if (m->state == MOUNT_UNMOUNTING ||
1021 m->state == MOUNT_UNMOUNTING_SIGTERM ||
60b912f6
LP
1022 m->state == MOUNT_UNMOUNTING_SIGKILL ||
1023 m->state == MOUNT_MOUNTING_SIGTERM ||
1024 m->state == MOUNT_MOUNTING_SIGKILL)
e537352b
LP
1025 return -EAGAIN;
1026
1027 /* Already on it! */
60b912f6 1028 if (m->state == MOUNT_MOUNTING)
e537352b
LP
1029 return 0;
1030
fdf20a31 1031 assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
e537352b 1032
9d2f5178
LP
1033 m->result = MOUNT_SUCCESS;
1034 m->reload_result = MOUNT_SUCCESS;
1035
8d567588 1036 mount_enter_mounting(m);
e537352b
LP
1037 return 0;
1038}
1039
1040static int mount_stop(Unit *u) {
1041 Mount *m = MOUNT(u);
1042
1043 assert(m);
1044
e537352b
LP
1045 /* Already on it */
1046 if (m->state == MOUNT_UNMOUNTING ||
1047 m->state == MOUNT_UNMOUNTING_SIGKILL ||
60b912f6
LP
1048 m->state == MOUNT_UNMOUNTING_SIGTERM ||
1049 m->state == MOUNT_MOUNTING_SIGTERM ||
1050 m->state == MOUNT_MOUNTING_SIGKILL)
e537352b
LP
1051 return 0;
1052
3f6c78dc
LP
1053 assert(m->state == MOUNT_MOUNTING ||
1054 m->state == MOUNT_MOUNTING_DONE ||
1055 m->state == MOUNT_MOUNTED ||
3f6c78dc
LP
1056 m->state == MOUNT_REMOUNTING ||
1057 m->state == MOUNT_REMOUNTING_SIGTERM ||
1058 m->state == MOUNT_REMOUNTING_SIGKILL);
e537352b 1059
9d2f5178 1060 mount_enter_unmounting(m);
e537352b
LP
1061 return 0;
1062}
1063
1064static int mount_reload(Unit *u) {
1065 Mount *m = MOUNT(u);
1066
1067 assert(m);
1068
1069 if (m->state == MOUNT_MOUNTING_DONE)
1070 return -EAGAIN;
1071
1072 assert(m->state == MOUNT_MOUNTED);
1073
9d2f5178 1074 mount_enter_remounting(m);
e537352b
LP
1075 return 0;
1076}
1077
a16e1123
LP
1078static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
1079 Mount *m = MOUNT(u);
1080
1081 assert(m);
1082 assert(f);
1083 assert(fds);
1084
1085 unit_serialize_item(u, f, "state", mount_state_to_string(m->state));
9d2f5178
LP
1086 unit_serialize_item(u, f, "result", mount_result_to_string(m->result));
1087 unit_serialize_item(u, f, "reload-result", mount_result_to_string(m->reload_result));
a16e1123
LP
1088
1089 if (m->control_pid > 0)
5925dd3c 1090 unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) m->control_pid);
a16e1123
LP
1091
1092 if (m->control_command_id >= 0)
1093 unit_serialize_item(u, f, "control-command", mount_exec_command_to_string(m->control_command_id));
1094
1095 return 0;
1096}
1097
1098static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
1099 Mount *m = MOUNT(u);
a16e1123
LP
1100
1101 assert(u);
1102 assert(key);
1103 assert(value);
1104 assert(fds);
1105
1106 if (streq(key, "state")) {
1107 MountState state;
1108
1109 if ((state = mount_state_from_string(value)) < 0)
1110 log_debug("Failed to parse state value %s", value);
1111 else
1112 m->deserialized_state = state;
9d2f5178
LP
1113 } else if (streq(key, "result")) {
1114 MountResult f;
a16e1123 1115
9d2f5178
LP
1116 f = mount_result_from_string(value);
1117 if (f < 0)
1118 log_debug("Failed to parse result value %s", value);
1119 else if (f != MOUNT_SUCCESS)
1120 m->result = f;
1121
1122 } else if (streq(key, "reload-result")) {
1123 MountResult f;
1124
1125 f = mount_result_from_string(value);
1126 if (f < 0)
1127 log_debug("Failed to parse reload result value %s", value);
1128 else if (f != MOUNT_SUCCESS)
1129 m->reload_result = f;
a16e1123
LP
1130
1131 } else if (streq(key, "control-pid")) {
5925dd3c 1132 pid_t pid;
a16e1123 1133
e364ad06 1134 if (parse_pid(value, &pid) < 0)
a16e1123
LP
1135 log_debug("Failed to parse control-pid value %s", value);
1136 else
5925dd3c 1137 m->control_pid = pid;
a16e1123
LP
1138 } else if (streq(key, "control-command")) {
1139 MountExecCommand id;
1140
1141 if ((id = mount_exec_command_from_string(value)) < 0)
1142 log_debug("Failed to parse exec-command value %s", value);
1143 else {
1144 m->control_command_id = id;
1145 m->control_command = m->exec_command + id;
1146 }
1147
1148 } else
1149 log_debug("Unknown serialization key '%s'", key);
1150
1151 return 0;
1152}
1153
e537352b
LP
1154static UnitActiveState mount_active_state(Unit *u) {
1155 assert(u);
1156
1157 return state_translation_table[MOUNT(u)->state];
1158}
1159
10a94420
LP
1160static const char *mount_sub_state_to_string(Unit *u) {
1161 assert(u);
1162
a16e1123 1163 return mount_state_to_string(MOUNT(u)->state);
10a94420
LP
1164}
1165
701cc384
LP
1166static bool mount_check_gc(Unit *u) {
1167 Mount *m = MOUNT(u);
1168
1169 assert(m);
1170
6b1dc2bd 1171 return m->from_proc_self_mountinfo;
701cc384
LP
1172}
1173
e537352b
LP
1174static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
1175 Mount *m = MOUNT(u);
9d2f5178 1176 MountResult f;
e537352b
LP
1177
1178 assert(m);
1179 assert(pid >= 0);
1180
8c47c732
LP
1181 if (pid != m->control_pid)
1182 return;
e537352b 1183
e537352b
LP
1184 m->control_pid = 0;
1185
9d2f5178
LP
1186 if (is_clean_exit(code, status))
1187 f = MOUNT_SUCCESS;
1188 else if (code == CLD_EXITED)
1189 f = MOUNT_FAILURE_EXIT_CODE;
1190 else if (code == CLD_KILLED)
1191 f = MOUNT_FAILURE_SIGNAL;
1192 else if (code == CLD_DUMPED)
1193 f = MOUNT_FAILURE_CORE_DUMP;
1194 else
1195 assert_not_reached("Unknown code");
1196
1197 if (f != MOUNT_SUCCESS)
1198 m->result = f;
8c47c732 1199
a16e1123 1200 if (m->control_command) {
6ea832a2 1201 exec_status_exit(&m->control_command->exec_status, &m->exec_context, pid, code, status);
9d2f5178 1202
a16e1123
LP
1203 m->control_command = NULL;
1204 m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
1205 }
1206
9d2f5178 1207 log_full(f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
ac155bb8 1208 "%s mount process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
e537352b
LP
1209
1210 /* Note that mount(8) returning and the kernel sending us a
1211 * mount table change event might happen out-of-order. If an
1212 * operation succeed we assume the kernel will follow soon too
1213 * and already change into the resulting state. If it fails
1214 * we check if the kernel still knows about the mount. and
1215 * change state accordingly. */
1216
1217 switch (m->state) {
1218
1219 case MOUNT_MOUNTING:
1220 case MOUNT_MOUNTING_DONE:
1221 case MOUNT_MOUNTING_SIGKILL:
1222 case MOUNT_MOUNTING_SIGTERM:
e537352b 1223
9d2f5178
LP
1224 if (f == MOUNT_SUCCESS)
1225 mount_enter_mounted(m, f);
e537352b 1226 else if (m->from_proc_self_mountinfo)
9d2f5178 1227 mount_enter_mounted(m, f);
e537352b 1228 else
9d2f5178 1229 mount_enter_dead(m, f);
e537352b
LP
1230 break;
1231
e2f3b44c
LP
1232 case MOUNT_REMOUNTING:
1233 case MOUNT_REMOUNTING_SIGKILL:
1234 case MOUNT_REMOUNTING_SIGTERM:
1235
9d2f5178 1236 m->reload_result = f;
e2f3b44c 1237 if (m->from_proc_self_mountinfo)
9d2f5178 1238 mount_enter_mounted(m, MOUNT_SUCCESS);
e2f3b44c 1239 else
9d2f5178 1240 mount_enter_dead(m, MOUNT_SUCCESS);
e2f3b44c
LP
1241
1242 break;
1243
e537352b
LP
1244 case MOUNT_UNMOUNTING:
1245 case MOUNT_UNMOUNTING_SIGKILL:
1246 case MOUNT_UNMOUNTING_SIGTERM:
1247
9d2f5178
LP
1248 if (f == MOUNT_SUCCESS)
1249 mount_enter_dead(m, f);
e537352b 1250 else if (m->from_proc_self_mountinfo)
9d2f5178 1251 mount_enter_mounted(m, f);
e537352b 1252 else
9d2f5178 1253 mount_enter_dead(m, f);
e537352b
LP
1254 break;
1255
1256 default:
1257 assert_not_reached("Uh, control process died at wrong time.");
1258 }
c4e2ceae
LP
1259
1260 /* Notify clients about changed exit status */
1261 unit_add_to_dbus_queue(u);
e537352b
LP
1262}
1263
1264static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
1265 Mount *m = MOUNT(u);
1266
1267 assert(m);
1268 assert(elapsed == 1);
1269 assert(w == &m->timer_watch);
1270
1271 switch (m->state) {
1272
1273 case MOUNT_MOUNTING:
1274 case MOUNT_MOUNTING_DONE:
ac155bb8 1275 log_warning("%s mounting timed out. Stopping.", u->id);
9d2f5178 1276 mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
e537352b
LP
1277 break;
1278
1279 case MOUNT_REMOUNTING:
ac155bb8 1280 log_warning("%s remounting timed out. Stopping.", u->id);
9d2f5178
LP
1281 m->reload_result = MOUNT_FAILURE_TIMEOUT;
1282 mount_enter_mounted(m, MOUNT_SUCCESS);
e537352b
LP
1283 break;
1284
1285 case MOUNT_UNMOUNTING:
ac155bb8 1286 log_warning("%s unmounting timed out. Stopping.", u->id);
9d2f5178 1287 mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
e537352b
LP
1288 break;
1289
1290 case MOUNT_MOUNTING_SIGTERM:
ba035df2 1291 if (m->exec_context.send_sigkill) {
ac155bb8 1292 log_warning("%s mounting timed out. Killing.", u->id);
9d2f5178 1293 mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
ba035df2 1294 } else {
ac155bb8 1295 log_warning("%s mounting timed out. Skipping SIGKILL. Ignoring.", u->id);
ba035df2
LP
1296
1297 if (m->from_proc_self_mountinfo)
9d2f5178 1298 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1299 else
9d2f5178 1300 mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1301 }
e537352b
LP
1302 break;
1303
1304 case MOUNT_REMOUNTING_SIGTERM:
ba035df2 1305 if (m->exec_context.send_sigkill) {
ac155bb8 1306 log_warning("%s remounting timed out. Killing.", u->id);
9d2f5178 1307 mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
ba035df2 1308 } else {
ac155bb8 1309 log_warning("%s remounting timed out. Skipping SIGKILL. Ignoring.", u->id);
ba035df2
LP
1310
1311 if (m->from_proc_self_mountinfo)
9d2f5178 1312 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1313 else
9d2f5178 1314 mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1315 }
e537352b
LP
1316 break;
1317
1318 case MOUNT_UNMOUNTING_SIGTERM:
ba035df2 1319 if (m->exec_context.send_sigkill) {
ac155bb8 1320 log_warning("%s unmounting timed out. Killing.", u->id);
9d2f5178 1321 mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
ba035df2 1322 } else {
ac155bb8 1323 log_warning("%s unmounting timed out. Skipping SIGKILL. Ignoring.", u->id);
ba035df2
LP
1324
1325 if (m->from_proc_self_mountinfo)
9d2f5178 1326 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1327 else
9d2f5178 1328 mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1329 }
e537352b
LP
1330 break;
1331
1332 case MOUNT_MOUNTING_SIGKILL:
1333 case MOUNT_REMOUNTING_SIGKILL:
1334 case MOUNT_UNMOUNTING_SIGKILL:
ac155bb8 1335 log_warning("%s mount process still around after SIGKILL. Ignoring.", u->id);
e537352b
LP
1336
1337 if (m->from_proc_self_mountinfo)
9d2f5178 1338 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
e537352b 1339 else
9d2f5178 1340 mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
e537352b
LP
1341 break;
1342
1343 default:
1344 assert_not_reached("Timeout at wrong time.");
1345 }
1346}
1347
1348static int mount_add_one(
1349 Manager *m,
1350 const char *what,
1351 const char *where,
1352 const char *options,
1353 const char *fstype,
9fff8a1f 1354 int passno,
e537352b 1355 bool set_flags) {
b08d03ff
LP
1356 int r;
1357 Unit *u;
1358 bool delete;
e537352b 1359 char *e, *w = NULL, *o = NULL, *f = NULL;
4e85aff4 1360 MountParameters *p;
b08d03ff 1361
f50e0a01 1362 assert(m);
b08d03ff
LP
1363 assert(what);
1364 assert(where);
e537352b
LP
1365 assert(options);
1366 assert(fstype);
1367
e537352b
LP
1368 /* Ignore API mount points. They should never be referenced in
1369 * dependencies ever. */
33ff02c9 1370 if (mount_point_is_api(where) || mount_point_ignore(where))
57f2a956 1371 return 0;
b08d03ff 1372
8d567588
LP
1373 if (streq(fstype, "autofs"))
1374 return 0;
1375
4e85aff4
LP
1376 /* probably some kind of swap, ignore */
1377 if (!is_path(where))
b08d03ff
LP
1378 return 0;
1379
7d17cfbc
MS
1380 e = unit_name_from_path(where, ".mount");
1381 if (!e)
b08d03ff
LP
1382 return -ENOMEM;
1383
7d17cfbc
MS
1384 u = manager_get_unit(m, e);
1385 if (!u) {
b08d03ff
LP
1386 delete = true;
1387
7d17cfbc
MS
1388 u = unit_new(m, sizeof(Mount));
1389 if (!u) {
b08d03ff
LP
1390 free(e);
1391 return -ENOMEM;
1392 }
1393
1394 r = unit_add_name(u, e);
1395 free(e);
1396
1397 if (r < 0)
1398 goto fail;
1399
7d17cfbc
MS
1400 MOUNT(u)->where = strdup(where);
1401 if (!MOUNT(u)->where) {
07b0b134
ML
1402 r = -ENOMEM;
1403 goto fail;
1404 }
f50e0a01 1405
f94ea366 1406 unit_add_to_load_queue(u);
b08d03ff
LP
1407 } else {
1408 delete = false;
1409 free(e);
1410 }
1411
e537352b
LP
1412 if (!(w = strdup(what)) ||
1413 !(o = strdup(options)) ||
1414 !(f = strdup(fstype))) {
1415 r = -ENOMEM;
1416 goto fail;
1417 }
1418
6b1dc2bd
LP
1419 p = &MOUNT(u)->parameters_proc_self_mountinfo;
1420 if (set_flags) {
1421 MOUNT(u)->is_mounted = true;
1422 MOUNT(u)->just_mounted = !MOUNT(u)->from_proc_self_mountinfo;
1423 MOUNT(u)->just_changed = !streq_ptr(p->options, o);
ef734fd6 1424 }
f50e0a01 1425
6b1dc2bd
LP
1426 MOUNT(u)->from_proc_self_mountinfo = true;
1427
4e85aff4
LP
1428 free(p->what);
1429 p->what = w;
b08d03ff 1430
4e85aff4
LP
1431 free(p->options);
1432 p->options = o;
e537352b 1433
4e85aff4
LP
1434 free(p->fstype);
1435 p->fstype = f;
b08d03ff 1436
9fff8a1f
LP
1437 p->passno = passno;
1438
c1e1601e
LP
1439 unit_add_to_dbus_queue(u);
1440
b08d03ff
LP
1441 return 0;
1442
1443fail:
e537352b
LP
1444 free(w);
1445 free(o);
1446 free(f);
1447
b08d03ff
LP
1448 if (delete && u)
1449 unit_free(u);
1450
4e85aff4 1451 return r;
b08d03ff
LP
1452}
1453
ef734fd6 1454static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
60b912f6 1455 int r = 0;
1ddff895 1456 unsigned i;
a2e0f3d3 1457 char *device, *path, *options, *options2, *fstype, *d, *p, *o;
b08d03ff
LP
1458
1459 assert(m);
1460
ef734fd6 1461 rewind(m->proc_self_mountinfo);
b08d03ff 1462
1ddff895 1463 for (i = 1;; i++) {
b08d03ff 1464 int k;
e537352b 1465
a2e0f3d3 1466 device = path = options = options2 = fstype = d = p = o = NULL;
b08d03ff 1467
ef734fd6 1468 if ((k = fscanf(m->proc_self_mountinfo,
b08d03ff
LP
1469 "%*s " /* (1) mount id */
1470 "%*s " /* (2) parent id */
1471 "%*s " /* (3) major:minor */
1472 "%*s " /* (4) root */
1473 "%ms " /* (5) mount point */
e537352b 1474 "%ms" /* (6) mount options */
b08d03ff 1475 "%*[^-]" /* (7) optional fields */
c899f8c6 1476 "- " /* (8) separator */
e537352b 1477 "%ms " /* (9) file system type */
ef734fd6 1478 "%ms" /* (10) mount source */
a2e0f3d3 1479 "%ms" /* (11) mount options 2 */
ef734fd6 1480 "%*[^\n]", /* some rubbish at the end */
b08d03ff 1481 &path,
e537352b
LP
1482 &options,
1483 &fstype,
a2e0f3d3
LP
1484 &device,
1485 &options2)) != 5) {
b08d03ff 1486
ef734fd6
LP
1487 if (k == EOF)
1488 break;
b08d03ff 1489
1ddff895
FF
1490 log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
1491 goto clean_up;
b08d03ff
LP
1492 }
1493
f7f21d33
LP
1494 o = join(options, ",", options2, NULL);
1495 if (!o) {
a2e0f3d3
LP
1496 r = -ENOMEM;
1497 goto finish;
1498 }
1499
e537352b
LP
1500 if (!(d = cunescape(device)) ||
1501 !(p = cunescape(path))) {
1502 r = -ENOMEM;
1503 goto finish;
b08d03ff 1504 }
b08d03ff 1505
6b1dc2bd 1506 if ((k = mount_add_one(m, d, p, o, fstype, 0, set_flags)) < 0)
60b912f6 1507 r = k;
b08d03ff 1508
1ddff895 1509clean_up:
e537352b
LP
1510 free(device);
1511 free(path);
1512 free(options);
a2e0f3d3 1513 free(options2);
e537352b 1514 free(fstype);
b08d03ff
LP
1515 free(d);
1516 free(p);
a2e0f3d3 1517 free(o);
b08d03ff
LP
1518 }
1519
e537352b
LP
1520finish:
1521 free(device);
1522 free(path);
1523 free(options);
a2e0f3d3 1524 free(options2);
e537352b
LP
1525 free(fstype);
1526 free(d);
1527 free(p);
a2e0f3d3 1528 free(o);
e537352b
LP
1529
1530 return r;
1531}
1532
1533static void mount_shutdown(Manager *m) {
1534 assert(m);
1535
a16e1123 1536 if (m->proc_self_mountinfo) {
e537352b 1537 fclose(m->proc_self_mountinfo);
a16e1123
LP
1538 m->proc_self_mountinfo = NULL;
1539 }
b08d03ff
LP
1540}
1541
1542static int mount_enumerate(Manager *m) {
1543 int r;
ef734fd6 1544 struct epoll_event ev;
b08d03ff
LP
1545 assert(m);
1546
a16e1123
LP
1547 if (!m->proc_self_mountinfo) {
1548 if (!(m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
1549 return -errno;
ef734fd6 1550
a16e1123
LP
1551 m->mount_watch.type = WATCH_MOUNT;
1552 m->mount_watch.fd = fileno(m->proc_self_mountinfo);
ef734fd6 1553
a16e1123 1554 zero(ev);
4e434314 1555 ev.events = EPOLLPRI;
a16e1123 1556 ev.data.ptr = &m->mount_watch;
ef734fd6 1557
a16e1123
LP
1558 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0)
1559 return -errno;
1560 }
ef734fd6 1561
ef734fd6 1562 if ((r = mount_load_proc_self_mountinfo(m, false)) < 0)
b08d03ff
LP
1563 goto fail;
1564
1565 return 0;
1566
1567fail:
1568 mount_shutdown(m);
1569 return r;
5cb5a6ff
LP
1570}
1571
ef734fd6 1572void mount_fd_event(Manager *m, int events) {
595ed347 1573 Unit *u;
ef734fd6
LP
1574 int r;
1575
1576 assert(m);
4e434314 1577 assert(events & EPOLLPRI);
ef734fd6
LP
1578
1579 /* The manager calls this for every fd event happening on the
1580 * /proc/self/mountinfo file, which informs us about mounting
1581 * table changes */
1582
1583 if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) {
e364ad06 1584 log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-r));
e537352b
LP
1585
1586 /* Reset flags, just in case, for later calls */
595ed347
MS
1587 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
1588 Mount *mount = MOUNT(u);
e537352b
LP
1589
1590 mount->is_mounted = mount->just_mounted = mount->just_changed = false;
1591 }
1592
ef734fd6
LP
1593 return;
1594 }
1595
1596 manager_dispatch_load_queue(m);
1597
595ed347
MS
1598 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
1599 Mount *mount = MOUNT(u);
ef734fd6 1600
e537352b
LP
1601 if (!mount->is_mounted) {
1602 /* This has just been unmounted. */
1603
ef734fd6 1604 mount->from_proc_self_mountinfo = false;
e537352b
LP
1605
1606 switch (mount->state) {
1607
1608 case MOUNT_MOUNTED:
9d2f5178 1609 mount_enter_dead(mount, MOUNT_SUCCESS);
e537352b
LP
1610 break;
1611
1612 default:
1613 mount_set_state(mount, mount->state);
1614 break;
1615
1616 }
1617
1618 } else if (mount->just_mounted || mount->just_changed) {
1619
60b912f6 1620 /* New or changed mount entry */
e537352b
LP
1621
1622 switch (mount->state) {
1623
1624 case MOUNT_DEAD:
fdf20a31 1625 case MOUNT_FAILED:
9d2f5178 1626 mount_enter_mounted(mount, MOUNT_SUCCESS);
e537352b
LP
1627 break;
1628
1629 case MOUNT_MOUNTING:
8d567588 1630 mount_enter_mounting_done(mount);
e537352b
LP
1631 break;
1632
1633 default:
1634 /* Nothing really changed, but let's
1635 * issue an notification call
1636 * nonetheless, in case somebody is
1637 * waiting for this. (e.g. file system
1638 * ro/rw remounts.) */
1639 mount_set_state(mount, mount->state);
1640 break;
1641 }
1642 }
1643
1644 /* Reset the flags for later calls */
1645 mount->is_mounted = mount->just_mounted = mount->just_changed = false;
1646 }
1647}
1648
fdf20a31 1649static void mount_reset_failed(Unit *u) {
5632e374
LP
1650 Mount *m = MOUNT(u);
1651
1652 assert(m);
1653
fdf20a31 1654 if (m->state == MOUNT_FAILED)
5632e374
LP
1655 mount_set_state(m, MOUNT_DEAD);
1656
9d2f5178
LP
1657 m->result = MOUNT_SUCCESS;
1658 m->reload_result = MOUNT_SUCCESS;
5632e374
LP
1659}
1660
8a0867d6
LP
1661static int mount_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
1662 Mount *m = MOUNT(u);
1663 int r = 0;
1664 Set *pid_set = NULL;
1665
1666 assert(m);
1667
1668 if (who == KILL_MAIN) {
1669 dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Mount units have no main processes");
a17204af 1670 return -ESRCH;
8a0867d6
LP
1671 }
1672
1673 if (m->control_pid <= 0 && who == KILL_CONTROL) {
1674 dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
a17204af 1675 return -ESRCH;
8a0867d6
LP
1676 }
1677
3611581e
LP
1678 if (who == KILL_CONTROL || who == KILL_ALL)
1679 if (m->control_pid > 0)
1680 if (kill(m->control_pid, signo) < 0)
1681 r = -errno;
8a0867d6 1682
3611581e 1683 if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
8a0867d6
LP
1684 int q;
1685
1686 if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
1687 return -ENOMEM;
1688
1689 /* Exclude the control pid from being killed via the cgroup */
1690 if (m->control_pid > 0)
1691 if ((q = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0) {
1692 r = q;
1693 goto finish;
1694 }
1695
88f3e0c9 1696 q = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, signo, false, false, pid_set, NULL);
ecedd90f 1697 if (q < 0)
3611581e 1698 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
8a0867d6
LP
1699 r = q;
1700 }
1701
1702finish:
1703 if (pid_set)
1704 set_free(pid_set);
1705
1706 return r;
1707}
1708
a16e1123
LP
1709static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
1710 [MOUNT_DEAD] = "dead",
1711 [MOUNT_MOUNTING] = "mounting",
1712 [MOUNT_MOUNTING_DONE] = "mounting-done",
1713 [MOUNT_MOUNTED] = "mounted",
1714 [MOUNT_REMOUNTING] = "remounting",
1715 [MOUNT_UNMOUNTING] = "unmounting",
1716 [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
1717 [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
1718 [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
1719 [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
1720 [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
1721 [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
fdf20a31 1722 [MOUNT_FAILED] = "failed"
a16e1123
LP
1723};
1724
1725DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
1726
1727static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
1728 [MOUNT_EXEC_MOUNT] = "ExecMount",
1729 [MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
1730 [MOUNT_EXEC_REMOUNT] = "ExecRemount",
1731};
1732
1733DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand);
1734
9d2f5178
LP
1735static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
1736 [MOUNT_SUCCESS] = "success",
1737 [MOUNT_FAILURE_RESOURCES] = "resources",
1738 [MOUNT_FAILURE_TIMEOUT] = "timeout",
1739 [MOUNT_FAILURE_EXIT_CODE] = "exit-code",
1740 [MOUNT_FAILURE_SIGNAL] = "signal",
1741 [MOUNT_FAILURE_CORE_DUMP] = "core-dump"
1742};
1743
1744DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
1745
87f0e418 1746const UnitVTable mount_vtable = {
5cb5a6ff 1747 .suffix = ".mount",
7d17cfbc 1748 .object_size = sizeof(Mount),
f975e971
LP
1749 .sections =
1750 "Unit\0"
1751 "Mount\0"
1752 "Install\0",
5cb5a6ff 1753
e537352b 1754 .no_alias = true,
9e2f7c11 1755 .no_instances = true,
e537352b
LP
1756
1757 .init = mount_init,
1758 .load = mount_load,
034c6ed7 1759 .done = mount_done,
e537352b 1760
f50e0a01
LP
1761 .coldplug = mount_coldplug,
1762
034c6ed7 1763 .dump = mount_dump,
5cb5a6ff 1764
e537352b
LP
1765 .start = mount_start,
1766 .stop = mount_stop,
1767 .reload = mount_reload,
1768
8a0867d6
LP
1769 .kill = mount_kill,
1770
a16e1123
LP
1771 .serialize = mount_serialize,
1772 .deserialize_item = mount_deserialize_item,
1773
f50e0a01 1774 .active_state = mount_active_state,
10a94420 1775 .sub_state_to_string = mount_sub_state_to_string,
b08d03ff 1776
701cc384
LP
1777 .check_gc = mount_check_gc,
1778
e537352b
LP
1779 .sigchld_event = mount_sigchld_event,
1780 .timer_event = mount_timer_event,
1781
fdf20a31 1782 .reset_failed = mount_reset_failed,
5632e374 1783
c4e2ceae 1784 .bus_interface = "org.freedesktop.systemd1.Mount",
4139c1b2 1785 .bus_message_handler = bus_mount_message_handler,
c4e2ceae 1786 .bus_invalidating_properties = bus_mount_invalidating_properties,
4139c1b2 1787
f50e0a01 1788 .enumerate = mount_enumerate,
c6918296
MS
1789 .shutdown = mount_shutdown,
1790
1791 .status_message_formats = {
1792 .starting_stopping = {
1793 [0] = "Mounting %s...",
1794 [1] = "Unmounting %s...",
1795 },
1796 .finished_start_job = {
1797 [JOB_DONE] = "Mounted %s.",
1798 [JOB_FAILED] = "Failed to mount %s.",
1799 [JOB_DEPENDENCY] = "Dependency failed for %s.",
1800 [JOB_TIMEOUT] = "Timed out mounting %s.",
1801 },
1802 .finished_stop_job = {
1803 [JOB_DONE] = "Unmounted %s.",
1804 [JOB_FAILED] = "Failed unmounting %s.",
1805 [JOB_TIMEOUT] = "Timed out unmounting %s.",
1806 },
1807 },
5cb5a6ff 1808};