chiark / gitweb /
import: print nice warning if we need btrfs but /var/lib/machines is not btrfs
[elogind.git] / src / gpt-auto-generator / gpt-auto-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 2013 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 <unistd.h>
23 #include <stdlib.h>
24 #include <sys/statfs.h>
25 #include <blkid/blkid.h>
26
27 #include "sd-id128.h"
28 #include "libudev.h"
29 #include "path-util.h"
30 #include "util.h"
31 #include "mkdir.h"
32 #include "missing.h"
33 #include "udev-util.h"
34 #include "special.h"
35 #include "unit-name.h"
36 #include "virt.h"
37 #include "generator.h"
38 #include "gpt.h"
39 #include "fileio.h"
40 #include "efivars.h"
41 #include "blkid-util.h"
42 #include "btrfs-util.h"
43
44 static const char *arg_dest = "/tmp";
45 static bool arg_enabled = true;
46 static bool arg_root_enabled = true;
47 static bool arg_root_rw = false;
48
49 static int add_swap(const char *path) {
50         _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
51         _cleanup_fclose_ FILE *f = NULL;
52
53         assert(path);
54
55         log_debug("Adding swap: %s", path);
56
57         name = unit_name_from_path(path, ".swap");
58         if (!name)
59                 return log_oom();
60
61         unit = strjoin(arg_dest, "/", name, NULL);
62         if (!unit)
63                 return log_oom();
64
65         f = fopen(unit, "wxe");
66         if (!f)
67                 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
68
69         fprintf(f,
70                 "# Automatically generated by systemd-gpt-auto-generator\n\n"
71                 "[Unit]\n"
72                 "Description=Swap Partition\n"
73                 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
74                 "[Swap]\n"
75                 "What=%s\n",
76                 path);
77
78         fflush(f);
79         if (ferror(f))
80                 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
81
82         lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
83         if (!lnk)
84                 return log_oom();
85
86         mkdir_parents_label(lnk, 0755);
87         if (symlink(unit, lnk) < 0)
88                 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
89
90         return 0;
91 }
92
93 static int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
94         _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
95         _cleanup_fclose_ FILE *f = NULL;
96         char *from, *ret;
97         int r;
98
99         assert(id);
100         assert(what);
101         assert(device);
102
103         d = unit_name_from_path(what, ".device");
104         if (!d)
105                 return log_oom();
106
107         e = unit_name_escape(id);
108         if (!e)
109                 return log_oom();
110
111         n = unit_name_build("systemd-cryptsetup", e, ".service");
112         if (!n)
113                 return log_oom();
114
115         p = strjoin(arg_dest, "/", n, NULL);
116         if (!p)
117                 return log_oom();
118
119         f = fopen(p, "wxe");
120         if (!f)
121                 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
122
123         fprintf(f,
124                 "# Automatically generated by systemd-gpt-auto-generator\n\n"
125                 "[Unit]\n"
126                 "Description=Cryptography Setup for %%I\n"
127                 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
128                 "DefaultDependencies=no\n"
129                 "Conflicts=umount.target\n"
130                 "BindsTo=dev-mapper-%%i.device %s\n"
131                 "Before=umount.target cryptsetup.target\n"
132                 "After=%s\n"
133                 "IgnoreOnIsolate=true\n"
134                 "[Service]\n"
135                 "Type=oneshot\n"
136                 "RemainAfterExit=yes\n"
137                 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
138                 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
139                 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
140                 d, d,
141                 id, what, rw ? "" : "read-only",
142                 id);
143
144         fflush(f);
145         if (ferror(f))
146                 return log_error_errno(errno, "Failed to write file %s: %m", p);
147
148         from = strjoina("../", n);
149
150         to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
151         if (!to)
152                 return log_oom();
153
154         mkdir_parents_label(to, 0755);
155         if (symlink(from, to) < 0)
156                 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
157
158         free(to);
159         to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
160         if (!to)
161                 return log_oom();
162
163         mkdir_parents_label(to, 0755);
164         if (symlink(from, to) < 0)
165                 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
166
167         free(to);
168         to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
169         if (!to)
170                 return log_oom();
171
172         mkdir_parents_label(to, 0755);
173         if (symlink(from, to) < 0)
174                 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
175
176         free(p);
177         p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
178         if (!p)
179                 return log_oom();
180
181         mkdir_parents_label(p, 0755);
182         r = write_string_file(p,
183                         "# Automatically generated by systemd-gpt-auto-generator\n\n"
184                         "[Unit]\n"
185                         "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
186         if (r < 0)
187                 return log_error_errno(r, "Failed to write device drop-in: %m");
188
189         ret = strappend("/dev/mapper/", id);
190         if (!ret)
191                 return log_oom();
192
193         *device = ret;
194         return 0;
195 }
196
197 static int add_mount(
198                 const char *id,
199                 const char *what,
200                 const char *where,
201                 const char *fstype,
202                 bool rw,
203                 const char *description,
204                 const char *post) {
205
206         _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
207         _cleanup_fclose_ FILE *f = NULL;
208         int r;
209
210         assert(id);
211         assert(what);
212         assert(where);
213         assert(description);
214
215         log_debug("Adding %s: %s %s", where, what, strna(fstype));
216
217         if (streq_ptr(fstype, "crypto_LUKS")) {
218
219                 r = add_cryptsetup(id, what, rw, &crypto_what);
220                 if (r < 0)
221                         return r;
222
223                 what = crypto_what;
224                 fstype = NULL;
225         }
226
227         unit = unit_name_from_path(where, ".mount");
228         if (!unit)
229                 return log_oom();
230
231         p = strjoin(arg_dest, "/", unit, NULL);
232         if (!p)
233                 return log_oom();
234
235         f = fopen(p, "wxe");
236         if (!f)
237                 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
238
239         fprintf(f,
240                 "# Automatically generated by systemd-gpt-auto-generator\n\n"
241                 "[Unit]\n"
242                 "Description=%s\n"
243                 "Documentation=man:systemd-gpt-auto-generator(8)\n",
244                 description);
245
246         if (post)
247                 fprintf(f, "Before=%s\n", post);
248
249         r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
250         if (r < 0)
251                 return r;
252
253         fprintf(f,
254                 "\n"
255                 "[Mount]\n"
256                 "What=%s\n"
257                 "Where=%s\n",
258                 what, where);
259
260         if (fstype)
261                 fprintf(f, "Type=%s\n", fstype);
262
263         fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
264
265         fflush(f);
266         if (ferror(f))
267                 return log_error_errno(errno, "Failed to write unit file %s: %m", p);
268
269         if (post) {
270                 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
271                 if (!lnk)
272                         return log_oom();
273
274                 mkdir_parents_label(lnk, 0755);
275                 if (symlink(p, lnk) < 0)
276                         return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
277         }
278
279         return 0;
280 }
281
282 static int probe_and_add_mount(
283                 const char *id,
284                 const char *what,
285                 const char *where,
286                 bool rw,
287                 const char *description,
288                 const char *post) {
289
290         _cleanup_blkid_free_probe_ blkid_probe b = NULL;
291         const char *fstype;
292         int r;
293
294         assert(id);
295         assert(what);
296         assert(where);
297         assert(description);
298
299         if (path_is_mount_point(where, true) <= 0 &&
300             dir_is_empty(where) <= 0) {
301                 log_debug("%s already populated, ignoring.", where);
302                 return 0;
303         }
304
305         /* Let's check the partition type here, so that we know
306          * whether to do LUKS magic. */
307
308         errno = 0;
309         b = blkid_new_probe_from_filename(what);
310         if (!b) {
311                 if (errno == 0)
312                         return log_oom();
313                 log_error_errno(errno, "Failed to allocate prober: %m");
314                 return -errno;
315         }
316
317         blkid_probe_enable_superblocks(b, 1);
318         blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
319
320         errno = 0;
321         r = blkid_do_safeprobe(b);
322         if (r == -2 || r == 1) /* no result or uncertain */
323                 return 0;
324         else if (r != 0) {
325                 if (errno == 0)
326                         errno = EIO;
327                 log_error_errno(errno, "Failed to probe %s: %m", what);
328                 return -errno;
329         }
330
331         blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
332
333         return add_mount(
334                         id,
335                         what,
336                         where,
337                         fstype,
338                         rw,
339                         description,
340                         post);
341 }
342
343 static int enumerate_partitions(dev_t devnum) {
344
345         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
346         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
347         _cleanup_blkid_free_probe_ blkid_probe b = NULL;
348         _cleanup_udev_unref_ struct udev *udev = NULL;
349         _cleanup_free_ char *home = NULL, *srv = NULL;
350         struct udev_list_entry *first, *item;
351         struct udev_device *parent = NULL;
352         const char *node, *pttype, *devtype;
353         int home_nr = -1, srv_nr = -1;
354         bool home_rw = true, srv_rw = true;
355         blkid_partlist pl;
356         int r, k;
357         dev_t pn;
358
359         udev = udev_new();
360         if (!udev)
361                 return log_oom();
362
363         d = udev_device_new_from_devnum(udev, 'b', devnum);
364         if (!d)
365                 return log_oom();
366
367         parent = udev_device_get_parent(d);
368         if (!parent) {
369                 log_debug("Not a partitioned device, ignoring.");
370                 return 0;
371         }
372
373         /* Does it have a devtype? */
374         devtype = udev_device_get_devtype(parent);
375         if (!devtype) {
376                 log_debug("Parent doesn't have a device type, ignoring.");
377                 return 0;
378         }
379
380         /* Is this a disk or a partition? We only care for disks... */
381         if (!streq(devtype, "disk")) {
382                 log_debug("Parent isn't a raw disk, ignoring.");
383                 return 0;
384         }
385
386         /* Does it have a device node? */
387         node = udev_device_get_devnode(parent);
388         if (!node) {
389                 log_debug("Parent device does not have device node, ignoring.");
390                 return 0;
391         }
392
393         log_debug("Root device %s.", node);
394
395         pn = udev_device_get_devnum(parent);
396         if (major(pn) == 0)
397                 return 0;
398
399         errno = 0;
400         b = blkid_new_probe_from_filename(node);
401         if (!b) {
402                 if (errno == 0)
403                         return log_oom();
404
405                 log_error_errno(errno, "Failed allocate prober: %m");
406                 return -errno;
407         }
408
409         blkid_probe_enable_partitions(b, 1);
410         blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
411
412         errno = 0;
413         r = blkid_do_safeprobe(b);
414         if (r == -2 || r == 1) /* no result or uncertain */
415                 return 0;
416         else if (r != 0) {
417                 if (errno == 0)
418                         errno = EIO;
419                 log_error_errno(errno, "Failed to probe %s: %m", node);
420                 return -errno;
421         }
422
423         errno = 0;
424         r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
425         if (r != 0) {
426                 if (errno == 0)
427                         errno = EIO;
428                 log_error_errno(errno, "Failed to determine partition table type of %s: %m", node);
429                 return -errno;
430         }
431
432         /* We only do this all for GPT... */
433         if (!streq_ptr(pttype, "gpt")) {
434                 log_debug("Not a GPT partition table, ignoring.");
435                 return 0;
436         }
437
438         errno = 0;
439         pl = blkid_probe_get_partitions(b);
440         if (!pl) {
441                 if (errno == 0)
442                         return log_oom();
443
444                 log_error_errno(errno, "Failed to list partitions of %s: %m", node);
445                 return -errno;
446         }
447
448         e = udev_enumerate_new(udev);
449         if (!e)
450                 return log_oom();
451
452         r = udev_enumerate_add_match_parent(e, parent);
453         if (r < 0)
454                 return log_oom();
455
456         r = udev_enumerate_add_match_subsystem(e, "block");
457         if (r < 0)
458                 return log_oom();
459
460         r = udev_enumerate_scan_devices(e);
461         if (r < 0)
462                 return log_error_errno(r, "Failed to enumerate partitions on %s: %m", node);
463
464         first = udev_enumerate_get_list_entry(e);
465         udev_list_entry_foreach(item, first) {
466                 _cleanup_udev_device_unref_ struct udev_device *q;
467                 const char *stype, *subnode;
468                 sd_id128_t type_id;
469                 blkid_partition pp;
470                 dev_t qn;
471                 int nr;
472                 unsigned long long flags;
473
474                 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
475                 if (!q)
476                         continue;
477
478                 qn = udev_device_get_devnum(q);
479                 if (major(qn) == 0)
480                         continue;
481
482                 if (qn == devnum)
483                         continue;
484
485                 if (qn == pn)
486                         continue;
487
488                 subnode = udev_device_get_devnode(q);
489                 if (!subnode)
490                         continue;
491
492                 pp = blkid_partlist_devno_to_partition(pl, qn);
493                 if (!pp)
494                         continue;
495
496                 flags = blkid_partition_get_flags(pp);
497
498                 /* Ignore partitions that are not marked for automatic
499                  * mounting on discovery */
500                 if (flags & GPT_FLAG_NO_AUTO)
501                         continue;
502
503                 nr = blkid_partition_get_partno(pp);
504                 if (nr < 0)
505                         continue;
506
507                 stype = blkid_partition_get_type_string(pp);
508                 if (!stype)
509                         continue;
510
511                 if (sd_id128_from_string(stype, &type_id) < 0)
512                         continue;
513
514                 if (sd_id128_equal(type_id, GPT_SWAP)) {
515
516                         if (flags & GPT_FLAG_READ_ONLY) {
517                                 log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
518                                 continue;
519                         }
520
521                         k = add_swap(subnode);
522                         if (k < 0)
523                                 r = k;
524
525                 } else if (sd_id128_equal(type_id, GPT_HOME)) {
526
527                         /* We only care for the first /home partition */
528                         if (home && nr >= home_nr)
529                                 continue;
530
531                         home_nr = nr;
532                         home_rw = !(flags & GPT_FLAG_READ_ONLY),
533
534                         free(home);
535                         home = strdup(subnode);
536                         if (!home)
537                                 return log_oom();
538
539                 } else if (sd_id128_equal(type_id, GPT_SRV)) {
540
541                         /* We only care for the first /srv partition */
542                         if (srv && nr >= srv_nr)
543                                 continue;
544
545                         srv_nr = nr;
546                         srv_rw = !(flags & GPT_FLAG_READ_ONLY),
547
548                         free(srv);
549                         srv = strdup(node);
550                         if (!srv)
551                                 return log_oom();
552                 }
553         }
554
555         if (home) {
556                 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
557                 if (k < 0)
558                         r = k;
559         }
560
561         if (srv) {
562                 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
563                 if (k < 0)
564                         r = k;
565         }
566
567         return r;
568 }
569
570 static int get_block_device(const char *path, dev_t *dev) {
571         struct stat st;
572         struct statfs sfs;
573
574         assert(path);
575         assert(dev);
576
577         if (lstat(path, &st))
578                 return -errno;
579
580         if (major(st.st_dev) != 0) {
581                 *dev = st.st_dev;
582                 return 1;
583         }
584
585         if (statfs(path, &sfs) < 0)
586                 return -errno;
587
588         if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
589                 return btrfs_get_block_device(path, dev);
590
591         return 0;
592 }
593
594 static int parse_proc_cmdline_item(const char *key, const char *value) {
595         int r;
596
597         assert(key);
598
599         if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
600
601                 r = parse_boolean(value);
602                 if (r < 0)
603                         log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
604                 else
605                         arg_enabled = r;
606
607         } else if (streq(key, "root") && value) {
608
609                 /* Disable root disk logic if there's a root= value
610                  * specified (unless it happens to be "gpt-auto") */
611
612                 arg_root_enabled = streq(value, "gpt-auto");
613
614         } else if (streq(key, "rw") && !value)
615                 arg_root_rw = true;
616         else if (streq(key, "ro") && !value)
617                 arg_root_rw = false;
618
619         return 0;
620 }
621
622 static int add_root_mount(void) {
623
624 #ifdef ENABLE_EFI
625         int r;
626
627         if (!is_efi_boot()) {
628                 log_debug("Not a EFI boot, not creating root mount.");
629                 return 0;
630         }
631
632         r = efi_loader_get_device_part_uuid(NULL);
633         if (r == -ENOENT) {
634                 log_debug("EFI loader partition unknown, exiting.");
635                 return 0;
636         } else if (r < 0)
637                 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
638
639         /* OK, we have an ESP partition, this is fantastic, so let's
640          * wait for a root device to show up. A udev rule will create
641          * the link for us under the right name. */
642
643         return add_mount(
644                         "root",
645                         "/dev/gpt-auto-root",
646                         in_initrd() ? "/sysroot" : "/",
647                         NULL,
648                         arg_root_rw,
649                         "Root Partition",
650                         in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
651 #else
652         return 0;
653 #endif
654 }
655
656 static int add_mounts(void) {
657         dev_t devno;
658         int r;
659
660         r = get_block_device("/", &devno);
661         if (r < 0)
662                 return log_error_errno(r, "Failed to determine block device of root file system: %m");
663         else if (r == 0) {
664                 log_debug("Root file system not on a (single) block device.");
665                 return 0;
666         }
667
668         return enumerate_partitions(devno);
669 }
670
671 int main(int argc, char *argv[]) {
672         int r = 0;
673
674         if (argc > 1 && argc != 4) {
675                 log_error("This program takes three or no arguments.");
676                 return EXIT_FAILURE;
677         }
678
679         if (argc > 1)
680                 arg_dest = argv[3];
681
682         log_set_target(LOG_TARGET_SAFE);
683         log_parse_environment();
684         log_open();
685
686         umask(0022);
687
688         if (detect_container(NULL) > 0) {
689                 log_debug("In a container, exiting.");
690                 return EXIT_SUCCESS;
691         }
692
693         r = parse_proc_cmdline(parse_proc_cmdline_item);
694         if (r < 0)
695                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
696
697         if (!arg_enabled) {
698                 log_debug("Disabled, exiting.");
699                 return EXIT_SUCCESS;
700         }
701
702         if (arg_root_enabled)
703                 r = add_root_mount();
704
705         if (!in_initrd()) {
706                 int k;
707
708                 k = add_mounts();
709                 if (k < 0)
710                         r = k;
711         }
712
713         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
714 }