chiark / gitweb /
core: always create /dev/kdbus/ns (and make it private 0700) after setting up the...
[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 "path-util.h"
34 #include "util.h"
35 #include "mkdir.h"
36 #include "missing.h"
37 #include "sd-id128.h"
38 #include "libudev.h"
39 #include "udev-util.h"
40 #include "special.h"
41 #include "unit-name.h"
42 #include "virt.h"
43
44 /* TODO:
45  *
46  * - Properly handle cryptsetup partitions
47  * - Define new partition type for encrypted swap
48  * - Make /home automount rather than mount
49  *
50  */
51
52 #define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
53 #define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
54
55 static const char *arg_dest = "/tmp";
56
57 DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe);
58 #define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep)
59
60 static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) {
61         _cleanup_blkid_freep_probe_ blkid_probe b = NULL;
62         const char *v;
63         int r;
64
65         errno = 0;
66         b = blkid_new_probe_from_filename(node);
67         if (!b)
68                 return errno != 0 ? -errno : -ENOMEM;
69
70         blkid_probe_enable_superblocks(b, 1);
71         blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
72         blkid_probe_enable_partitions(b, 1);
73         blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
74
75         errno = 0;
76         r = blkid_do_safeprobe(b);
77         if (r == -2)
78                 return -ENODEV;
79         else if (r == 1)
80                 return -ENODEV;
81         else if (r != 0)
82                 return errno ? -errno : -EIO;
83
84         errno = 0;
85         r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
86         if (r != 0)
87                 /* return 0 if we're not on GPT */
88                 return errno ? -errno : 0;
89
90         if (strcmp(v, "gpt") != 0)
91                 return 0;
92
93         if (type) {
94                 errno = 0;
95                 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
96                 if (r != 0)
97                         return errno ? -errno : -EIO;
98
99                 r = sd_id128_from_string(v, type);
100                 if (r < 0)
101                         return r;
102         }
103
104         if (nr) {
105                 errno = 0;
106                 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
107                 if (r != 0)
108                         return errno ? -errno : -EIO;
109
110                 r = safe_atou(v, nr);
111                 if (r < 0)
112                         return r;
113         }
114
115
116         if (fstype) {
117                 errno = 0;
118                 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
119                 if (r != 0)
120                         *fstype = NULL;
121                 else {
122                         char *fst;
123
124                         fst = strdup(v);
125                         if (!fst)
126                                 return -ENOMEM;
127
128                         *fstype = fst;
129                 }
130         }
131
132         return 1;
133 }
134
135 static int add_swap(const char *path, const char *fstype) {
136         _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
137         _cleanup_fclose_ FILE *f = NULL;
138
139         log_debug("Adding swap: %s %s", path, fstype);
140
141         name = unit_name_from_path(path, ".swap");
142         if (!name)
143                 return log_oom();
144
145         unit = strjoin(arg_dest, "/", name, NULL);
146         if (!unit)
147                 return log_oom();
148
149         f = fopen(unit, "wxe");
150         if (!f) {
151                 log_error("Failed to create unit file %s: %m", unit);
152                 return -errno;
153         }
154
155         fprintf(f,
156                 "# Automatically generated by systemd-gpt-auto-generator\n\n"
157                 "[Unit]\n"
158                 "DefaultDependencies=no\n"
159                 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
160                 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n"
161                 "[Swap]\n"
162                 "What=%s\n",
163                 path);
164
165         fflush(f);
166         if (ferror(f)) {
167                 log_error("Failed to write unit file %s: %m", unit);
168                 return -errno;
169         }
170
171         lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
172         if (!lnk)
173                 return log_oom();
174
175         mkdir_parents_label(lnk, 0755);
176         if (symlink(unit, lnk) < 0) {
177                 log_error("Failed to create symlink %s: %m", lnk);
178                 return -errno;
179         }
180
181         return 0;
182 }
183
184 static int add_home(const char *path, const char *fstype) {
185         _cleanup_free_ char *unit = NULL, *lnk = NULL, *fsck = NULL;
186         _cleanup_fclose_ FILE *f = NULL;
187
188         if (dir_is_empty("/home") <= 0)
189                 return 0;
190
191         log_debug("Adding home: %s %s", path, fstype);
192
193         unit = strappend(arg_dest, "/home.mount");
194         if (!unit)
195                 return log_oom();
196
197         f = fopen(unit, "wxe");
198         if (!f) {
199                 log_error("Failed to create unit file %s: %m", unit);
200                 return -errno;
201         }
202
203         fsck = unit_name_from_path_instance("systemd-fsck", path, ".service");
204         if (!fsck)
205                 return log_oom();
206
207         fprintf(f,
208                 "# Automatically generated by systemd-gpt-auto-generator\n\n"
209                 "[Unit]\n"
210                 "DefaultDependencies=no\n"
211                 "Requires=%s\n"
212                 "After=" SPECIAL_LOCAL_FS_PRE_TARGET " %s\n"
213                 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
214                 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n"
215                 "[Mount]\n"
216                 "What=%s\n"
217                 "Where=/home\n"
218                 "Type=%s\n",
219                 fsck, fsck, path, fstype);
220
221         fflush(f);
222         if (ferror(f)) {
223                 log_error("Failed to write unit file %s: %m", unit);
224                 return -errno;
225         }
226
227         lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/home.mount", NULL);
228         if (!lnk)
229                 return log_oom();
230
231         mkdir_parents_label(lnk, 0755);
232         if (symlink(unit, lnk) < 0) {
233                 log_error("Failed to create symlink %s: %m", lnk);
234                 return -errno;
235         }
236
237         return 0;
238 }
239
240 static int enumerate_partitions(struct udev *udev, dev_t dev) {
241         struct udev_device *parent = NULL;
242         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
243         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
244         struct udev_list_entry *first, *item;
245         unsigned home_nr = (unsigned) -1;
246         _cleanup_free_ char *home = NULL, *home_fstype = NULL;
247         int r;
248
249         e = udev_enumerate_new(udev);
250         if (!e)
251                 return log_oom();
252
253         d = udev_device_new_from_devnum(udev, 'b', dev);
254         if (!d)
255                 return log_oom();
256
257         parent = udev_device_get_parent(d);
258         if (!parent)
259                 return log_oom();
260
261         r = udev_enumerate_add_match_parent(e, parent);
262         if (r < 0)
263                 return log_oom();
264
265         r = udev_enumerate_add_match_subsystem(e, "block");
266         if (r < 0)
267                 return log_oom();
268
269         r = udev_enumerate_scan_devices(e);
270         if (r < 0) {
271                 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s",
272                           major(dev), minor(dev), strerror(-r));
273                 return r;
274         }
275
276         first = udev_enumerate_get_list_entry(e);
277         udev_list_entry_foreach(item, first) {
278                 _cleanup_free_ char *fstype = NULL;
279                 const char *node = NULL;
280                 _cleanup_udev_device_unref_ struct udev_device *q;
281                 sd_id128_t type_id;
282                 unsigned nr;
283
284                 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
285                 if (!q)
286                         return log_oom();
287
288                 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
289                         continue;
290
291                 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
292                         continue;
293
294                 node = udev_device_get_devnode(q);
295                 if (!node)
296                         return log_oom();
297
298                 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
299                 if (r < 0) {
300                         log_error("Failed to verify GPT partition %s: %s",
301                                   node, strerror(-r));
302                         return r;
303                 }
304                 if (r == 0)
305                         continue;
306
307                 if (sd_id128_equal(type_id, GPT_SWAP))
308                         add_swap(node, fstype);
309                 else if (sd_id128_equal(type_id, GPT_HOME)) {
310                         if (!home || nr < home_nr) {
311                                 free(home);
312                                 home = strdup(node);
313                                 if (!home)
314                                         return log_oom();
315
316                                 home_nr = nr;
317
318                                 free(home_fstype);
319                                 home_fstype = fstype;
320                                 fstype = NULL;
321                         }
322                 }
323         }
324
325         if (home && home_fstype)
326                 add_home(home, home_fstype);
327
328         return r;
329 }
330
331 static int get_btrfs_block_device(const char *path, dev_t *dev) {
332         struct btrfs_ioctl_fs_info_args fsi = {};
333         _cleanup_close_ int fd = -1;
334         uint64_t id;
335
336         assert(path);
337         assert(dev);
338
339         fd = open(path, O_DIRECTORY|O_CLOEXEC);
340         if (fd < 0)
341                 return -errno;
342
343         if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
344                 return -errno;
345
346         /* We won't do this for btrfs RAID */
347         if (fsi.num_devices != 1)
348                 return 0;
349
350         for (id = 1; id <= fsi.max_id; id++) {
351                 struct btrfs_ioctl_dev_info_args di = {
352                         .devid = id,
353                 };
354                 struct stat st;
355
356                 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
357                         if (errno == ENODEV)
358                                 continue;
359
360                         return -errno;
361                 }
362
363                 if (stat((char*) di.path, &st) < 0)
364                         return -errno;
365
366                 if (!S_ISBLK(st.st_mode))
367                         return -ENODEV;
368
369                 if (major(st.st_rdev) == 0)
370                         return -ENODEV;
371
372                 *dev = st.st_rdev;
373                 return 1;
374         }
375
376         return -ENODEV;
377 }
378
379 static int get_block_device(const char *path, dev_t *dev) {
380         struct stat st;
381         struct statfs sfs;
382
383         assert(path);
384         assert(dev);
385
386         if (lstat("/", &st))
387                 return -errno;
388
389         if (major(st.st_dev) != 0) {
390                 *dev = st.st_dev;
391                 return 1;
392         }
393
394         if (statfs("/", &sfs) < 0)
395                 return -errno;
396
397         if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
398                 return get_btrfs_block_device(path, dev);
399
400         return 0;
401 }
402
403 static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
404         _cleanup_udev_device_unref_ struct udev_device *d;
405         const char *t;
406         char *n;
407
408         d = udev_device_new_from_devnum(udev, 'b', devno);
409         if (!d)
410                 return log_oom();
411
412         t = udev_device_get_devnode(d);
413         if (!t)
414                 return -ENODEV;
415
416         n = strdup(t);
417         if (!n)
418                 return -ENOMEM;
419
420         *ret = n;
421         return 0;
422 }
423
424 int main(int argc, char *argv[]) {
425         _cleanup_free_ char *node = NULL;
426         _cleanup_udev_unref_ struct udev *udev = NULL;
427         dev_t devno;
428         int r = 0;
429
430         if (argc > 1 && argc != 4) {
431                 log_error("This program takes three or no arguments.");
432                 r = -EINVAL;
433                 goto finish;
434         }
435
436         if (argc > 1)
437                 arg_dest = argv[3];
438
439         log_set_target(LOG_TARGET_SAFE);
440         log_parse_environment();
441         log_open();
442
443         umask(0022);
444
445         if (in_initrd()) {
446                 log_debug("In initrd, exiting.");
447                 goto finish;
448         }
449
450         if (detect_container(NULL) > 0) {
451                 log_debug("In a container, exiting.");
452                 goto finish;
453         }
454
455         r = get_block_device("/", &devno);
456         if (r < 0) {
457                 log_error("Failed to determine block device of root file system: %s", strerror(-r));
458                 goto finish;
459         }
460         if (r == 0) {
461                 log_debug("Root file system not on a (single) block device.");
462                 goto finish;
463         }
464
465         udev = udev_new();
466         if (!udev) {
467                 r = log_oom();
468                 goto finish;
469         }
470
471         r = devno_to_devnode(udev, devno, &node);
472         if (r < 0) {
473                 log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
474                 goto finish;
475         }
476
477         log_debug("Root device %s.", node);
478
479         r = verify_gpt_partition(node, NULL, NULL, NULL);
480         if (r < 0) {
481                 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
482                 goto finish;
483         }
484         if (r == 0)
485                 goto finish;
486
487         r = enumerate_partitions(udev, devno);
488
489 finish:
490         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
491 }