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