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