]> git.ipfire.org Git - ipfire-2.x.git/blob - src/installer/hw.c
installer: Create a flag that marks if EFI support is available
[ipfire-2.x.git] / src / installer / hw.c
1 /*#############################################################################
2 # #
3 # IPFire - An Open Source Firewall Distribution #
4 # Copyright (C) 2014 IPFire development team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #ifndef _GNU_SOURCE
22 #define _GNU_SOURCE
23 #endif
24
25 #include <assert.h>
26 #include <blkid/blkid.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <libudev.h>
30 #include <linux/loop.h>
31 #include <math.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/ioctl.h>
36 #include <sys/mount.h>
37 #include <sys/stat.h>
38 #include <sys/swap.h>
39 #include <sys/sysinfo.h>
40 #include <sys/utsname.h>
41 #include <unistd.h>
42
43 #include <linux/fs.h>
44
45 #include <libsmooth.h>
46
47 #include "hw.h"
48
49 const char* other_filesystems[] = {
50 "/dev",
51 "/proc",
52 "/sys",
53 NULL
54 };
55
56 static int system_chroot(const char* output, const char* path, const char* cmd) {
57 char chroot_cmd[STRING_SIZE];
58
59 snprintf(chroot_cmd, sizeof(chroot_cmd), "/usr/sbin/chroot %s %s", path, cmd);
60
61 return mysystem(output, chroot_cmd);
62 }
63
64 struct hw* hw_init() {
65 struct hw* hw = calloc(1, sizeof(*hw));
66 assert(hw);
67
68 // Initialize libudev
69 hw->udev = udev_new();
70 if (!hw->udev) {
71 fprintf(stderr, "Could not create udev instance\n");
72 exit(1);
73 }
74
75 // What architecture are we running on?
76 struct utsname uname_data;
77 int ret = uname(&uname_data);
78 if (ret == 0)
79 snprintf(hw->arch, sizeof(hw->arch), "%s", uname_data.machine);
80
81 // Detect if we are running in EFI mode
82 ret = access("/sys/firmware/efi", R_OK);
83 if (ret == 0)
84 hw->efi_supported = 1;
85
86 // Should we install in EFI mode?
87 hw->efi = 1;
88
89 return hw;
90 }
91
92 void hw_free(struct hw* hw) {
93 if (hw->udev)
94 udev_unref(hw->udev);
95
96 free(hw);
97 }
98
99 static int strstartswith(const char* a, const char* b) {
100 return (strncmp(a, b, strlen(b)) == 0);
101 }
102
103 static char loop_device[STRING_SIZE];
104
105 static int setup_loop_device(const char* source, const char* device) {
106 int file_fd = open(source, O_RDWR);
107 if (file_fd < 0)
108 goto ERROR;
109
110 int device_fd = -1;
111 if ((device_fd = open(device, O_RDWR)) < 0)
112 goto ERROR;
113
114 if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0)
115 goto ERROR;
116
117 close(file_fd);
118 close(device_fd);
119
120 return 0;
121
122 ERROR:
123 if (file_fd >= 0)
124 close(file_fd);
125
126 if (device_fd >= 0) {
127 ioctl(device_fd, LOOP_CLR_FD, 0);
128 close(device_fd);
129 }
130
131 return -1;
132 }
133
134 int hw_mount(const char* source, const char* target, const char* fs, int flags) {
135 const char* loop_device = "/dev/loop0";
136
137 // Create target if it does not exist
138 if (access(target, X_OK) != 0)
139 mkdir(target, S_IRWXU|S_IRWXG|S_IRWXO);
140
141 struct stat st;
142 stat(source, &st);
143
144 if (S_ISREG(st.st_mode)) {
145 int r = setup_loop_device(source, loop_device);
146 if (r == 0) {
147 source = loop_device;
148 } else {
149 return -1;
150 }
151 }
152
153 int r = mount(source, target, fs, flags, NULL);
154
155 if (r) {
156 fprintf(stderr, "Error mounting %s to %s (fs = %s, flags = %d): %s\n",
157 source, target, fs, flags, strerror(r));
158 }
159
160 return r;
161 }
162
163 int hw_umount(const char* target) {
164 int r = umount2(target, 0);
165
166 if (r && errno == EBUSY) {
167 // Give it a moment to settle
168 sleep(1);
169
170 r = umount2(target, MNT_FORCE);
171 }
172
173 return r;
174 }
175
176 static int hw_test_source_medium(const char* path) {
177 int ret = hw_mount(path, SOURCE_MOUNT_PATH, "iso9660", MS_RDONLY);
178
179 // If the source could not be mounted we
180 // cannot proceed.
181 if (ret != 0)
182 return ret;
183
184 // Check if the test file exists.
185 ret = access(SOURCE_TEST_FILE, R_OK);
186
187 // Umount the test device.
188 hw_umount(SOURCE_MOUNT_PATH);
189
190 return ret;
191 }
192
193 char* hw_find_source_medium(struct hw* hw) {
194 char* ret = NULL;
195
196 struct udev_enumerate* enumerate = udev_enumerate_new(hw->udev);
197
198 udev_enumerate_add_match_subsystem(enumerate, "block");
199 udev_enumerate_scan_devices(enumerate);
200
201 struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
202
203 struct udev_list_entry* dev_list_entry;
204 udev_list_entry_foreach(dev_list_entry, devices) {
205 const char* path = udev_list_entry_get_name(dev_list_entry);
206 struct udev_device* dev = udev_device_new_from_syspath(hw->udev, path);
207
208 const char* dev_path = udev_device_get_devnode(dev);
209
210 // Skip everything what we cannot work with
211 if (strstartswith(dev_path, "/dev/loop") || strstartswith(dev_path, "/dev/fd") ||
212 strstartswith(dev_path, "/dev/ram") || strstartswith(dev_path, "/dev/md"))
213 continue;
214
215 if (hw_test_source_medium(dev_path) == 0) {
216 ret = strdup(dev_path);
217 }
218
219 udev_device_unref(dev);
220
221 // If a suitable device was found the search will end.
222 if (ret)
223 break;
224 }
225
226 udev_enumerate_unref(enumerate);
227
228 return ret;
229 }
230
231 static struct hw_disk** hw_create_disks() {
232 struct hw_disk** ret = malloc(sizeof(*ret) * (HW_MAX_DISKS + 1));
233
234 return ret;
235 }
236
237 static unsigned long long hw_block_device_get_size(const char* dev) {
238 int fd = open(dev, O_RDONLY);
239 if (fd < 0)
240 return 0;
241
242 unsigned long long size = blkid_get_dev_size(fd);
243 close(fd);
244
245 return size;
246 }
247
248 struct hw_disk** hw_find_disks(struct hw* hw, const char* sourcedrive) {
249 struct hw_disk** ret = hw_create_disks();
250 struct hw_disk** disks = ret;
251
252 struct udev_enumerate* enumerate = udev_enumerate_new(hw->udev);
253
254 udev_enumerate_add_match_subsystem(enumerate, "block");
255 udev_enumerate_scan_devices(enumerate);
256
257 struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
258
259 struct udev_list_entry* dev_list_entry;
260 unsigned int i = HW_MAX_DISKS;
261 udev_list_entry_foreach(dev_list_entry, devices) {
262 const char* path = udev_list_entry_get_name(dev_list_entry);
263 struct udev_device* dev = udev_device_new_from_syspath(hw->udev, path);
264
265 const char* dev_path = udev_device_get_devnode(dev);
266
267 // Skip everything what we cannot work with
268 if (strstartswith(dev_path, "/dev/loop") || strstartswith(dev_path, "/dev/fd") ||
269 strstartswith(dev_path, "/dev/ram") || strstartswith(dev_path, "/dev/sr") ||
270 strstartswith(dev_path, "/dev/md")) {
271 udev_device_unref(dev);
272 continue;
273 }
274
275 // Skip sourcedrive if we need to
276 if (sourcedrive && (strcmp(dev_path, sourcedrive) == 0)) {
277 udev_device_unref(dev);
278 continue;
279 }
280
281 // DEVTYPE must be disk (otherwise we will see all sorts of partitions here)
282 const char* devtype = udev_device_get_property_value(dev, "DEVTYPE");
283 if (devtype && (strcmp(devtype, "disk") != 0)) {
284 udev_device_unref(dev);
285 continue;
286 }
287
288 // Skip devices with a size of zero
289 unsigned long long size = hw_block_device_get_size(dev_path);
290 if (size == 0) {
291 udev_device_unref(dev);
292 continue;
293 }
294
295 struct hw_disk* disk = malloc(sizeof(*disk));
296 if (disk == NULL)
297 return NULL;
298
299 disk->ref = 1;
300
301 strncpy(disk->path, dev_path, sizeof(disk->path));
302 const char* p = disk->path + 5;
303
304 disk->size = size;
305
306 // Vendor
307 const char* vendor = udev_device_get_property_value(dev, "ID_VENDOR");
308 if (!vendor)
309 vendor = udev_device_get_sysattr_value(dev, "vendor");
310 if (!vendor)
311 vendor = udev_device_get_sysattr_value(dev, "manufacturer");
312
313 if (vendor)
314 strncpy(disk->vendor, vendor, sizeof(disk->vendor));
315 else
316 *disk->vendor = '\0';
317
318 // Model
319 const char* model = udev_device_get_property_value(dev, "ID_MODEL");
320 if (!model)
321 model = udev_device_get_sysattr_value(dev, "model");
322 if (!model)
323 model = udev_device_get_sysattr_value(dev, "product");
324
325 if (model)
326 strncpy(disk->model, model, sizeof(disk->model));
327 else
328 *disk->model = '\0';
329
330 // Format description
331 char size_str[STRING_SIZE];
332 snprintf(size_str, sizeof(size_str), "%4.1fGB", (double)disk->size / pow(1024, 3));
333
334 if (*disk->vendor && *disk->model) {
335 snprintf(disk->description, sizeof(disk->description),
336 "%s - %s - %s - %s", size_str, p, disk->vendor, disk->model);
337
338 } else if (*disk->vendor || *disk->model) {
339 snprintf(disk->description, sizeof(disk->description),
340 "%s - %s - %s", size_str, p, (*disk->vendor) ? disk->vendor : disk->model);
341
342 } else {
343 snprintf(disk->description, sizeof(disk->description),
344 "%s - %s", size_str, p);
345 }
346
347 // Cut off the description string after 40 characters
348 disk->description[41] = '\0';
349
350 *disks++ = disk;
351
352 if (--i == 0)
353 break;
354
355 udev_device_unref(dev);
356 }
357
358 udev_enumerate_unref(enumerate);
359
360 *disks = NULL;
361
362 return ret;
363 }
364
365 void hw_free_disks(struct hw_disk** disks) {
366 struct hw_disk** disk = disks;
367
368 while (*disk != NULL) {
369 if (--(*disk)->ref == 0)
370 free(*disk);
371
372 disk++;
373 }
374
375 free(disks);
376 }
377
378 unsigned int hw_count_disks(const struct hw_disk** disks) {
379 unsigned int ret = 0;
380
381 while (*disks++)
382 ret++;
383
384 return ret;
385 }
386
387 struct hw_disk** hw_select_disks(struct hw_disk** disks, int* selection) {
388 struct hw_disk** ret = hw_create_disks();
389 struct hw_disk** selected_disks = ret;
390
391 unsigned int num_disks = hw_count_disks((const struct hw_disk**)disks);
392
393 for (unsigned int i = 0; i < num_disks; i++) {
394 if (!selection || selection[i]) {
395 struct hw_disk *selected_disk = disks[i];
396 selected_disk->ref++;
397
398 *selected_disks++ = selected_disk;
399 }
400 }
401
402 // Set sentinel
403 *selected_disks = NULL;
404
405 return ret;
406 }
407
408 struct hw_disk** hw_select_first_disk(const struct hw_disk** disks) {
409 struct hw_disk** ret = hw_create_disks();
410 struct hw_disk** selected_disks = ret;
411
412 unsigned int num_disks = hw_count_disks(disks);
413 assert(num_disks > 0);
414
415 for (unsigned int i = 0; i < num_disks; i++) {
416 struct hw_disk *disk = disks[i];
417 disk->ref++;
418
419 *selected_disks++ = disk;
420 break;
421 }
422
423 // Set sentinel
424 *selected_disks = NULL;
425
426 return ret;
427 }
428
429 static unsigned long long hw_swap_size(struct hw_destination* dest) {
430 unsigned long long memory = hw_memory();
431
432 unsigned long long swap_size = memory / 4;
433
434 // Min. swap size is 128MB
435 if (swap_size < MB2BYTES(128))
436 swap_size = MB2BYTES(128);
437
438 // Cap swap size to 1GB
439 else if (swap_size > MB2BYTES(1024))
440 swap_size = MB2BYTES(1024);
441
442 return swap_size;
443 }
444
445 static unsigned long long hw_boot_size(struct hw_destination* dest) {
446 return MB2BYTES(128);
447 }
448
449 static int hw_device_has_p_suffix(const struct hw_destination* dest) {
450 // All RAID devices have the p suffix.
451 if (dest->is_raid)
452 return 1;
453
454 // Devices with a number at the end have the p suffix, too.
455 // e.g. mmcblk0, cciss0
456 unsigned int last_char = strlen(dest->path) - 1;
457 if ((dest->path[last_char] >= '0') && (dest->path[last_char] <= '9'))
458 return 1;
459
460 return 0;
461 }
462
463 static int hw_calculate_partition_table(struct hw* hw, struct hw_destination* dest, int disable_swap) {
464 char path[DEV_SIZE];
465 int part_idx = 1;
466
467 snprintf(path, sizeof(path), "%s%s", dest->path,
468 hw_device_has_p_suffix(dest) ? "p" : "");
469 dest->part_boot_idx = 0;
470
471 // Determine the size of the target block device
472 if (dest->is_raid) {
473 dest->size = (dest->disk1->size >= dest->disk2->size) ?
474 dest->disk2->size : dest->disk1->size;
475
476 // The RAID will install some metadata at the end of the disk
477 // and we will save up some space for that.
478 dest->size -= MB2BYTES(2);
479 } else {
480 dest->size = dest->disk1->size;
481 }
482
483 // As we add some extra space before the beginning of the first
484 // partition, we need to substract that here.
485 dest->size -= MB2BYTES(1);
486
487 // Add some more space for partition tables, etc.
488 dest->size -= MB2BYTES(1);
489
490 // The disk has to have at least 2GB
491 if (dest->size <= MB2BYTES(2048))
492 return -1;
493
494 // Determine partition table
495 dest->part_table = HW_PART_TABLE_MSDOS;
496
497 // Disks over 2TB need to use GPT
498 if (dest->size >= MB2BYTES(2047 * 1024))
499 dest->part_table = HW_PART_TABLE_GPT;
500
501 // We also use GPT on raid disks by default
502 else if (dest->is_raid)
503 dest->part_table = HW_PART_TABLE_GPT;
504
505 // When using GPT, GRUB2 needs a little bit of space to put
506 // itself in.
507 if (dest->part_table == HW_PART_TABLE_GPT) {
508 snprintf(dest->part_bootldr, sizeof(dest->part_bootldr),
509 "%s%d", path, part_idx);
510
511 dest->size_bootldr = MB2BYTES(4);
512
513 dest->part_boot_idx = part_idx++;
514 } else {
515 *dest->part_bootldr = '\0';
516 dest->size_bootldr = 0;
517 }
518
519 dest->size_boot = hw_boot_size(dest);
520
521 // Create an EFI partition when running in EFI mode
522 if (hw->efi)
523 dest->size_boot_efi = MB2BYTES(32);
524 else
525 dest->size_boot_efi = 0;
526
527 // Determine the size of the data partition.
528 unsigned long long space_left = dest->size - \
529 (dest->size_bootldr + dest->size_boot + dest->size_boot_efi);
530
531 // If we have less than 2GB left, we disable swap
532 if (space_left <= MB2BYTES(2048))
533 disable_swap = 1;
534
535 // Should we use swap?
536 if (disable_swap)
537 dest->size_swap = 0;
538 else
539 dest->size_swap = hw_swap_size(dest);
540
541 // Subtract swap
542 space_left -= dest->size_swap;
543
544 // Root is getting what ever is left
545 dest->size_root = space_left;
546
547 // Set partition names
548 if (dest->size_boot > 0) {
549 if (dest->part_boot_idx == 0)
550 dest->part_boot_idx = part_idx;
551
552 snprintf(dest->part_boot, sizeof(dest->part_boot), "%s%d", path, part_idx++);
553 } else
554 *dest->part_boot = '\0';
555
556 if (dest->size_boot_efi > 0) {
557 dest->part_boot_efi_idx = part_idx;
558
559 snprintf(dest->part_boot_efi, sizeof(dest->part_boot_efi),
560 "%s%d", path, part_idx++);
561 } else
562 *dest->part_boot_efi = '\0';
563
564 if (dest->size_swap > 0)
565 snprintf(dest->part_swap, sizeof(dest->part_swap), "%s%d", path, part_idx++);
566 else
567 *dest->part_swap = '\0';
568
569 // There is always a root partition
570 if (dest->part_boot_idx == 0)
571 dest->part_boot_idx = part_idx;
572
573 snprintf(dest->part_root, sizeof(dest->part_root), "%s%d", path, part_idx++);
574
575 return 0;
576 }
577
578 struct hw_destination* hw_make_destination(struct hw* hw, int part_type, struct hw_disk** disks, int disable_swap) {
579 struct hw_destination* dest = malloc(sizeof(*dest));
580
581 if (part_type == HW_PART_TYPE_NORMAL) {
582 dest->disk1 = *disks;
583 dest->disk2 = NULL;
584
585 strncpy(dest->path, dest->disk1->path, sizeof(dest->path));
586
587 } else if (part_type == HW_PART_TYPE_RAID1) {
588 dest->disk1 = *disks++;
589 dest->disk2 = *disks;
590 dest->raid_level = 1;
591
592 snprintf(dest->path, sizeof(dest->path), "/dev/md0");
593 }
594
595 // Is this a RAID device?
596 dest->is_raid = (part_type > HW_PART_TYPE_NORMAL);
597
598 int r = hw_calculate_partition_table(hw, dest, disable_swap);
599 if (r)
600 return NULL;
601
602 // Set default filesystem
603 dest->filesystem = HW_FS_DEFAULT;
604
605 return dest;
606 }
607
608 unsigned long long hw_memory() {
609 struct sysinfo si;
610
611 int r = sysinfo(&si);
612 if (r < 0)
613 return 0;
614
615 return si.totalram;
616 }
617
618 static int hw_zero_out_device(const char* path, int bytes) {
619 char block[512];
620 memset(block, 0, sizeof(block));
621
622 int blocks = bytes / sizeof(block);
623
624 int fd = open(path, O_WRONLY);
625 if (fd < 0)
626 return -1;
627
628 unsigned int bytes_written = 0;
629 while (blocks-- > 0) {
630 bytes_written += write(fd, block, sizeof(block));
631 }
632
633 fsync(fd);
634 close(fd);
635
636 return bytes_written;
637 }
638
639 static int try_open(const char* path) {
640 FILE* f = fopen(path, "r");
641 if (f) {
642 fclose(f);
643 return 0;
644 }
645
646 return -1;
647 }
648
649 int hw_create_partitions(struct hw_destination* dest, const char* output) {
650 // Before we write a new partition table to the disk, we will erase
651 // the first couple of megabytes at the beginning of the device to
652 // get rid of all left other things like bootloaders and partition tables.
653 // This solves some problems when changing from MBR to GPT partitions or
654 // the other way around.
655 int r = hw_zero_out_device(dest->path, MB2BYTES(10));
656 if (r <= 0)
657 return r;
658
659 char* cmd = NULL;
660 asprintf(&cmd, "/usr/sbin/parted -s %s -a optimal", dest->path);
661
662 // Set partition type
663 if (dest->part_table == HW_PART_TABLE_MSDOS)
664 asprintf(&cmd, "%s mklabel msdos", cmd);
665 else if (dest->part_table == HW_PART_TABLE_GPT)
666 asprintf(&cmd, "%s mklabel gpt", cmd);
667
668 unsigned long long part_start = MB2BYTES(1);
669
670 if (*dest->part_bootldr) {
671 asprintf(&cmd, "%s mkpart %s ext2 %lluB %lluB", cmd,
672 (dest->part_table == HW_PART_TABLE_GPT) ? "BOOTLDR" : "primary",
673 part_start, part_start + dest->size_bootldr - 1);
674
675 part_start += dest->size_bootldr;
676 }
677
678 if (*dest->part_boot) {
679 asprintf(&cmd, "%s mkpart %s ext2 %lluB %lluB", cmd,
680 (dest->part_table == HW_PART_TABLE_GPT) ? "BOOT" : "primary",
681 part_start, part_start + dest->size_boot - 1);
682
683 part_start += dest->size_boot;
684 }
685
686 if (*dest->part_boot_efi) {
687 asprintf(&cmd, "%s mkpart %s fat32 %lluB %lluB", cmd,
688 (dest->part_table == HW_PART_TABLE_GPT) ? "ESP" : "primary",
689 part_start, part_start + dest->size_boot_efi - 1);
690
691 part_start += dest->size_boot_efi;
692 }
693
694 if (*dest->part_swap) {
695 asprintf(&cmd, "%s mkpart %s linux-swap %lluB %lluB", cmd,
696 (dest->part_table == HW_PART_TABLE_GPT) ? "SWAP" : "primary",
697 part_start, part_start + dest->size_swap - 1);
698
699 part_start += dest->size_swap;
700 }
701
702 if (*dest->part_root) {
703 asprintf(&cmd, "%s mkpart %s ext2 %lluB %lluB", cmd,
704 (dest->part_table == HW_PART_TABLE_GPT) ? "ROOT" : "primary",
705 part_start, part_start + dest->size_root - 1);
706
707 part_start += dest->size_root;
708 }
709
710 if (dest->part_boot_idx > 0)
711 asprintf(&cmd, "%s set %d boot on", cmd, dest->part_boot_idx);
712
713 if (dest->part_boot_efi_idx > 0)
714 asprintf(&cmd, "%s set %d esp on", cmd, dest->part_boot_efi_idx);
715
716 if (dest->part_table == HW_PART_TABLE_GPT) {
717 if (*dest->part_bootldr) {
718 asprintf(&cmd, "%s set %d bios_grub on", cmd, dest->part_boot_idx);
719 }
720 asprintf(&cmd, "%s disk_set pmbr_boot on", cmd);
721 }
722
723 r = mysystem(output, cmd);
724
725 // Wait until the system re-read the partition table
726 if (r == 0) {
727 unsigned int counter = 10;
728
729 while (counter-- > 0) {
730 sleep(1);
731
732 if (*dest->part_bootldr && (try_open(dest->part_bootldr) != 0))
733 continue;
734
735 if (*dest->part_boot && (try_open(dest->part_boot) != 0))
736 continue;
737
738 if (*dest->part_boot_efi && (try_open(dest->part_boot_efi) != 0))
739 continue;
740
741 if (*dest->part_swap && (try_open(dest->part_swap) != 0))
742 continue;
743
744 if (*dest->part_root && (try_open(dest->part_root) != 0))
745 continue;
746
747 // All partitions do exist, exiting the loop.
748 break;
749 }
750 }
751
752 if (cmd)
753 free(cmd);
754
755 return r;
756 }
757
758 static int hw_format_filesystem(const char* path, int fs, const char* output) {
759 char cmd[STRING_SIZE] = "\0";
760
761 // Swap
762 if (fs == HW_FS_SWAP) {
763 snprintf(cmd, sizeof(cmd), "/sbin/mkswap -v1 %s &>/dev/null", path);
764 // ReiserFS
765 } else if (fs == HW_FS_REISERFS) {
766 snprintf(cmd, sizeof(cmd), "/sbin/mkreiserfs -f %s ", path);
767
768 // EXT4
769 } else if (fs == HW_FS_EXT4) {
770 snprintf(cmd, sizeof(cmd), "/sbin/mke2fs -FF -T ext4 %s", path);
771
772 // EXT4 w/o journal
773 } else if (fs == HW_FS_EXT4_WO_JOURNAL) {
774 snprintf(cmd, sizeof(cmd), "/sbin/mke2fs -FF -T ext4 -O ^has_journal %s", path);
775
776 // XFS
777 } else if (fs == HW_FS_XFS) {
778 snprintf(cmd, sizeof(cmd), "/sbin/mkfs.xfs -f %s", path);
779
780 // FAT32
781 } else if (fs == HW_FS_FAT32) {
782 snprintf(cmd, sizeof(cmd), "/sbin/mkfs.vfat %s", path);
783 }
784
785 assert(*cmd);
786
787 int r = mysystem(output, cmd);
788
789 return r;
790 }
791
792 int hw_create_filesystems(struct hw_destination* dest, const char* output) {
793 int r;
794
795 // boot
796 if (*dest->part_boot) {
797 r = hw_format_filesystem(dest->part_boot, dest->filesystem, output);
798 if (r)
799 return r;
800 }
801
802 // ESP
803 if (*dest->part_boot_efi) {
804 r = hw_format_filesystem(dest->part_boot_efi, HW_FS_FAT32, output);
805 if (r)
806 return r;
807 }
808
809 // swap
810 if (*dest->part_swap) {
811 r = hw_format_filesystem(dest->part_swap, HW_FS_SWAP, output);
812 if (r)
813 return r;
814 }
815
816 // root
817 r = hw_format_filesystem(dest->part_root, dest->filesystem, output);
818 if (r)
819 return r;
820
821 return 0;
822 }
823
824 int hw_mount_filesystems(struct hw_destination* dest, const char* prefix) {
825 char target[STRING_SIZE];
826
827 assert(*prefix == '/');
828
829 const char* filesystem;
830 switch (dest->filesystem) {
831 case HW_FS_REISERFS:
832 filesystem = "reiserfs";
833 break;
834
835 case HW_FS_EXT4:
836 case HW_FS_EXT4_WO_JOURNAL:
837 filesystem = "ext4";
838 break;
839
840 case HW_FS_XFS:
841 filesystem = "xfs";
842 break;
843
844 case HW_FS_FAT32:
845 filesystem = "vfat";
846 break;
847
848 default:
849 assert(0);
850 }
851
852 // root
853 int r = hw_mount(dest->part_root, prefix, filesystem, 0);
854 if (r)
855 return r;
856
857 // boot
858 if (*dest->part_boot) {
859 snprintf(target, sizeof(target), "%s%s", prefix, HW_PATH_BOOT);
860 mkdir(target, S_IRWXU|S_IRWXG|S_IRWXO);
861
862 r = hw_mount(dest->part_boot, target, filesystem, 0);
863 if (r) {
864 hw_umount_filesystems(dest, prefix);
865
866 return r;
867 }
868 }
869
870 // ESP
871 if (*dest->part_boot_efi) {
872 snprintf(target, sizeof(target), "%s%s", prefix, HW_PATH_BOOT_EFI);
873 mkdir(target, S_IRWXU|S_IRWXG|S_IRWXO);
874
875 r = hw_mount(dest->part_boot_efi, target, "vfat", 0);
876 if (r) {
877 hw_umount_filesystems(dest, prefix);
878
879 return r;
880 }
881 }
882
883 // swap
884 if (*dest->part_swap) {
885 r = swapon(dest->part_swap, 0);
886 if (r) {
887 hw_umount_filesystems(dest, prefix);
888
889 return r;
890 }
891 }
892
893 // bind-mount misc filesystems
894 char** otherfs = other_filesystems;
895 while (*otherfs) {
896 snprintf(target, sizeof(target), "%s%s", prefix, *otherfs);
897
898 mkdir(target, S_IRWXU|S_IRWXG|S_IRWXO);
899 r = hw_mount(*otherfs, target, NULL, MS_BIND);
900 if (r) {
901 hw_umount_filesystems(dest, prefix);
902
903 return r;
904 }
905
906 otherfs++;
907 }
908
909 return 0;
910 }
911
912 int hw_umount_filesystems(struct hw_destination* dest, const char* prefix) {
913 int r;
914 char target[STRING_SIZE];
915
916 // Write all buffers to disk before umounting
917 hw_sync();
918
919 // ESP
920 if (*dest->part_boot_efi) {
921 snprintf(target, sizeof(target), "%s%s", prefix, HW_PATH_BOOT_EFI);
922 r = hw_umount(target);
923 if (r)
924 return -1;
925 }
926
927 // boot
928 if (*dest->part_boot) {
929 snprintf(target, sizeof(target), "%s%s", prefix, HW_PATH_BOOT);
930 r = hw_umount(target);
931 if (r)
932 return -1;
933 }
934
935 // swap
936 if (*dest->part_swap) {
937 swapoff(dest->part_swap);
938 }
939
940 // misc filesystems
941 char** otherfs = other_filesystems;
942 while (*otherfs) {
943 snprintf(target, sizeof(target), "%s%s", prefix, *otherfs++);
944 r = hw_umount(target);
945 if (r)
946 return -1;
947 }
948
949 // root
950 r = hw_umount(prefix);
951 if (r)
952 return -1;
953
954 return 0;
955 }
956
957 int hw_destroy_raid_superblocks(const struct hw_destination* dest, const char* output) {
958 char cmd[STRING_SIZE];
959
960 hw_stop_all_raid_arrays(output);
961 hw_stop_all_raid_arrays(output);
962
963 if (dest->disk1) {
964 snprintf(cmd, sizeof(cmd), "/sbin/mdadm --zero-superblock %s", dest->disk1->path);
965 mysystem(output, cmd);
966 }
967
968 if (dest->disk2) {
969 snprintf(cmd, sizeof(cmd), "/sbin/mdadm --zero-superblock %s", dest->disk2->path);
970 mysystem(output, cmd);
971 }
972
973 return 0;
974 }
975
976 int hw_setup_raid(struct hw_destination* dest, const char* output) {
977 char* cmd = NULL;
978 int r;
979
980 assert(dest->is_raid);
981
982 // Stop all RAID arrays that might be around (again).
983 // It seems that there is some sort of race-condition with udev re-enabling
984 // the raid arrays and therefore locking the disks.
985 r = hw_destroy_raid_superblocks(dest, output);
986
987 asprintf(&cmd, "echo \"y\" | /sbin/mdadm --create --verbose --metadata=%s --auto=mdp %s",
988 RAID_METADATA, dest->path);
989
990 switch (dest->raid_level) {
991 case 1:
992 asprintf(&cmd, "%s --level=1 --raid-devices=2", cmd);
993 break;
994
995 default:
996 assert(0);
997 }
998
999 if (dest->disk1) {
1000 asprintf(&cmd, "%s %s", cmd, dest->disk1->path);
1001
1002 // Clear all data at the beginning
1003 r = hw_zero_out_device(dest->disk1->path, MB2BYTES(10));
1004 if (r <= 0)
1005 return r;
1006 }
1007
1008 if (dest->disk2) {
1009 asprintf(&cmd, "%s %s", cmd, dest->disk2->path);
1010
1011 // Clear all data at the beginning
1012 r = hw_zero_out_device(dest->disk2->path, MB2BYTES(10));
1013 if (r <= 0)
1014 return r;
1015 }
1016
1017 r = mysystem(output, cmd);
1018 free(cmd);
1019
1020 // Wait a moment until the device has been properly brought up
1021 if (r == 0) {
1022 unsigned int counter = 10;
1023 while (counter-- > 0) {
1024 sleep(1);
1025
1026 // If the raid device has not yet been properly brought up,
1027 // opening it will fail with the message: Device or resource busy
1028 // Hence we will wait a bit until it becomes usable.
1029 if (try_open(dest->path) == 0)
1030 break;
1031 }
1032 }
1033
1034 return r;
1035 }
1036
1037 int hw_stop_all_raid_arrays(const char* output) {
1038 return mysystem(output, "/sbin/mdadm --stop --scan --verbose");
1039 }
1040
1041 int hw_install_bootloader(struct hw* hw, struct hw_destination* dest, const char* output) {
1042 char cmd[STRING_SIZE];
1043 int r;
1044
1045 char cmd_grub[STRING_SIZE];
1046 snprintf(cmd_grub, sizeof(cmd_grub), "/usr/sbin/grub-install --target=i386-pc"
1047 " --no-floppy --recheck");
1048
1049 if (dest->is_raid) {
1050 snprintf(cmd, sizeof(cmd), "%s %s", cmd_grub, dest->disk1->path);
1051 r = system_chroot(output, DESTINATION_MOUNT_PATH, cmd);
1052 if (r)
1053 return r;
1054
1055 snprintf(cmd, sizeof(cmd), "%s %s", cmd_grub, dest->disk2->path);
1056 r = system_chroot(output, DESTINATION_MOUNT_PATH, cmd);
1057 if (r)
1058 return r;
1059 } else {
1060 snprintf(cmd, sizeof(cmd), "%s %s", cmd_grub, dest->path);
1061 r = system_chroot(output, DESTINATION_MOUNT_PATH, cmd);
1062 if (r)
1063 return r;
1064 }
1065
1066 // Install GRUB in EFI mode
1067 if (hw->efi) {
1068 snprintf(cmd, sizeof(cmd), "/usr/sbin/grub-install"
1069 " --target=%s-efi --efi-directory=%s %s", hw->arch, HW_PATH_BOOT_EFI,
1070 (hw->efi_supported) ? "" : "--no-nvram");
1071
1072 r = system_chroot(output, DESTINATION_MOUNT_PATH, cmd);
1073 if (r)
1074 return r;
1075 }
1076
1077 // Generate configuration file
1078 snprintf(cmd, sizeof(cmd), "/usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg");
1079 r = system_chroot(output, DESTINATION_MOUNT_PATH, cmd);
1080 if (r)
1081 return r;
1082
1083 hw_sync();
1084
1085 return 0;
1086 }
1087
1088 static char* hw_get_uuid(const char* dev) {
1089 blkid_probe p = blkid_new_probe_from_filename(dev);
1090 const char* buffer = NULL;
1091 char* uuid = NULL;
1092
1093 if (!p)
1094 return NULL;
1095
1096 blkid_do_probe(p);
1097 blkid_probe_lookup_value(p, "UUID", &buffer, NULL);
1098
1099 if (buffer)
1100 uuid = strdup(buffer);
1101
1102 blkid_free_probe(p);
1103
1104 return uuid;
1105 }
1106
1107 #define FSTAB_FMT "UUID=%s %-8s %-4s %-10s %d %d\n"
1108
1109 int hw_write_fstab(struct hw_destination* dest) {
1110 FILE* f = fopen(DESTINATION_MOUNT_PATH "/etc/fstab", "w");
1111 if (!f)
1112 return -1;
1113
1114 char* uuid = NULL;
1115
1116 // boot
1117 if (*dest->part_boot) {
1118 uuid = hw_get_uuid(dest->part_boot);
1119
1120 if (uuid) {
1121 fprintf(f, FSTAB_FMT, uuid, "/boot", "auto", "defaults", 1, 2);
1122 free(uuid);
1123 }
1124 }
1125
1126 // ESP
1127 if (*dest->part_boot_efi) {
1128 uuid = hw_get_uuid(dest->part_boot_efi);
1129
1130 if (uuid) {
1131 fprintf(f, FSTAB_FMT, uuid, "/boot/efi", "auto", "defaults", 1, 2);
1132 free(uuid);
1133 }
1134 }
1135
1136
1137 // swap
1138 if (*dest->part_swap) {
1139 uuid = hw_get_uuid(dest->part_swap);
1140
1141 if (uuid) {
1142 fprintf(f, FSTAB_FMT, uuid, "swap", "swap", "defaults,pri=1", 0, 0);
1143 free(uuid);
1144 }
1145 }
1146
1147 // root
1148 uuid = hw_get_uuid(dest->part_root);
1149 if (uuid) {
1150 fprintf(f, FSTAB_FMT, uuid, "/", "auto", "defaults", 1, 1);
1151 free(uuid);
1152 }
1153
1154 fclose(f);
1155
1156 return 0;
1157 }
1158
1159 void hw_sync() {
1160 sync();
1161 sync();
1162 sync();
1163 }
1164
1165 int hw_start_networking(const char* output) {
1166 return mysystem(output, "/usr/bin/start-networking.sh");
1167 }
1168
1169 char* hw_find_backup_file(const char* output, const char* search_path) {
1170 char path[STRING_SIZE];
1171
1172 snprintf(path, sizeof(path), "%s/backup.ipf", search_path);
1173 int r = access(path, R_OK);
1174
1175 if (r == 0)
1176 return strdup(path);
1177
1178 return NULL;
1179 }
1180
1181 int hw_restore_backup(const char* output, const char* backup_path, const char* destination) {
1182 char command[STRING_SIZE];
1183
1184 snprintf(command, sizeof(command), "/bin/tar xzpf %s -C %s", backup_path, destination);
1185 int rc = mysystem(output, command);
1186
1187 if (rc)
1188 return -1;
1189
1190 return 0;
1191 }