]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/mount.c
man: fix man page chapter in Makefile.am
[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 */
93a1d735 369 name = unit_name_from_path_instance("systemd-fsck", p->what, ".service");
6b1dc2bd 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
1a4ac875
MS
540static int mount_add_extras(Mount *m) {
541 Unit *u = UNIT(m);
e537352b
LP
542 int r;
543
1a4ac875
MS
544 r = unit_add_exec_dependencies(u, &m->exec_context);
545 if (r < 0)
e537352b
LP
546 return r;
547
1a4ac875
MS
548 if (UNIT(m)->fragment_path)
549 m->from_fragment = true;
e537352b 550
1a4ac875
MS
551 if (!m->where) {
552 m->where = unit_name_to_path(u->id);
a16e1123 553 if (!m->where)
1a4ac875
MS
554 return -ENOMEM;
555 }
a16e1123 556
1a4ac875 557 path_kill_slashes(m->where);
e537352b 558
1a4ac875
MS
559 if (!UNIT(m)->description) {
560 r = unit_set_description(u, m->where);
561 if (r < 0)
173a8d04 562 return r;
1a4ac875 563 }
6e2ef85b 564
1a4ac875
MS
565 r = mount_add_device_links(m);
566 if (r < 0)
567 return r;
6e2ef85b 568
1a4ac875
MS
569 r = mount_add_mount_links(m);
570 if (r < 0)
571 return r;
6e2ef85b 572
1a4ac875
MS
573 r = mount_add_socket_links(m);
574 if (r < 0)
575 return r;
e537352b 576
1a4ac875
MS
577 r = mount_add_swap_links(m);
578 if (r < 0)
579 return r;
01f78473 580
1a4ac875
MS
581 r = mount_add_path_links(m);
582 if (r < 0)
583 return r;
7c8fa05c 584
1a4ac875
MS
585 r = mount_add_requires_mounts_links(m);
586 if (r < 0)
587 return r;
588
589 r = mount_add_automount_links(m);
590 if (r < 0)
591 return r;
592
593 r = mount_add_quota_links(m);
594 if (r < 0)
595 return r;
e537352b 596
1a4ac875
MS
597 if (UNIT(m)->default_dependencies) {
598 r = mount_add_default_dependencies(m);
6b1dc2bd 599 if (r < 0)
e537352b 600 return r;
1a4ac875 601 }
4e67ddd6 602
1a4ac875
MS
603 r = unit_add_default_cgroups(u);
604 if (r < 0)
605 return r;
8024c3a7 606
1a4ac875
MS
607 r = mount_fix_timeouts(m);
608 if (r < 0)
609 return r;
610
611 return 0;
612}
613
614static int mount_load(Unit *u) {
615 Mount *m = MOUNT(u);
616 int r;
617
618 assert(u);
619 assert(u->load_state == UNIT_STUB);
620
8eba616f
MS
621 if (m->from_proc_self_mountinfo)
622 r = unit_load_fragment_and_dropin_optional(u);
623 else
624 r = unit_load_fragment_and_dropin(u);
625
1a4ac875
MS
626 if (r < 0)
627 return r;
155da457 628
1a4ac875
MS
629 /* This is a new unit? Then let's add in some extras */
630 if (u->load_state == UNIT_LOADED) {
631 r = mount_add_extras(m);
632 if (r < 0)
633 return r;
e537352b
LP
634 }
635
8d567588 636 return mount_verify(m);
e537352b
LP
637}
638
a16e1123
LP
639static int mount_notify_automount(Mount *m, int status) {
640 Unit *p;
641 int r;
57020a3a 642 Iterator i;
a16e1123
LP
643
644 assert(m);
645
1124fe6f 646 SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
ac155bb8 647 if (p->type == UNIT_AUTOMOUNT) {
57020a3a
LP
648 r = automount_send_ready(AUTOMOUNT(p), status);
649 if (r < 0)
650 return r;
651 }
a16e1123 652
57020a3a 653 return 0;
a16e1123
LP
654}
655
e537352b
LP
656static void mount_set_state(Mount *m, MountState state) {
657 MountState old_state;
658 assert(m);
659
660 old_state = m->state;
661 m->state = state;
662
663 if (state != MOUNT_MOUNTING &&
664 state != MOUNT_MOUNTING_DONE &&
665 state != MOUNT_REMOUNTING &&
666 state != MOUNT_UNMOUNTING &&
667 state != MOUNT_MOUNTING_SIGTERM &&
668 state != MOUNT_MOUNTING_SIGKILL &&
669 state != MOUNT_UNMOUNTING_SIGTERM &&
670 state != MOUNT_UNMOUNTING_SIGKILL &&
671 state != MOUNT_REMOUNTING_SIGTERM &&
672 state != MOUNT_REMOUNTING_SIGKILL) {
673 unit_unwatch_timer(UNIT(m), &m->timer_watch);
a16e1123 674 mount_unwatch_control_pid(m);
e537352b 675 m->control_command = NULL;
a16e1123 676 m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
e537352b
LP
677 }
678
8d567588
LP
679 if (state == MOUNT_MOUNTED ||
680 state == MOUNT_REMOUNTING)
681 mount_notify_automount(m, 0);
682 else if (state == MOUNT_DEAD ||
683 state == MOUNT_UNMOUNTING ||
684 state == MOUNT_MOUNTING_SIGTERM ||
685 state == MOUNT_MOUNTING_SIGKILL ||
686 state == MOUNT_REMOUNTING_SIGTERM ||
687 state == MOUNT_REMOUNTING_SIGKILL ||
688 state == MOUNT_UNMOUNTING_SIGTERM ||
689 state == MOUNT_UNMOUNTING_SIGKILL ||
36fcd77e
MS
690 state == MOUNT_FAILED) {
691 if (state != old_state)
692 mount_notify_automount(m, -ENODEV);
693 }
8d567588 694
e537352b 695 if (state != old_state)
40d50879 696 log_debug("%s changed %s -> %s",
1124fe6f 697 UNIT(m)->id,
a16e1123
LP
698 mount_state_to_string(old_state),
699 mount_state_to_string(state));
e537352b 700
9d2f5178
LP
701 unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
702 m->reload_result = MOUNT_SUCCESS;
e537352b
LP
703}
704
705static int mount_coldplug(Unit *u) {
706 Mount *m = MOUNT(u);
a16e1123
LP
707 MountState new_state = MOUNT_DEAD;
708 int r;
e537352b
LP
709
710 assert(m);
711 assert(m->state == MOUNT_DEAD);
712
a16e1123
LP
713 if (m->deserialized_state != m->state)
714 new_state = m->deserialized_state;
715 else if (m->from_proc_self_mountinfo)
716 new_state = MOUNT_MOUNTED;
e537352b 717
a16e1123 718 if (new_state != m->state) {
e537352b 719
a16e1123
LP
720 if (new_state == MOUNT_MOUNTING ||
721 new_state == MOUNT_MOUNTING_DONE ||
722 new_state == MOUNT_REMOUNTING ||
723 new_state == MOUNT_UNMOUNTING ||
724 new_state == MOUNT_MOUNTING_SIGTERM ||
725 new_state == MOUNT_MOUNTING_SIGKILL ||
726 new_state == MOUNT_UNMOUNTING_SIGTERM ||
727 new_state == MOUNT_UNMOUNTING_SIGKILL ||
728 new_state == MOUNT_REMOUNTING_SIGTERM ||
729 new_state == MOUNT_REMOUNTING_SIGKILL) {
e537352b 730
a16e1123
LP
731 if (m->control_pid <= 0)
732 return -EBADMSG;
e537352b 733
a16e1123
LP
734 if ((r = unit_watch_pid(UNIT(m), m->control_pid)) < 0)
735 return r;
e537352b 736
a16e1123
LP
737 if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
738 return r;
739 }
e537352b 740
a16e1123
LP
741 mount_set_state(m, new_state);
742 }
e537352b
LP
743
744 return 0;
e537352b
LP
745}
746
747static void mount_dump(Unit *u, FILE *f, const char *prefix) {
748 Mount *m = MOUNT(u);
749 MountParameters *p;
750
751 assert(m);
752 assert(f);
753
cb39ed3f 754 p = get_mount_parameters(m);
e537352b
LP
755
756 fprintf(f,
757 "%sMount State: %s\n"
81a5c6d0 758 "%sResult: %s\n"
e537352b
LP
759 "%sWhere: %s\n"
760 "%sWhat: %s\n"
761 "%sFile System Type: %s\n"
762 "%sOptions: %s\n"
e537352b
LP
763 "%sFrom /proc/self/mountinfo: %s\n"
764 "%sFrom fragment: %s\n"
3e5235b0 765 "%sDirectoryMode: %04o\n",
a16e1123 766 prefix, mount_state_to_string(m->state),
81a5c6d0 767 prefix, mount_result_to_string(m->result),
e537352b
LP
768 prefix, m->where,
769 prefix, strna(p->what),
770 prefix, strna(p->fstype),
771 prefix, strna(p->options),
e537352b
LP
772 prefix, yes_no(m->from_proc_self_mountinfo),
773 prefix, yes_no(m->from_fragment),
3e5235b0 774 prefix, m->directory_mode);
e537352b
LP
775
776 if (m->control_pid > 0)
777 fprintf(f,
bb00e604
LP
778 "%sControl PID: %lu\n",
779 prefix, (unsigned long) m->control_pid);
e537352b
LP
780
781 exec_context_dump(&m->exec_context, f, prefix);
782}
783
a16e1123
LP
784static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
785 pid_t pid;
786 int r;
787
788 assert(m);
789 assert(c);
790 assert(_pid);
791
792 if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
793 goto fail;
794
795 if ((r = exec_spawn(c,
796 NULL,
797 &m->exec_context,
798 NULL, 0,
1124fe6f 799 UNIT(m)->manager->environment,
a16e1123
LP
800 true,
801 true,
1e3ad081 802 true,
1124fe6f
MS
803 UNIT(m)->manager->confirm_spawn,
804 UNIT(m)->cgroup_bondings,
805 UNIT(m)->cgroup_attributes,
ecedd90f 806 NULL,
62bca2c6 807 UNIT(m)->id,
f2b68789 808 NULL,
a16e1123
LP
809 &pid)) < 0)
810 goto fail;
811
812 if ((r = unit_watch_pid(UNIT(m), pid)) < 0)
813 /* FIXME: we need to do something here */
814 goto fail;
815
816 *_pid = pid;
817
818 return 0;
819
820fail:
821 unit_unwatch_timer(UNIT(m), &m->timer_watch);
822
823 return r;
824}
825
9d2f5178 826static void mount_enter_dead(Mount *m, MountResult f) {
e537352b
LP
827 assert(m);
828
9d2f5178
LP
829 if (f != MOUNT_SUCCESS)
830 m->result = f;
e537352b 831
9d2f5178 832 mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
e537352b
LP
833}
834
9d2f5178 835static void mount_enter_mounted(Mount *m, MountResult f) {
80876c20
LP
836 assert(m);
837
9d2f5178
LP
838 if (f != MOUNT_SUCCESS)
839 m->result = f;
80876c20
LP
840
841 mount_set_state(m, MOUNT_MOUNTED);
842}
843
9d2f5178 844static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
e537352b 845 int r;
ca949c9d
LP
846 Set *pid_set = NULL;
847 bool wait_for_exit = false;
e537352b
LP
848
849 assert(m);
850
9d2f5178
LP
851 if (f != MOUNT_SUCCESS)
852 m->result = f;
e537352b 853
2e22afe9 854 if (m->exec_context.kill_mode != KILL_NONE) {
80876c20
LP
855 int sig = (state == MOUNT_MOUNTING_SIGTERM ||
856 state == MOUNT_UNMOUNTING_SIGTERM ||
2e22afe9 857 state == MOUNT_REMOUNTING_SIGTERM) ? m->exec_context.kill_signal : SIGKILL;
e537352b 858
ca949c9d 859 if (m->control_pid > 0) {
cd25cce9 860 if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH)
e537352b 861
ca949c9d
LP
862 log_warning("Failed to kill control process %li: %m", (long) m->control_pid);
863 else
864 wait_for_exit = true;
e537352b
LP
865 }
866
ca949c9d 867 if (m->exec_context.kill_mode == KILL_CONTROL_GROUP) {
2e22afe9 868
ca949c9d
LP
869 if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
870 r = -ENOMEM;
e537352b
LP
871 goto fail;
872 }
ca949c9d
LP
873
874 /* Exclude the control pid from being killed via the cgroup */
875 if (m->control_pid > 0)
876 if ((r = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0)
877 goto fail;
878
88f3e0c9 879 r = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, sig, true, false, pid_set, NULL);
ecedd90f 880 if (r < 0) {
ca949c9d
LP
881 if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
882 log_warning("Failed to kill control group: %s", strerror(-r));
883 } else if (r > 0)
884 wait_for_exit = true;
885
886 set_free(pid_set);
da19d5c1 887 pid_set = NULL;
ca949c9d 888 }
e537352b
LP
889 }
890
ca949c9d 891 if (wait_for_exit) {
80876c20
LP
892 if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
893 goto fail;
e537352b 894
80876c20
LP
895 mount_set_state(m, state);
896 } else if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
9d2f5178 897 mount_enter_mounted(m, MOUNT_SUCCESS);
80876c20 898 else
9d2f5178 899 mount_enter_dead(m, MOUNT_SUCCESS);
e537352b
LP
900
901 return;
902
903fail:
1124fe6f 904 log_warning("%s failed to kill processes: %s", UNIT(m)->id, strerror(-r));
e537352b 905
80876c20 906 if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
9d2f5178 907 mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
80876c20 908 else
9d2f5178 909 mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
ca949c9d
LP
910
911 if (pid_set)
912 set_free(pid_set);
e537352b
LP
913}
914
9d2f5178 915static void mount_enter_unmounting(Mount *m) {
e537352b
LP
916 int r;
917
918 assert(m);
919
a16e1123
LP
920 m->control_command_id = MOUNT_EXEC_UNMOUNT;
921 m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
e537352b
LP
922
923 if ((r = exec_command_set(
a16e1123 924 m->control_command,
e537352b
LP
925 "/bin/umount",
926 m->where,
927 NULL)) < 0)
928 goto fail;
929
a16e1123 930 mount_unwatch_control_pid(m);
5e94833f 931
a16e1123 932 if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
e537352b
LP
933 goto fail;
934
935 mount_set_state(m, MOUNT_UNMOUNTING);
936
937 return;
938
939fail:
1124fe6f 940 log_warning("%s failed to run 'umount' task: %s", UNIT(m)->id, strerror(-r));
9d2f5178 941 mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
e537352b
LP
942}
943
8d567588 944static void mount_enter_mounting(Mount *m) {
e537352b 945 int r;
cb39ed3f 946 MountParameters *p;
e537352b
LP
947
948 assert(m);
949
a16e1123
LP
950 m->control_command_id = MOUNT_EXEC_MOUNT;
951 m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
e537352b 952
d2e54fae 953 mkdir_p_label(m->where, m->directory_mode);
3e5235b0 954
cb39ed3f 955 /* Create the source directory for bind-mounts if needed */
6b1dc2bd 956 p = get_mount_parameters_fragment(m);
cb39ed3f 957 if (p && mount_is_bind(p))
d2e54fae 958 mkdir_p_label(p->what, m->directory_mode);
2b583ce6 959
e537352b
LP
960 if (m->from_fragment)
961 r = exec_command_set(
a16e1123 962 m->control_command,
e537352b
LP
963 "/bin/mount",
964 m->parameters_fragment.what,
965 m->where,
40b8a332 966 "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto",
8d567588 967 m->parameters_fragment.options ? "-o" : NULL, m->parameters_fragment.options,
e537352b 968 NULL);
e537352b
LP
969 else
970 r = -ENOENT;
971
972 if (r < 0)
973 goto fail;
974
a16e1123 975 mount_unwatch_control_pid(m);
5e94833f 976
a16e1123 977 if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
e537352b
LP
978 goto fail;
979
980 mount_set_state(m, MOUNT_MOUNTING);
981
982 return;
983
984fail:
1124fe6f 985 log_warning("%s failed to run 'mount' task: %s", UNIT(m)->id, strerror(-r));
9d2f5178 986 mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
e537352b
LP
987}
988
8d567588 989static void mount_enter_mounting_done(Mount *m) {
e537352b
LP
990 assert(m);
991
e537352b
LP
992 mount_set_state(m, MOUNT_MOUNTING_DONE);
993}
994
9d2f5178 995static void mount_enter_remounting(Mount *m) {
e537352b
LP
996 int r;
997
998 assert(m);
999
a16e1123
LP
1000 m->control_command_id = MOUNT_EXEC_REMOUNT;
1001 m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
e537352b
LP
1002
1003 if (m->from_fragment) {
1004 char *buf = NULL;
1005 const char *o;
1006
1007 if (m->parameters_fragment.options) {
1008 if (!(buf = strappend("remount,", m->parameters_fragment.options))) {
1009 r = -ENOMEM;
1010 goto fail;
1011 }
1012
1013 o = buf;
1014 } else
1015 o = "remount";
1016
1017 r = exec_command_set(
a16e1123 1018 m->control_command,
e537352b
LP
1019 "/bin/mount",
1020 m->parameters_fragment.what,
1021 m->where,
40b8a332 1022 "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto",
e537352b
LP
1023 "-o", o,
1024 NULL);
1025
1026 free(buf);
6b1dc2bd 1027 } else
e537352b
LP
1028 r = -ENOENT;
1029
60b912f6 1030 if (r < 0)
e537352b 1031 goto fail;
e537352b 1032
a16e1123 1033 mount_unwatch_control_pid(m);
5e94833f 1034
a16e1123 1035 if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
e537352b
LP
1036 goto fail;
1037
1038 mount_set_state(m, MOUNT_REMOUNTING);
1039
1040 return;
1041
1042fail:
1124fe6f 1043 log_warning("%s failed to run 'remount' task: %s", UNIT(m)->id, strerror(-r));
9d2f5178
LP
1044 m->reload_result = MOUNT_FAILURE_RESOURCES;
1045 mount_enter_mounted(m, MOUNT_SUCCESS);
e537352b
LP
1046}
1047
1048static int mount_start(Unit *u) {
1049 Mount *m = MOUNT(u);
1050
1051 assert(m);
1052
1053 /* We cannot fulfill this request right now, try again later
1054 * please! */
1055 if (m->state == MOUNT_UNMOUNTING ||
1056 m->state == MOUNT_UNMOUNTING_SIGTERM ||
60b912f6
LP
1057 m->state == MOUNT_UNMOUNTING_SIGKILL ||
1058 m->state == MOUNT_MOUNTING_SIGTERM ||
1059 m->state == MOUNT_MOUNTING_SIGKILL)
e537352b
LP
1060 return -EAGAIN;
1061
1062 /* Already on it! */
60b912f6 1063 if (m->state == MOUNT_MOUNTING)
e537352b
LP
1064 return 0;
1065
fdf20a31 1066 assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
e537352b 1067
9d2f5178
LP
1068 m->result = MOUNT_SUCCESS;
1069 m->reload_result = MOUNT_SUCCESS;
1070
8d567588 1071 mount_enter_mounting(m);
e537352b
LP
1072 return 0;
1073}
1074
1075static int mount_stop(Unit *u) {
1076 Mount *m = MOUNT(u);
1077
1078 assert(m);
1079
e537352b
LP
1080 /* Already on it */
1081 if (m->state == MOUNT_UNMOUNTING ||
1082 m->state == MOUNT_UNMOUNTING_SIGKILL ||
60b912f6
LP
1083 m->state == MOUNT_UNMOUNTING_SIGTERM ||
1084 m->state == MOUNT_MOUNTING_SIGTERM ||
1085 m->state == MOUNT_MOUNTING_SIGKILL)
e537352b
LP
1086 return 0;
1087
3f6c78dc
LP
1088 assert(m->state == MOUNT_MOUNTING ||
1089 m->state == MOUNT_MOUNTING_DONE ||
1090 m->state == MOUNT_MOUNTED ||
3f6c78dc
LP
1091 m->state == MOUNT_REMOUNTING ||
1092 m->state == MOUNT_REMOUNTING_SIGTERM ||
1093 m->state == MOUNT_REMOUNTING_SIGKILL);
e537352b 1094
9d2f5178 1095 mount_enter_unmounting(m);
e537352b
LP
1096 return 0;
1097}
1098
1099static int mount_reload(Unit *u) {
1100 Mount *m = MOUNT(u);
1101
1102 assert(m);
1103
1104 if (m->state == MOUNT_MOUNTING_DONE)
1105 return -EAGAIN;
1106
1107 assert(m->state == MOUNT_MOUNTED);
1108
9d2f5178 1109 mount_enter_remounting(m);
e537352b
LP
1110 return 0;
1111}
1112
a16e1123
LP
1113static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
1114 Mount *m = MOUNT(u);
1115
1116 assert(m);
1117 assert(f);
1118 assert(fds);
1119
1120 unit_serialize_item(u, f, "state", mount_state_to_string(m->state));
9d2f5178
LP
1121 unit_serialize_item(u, f, "result", mount_result_to_string(m->result));
1122 unit_serialize_item(u, f, "reload-result", mount_result_to_string(m->reload_result));
a16e1123
LP
1123
1124 if (m->control_pid > 0)
5925dd3c 1125 unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) m->control_pid);
a16e1123
LP
1126
1127 if (m->control_command_id >= 0)
1128 unit_serialize_item(u, f, "control-command", mount_exec_command_to_string(m->control_command_id));
1129
1130 return 0;
1131}
1132
1133static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
1134 Mount *m = MOUNT(u);
a16e1123
LP
1135
1136 assert(u);
1137 assert(key);
1138 assert(value);
1139 assert(fds);
1140
1141 if (streq(key, "state")) {
1142 MountState state;
1143
1144 if ((state = mount_state_from_string(value)) < 0)
1145 log_debug("Failed to parse state value %s", value);
1146 else
1147 m->deserialized_state = state;
9d2f5178
LP
1148 } else if (streq(key, "result")) {
1149 MountResult f;
a16e1123 1150
9d2f5178
LP
1151 f = mount_result_from_string(value);
1152 if (f < 0)
1153 log_debug("Failed to parse result value %s", value);
1154 else if (f != MOUNT_SUCCESS)
1155 m->result = f;
1156
1157 } else if (streq(key, "reload-result")) {
1158 MountResult f;
1159
1160 f = mount_result_from_string(value);
1161 if (f < 0)
1162 log_debug("Failed to parse reload result value %s", value);
1163 else if (f != MOUNT_SUCCESS)
1164 m->reload_result = f;
a16e1123
LP
1165
1166 } else if (streq(key, "control-pid")) {
5925dd3c 1167 pid_t pid;
a16e1123 1168
e364ad06 1169 if (parse_pid(value, &pid) < 0)
a16e1123
LP
1170 log_debug("Failed to parse control-pid value %s", value);
1171 else
5925dd3c 1172 m->control_pid = pid;
a16e1123
LP
1173 } else if (streq(key, "control-command")) {
1174 MountExecCommand id;
1175
1176 if ((id = mount_exec_command_from_string(value)) < 0)
1177 log_debug("Failed to parse exec-command value %s", value);
1178 else {
1179 m->control_command_id = id;
1180 m->control_command = m->exec_command + id;
1181 }
1182
1183 } else
1184 log_debug("Unknown serialization key '%s'", key);
1185
1186 return 0;
1187}
1188
e537352b
LP
1189static UnitActiveState mount_active_state(Unit *u) {
1190 assert(u);
1191
1192 return state_translation_table[MOUNT(u)->state];
1193}
1194
10a94420
LP
1195static const char *mount_sub_state_to_string(Unit *u) {
1196 assert(u);
1197
a16e1123 1198 return mount_state_to_string(MOUNT(u)->state);
10a94420
LP
1199}
1200
701cc384
LP
1201static bool mount_check_gc(Unit *u) {
1202 Mount *m = MOUNT(u);
1203
1204 assert(m);
1205
6b1dc2bd 1206 return m->from_proc_self_mountinfo;
701cc384
LP
1207}
1208
e537352b
LP
1209static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
1210 Mount *m = MOUNT(u);
9d2f5178 1211 MountResult f;
e537352b
LP
1212
1213 assert(m);
1214 assert(pid >= 0);
1215
8c47c732
LP
1216 if (pid != m->control_pid)
1217 return;
e537352b 1218
e537352b
LP
1219 m->control_pid = 0;
1220
9d2f5178
LP
1221 if (is_clean_exit(code, status))
1222 f = MOUNT_SUCCESS;
1223 else if (code == CLD_EXITED)
1224 f = MOUNT_FAILURE_EXIT_CODE;
1225 else if (code == CLD_KILLED)
1226 f = MOUNT_FAILURE_SIGNAL;
1227 else if (code == CLD_DUMPED)
1228 f = MOUNT_FAILURE_CORE_DUMP;
1229 else
1230 assert_not_reached("Unknown code");
1231
1232 if (f != MOUNT_SUCCESS)
1233 m->result = f;
8c47c732 1234
a16e1123 1235 if (m->control_command) {
6ea832a2 1236 exec_status_exit(&m->control_command->exec_status, &m->exec_context, pid, code, status);
9d2f5178 1237
a16e1123
LP
1238 m->control_command = NULL;
1239 m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
1240 }
1241
9d2f5178 1242 log_full(f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
ac155bb8 1243 "%s mount process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
e537352b
LP
1244
1245 /* Note that mount(8) returning and the kernel sending us a
1246 * mount table change event might happen out-of-order. If an
1247 * operation succeed we assume the kernel will follow soon too
1248 * and already change into the resulting state. If it fails
1249 * we check if the kernel still knows about the mount. and
1250 * change state accordingly. */
1251
1252 switch (m->state) {
1253
1254 case MOUNT_MOUNTING:
1255 case MOUNT_MOUNTING_DONE:
1256 case MOUNT_MOUNTING_SIGKILL:
1257 case MOUNT_MOUNTING_SIGTERM:
e537352b 1258
9d2f5178
LP
1259 if (f == MOUNT_SUCCESS)
1260 mount_enter_mounted(m, f);
e537352b 1261 else if (m->from_proc_self_mountinfo)
9d2f5178 1262 mount_enter_mounted(m, f);
e537352b 1263 else
9d2f5178 1264 mount_enter_dead(m, f);
e537352b
LP
1265 break;
1266
e2f3b44c
LP
1267 case MOUNT_REMOUNTING:
1268 case MOUNT_REMOUNTING_SIGKILL:
1269 case MOUNT_REMOUNTING_SIGTERM:
1270
9d2f5178 1271 m->reload_result = f;
e2f3b44c 1272 if (m->from_proc_self_mountinfo)
9d2f5178 1273 mount_enter_mounted(m, MOUNT_SUCCESS);
e2f3b44c 1274 else
9d2f5178 1275 mount_enter_dead(m, MOUNT_SUCCESS);
e2f3b44c
LP
1276
1277 break;
1278
e537352b
LP
1279 case MOUNT_UNMOUNTING:
1280 case MOUNT_UNMOUNTING_SIGKILL:
1281 case MOUNT_UNMOUNTING_SIGTERM:
1282
9d2f5178
LP
1283 if (f == MOUNT_SUCCESS)
1284 mount_enter_dead(m, f);
e537352b 1285 else if (m->from_proc_self_mountinfo)
9d2f5178 1286 mount_enter_mounted(m, f);
e537352b 1287 else
9d2f5178 1288 mount_enter_dead(m, f);
e537352b
LP
1289 break;
1290
1291 default:
1292 assert_not_reached("Uh, control process died at wrong time.");
1293 }
c4e2ceae
LP
1294
1295 /* Notify clients about changed exit status */
1296 unit_add_to_dbus_queue(u);
e537352b
LP
1297}
1298
1299static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
1300 Mount *m = MOUNT(u);
1301
1302 assert(m);
1303 assert(elapsed == 1);
1304 assert(w == &m->timer_watch);
1305
1306 switch (m->state) {
1307
1308 case MOUNT_MOUNTING:
1309 case MOUNT_MOUNTING_DONE:
ac155bb8 1310 log_warning("%s mounting timed out. Stopping.", u->id);
9d2f5178 1311 mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
e537352b
LP
1312 break;
1313
1314 case MOUNT_REMOUNTING:
ac155bb8 1315 log_warning("%s remounting timed out. Stopping.", u->id);
9d2f5178
LP
1316 m->reload_result = MOUNT_FAILURE_TIMEOUT;
1317 mount_enter_mounted(m, MOUNT_SUCCESS);
e537352b
LP
1318 break;
1319
1320 case MOUNT_UNMOUNTING:
ac155bb8 1321 log_warning("%s unmounting timed out. Stopping.", u->id);
9d2f5178 1322 mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
e537352b
LP
1323 break;
1324
1325 case MOUNT_MOUNTING_SIGTERM:
ba035df2 1326 if (m->exec_context.send_sigkill) {
ac155bb8 1327 log_warning("%s mounting timed out. Killing.", u->id);
9d2f5178 1328 mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
ba035df2 1329 } else {
ac155bb8 1330 log_warning("%s mounting timed out. Skipping SIGKILL. Ignoring.", u->id);
ba035df2
LP
1331
1332 if (m->from_proc_self_mountinfo)
9d2f5178 1333 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1334 else
9d2f5178 1335 mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1336 }
e537352b
LP
1337 break;
1338
1339 case MOUNT_REMOUNTING_SIGTERM:
ba035df2 1340 if (m->exec_context.send_sigkill) {
ac155bb8 1341 log_warning("%s remounting timed out. Killing.", u->id);
9d2f5178 1342 mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
ba035df2 1343 } else {
ac155bb8 1344 log_warning("%s remounting timed out. Skipping SIGKILL. Ignoring.", u->id);
ba035df2
LP
1345
1346 if (m->from_proc_self_mountinfo)
9d2f5178 1347 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1348 else
9d2f5178 1349 mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1350 }
e537352b
LP
1351 break;
1352
1353 case MOUNT_UNMOUNTING_SIGTERM:
ba035df2 1354 if (m->exec_context.send_sigkill) {
ac155bb8 1355 log_warning("%s unmounting timed out. Killing.", u->id);
9d2f5178 1356 mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
ba035df2 1357 } else {
ac155bb8 1358 log_warning("%s unmounting timed out. Skipping SIGKILL. Ignoring.", u->id);
ba035df2
LP
1359
1360 if (m->from_proc_self_mountinfo)
9d2f5178 1361 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1362 else
9d2f5178 1363 mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
ba035df2 1364 }
e537352b
LP
1365 break;
1366
1367 case MOUNT_MOUNTING_SIGKILL:
1368 case MOUNT_REMOUNTING_SIGKILL:
1369 case MOUNT_UNMOUNTING_SIGKILL:
ac155bb8 1370 log_warning("%s mount process still around after SIGKILL. Ignoring.", u->id);
e537352b
LP
1371
1372 if (m->from_proc_self_mountinfo)
9d2f5178 1373 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
e537352b 1374 else
9d2f5178 1375 mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
e537352b
LP
1376 break;
1377
1378 default:
1379 assert_not_reached("Timeout at wrong time.");
1380 }
1381}
1382
1383static int mount_add_one(
1384 Manager *m,
1385 const char *what,
1386 const char *where,
1387 const char *options,
1388 const char *fstype,
9fff8a1f 1389 int passno,
e537352b 1390 bool set_flags) {
b08d03ff
LP
1391 int r;
1392 Unit *u;
1393 bool delete;
e537352b 1394 char *e, *w = NULL, *o = NULL, *f = NULL;
4e85aff4 1395 MountParameters *p;
b08d03ff 1396
f50e0a01 1397 assert(m);
b08d03ff
LP
1398 assert(what);
1399 assert(where);
e537352b
LP
1400 assert(options);
1401 assert(fstype);
1402
e537352b
LP
1403 /* Ignore API mount points. They should never be referenced in
1404 * dependencies ever. */
33ff02c9 1405 if (mount_point_is_api(where) || mount_point_ignore(where))
57f2a956 1406 return 0;
b08d03ff 1407
8d567588
LP
1408 if (streq(fstype, "autofs"))
1409 return 0;
1410
4e85aff4
LP
1411 /* probably some kind of swap, ignore */
1412 if (!is_path(where))
b08d03ff
LP
1413 return 0;
1414
7d17cfbc
MS
1415 e = unit_name_from_path(where, ".mount");
1416 if (!e)
b08d03ff
LP
1417 return -ENOMEM;
1418
7d17cfbc
MS
1419 u = manager_get_unit(m, e);
1420 if (!u) {
b08d03ff
LP
1421 delete = true;
1422
7d17cfbc
MS
1423 u = unit_new(m, sizeof(Mount));
1424 if (!u) {
b08d03ff
LP
1425 free(e);
1426 return -ENOMEM;
1427 }
1428
1429 r = unit_add_name(u, e);
1430 free(e);
1431
1432 if (r < 0)
1433 goto fail;
1434
7d17cfbc
MS
1435 MOUNT(u)->where = strdup(where);
1436 if (!MOUNT(u)->where) {
07b0b134
ML
1437 r = -ENOMEM;
1438 goto fail;
1439 }
f50e0a01 1440
f94ea366 1441 unit_add_to_load_queue(u);
b08d03ff
LP
1442 } else {
1443 delete = false;
1444 free(e);
8eba616f
MS
1445
1446 if (u->load_state == UNIT_ERROR) {
1447 u->load_state = UNIT_LOADED;
1448 u->load_error = 0;
1449 r = mount_add_extras(MOUNT(u));
1450 if (r < 0)
1451 goto fail;
1452 }
b08d03ff
LP
1453 }
1454
e537352b
LP
1455 if (!(w = strdup(what)) ||
1456 !(o = strdup(options)) ||
1457 !(f = strdup(fstype))) {
1458 r = -ENOMEM;
1459 goto fail;
1460 }
1461
6b1dc2bd
LP
1462 p = &MOUNT(u)->parameters_proc_self_mountinfo;
1463 if (set_flags) {
1464 MOUNT(u)->is_mounted = true;
1465 MOUNT(u)->just_mounted = !MOUNT(u)->from_proc_self_mountinfo;
1466 MOUNT(u)->just_changed = !streq_ptr(p->options, o);
ef734fd6 1467 }
f50e0a01 1468
6b1dc2bd
LP
1469 MOUNT(u)->from_proc_self_mountinfo = true;
1470
4e85aff4
LP
1471 free(p->what);
1472 p->what = w;
b08d03ff 1473
4e85aff4
LP
1474 free(p->options);
1475 p->options = o;
e537352b 1476
4e85aff4
LP
1477 free(p->fstype);
1478 p->fstype = f;
b08d03ff 1479
9fff8a1f
LP
1480 p->passno = passno;
1481
c1e1601e
LP
1482 unit_add_to_dbus_queue(u);
1483
b08d03ff
LP
1484 return 0;
1485
1486fail:
e537352b
LP
1487 free(w);
1488 free(o);
1489 free(f);
1490
b08d03ff
LP
1491 if (delete && u)
1492 unit_free(u);
1493
4e85aff4 1494 return r;
b08d03ff
LP
1495}
1496
ef734fd6 1497static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
60b912f6 1498 int r = 0;
1ddff895 1499 unsigned i;
a2e0f3d3 1500 char *device, *path, *options, *options2, *fstype, *d, *p, *o;
b08d03ff
LP
1501
1502 assert(m);
1503
ef734fd6 1504 rewind(m->proc_self_mountinfo);
b08d03ff 1505
1ddff895 1506 for (i = 1;; i++) {
b08d03ff 1507 int k;
e537352b 1508
a2e0f3d3 1509 device = path = options = options2 = fstype = d = p = o = NULL;
b08d03ff 1510
ef734fd6 1511 if ((k = fscanf(m->proc_self_mountinfo,
b08d03ff
LP
1512 "%*s " /* (1) mount id */
1513 "%*s " /* (2) parent id */
1514 "%*s " /* (3) major:minor */
1515 "%*s " /* (4) root */
1516 "%ms " /* (5) mount point */
e537352b 1517 "%ms" /* (6) mount options */
b08d03ff 1518 "%*[^-]" /* (7) optional fields */
c899f8c6 1519 "- " /* (8) separator */
e537352b 1520 "%ms " /* (9) file system type */
ef734fd6 1521 "%ms" /* (10) mount source */
a2e0f3d3 1522 "%ms" /* (11) mount options 2 */
ef734fd6 1523 "%*[^\n]", /* some rubbish at the end */
b08d03ff 1524 &path,
e537352b
LP
1525 &options,
1526 &fstype,
a2e0f3d3
LP
1527 &device,
1528 &options2)) != 5) {
b08d03ff 1529
ef734fd6
LP
1530 if (k == EOF)
1531 break;
b08d03ff 1532
1ddff895
FF
1533 log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
1534 goto clean_up;
b08d03ff
LP
1535 }
1536
f7f21d33
LP
1537 o = join(options, ",", options2, NULL);
1538 if (!o) {
a2e0f3d3
LP
1539 r = -ENOMEM;
1540 goto finish;
1541 }
1542
e537352b
LP
1543 if (!(d = cunescape(device)) ||
1544 !(p = cunescape(path))) {
1545 r = -ENOMEM;
1546 goto finish;
b08d03ff 1547 }
b08d03ff 1548
6b1dc2bd 1549 if ((k = mount_add_one(m, d, p, o, fstype, 0, set_flags)) < 0)
60b912f6 1550 r = k;
b08d03ff 1551
1ddff895 1552clean_up:
e537352b
LP
1553 free(device);
1554 free(path);
1555 free(options);
a2e0f3d3 1556 free(options2);
e537352b 1557 free(fstype);
b08d03ff
LP
1558 free(d);
1559 free(p);
a2e0f3d3 1560 free(o);
b08d03ff
LP
1561 }
1562
e537352b
LP
1563finish:
1564 free(device);
1565 free(path);
1566 free(options);
a2e0f3d3 1567 free(options2);
e537352b
LP
1568 free(fstype);
1569 free(d);
1570 free(p);
a2e0f3d3 1571 free(o);
e537352b
LP
1572
1573 return r;
1574}
1575
1576static void mount_shutdown(Manager *m) {
1577 assert(m);
1578
a16e1123 1579 if (m->proc_self_mountinfo) {
e537352b 1580 fclose(m->proc_self_mountinfo);
a16e1123
LP
1581 m->proc_self_mountinfo = NULL;
1582 }
b08d03ff
LP
1583}
1584
1585static int mount_enumerate(Manager *m) {
1586 int r;
ef734fd6 1587 struct epoll_event ev;
b08d03ff
LP
1588 assert(m);
1589
a16e1123
LP
1590 if (!m->proc_self_mountinfo) {
1591 if (!(m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
1592 return -errno;
ef734fd6 1593
a16e1123
LP
1594 m->mount_watch.type = WATCH_MOUNT;
1595 m->mount_watch.fd = fileno(m->proc_self_mountinfo);
ef734fd6 1596
a16e1123 1597 zero(ev);
4e434314 1598 ev.events = EPOLLPRI;
a16e1123 1599 ev.data.ptr = &m->mount_watch;
ef734fd6 1600
a16e1123
LP
1601 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0)
1602 return -errno;
1603 }
ef734fd6 1604
ef734fd6 1605 if ((r = mount_load_proc_self_mountinfo(m, false)) < 0)
b08d03ff
LP
1606 goto fail;
1607
1608 return 0;
1609
1610fail:
1611 mount_shutdown(m);
1612 return r;
5cb5a6ff
LP
1613}
1614
ef734fd6 1615void mount_fd_event(Manager *m, int events) {
595ed347 1616 Unit *u;
ef734fd6
LP
1617 int r;
1618
1619 assert(m);
4e434314 1620 assert(events & EPOLLPRI);
ef734fd6
LP
1621
1622 /* The manager calls this for every fd event happening on the
1623 * /proc/self/mountinfo file, which informs us about mounting
1624 * table changes */
1625
1626 if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) {
e364ad06 1627 log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-r));
e537352b
LP
1628
1629 /* Reset flags, just in case, for later calls */
595ed347
MS
1630 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
1631 Mount *mount = MOUNT(u);
e537352b
LP
1632
1633 mount->is_mounted = mount->just_mounted = mount->just_changed = false;
1634 }
1635
ef734fd6
LP
1636 return;
1637 }
1638
1639 manager_dispatch_load_queue(m);
1640
595ed347
MS
1641 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
1642 Mount *mount = MOUNT(u);
ef734fd6 1643
e537352b
LP
1644 if (!mount->is_mounted) {
1645 /* This has just been unmounted. */
1646
ef734fd6 1647 mount->from_proc_self_mountinfo = false;
e537352b
LP
1648
1649 switch (mount->state) {
1650
1651 case MOUNT_MOUNTED:
9d2f5178 1652 mount_enter_dead(mount, MOUNT_SUCCESS);
e537352b
LP
1653 break;
1654
1655 default:
1656 mount_set_state(mount, mount->state);
1657 break;
1658
1659 }
1660
1661 } else if (mount->just_mounted || mount->just_changed) {
1662
60b912f6 1663 /* New or changed mount entry */
e537352b
LP
1664
1665 switch (mount->state) {
1666
1667 case MOUNT_DEAD:
fdf20a31 1668 case MOUNT_FAILED:
9d2f5178 1669 mount_enter_mounted(mount, MOUNT_SUCCESS);
e537352b
LP
1670 break;
1671
1672 case MOUNT_MOUNTING:
8d567588 1673 mount_enter_mounting_done(mount);
e537352b
LP
1674 break;
1675
1676 default:
1677 /* Nothing really changed, but let's
1678 * issue an notification call
1679 * nonetheless, in case somebody is
1680 * waiting for this. (e.g. file system
1681 * ro/rw remounts.) */
1682 mount_set_state(mount, mount->state);
1683 break;
1684 }
1685 }
1686
1687 /* Reset the flags for later calls */
1688 mount->is_mounted = mount->just_mounted = mount->just_changed = false;
1689 }
1690}
1691
fdf20a31 1692static void mount_reset_failed(Unit *u) {
5632e374
LP
1693 Mount *m = MOUNT(u);
1694
1695 assert(m);
1696
fdf20a31 1697 if (m->state == MOUNT_FAILED)
5632e374
LP
1698 mount_set_state(m, MOUNT_DEAD);
1699
9d2f5178
LP
1700 m->result = MOUNT_SUCCESS;
1701 m->reload_result = MOUNT_SUCCESS;
5632e374
LP
1702}
1703
8a0867d6
LP
1704static int mount_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
1705 Mount *m = MOUNT(u);
1706 int r = 0;
1707 Set *pid_set = NULL;
1708
1709 assert(m);
1710
1711 if (who == KILL_MAIN) {
1712 dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Mount units have no main processes");
a17204af 1713 return -ESRCH;
8a0867d6
LP
1714 }
1715
1716 if (m->control_pid <= 0 && who == KILL_CONTROL) {
1717 dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
a17204af 1718 return -ESRCH;
8a0867d6
LP
1719 }
1720
3611581e
LP
1721 if (who == KILL_CONTROL || who == KILL_ALL)
1722 if (m->control_pid > 0)
1723 if (kill(m->control_pid, signo) < 0)
1724 r = -errno;
8a0867d6 1725
3611581e 1726 if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
8a0867d6
LP
1727 int q;
1728
1729 if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
1730 return -ENOMEM;
1731
1732 /* Exclude the control pid from being killed via the cgroup */
1733 if (m->control_pid > 0)
1734 if ((q = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0) {
1735 r = q;
1736 goto finish;
1737 }
1738
88f3e0c9 1739 q = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, signo, false, false, pid_set, NULL);
ecedd90f 1740 if (q < 0)
3611581e 1741 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
8a0867d6
LP
1742 r = q;
1743 }
1744
1745finish:
1746 if (pid_set)
1747 set_free(pid_set);
1748
1749 return r;
1750}
1751
a16e1123
LP
1752static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
1753 [MOUNT_DEAD] = "dead",
1754 [MOUNT_MOUNTING] = "mounting",
1755 [MOUNT_MOUNTING_DONE] = "mounting-done",
1756 [MOUNT_MOUNTED] = "mounted",
1757 [MOUNT_REMOUNTING] = "remounting",
1758 [MOUNT_UNMOUNTING] = "unmounting",
1759 [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
1760 [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
1761 [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
1762 [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
1763 [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
1764 [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
fdf20a31 1765 [MOUNT_FAILED] = "failed"
a16e1123
LP
1766};
1767
1768DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
1769
1770static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
1771 [MOUNT_EXEC_MOUNT] = "ExecMount",
1772 [MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
1773 [MOUNT_EXEC_REMOUNT] = "ExecRemount",
1774};
1775
1776DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand);
1777
9d2f5178
LP
1778static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
1779 [MOUNT_SUCCESS] = "success",
1780 [MOUNT_FAILURE_RESOURCES] = "resources",
1781 [MOUNT_FAILURE_TIMEOUT] = "timeout",
1782 [MOUNT_FAILURE_EXIT_CODE] = "exit-code",
1783 [MOUNT_FAILURE_SIGNAL] = "signal",
1784 [MOUNT_FAILURE_CORE_DUMP] = "core-dump"
1785};
1786
1787DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
1788
87f0e418 1789const UnitVTable mount_vtable = {
7d17cfbc 1790 .object_size = sizeof(Mount),
f975e971
LP
1791 .sections =
1792 "Unit\0"
1793 "Mount\0"
1794 "Install\0",
5cb5a6ff 1795
e537352b 1796 .no_alias = true,
9e2f7c11 1797 .no_instances = true,
e537352b
LP
1798
1799 .init = mount_init,
1800 .load = mount_load,
034c6ed7 1801 .done = mount_done,
e537352b 1802
f50e0a01
LP
1803 .coldplug = mount_coldplug,
1804
034c6ed7 1805 .dump = mount_dump,
5cb5a6ff 1806
e537352b
LP
1807 .start = mount_start,
1808 .stop = mount_stop,
1809 .reload = mount_reload,
1810
8a0867d6
LP
1811 .kill = mount_kill,
1812
a16e1123
LP
1813 .serialize = mount_serialize,
1814 .deserialize_item = mount_deserialize_item,
1815
f50e0a01 1816 .active_state = mount_active_state,
10a94420 1817 .sub_state_to_string = mount_sub_state_to_string,
b08d03ff 1818
701cc384
LP
1819 .check_gc = mount_check_gc,
1820
e537352b
LP
1821 .sigchld_event = mount_sigchld_event,
1822 .timer_event = mount_timer_event,
1823
fdf20a31 1824 .reset_failed = mount_reset_failed,
5632e374 1825
c4e2ceae 1826 .bus_interface = "org.freedesktop.systemd1.Mount",
4139c1b2 1827 .bus_message_handler = bus_mount_message_handler,
c4e2ceae 1828 .bus_invalidating_properties = bus_mount_invalidating_properties,
4139c1b2 1829
f50e0a01 1830 .enumerate = mount_enumerate,
c6918296
MS
1831 .shutdown = mount_shutdown,
1832
1833 .status_message_formats = {
1834 .starting_stopping = {
1835 [0] = "Mounting %s...",
1836 [1] = "Unmounting %s...",
1837 },
1838 .finished_start_job = {
1839 [JOB_DONE] = "Mounted %s.",
1840 [JOB_FAILED] = "Failed to mount %s.",
1841 [JOB_DEPENDENCY] = "Dependency failed for %s.",
1842 [JOB_TIMEOUT] = "Timed out mounting %s.",
1843 },
1844 .finished_stop_job = {
1845 [JOB_DONE] = "Unmounted %s.",
1846 [JOB_FAILED] = "Failed unmounting %s.",
1847 [JOB_TIMEOUT] = "Timed out unmounting %s.",
1848 },
1849 },
5cb5a6ff 1850};