diff --git a/usr.sbin/bsdinstall/partedit/partedit.c b/usr.sbin/bsdinstall/partedit/partedit.c --- a/usr.sbin/bsdinstall/partedit/partedit.c +++ b/usr.sbin/bsdinstall/partedit/partedit.c @@ -323,6 +323,22 @@ return (TRUE); } +static int +mountpoint_sorter(const void *xa, const void *xb) +{ + struct partition_metadata *a = *(struct partition_metadata **)xa; + struct partition_metadata *b = *(struct partition_metadata **)xb; + + if (a->fstab == NULL && b->fstab == NULL) + return 0; + if (a->fstab == NULL) + return 1; + if (b->fstab == NULL) + return -1; + + return strcmp(a->fstab->fs_file, b->fstab->fs_file); +} + static int apply_changes(struct gmesh *mesh) { @@ -386,6 +402,29 @@ free(__DECONST(char *, items[i*2])); free(items); + /* Sort filesystems for fstab so that mountpoints are ordered */ + { + struct partition_metadata **tobesorted; + struct partition_metadata *tmp; + int nparts = 0; + TAILQ_FOREACH(md, &part_metadata, metadata) + nparts++; + tobesorted = malloc(sizeof(struct partition_metadata *)*nparts); + nparts = 0; + TAILQ_FOREACH_SAFE(md, &part_metadata, metadata, tmp) { + tobesorted[nparts++] = md; + TAILQ_REMOVE(&part_metadata, md, metadata); + } + qsort(tobesorted, nparts, sizeof(tobesorted[0]), + mountpoint_sorter); + + /* Now re-add everything */ + while (nparts-- > 0) + TAILQ_INSERT_HEAD(&part_metadata, + tobesorted[nparts], metadata); + free(tobesorted); + } + if (getenv("PATH_FSTAB") != NULL) fstab_path = getenv("PATH_FSTAB"); else diff --git a/usr.sbin/bsdinstall/scripts/script b/usr.sbin/bsdinstall/scripts/script --- a/usr.sbin/bsdinstall/scripts/script +++ b/usr.sbin/bsdinstall/scripts/script @@ -116,14 +116,28 @@ # Unpack distributions bsdinstall checksum -for set in $DISTRIBUTIONS; do - f_dprintf "Extracting $BSDINSTALL_DISTDIR/$set" - # XXX: this will fail if any mountpoints are FAT, due to inability to - # set ctime/mtime on the root of FAT partitions. tar has no option to - # ignore this. We probably need to switch back to distextract here - # to properly support EFI. - tar -xf "$BSDINSTALL_DISTDIR/$set" -C $BSDINSTALL_CHROOT -done +if [ -t 0 ]; then + # If install is a tty, use distextract as normal + bsdinstall distextract +else + # Otherwise, we need to use tar (see https://reviews.freebsd.org/D10736) + for set in $DISTRIBUTIONS; do + f_dprintf "Extracting $BSDINSTALL_DISTDIR/$set" + # XXX: The below fails if any mountpoints are FAT, due to + # inability to set ctime/mtime on the root of FAT partitions, + # which is needed to support e.g. EFI system partitions. tar has + # no option to ignore this (distextract ignores them internally + # through a hack), and returns 1 on any warning or error, + # effectively turning all warnings into fatal errors. + # + # Work around this in an extremely lame way for the specific + # case of EFI system partitions only. This *ONLY WORKS* if + # /boot/efi is empty and does not handle analagous problems on + # other systems (ARM, PPC64). + tar -xf "$BSDINSTALL_DISTDIR/$set" -C $BSDINSTALL_CHROOT --exclude boot/efi + mkdir -p $BSDINSTALL_CHROOT/boot/efi + done +fi # Configure bootloader if needed bsdinstall bootconfig