]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/fstab-generator/fstab-generator.c
util: don't require libcap when building libsystemd-shared
[thirdparty/systemd.git] / src / fstab-generator / fstab-generator.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdio.h>
23 #include <mntent.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "log.h"
29 #include "util.h"
30 #include "unit-name.h"
31 #include "path-util.h"
32 #include "mount-setup.h"
33 #include "special.h"
34 #include "mkdir.h"
35
36 static const char *arg_dest = "/tmp";
37
38 static int device_name(const char *path, char **unit) {
39 char *p;
40
41 assert(path);
42
43 if (!is_device_path(path))
44 return 0;
45
46 p = unit_name_from_path(path, ".device");
47 if (!p)
48 return -ENOMEM;
49
50 *unit = p;
51 return 1;
52 }
53
54 static int mount_find_pri(struct mntent *me, int *ret) {
55 char *end, *pri;
56 unsigned long r;
57
58 assert(me);
59 assert(ret);
60
61 pri = hasmntopt(me, "pri");
62 if (!pri)
63 return 0;
64
65 pri += 4;
66
67 errno = 0;
68 r = strtoul(pri, &end, 10);
69 if (errno != 0)
70 return -errno;
71
72 if (end == pri || (*end != ',' && *end != 0))
73 return -EINVAL;
74
75 *ret = (int) r;
76 return 1;
77 }
78
79 static int add_swap(const char *what, struct mntent *me) {
80 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
81 FILE *f = NULL;
82 bool noauto, nofail;
83 int r, pri = -1;
84
85 assert(what);
86 assert(me);
87
88 r = mount_find_pri(me, &pri);
89 if (r < 0) {
90 log_error("Failed to parse priority");
91 return pri;
92 }
93
94 noauto = !!hasmntopt(me, "noauto");
95 nofail = !!hasmntopt(me, "nofail");
96
97 name = unit_name_from_path(what, ".swap");
98 if (!name) {
99 log_error("Out of memory");
100 r = -ENOMEM;
101 goto finish;
102 }
103
104 unit = join(arg_dest, "/", name, NULL);
105 if (!unit) {
106 log_error("Out of memory");
107 r = -ENOMEM;
108 goto finish;
109 }
110
111 f = fopen(unit, "wxe");
112 if (!f) {
113 r = -errno;
114 log_error("Failed to create unit file: %m");
115 goto finish;
116 }
117
118 fputs("# Automatically generated by systemd-fstab-generator\n\n"
119 "[Unit]\n"
120 "SourcePath=/etc/fstab\n"
121 "DefaultDependencies=no\n"
122 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
123 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
124
125 if (!noauto && !nofail)
126 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
127
128 fprintf(f,
129 "\n"
130 "[Swap]\n"
131 "What=%s\n",
132 what);
133
134 if (pri >= 0)
135 fprintf(f,
136 "Priority=%i\n",
137 pri);
138
139 fflush(f);
140 if (ferror(f)) {
141 log_error("Failed to write unit file: %m");
142 r = -errno;
143 goto finish;
144 }
145
146 if (!noauto) {
147 lnk = join(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
148 if (!lnk) {
149 log_error("Out of memory");
150 r = -ENOMEM;
151 goto finish;
152 }
153
154 mkdir_parents(lnk, 0755);
155 if (symlink(unit, lnk) < 0) {
156 log_error("Failed to create symlink: %m");
157 r = -errno;
158 goto finish;
159 }
160
161 r = device_name(what, &device);
162 if (r < 0) {
163 log_error("Out of memory");
164 r = -ENOMEM;
165 goto finish;
166 }
167
168 if (r > 0) {
169 free(lnk);
170 lnk = join(arg_dest, "/", device, ".wants/", name, NULL);
171 if (!lnk) {
172 log_error("Out of memory");
173 r = -ENOMEM;
174 goto finish;
175 }
176
177 mkdir_parents(lnk, 0755);
178 if (symlink(unit, lnk) < 0) {
179 log_error("Failed to create symlink: %m");
180 r = -errno;
181 goto finish;
182 }
183 }
184 }
185
186 r = 0;
187 finish:
188 if (f)
189 fclose(f);
190
191 free(unit);
192 free(lnk);
193 free(name);
194 free(device);
195
196 return r;
197 }
198
199 static bool mount_is_bind(struct mntent *me) {
200 assert(me);
201
202 return
203 hasmntopt(me, "bind") ||
204 streq(me->mnt_opts, "bind");
205 }
206
207 static bool mount_is_network(struct mntent *me) {
208 assert(me);
209
210 return
211 hasmntopt(me, "_netdev") ||
212 fstype_is_network(me->mnt_type);
213 }
214
215 static int add_mount(const char *what, const char *where, struct mntent *me) {
216 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL, *automount_name = NULL, *automount_unit = NULL;
217 FILE *f = NULL;
218 bool noauto, nofail, automount, isbind, isnetwork;
219 int r;
220 const char *post, *pre;
221
222 assert(what);
223 assert(where);
224 assert(me);
225
226 if (streq(me->mnt_type, "autofs"))
227 return 0;
228
229 if (!is_path(where)) {
230 log_warning("Mount point %s is not a valid path, ignoring.", where);
231 return 0;
232 }
233
234 if (mount_point_is_api(where) ||
235 mount_point_ignore(where))
236 return 0;
237
238 isnetwork = mount_is_network(me);
239 isbind = mount_is_bind(me);
240
241 noauto = !!hasmntopt(me, "noauto");
242 nofail = !!hasmntopt(me, "nofail");
243 automount =
244 hasmntopt(me, "comment=systemd.automount") ||
245 hasmntopt(me, "x-systemd.automount");
246
247 if (isnetwork) {
248 post = SPECIAL_REMOTE_FS_TARGET;
249 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
250 } else {
251 post = SPECIAL_LOCAL_FS_TARGET;
252 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
253 }
254
255 name = unit_name_from_path(where, ".mount");
256 if (!name) {
257 log_error("Out of memory");
258 r = -ENOMEM;
259 goto finish;
260 }
261
262 unit = join(arg_dest, "/", name, NULL);
263 if (!unit) {
264 log_error("Out of memory");
265 r = -ENOMEM;
266 goto finish;
267 }
268
269 f = fopen(unit, "wxe");
270 if (!f) {
271 r = -errno;
272 log_error("Failed to create unit file: %m");
273 goto finish;
274 }
275
276 fputs("# Automatically generated by systemd-fstab-generator\n\n"
277 "[Unit]\n"
278 "SourcePath=/etc/fstab\n"
279 "DefaultDependencies=no\n", f);
280
281 if (!path_equal(where, "/"))
282 fprintf(f,
283 "After=%s\n"
284 "Wants=%s\n"
285 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
286 "Before=" SPECIAL_UMOUNT_TARGET "\n",
287 pre,
288 pre);
289
290
291 if (!noauto && !nofail && !automount)
292 fprintf(f,
293 "Before=%s\n",
294 post);
295
296 fprintf(f,
297 "\n"
298 "[Mount]\n"
299 "What=%s\n"
300 "Where=%s\n"
301 "Type=%s\n"
302 "FsckPassNo=%i\n",
303 what,
304 where,
305 me->mnt_type,
306 me->mnt_passno);
307
308 if (!isempty(me->mnt_opts) &&
309 !streq(me->mnt_opts, "defaults"))
310 fprintf(f,
311 "Options=%s\n",
312 me->mnt_opts);
313
314 fflush(f);
315 if (ferror(f)) {
316 log_error("Failed to write unit file: %m");
317 r = -errno;
318 goto finish;
319 }
320
321 if (!noauto) {
322 lnk = join(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
323 if (!lnk) {
324 log_error("Out of memory");
325 r = -ENOMEM;
326 goto finish;
327 }
328
329 mkdir_parents(lnk, 0755);
330 if (symlink(unit, lnk) < 0) {
331 log_error("Failed to create symlink: %m");
332 r = -errno;
333 goto finish;
334 }
335
336 if (!isbind &&
337 !path_equal(where, "/")) {
338
339 r = device_name(what, &device);
340 if (r < 0) {
341 log_error("Out of memory");
342 r = -ENOMEM;
343 goto finish;
344 }
345
346 if (r > 0) {
347 free(lnk);
348 lnk = join(arg_dest, "/", device, ".wants/", name, NULL);
349 if (!lnk) {
350 log_error("Out of memory");
351 r = -ENOMEM;
352 goto finish;
353 }
354
355 mkdir_parents(lnk, 0755);
356 if (symlink(unit, lnk) < 0) {
357 log_error("Failed to creat symlink: %m");
358 r = -errno;
359 goto finish;
360 }
361 }
362 }
363 }
364
365 if (automount && !path_equal(where, "/")) {
366 automount_name = unit_name_from_path(where, ".automount");
367 if (!name) {
368 log_error("Out of memory");
369 r = -ENOMEM;
370 goto finish;
371 }
372
373 automount_unit = join(arg_dest, "/", automount_name, NULL);
374 if (!automount_unit) {
375 log_error("Out of memory");
376 r = -ENOMEM;
377 goto finish;
378 }
379
380 fclose(f);
381 f = fopen(automount_unit, "wxe");
382 if (!f) {
383 r = -errno;
384 log_error("Failed to create unit file: %m");
385 goto finish;
386 }
387
388 fprintf(f,
389 "# Automatically generated by systemd-fstab-generator\n\n"
390 "[Unit]\n"
391 "SourcePath=/etc/fstab\n"
392 "DefaultDependencies=no\n"
393 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
394 "Before=" SPECIAL_UMOUNT_TARGET " %s\n"
395 "\n"
396 "[Automount]\n"
397 "Where=%s\n",
398 post,
399 where);
400
401 fflush(f);
402 if (ferror(f)) {
403 log_error("Failed to write unit file: %m");
404 r = -errno;
405 goto finish;
406 }
407
408 free(lnk);
409 lnk = join(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
410 if (!lnk) {
411 log_error("Out of memory");
412 r = -ENOMEM;
413 goto finish;
414 }
415
416 mkdir_parents(lnk, 0755);
417 if (symlink(automount_unit, lnk) < 0) {
418 log_error("Failed to create symlink: %m");
419 r = -errno;
420 goto finish;
421 }
422 }
423
424 r = 0;
425 finish:
426 if (f)
427 fclose(f);
428
429 free(unit);
430 free(lnk);
431 free(name);
432 free(device);
433 free(automount_name);
434 free(automount_unit);
435
436 return r;
437 }
438
439 static int parse_fstab(void) {
440 FILE *f;
441 int r = 0;
442 struct mntent *me;
443
444 errno = 0;
445 f = setmntent("/etc/fstab", "r");
446 if (!f) {
447 if (errno == ENOENT)
448 return 0;
449
450 log_error("Failed to open /etc/fstab: %m");
451 return -errno;
452 }
453
454 while ((me = getmntent(f))) {
455 char *where, *what;
456 int k;
457
458 what = fstab_node_to_udev_node(me->mnt_fsname);
459 if (!what) {
460 log_error("Out of memory");
461 r = -ENOMEM;
462 goto finish;
463 }
464
465 where = strdup(me->mnt_dir);
466 if (!where) {
467 log_error("Out of memory");
468 free(what);
469 r = -ENOMEM;
470 goto finish;
471 }
472
473 if (is_path(what))
474 path_kill_slashes(what);
475
476 if (is_path(where))
477 path_kill_slashes(where);
478
479 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
480
481 if (streq(me->mnt_type, "swap"))
482 k = add_swap(what, me);
483 else
484 k = add_mount(what, where, me);
485
486 free(what);
487 free(where);
488
489 if (k < 0)
490 r = k;
491 }
492
493 finish:
494 endmntent(f);
495 return r;
496 }
497
498 int main(int argc, char *argv[]) {
499 int r;
500
501 if (argc > 1 && argc != 4) {
502 log_error("This program takes three or no arguments.");
503 return EXIT_FAILURE;
504 }
505
506 if (argc > 1)
507 arg_dest = argv[1];
508
509 log_set_target(LOG_TARGET_SAFE);
510 log_parse_environment();
511 log_open();
512
513 umask(0022);
514
515 r = parse_fstab();
516
517 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
518 }