]> git.ipfire.org Git - thirdparty/systemd.git/blame - mount.c
add mount enumerator
[thirdparty/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"
10#include "load-fstab.h"
11#include "load-dropin.h"
b08d03ff 12#include "log.h"
5cb5a6ff 13
87f0e418 14static int mount_init(Unit *u) {
5cb5a6ff 15 int r;
87f0e418 16 Mount *m = MOUNT(u);
5cb5a6ff
LP
17
18 assert(m);
19
20 /* Load a .mount file */
d46de8a1 21 if ((r = unit_load_fragment(u)) < 0)
5cb5a6ff
LP
22 return r;
23
24 /* Load entry from /etc/fstab */
87f0e418 25 if ((r = unit_load_fstab(u)) < 0)
5cb5a6ff
LP
26 return r;
27
28 /* Load drop-in directory data */
87f0e418 29 if ((r = unit_load_dropin(u)) < 0)
5cb5a6ff
LP
30 return r;
31
32 return r;
33}
34
87f0e418
LP
35static void mount_done(Unit *u) {
36 Mount *d = MOUNT(u);
034c6ed7
LP
37
38 assert(d);
b08d03ff
LP
39 free(d->what);
40 free(d->where);
034c6ed7
LP
41}
42
87f0e418 43static void mount_dump(Unit *u, FILE *f, const char *prefix) {
5cb5a6ff
LP
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
87f0e418 53 Mount *s = MOUNT(u);
5cb5a6ff
LP
54
55 assert(s);
56
57 fprintf(f,
58 "%sMount State: %s\n"
b08d03ff
LP
59 "%sWhere: %s\n"
60 "%sWhat: %s\n",
5cb5a6ff 61 prefix, state_table[s->state],
b08d03ff
LP
62 prefix, s->where,
63 prefix, s->what);
64}
65
66static void mount_shutdown(Manager *m) {
67}
68
69static 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
102static 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
139static 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
194fail:
195 if (delete && u)
196 unit_free(u);
197
198 return 0;
199}
200
201static 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
239static 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;
279finish:
280
281 endmntent(f);
282 return r;
283}
284
285static 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
351finish:
352 fclose(f);
353
354 return r;
355}
356
357static 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
369fail:
370 mount_shutdown(m);
371 return r;
5cb5a6ff
LP
372}
373
87f0e418 374static UnitActiveState mount_active_state(Unit *u) {
5cb5a6ff 375
87f0e418
LP
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,
5cb5a6ff
LP
382 };
383
87f0e418 384 return table[MOUNT(u)->state];
5cb5a6ff
LP
385}
386
87f0e418 387const UnitVTable mount_vtable = {
5cb5a6ff
LP
388 .suffix = ".mount",
389
034c6ed7
LP
390 .init = mount_init,
391 .done = mount_done,
034c6ed7 392 .dump = mount_dump,
5cb5a6ff 393
b08d03ff
LP
394 .enumerate = mount_enumerate,
395 .shutdown = mount_shutdown,
396
397 .active_state = mount_active_state
5cb5a6ff 398};