]> git.ipfire.org Git - people/ms/systemd.git/blame - mount.c
update fixme
[people/ms/systemd.git] / mount.c
CommitLineData
5cb5a6ff
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3#include <errno.h>
b08d03ff
LP
4#include <stdio.h>
5#include <mntent.h>
5cb5a6ff 6
87f0e418 7#include "unit.h"
5cb5a6ff
LP
8#include "mount.h"
9#include "load-fragment.h"
5cb5a6ff 10#include "load-dropin.h"
b08d03ff 11#include "log.h"
5cb5a6ff 12
f50e0a01
LP
13static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
14 [MOUNT_DEAD] = UNIT_INACTIVE,
15 [MOUNT_MOUNTING] = UNIT_ACTIVATING,
16 [MOUNT_MOUNTED] = UNIT_ACTIVE,
17 [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
18 [MOUNT_MAINTAINANCE] = UNIT_INACTIVE,
19};
5cb5a6ff 20
f50e0a01
LP
21static const char* const state_string_table[_MOUNT_STATE_MAX] = {
22 [MOUNT_DEAD] = "dead",
23 [MOUNT_MOUNTING] = "mounting",
24 [MOUNT_MOUNTED] = "mounted",
25 [MOUNT_UNMOUNTING] = "unmounting",
26 [MOUNT_MAINTAINANCE] = "maintainance"
27};
5cb5a6ff 28
87f0e418
LP
29static void mount_done(Unit *u) {
30 Mount *d = MOUNT(u);
034c6ed7
LP
31
32 assert(d);
b08d03ff
LP
33 free(d->what);
34 free(d->where);
034c6ed7
LP
35}
36
f50e0a01
LP
37static void mount_set_state(Mount *m, MountState state) {
38 MountState old_state;
39 assert(m);
40
41 old_state = m->state;
42 m->state = state;
43
44 log_debug("%s changed %s → %s", unit_id(UNIT(m)), state_string_table[old_state], state_string_table[state]);
45
46 unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state]);
47}
48
49static int mount_coldplug(Unit *u) {
50 Mount *m = MOUNT(u);
51
52 assert(m);
53 assert(m->state == MOUNT_DEAD);
5cb5a6ff 54
f50e0a01
LP
55 if (m->from_proc_self_mountinfo)
56 mount_set_state(m, MOUNT_MOUNTED);
5cb5a6ff 57
f50e0a01
LP
58 return 0;
59}
60
61static void mount_dump(Unit *u, FILE *f, const char *prefix) {
87f0e418 62 Mount *s = MOUNT(u);
5cb5a6ff
LP
63
64 assert(s);
65
66 fprintf(f,
67 "%sMount State: %s\n"
b08d03ff 68 "%sWhere: %s\n"
f50e0a01
LP
69 "%sWhat: %s\n"
70 "%sFrom /etc/fstab: %s\n"
71 "%sFrom /proc/self/mountinfo: %s\n",
72 prefix, state_string_table[s->state],
b08d03ff 73 prefix, s->where,
f50e0a01
LP
74 prefix, s->what,
75 prefix, yes_no(s->from_etc_fstab),
76 prefix, yes_no(s->from_proc_self_mountinfo));
77}
78
79static UnitActiveState mount_active_state(Unit *u) {
80 assert(u);
81
82 return state_translation_table[MOUNT(u)->state];
b08d03ff
LP
83}
84
85static void mount_shutdown(Manager *m) {
86}
87
88static int mount_add_node_links(Mount *m) {
89 Unit *device;
90 char *e;
91 int r;
92
93 assert(m);
94
95 /* Adds in links to the device that this node is based on */
96
97 if (!path_startswith(m->what, "/dev/"))
98 return 0;
99
100 if (!(e = unit_name_escape_path("node-", m->what+1, ".device")))
101 return -ENOMEM;
102
103 r = manager_load_unit(UNIT(m)->meta.manager, e, &device);
104 free(e);
105
106 if (r < 0)
107 return r;
108
109 if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, device)) < 0)
110 return r;
111
112 if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, device)) < 0)
113 return r;
114
115 if ((r = unit_add_dependency(device, UNIT_WANTS, UNIT(m))) < 0)
116 return r;
117
118 return 0;
119}
120
121static int mount_add_path_links(Mount *m) {
122 Iterator i;
123 Unit *other;
124 int r;
125
126 /* Adds in link to other mount points, that might lie below or
127 * above us in the hierarchy */
128
129 HASHMAP_FOREACH(other, UNIT(m)->meta.manager->units, i) {
130 Mount *n;
131
132 if (other->meta.type != UNIT_MOUNT)
133 continue;
134
135 n = MOUNT(other);
136
137 if (path_startswith(m->where, n->where)) {
138
139 if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, other)) < 0)
140 return r;
141
142 if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, other)) < 0)
143 return r;
144
145 } else if (startswith(n->where, m->where)) {
146
147 if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, other)) < 0)
148 return r;
149
150 if ((r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m))) < 0)
151 return r;
152 }
153 }
154
155 return 0;
156}
157
f50e0a01 158static int mount_add_one(Manager *m, const char *what, const char *where, bool live) {
b08d03ff
LP
159 char *e;
160 int r;
161 Unit *u;
162 bool delete;
163
f50e0a01 164 assert(m);
b08d03ff
LP
165 assert(what);
166 assert(where);
167
168 /* probably some kind of swap, which we don't cover for now */
169 if (where[0] != '/')
170 return 0;
171
172 if (streq(where, "/"))
173 e = strdup("rootfs.mount");
174 else
175 e = unit_name_escape_path("fs-", where+1, ".mount");
176
177 if (!e)
178 return -ENOMEM;
179
180 if (!(u = manager_get_unit(m, e))) {
181 delete = true;
182
183 if (!(u = unit_new(m))) {
184 free(e);
185 return -ENOMEM;
186 }
187
188 r = unit_add_name(u, e);
189 free(e);
190
191 if (r < 0)
192 goto fail;
193
194 if (!(MOUNT(u)->what = strdup(what)) ||
f50e0a01
LP
195 !(MOUNT(u)->where = strdup(where))) {
196 r = -ENOMEM;
197 goto fail;
198 }
199
200 if ((r = unit_set_description(u, where)) < 0)
b08d03ff 201 goto fail;
b08d03ff
LP
202 } else {
203 delete = false;
204 free(e);
205 }
206
f50e0a01
LP
207 if (live)
208 MOUNT(u)->from_proc_self_mountinfo = true;
209 else
210 MOUNT(u)->from_etc_fstab = true;
211
b08d03ff
LP
212 if ((r = mount_add_node_links(MOUNT(u))) < 0)
213 goto fail;
214
215 if ((r = mount_add_path_links(MOUNT(u))) < 0)
216 goto fail;
217
218 unit_add_to_load_queue(u);
f50e0a01 219
b08d03ff
LP
220 return 0;
221
222fail:
223 if (delete && u)
224 unit_free(u);
225
226 return 0;
227}
228
229static char *fstab_node_to_udev_node(char *p) {
230 char *dn, *t;
231 int r;
232
233 /* FIXME: to follow udev's logic 100% we need to leave valid
234 * UTF8 chars unescaped */
235
236 if (startswith(p, "LABEL=")) {
237
f50e0a01 238 if (!(t = xescape(p+6, "/ ")))
b08d03ff
LP
239 return NULL;
240
f50e0a01 241 r = asprintf(&dn, "/dev/disk/by-label/%s", t);
b08d03ff
LP
242 free(t);
243
244 if (r < 0)
245 return NULL;
246
247 return dn;
248 }
249
250 if (startswith(p, "UUID=")) {
251
f50e0a01 252 if (!(t = xescape(p+5, "/ ")))
b08d03ff
LP
253 return NULL;
254
f50e0a01 255 r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t));
b08d03ff
LP
256 free(t);
257
258 if (r < 0)
259 return NULL;
260
261 return dn;
262 }
263
264 return strdup(p);
265}
266
267static int mount_load_etc_fstab(Manager *m) {
268 FILE *f;
269 int r;
270 struct mntent* me;
271
272 assert(m);
273
274 errno = 0;
275 if (!(f = setmntent("/etc/fstab", "r")))
276 return -errno;
277
278 while ((me = getmntent(f))) {
279 char *where, *what;
280
281 if (!(what = fstab_node_to_udev_node(me->mnt_fsname))) {
282 r = -ENOMEM;
283 goto finish;
284 }
285
286 if (!(where = strdup(me->mnt_dir))) {
287 free(what);
288 r = -ENOMEM;
289 goto finish;
290 }
291
292 if (what[0] == '/')
293 path_kill_slashes(what);
294
295 if (where[0] == '/')
296 path_kill_slashes(where);
297
f50e0a01 298 r = mount_add_one(m, what, where, false);
b08d03ff
LP
299 free(what);
300 free(where);
301
302 if (r < 0)
303 goto finish;
304 }
305
306 r = 0;
307finish:
308
309 endmntent(f);
310 return r;
311}
312
f50e0a01 313static int mount_load_proc_self_mountinfo(Manager *m) {
b08d03ff
LP
314 FILE *f;
315 int r;
316
317 assert(m);
318
319 if (!(f = fopen("/proc/self/mountinfo", "r")))
320 return -errno;
321
322 for (;;) {
323 int k;
324 char *device, *path, *d, *p;
325
326 if ((k = fscanf(f,
327 "%*s " /* (1) mount id */
328 "%*s " /* (2) parent id */
329 "%*s " /* (3) major:minor */
330 "%*s " /* (4) root */
331 "%ms " /* (5) mount point */
332 "%*s" /* (6) mount options */
333 "%*[^-]" /* (7) optional fields */
334 "- " /* (8) seperator */
335 "%*s " /* (9) file system type */
336 "%ms" /* (10) mount source */
337 "%*[^\n]", /* some rubbish at the end */
338 &path,
339 &device)) != 2) {
340
341 if (k == EOF) {
342 if (feof(f))
343 break;
344
345 r = -errno;
346 goto finish;
347 }
348
349 r = -EBADMSG;
350 goto finish;
351 }
352
353 if (!(d = cunescape(device))) {
354 free(device);
355 free(path);
356 r = -ENOMEM;
357 goto finish;
358 }
359 free(device);
360
361 if (!(p = cunescape(path))) {
362 free(d);
363 free(path);
364 r = -ENOMEM;
365 goto finish;
366 }
367 free(path);
368
f50e0a01 369 r = mount_add_one(m, d, p, true);
b08d03ff
LP
370 free(d);
371 free(p);
372
373 if (r < 0)
374 goto finish;
375 }
376
377 r = 0;
378
379finish:
380 fclose(f);
381
382 return r;
383}
384
385static int mount_enumerate(Manager *m) {
386 int r;
387 assert(m);
388
389 if ((r = mount_load_etc_fstab(m)) < 0)
390 goto fail;
391
f50e0a01 392 if ((r = mount_load_proc_self_mountinfo(m)) < 0)
b08d03ff
LP
393 goto fail;
394
395 return 0;
396
397fail:
398 mount_shutdown(m);
399 return r;
5cb5a6ff
LP
400}
401
87f0e418 402const UnitVTable mount_vtable = {
5cb5a6ff
LP
403 .suffix = ".mount",
404
f50e0a01 405 .init = unit_load_fragment_and_dropin,
034c6ed7 406 .done = mount_done,
f50e0a01
LP
407 .coldplug = mount_coldplug,
408
034c6ed7 409 .dump = mount_dump,
5cb5a6ff 410
f50e0a01 411 .active_state = mount_active_state,
b08d03ff 412
f50e0a01
LP
413 .enumerate = mount_enumerate,
414 .shutdown = mount_shutdown
5cb5a6ff 415};