+ m->where = NULL;
+
+ mount_parameters_done(&m->parameters_etc_fstab);
+ mount_parameters_done(&m->parameters_proc_self_mountinfo);
+ mount_parameters_done(&m->parameters_fragment);
+
+ exec_context_done(&m->exec_context);
+ exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
+ m->control_command = NULL;
+
+ mount_unwatch_control_pid(m);
+
+ unit_unwatch_timer(u, &m->timer_watch);
+}
+
+int mount_add_node_links(Unit *u, const char *what) {
+ Unit *device;
+ char *e;
+ int r;
+
+ assert(u);
+
+ if (!what)
+ /* We observe kernel mounts only while they are live,
+ * hence don't create any links for them */
+ return 0;
+
+ /* Adds in links to the device that this node is based on */
+
+ if (!path_startswith(what, "/dev/"))
+ return 0;
+
+ if (!(e = unit_name_build_escape(what+1, NULL, ".device")))
+ return -ENOMEM;
+
+ r = manager_load_unit(u->meta.manager, e, NULL, &device);
+ free(e);
+
+ if (r < 0)
+ return r;
+
+ if ((r = unit_add_dependency(u, UNIT_AFTER, device, true)) < 0)
+ return r;
+
+ if ((r = unit_add_dependency(u, UNIT_REQUIRES, device, true)) < 0)
+ return r;
+
+ if (u->meta.manager->running_as == MANAGER_INIT ||
+ u->meta.manager->running_as == MANAGER_SYSTEM)
+ if ((r = unit_add_dependency(device, UNIT_WANTS, u, false)) < 0)
+ return r;
+
+ return 0;
+}
+
+int mount_add_path_links(Unit *u, const char *where, bool requires) {
+ Meta *other;
+ int r;
+
+ assert(u);
+
+ /* Adds in link to other mount points, that might lie below or
+ * above us in the hierarchy */
+
+ LIST_FOREACH(units_per_type, other, u->meta.manager->units_per_type[UNIT_MOUNT]) {
+ Mount *n;
+
+ n = (Mount*) other;
+
+ if (UNIT(n) == u)
+ continue;
+
+ if (u->meta.load_state != UNIT_LOADED)
+ continue;
+
+ if (path_startswith(where, n->where)) {
+
+ if ((r = unit_add_dependency(u, UNIT_AFTER, UNIT(other), true)) < 0)
+ return r;
+
+ if (requires)
+ if ((r = unit_add_dependency(u, UNIT_REQUIRES, UNIT(other), true)) < 0)
+ return r;
+
+ } else if (path_startswith(n->where, where)) {
+
+ if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(other), true)) < 0)
+ return r;
+
+ if (requires)
+ if ((r = unit_add_dependency(UNIT(other), UNIT_REQUIRES, u, true)) < 0)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+static char* mount_test_option(const char *haystack, const char *needle) {
+ struct mntent me;
+
+ assert(needle);
+
+ /* Like glibc's hasmntopt(), but works on a string, not a
+ * struct mntent */
+
+ if (!haystack)
+ return false;
+
+ zero(me);
+ me.mnt_opts = (char*) haystack;
+
+ return hasmntopt(&me, needle);
+}
+
+static int mount_add_target_links(Mount *m) {
+ const char *target;
+ MountParameters *p;
+ Unit *tu;
+ int r;
+ bool noauto, handle, automount;
+
+ assert(m);
+
+ if (m->from_fragment)
+ p = &m->parameters_fragment;
+ else if (m->from_etc_fstab)
+ p = &m->parameters_etc_fstab;
+ else
+ return 0;
+
+ noauto = !!mount_test_option(p->options, MNTOPT_NOAUTO);
+ handle = !!mount_test_option(p->options, "comment=systemd.mount");
+ automount = !!mount_test_option(p->options, "comment=systemd.automount");
+
+ if (noauto && !handle && !automount)
+ return 0;
+
+ if (mount_test_option(p->options, "_netdev") ||
+ fstype_is_network(p->fstype))
+ target = SPECIAL_REMOTE_FS_TARGET;
+ else
+ target = SPECIAL_LOCAL_FS_TARGET;
+
+ if ((r = manager_load_unit(UNIT(m)->meta.manager, target, NULL, &tu)) < 0)
+ return r;
+
+ if (automount) {
+ Unit *am;
+
+ if ((r = unit_load_related_unit(UNIT(m), ".automount", &am)) < 0)
+ return r;
+
+ if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(am), true)) < 0)
+ return r;
+
+ return unit_add_dependency(UNIT(am), UNIT_BEFORE, tu, true);
+
+ } else {
+
+ if (handle)
+ if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true)) < 0)
+ return r;
+
+ return unit_add_dependency(UNIT(m), UNIT_BEFORE, tu, true);
+ }
+}
+
+static int mount_verify(Mount *m) {
+ bool b;
+ char *e;
+ assert(m);
+
+ if (UNIT(m)->meta.load_state != UNIT_LOADED)
+ return 0;
+
+ if (!(e = unit_name_from_path(m->where, ".mount")))
+ return -ENOMEM;
+
+ b = unit_has_name(UNIT(m), e);
+ free(e);
+
+ if (!b) {
+ log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(m)->meta.id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mount_load(Unit *u) {
+ Mount *m = MOUNT(u);
+ int r;
+
+ assert(u);
+ assert(u->meta.load_state == UNIT_STUB);
+
+ if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
+ return r;
+
+ /* This is a new unit? Then let's add in some extras */
+ if (u->meta.load_state == UNIT_LOADED) {
+ const char *what = m->parameters_fragment.what;
+ if (!what)
+ what = m->parameters_etc_fstab.what;
+
+ if (!m->where)
+ if (!(m->where = unit_name_to_path(u->meta.id)))
+ return -ENOMEM;
+
+ path_kill_slashes(m->where);
+
+ /* Minor validity checking */
+ if ((m->parameters_fragment.options || m->parameters_fragment.fstype) && !m->parameters_fragment.what)
+ return -EBADMSG;
+
+ if (m->parameters_fragment.what)
+ m->from_fragment = true;
+
+ if ((r = mount_add_node_links(u, what)) < 0)
+ return r;
+
+ if ((r = mount_add_path_links(u, m->where, m->from_etc_fstab || m->from_fragment)) < 0)
+ return r;
+
+ if ((r = mount_add_target_links(MOUNT(u))) < 0)
+ return r;
+
+ if ((r = unit_add_default_cgroup(u)) < 0)
+ return r;
+ }
+
+ return mount_verify(m);
+}
+
+static int mount_notify_automount(Mount *m, int status) {
+ Unit *p;
+ int r;
+
+ assert(m);
+
+ if ((r = unit_get_related_unit(UNIT(m), ".automount", &p)) < 0)
+ return r == -ENOENT ? 0 : r;
+
+ return automount_send_ready(AUTOMOUNT(p), status);