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