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