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