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