Compare commits

..

59 Commits

Author SHA1 Message Date
b53d472be3 Modify Arch Install Scripts to work with Future Linux Install Scripts 2024-10-29 12:28:58 +08:00
Morten Linderud
a60ad80361
pacstrap: disable DownloadUser in pacman.conf
Fixes: https://gitlab.archlinux.org/archlinux/arch-install-scripts/-/issues/68

Signed-off-by: Morten Linderud <morten@linderud.pw>
2024-10-20 20:40:09 +02:00
Morten Linderud
cafd968c2a
ci: add m4
Signed-off-by: Morten Linderud <morten@linderud.pw>
2024-09-24 10:14:15 +02:00
Morten Linderud
66f37ab075
pacstrap: disable sandbox
Fixes: https://gitlab.archlinux.org/archlinux/arch-install-scripts/-/issues/68

Signed-off-by: Morten Linderud <morten@linderud.pw>
2024-09-24 10:12:41 +02:00
Morten Linderud
b4d12c1f1e
Revert "umount lazily to avoid race conditions"
This reverts commit 46a69d58e7.
2024-09-24 10:12:32 +02:00
Morten Linderud
ddb845d2fe
Revert "umount without sleep, as umount -l detaches inmediately"
This reverts commit c2065454b4.
2024-09-24 10:12:19 +02:00
Morten Linderud
2767ea5b5e
Merge remote-tracking branch 'origin/merge-requests/60'
* origin/merge-requests/60:
  umount without sleep, as umount -l detaches inmediately
  umount lazily to avoid race conditions
2024-04-07 20:04:36 +02:00
Morten Linderud
edb5576afd
Merge remote-tracking branch 'origin/merge-requests/61'
* origin/merge-requests/61:
  doc: remove footer
  tree-wide: add SPDX headers and shebang
  tree-wide: remove vim config
  editorconfig: we use 2 spaces for shell script indentation
  github: remove CI
2024-04-07 20:03:05 +02:00
Mike Yuan
8736a1b7d5
doc: remove footer
The information it provides is completely outdated
and pretty much irrelevant these days.
2024-04-07 00:30:43 +08:00
Mike Yuan
becff9f3e3
tree-wide: add SPDX headers and shebang 2024-04-07 00:30:43 +08:00
Mike Yuan
3561b8fe2a
tree-wide: remove vim config
Nowadays we've got a proper .editorconfig,
let's make it the only source of truth and
avoid the burden of keeping everything in sync.
2024-04-07 00:30:43 +08:00
Mike Yuan
f28810a3be
editorconfig: we use 2 spaces for shell script indentation 2024-04-07 00:30:43 +08:00
Mike Yuan
33a894f409
github: remove CI
The project has been migrated to Arch Linux GitLab.
2024-04-07 00:30:42 +08:00
Alberto Salvia Novella
c2065454b4 umount without sleep, as umount -l detaches inmediately 2024-02-16 18:14:23 +01:00
Alberto Salvia Novella
46a69d58e7 umount lazily to avoid race conditions 2024-01-18 02:15:09 +01:00
Morten Linderud
22493153c7
Merge remote-tracking branch 'origin/pull/57'
* origin/pull/57:
  arch-chroot: bind mount over a /etc/resolv.conf symlink
2023-09-09 15:14:59 +02:00
Morten Linderud
efad4f1881
Merge remote-tracking branch 'origin/pull/58'
* origin/pull/58:
  common: fix unshare chroot /dev symlinks
2023-09-09 15:09:02 +02:00
Сашка724ая
dbef490b03
common: fix unshare chroot /dev symlinks
Fixes invalid symlink paths for /dev/fd, /dev/stderr, /dev/stdin, /dev/stdout in arch-chroot when run in unshare mode.

Signed-off-by: Aleksandr Ksenofontov <github@sashok724.net>
2023-09-05 10:26:55 +10:00
nl6720
4d3aec66b8
arch-chroot: bind mount over a /etc/resolv.conf symlink
Use mount's a -c/--no-canonicalize option to ensure the bind mount to
/etc/resolv.conf in the chroot directory is mounted correctly.
This avoids issues when the chroot's /etc/resolv.conf is a symlink.

Bump required util-linux version to 2.39 which supports the new mount
API.

Fixes https://github.com/archlinux/arch-install-scripts/issues/55
Related to https://github.com/util-linux/util-linux/issues/2370
2023-08-11 14:42:18 +03:00
Morten Linderud
a5b772db02
genfstab: ensure swap devices adhere to -f
Signed-off-by: Morten Linderud <morten@linderud.pw>
2023-05-26 17:01:25 +02:00
Morten Linderud
8ef909063c
Merge remote-tracking branch 'origin/pull/51'
* origin/pull/51:
  pacstrap: silence "only applied to the deepest dir"
  arch-chroot: split variable declaration and assignment
  Add gitlab-ci based on the mkinitcpio one
  Add .editorconfig, from mkinitcpio
  tests: silence "referenced but not assigned" warnings
  tests: remove non-applicable ${1} handling
  common: split genfstab only helpers
  common: quote all arguments
  common: disable shellcheck SC2059
  common: remove unused msg2()
  common: remove unused is_array()
2023-05-05 22:10:12 +02:00
Emil Velikov
3abde514b4 pacstrap: silence "only applied to the deepest dir"
Shellcheck warns that only the deepest directory created will have the
requested permissions. That's fine - this is exactly what we want.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-03 13:46:34 +01:00
Emil Velikov
abef18a432 arch-chroot: split variable declaration and assignment
As suggested by shellcheck:

In arch-chroot line 164:
  local src=$(resolve_link /etc/resolv.conf)
        ^-^ SC2155 (warning): Declare and assign separately to avoid masking return values.

In arch-chroot line 165:
  local dest=$(resolve_link "$chrootdir/etc/resolv.conf" "$chrootdir")
        ^--^ SC2155 (warning): Declare and assign separately to avoid masking return values.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-03 13:46:34 +01:00
Emil Velikov
45a2073e33 Add gitlab-ci based on the mkinitcpio one
The in-tree config was seemingly never tested, since it fails loudly.
Copy/paste the mkinitcpio one and drop the non-applicable bat/coverage
sections.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-03 13:46:34 +01:00
Emil Velikov
d05e136ac2 Add .editorconfig, from mkinitcpio
Direct copy from mkinitcpio.

Note that the in-tree code-base consistently uses 2 space and redoing
that will be done at misc later point.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-03 13:46:34 +01:00
Emil Velikov
12733c86cb tests: silence "referenced but not assigned" warnings
The optstring* helpers do the assignment, which isn't particularly easy
for shellcheck to deduce. So silence the warnings.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-03 13:46:34 +01:00
Emil Velikov
3d05834dba tests: remove non-applicable ${1} handling
The arg was never set. Furthermore as-is shellcheck cannot realistically
evaluate the included source.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-03 13:46:34 +01:00
Emil Velikov
0c848b83b5 common: split genfstab only helpers
v2: drop warning and msg from fstab-helpers

v3: drop m4 -> sed conversion

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-03 13:46:15 +01:00
Emil Velikov
9f5888d4f2 common: quote all arguments
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-01 11:32:26 +01:00
Emil Velikov
b4490d003e common: disable shellcheck SC2059
As the inline comment says, the arguments are the actual modifiers.
Shout out to YHNdnzj for spotting this o/

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-01 11:32:26 +01:00
Emil Velikov
c239649760 common: remove unused msg2()
The function has been unused ever since it was introduced

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-01 11:32:26 +01:00
Emil Velikov
77e0895696 common: remove unused is_array()
The function hasn't been in use for a number of years.

Cc: Dave Reisner <dreisner@archlinux.org>
Fixes: b240f6e ("common: declare pseudofs types as hash")
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-05-01 11:32:26 +01:00
Morten Linderud
77c3cc7c1b
Merge remote-tracking branch 'origin/pull/50'
* origin/pull/50:
  arch-chroot: add option to preserve the chroot resolv.conf
2023-04-02 01:24:25 +02:00
Emil Velikov
aeaecf5ae5 arch-chroot: add option to preserve the chroot resolv.conf
There is a comprehensive inline comment about why we're touching the
chroot resolv.conf. Although it does not consider the cases where:
 - the link may be broken for specific reasons, and/or
 - working resolver within the chroot is not wanted

v2:
 - flip the condition check

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-29 21:28:31 +01:00
Morten Linderud
7e4e1c1bbf
Merge remote-tracking branch 'origin/pull/49'
* origin/pull/49:
  pacstrap: error out earlier, on invalid directory
  pacstrap: delay selecting chroot/unshare setup
  pacstrap: stop interleaving functions and sequential code
  pacstrap: move include_m4 after the globals
  genfstab: reshuffle while read loop
  arch-chroot: delay selecting chroot/unshare setup
  arch-chroot: stop interleaving functions and sequential code
  arch-chroot: move include_m4 after the globals
2023-03-29 20:44:23 +02:00
Morten Linderud
0feec4a50a
common: ensure /run is mounted with --make-private
udev doesn't work in the chroot which prevents some tools like lsblk to
retrieve the UUID of devices. This can be a bit problematic so instead
of having /run mounted as a tmpfs, do a bind-mound from the rootfs and
include `--make-private`.

This is similar to the previous implemention.

Fixes https://github.com/archlinux/arch-install-scripts/issues/24
Fixes https://github.com/archlinux/arch-install-scripts/pull/26
2023-03-26 20:03:51 +02:00
Emil Velikov
c72a394de7 pacstrap: error out earlier, on invalid directory
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 19:03:33 +01:00
Emil Velikov
8af3fa3b8e pacstrap: delay selecting chroot/unshare setup
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 19:03:33 +01:00
Emil Velikov
c911fbf92a pacstrap: stop interleaving functions and sequential code
Makes it easier to reason about the code.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 19:03:33 +01:00
Emil Velikov
6c68163d4b pacstrap: move include_m4 after the globals
After the m4 substitution, the globals end up mixed misc functions.
Just keep them at the top for legibility.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 19:03:33 +01:00
Emil Velikov
b07a1578d9 genfstab: reshuffle while read loop
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 19:03:33 +01:00
Emil Velikov
3a8e3de608 arch-chroot: delay selecting chroot/unshare setup
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 19:03:32 +01:00
Emil Velikov
a6765cc5c4 arch-chroot: stop interleaving functions and sequential code
Makes it easier to reason about the code.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 18:52:34 +01:00
Emil Velikov
7101c552a0 arch-chroot: move include_m4 after the globals
After the m4 substitution, the globals end up mixed misc functions.
Just keep them at the top for legibility.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 18:52:34 +01:00
Morten Linderud
f5acbb9058
Merge remote-tracking branch 'origin/pull/48'
* origin/pull/48:
  zsh: pacstrap bring it up-to date
  zsh: genfstab bring it up-to date
  zsh: arch-chroot bring it up-to date
  zsh: simplify arch-chroot and genfstab completion
  zsh: split completion into separate files
  make: move bash/zsh completions to separate directories
2023-03-26 19:41:43 +02:00
Morten Linderud
bc2a9a7cae
Merge remote-tracking branch 'origin/pull/47'
* origin/pull/47:
  make: add shellcheck target
  make: add more PHONY targets
  make: remove dummy uninstall target
2023-03-26 19:40:26 +02:00
Morten Linderud
c465332a17
Merge remote-tracking branch 'origin/pull/44'
* origin/pull/44:
  genfstab: remove atgc mount option
2023-03-26 19:40:09 +02:00
Morten Linderud
be937006c8
Merge remote-tracking branch 'origin/pull/45'
* origin/pull/45:
  ci: update differential-shellcheck
2023-03-26 19:39:46 +02:00
Emil Velikov
20a193d5b1 zsh: pacstrap bring it up-to date
Copy/pasta all the new options that have landed over the years.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 17:13:06 +01:00
Emil Velikov
a9768a0c45 zsh: genfstab bring it up-to date
Add the -f(ilter) and -t(ag) options. The latter being mutually
exclusive with -L/-U.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 17:13:06 +01:00
Emil Velikov
1ad274a58e zsh: arch-chroot bring it up-to date
Add -N (simple flag) -u (user/group), plus new directory and command
handling. The vast chunk of these are borrowed by the chroot completion,
as the inline comment indicates.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 17:13:06 +01:00
Emil Velikov
1f8a62bf0b zsh: simplify arch-chroot and genfstab completion
This will allow us to easily update and keep up-to date these two. The
final pacstrap one is fairly hairy and will be dealt with another time.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 17:13:06 +01:00
Emil Velikov
86088c21b1 zsh: split completion into separate files
The current file is borderline impossible to manage by zsh completion
noobies. Split it up for now, where follow-up commits will simplify
things.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 17:13:06 +01:00
Emil Velikov
6468bafc5e make: move bash/zsh completions to separate directories
Consequently, simplify the install target.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 17:13:06 +01:00
Emil Velikov
4b782e25ef make: add shellcheck target
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 17:08:19 +01:00
Emil Velikov
5520c61fb0 make: add more PHONY targets
The man and check targets were missing from the list

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 17:05:46 +01:00
Emil Velikov
06f697e3ae make: remove dummy uninstall target
The target does nothing, so we might as well remove it.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
2023-03-26 17:05:46 +01:00
Mike Yuan
f06deaaf26
ci: update differential-shellcheck
See also: https://github.com/redhat-plumbers-in-action/differential-shellcheck/issues/215
2023-03-26 18:19:37 +08:00
Mike Yuan
ad778b6f74
genfstab: remove atgc mount option
This is not changeable during remount,
so let's not include it automatically.
Users who want this feature should turn
to ArchWiki for help[1].

[1] https://wiki.archlinux.org/title/F2FS#Recommended_mount_options

See also: https://github.com/systemd/systemd/issues/26763
2023-03-12 06:42:45 +08:00
23 changed files with 791 additions and 848 deletions

26
.editorconfig Normal file
View File

@ -0,0 +1,26 @@
# EditorConfig
# https://editorconfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file, utf-8 charset, 2 space
# indentation, remove any whitespace characters preceding newline characters.
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space
indent_size = 2
# for shfmt
switch_case_indent = true
binary_next_line = true
[*.yml]
indent_style = space
indent_size = 4
# Tab indentation (no size specified)
[Makefile]
indent_style = tab

View File

@ -1,23 +0,0 @@
name: Differential ShellCheck
on:
pull_request:
branches:
- master
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Repository checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Differential ShellCheck
uses: redhat-plumbers-in-action/differential-shellcheck@latest
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,6 +1,27 @@
shellcheck:
stage: test
image: koalaman/shellcheck-alpine:latest
# SPDX-License-Identifier: GPL-2.0-only
stages:
- check
.pacman_install:
before_script:
# NOTE: Install latest archlinux-keyring before upgrading system. In the
# future this should not be needed anymore when we can guarantee a valid
# keyring for longer:
# https://gitlab.archlinux.org/archlinux/archlinux-keyring/-/issues/4
- echo -e "\e[0Ksection_start:`date +%s`:pacman[collapsed=true]\r\e[0KInstalling dependencies"
- pacman -Sy --needed --noconfirm archlinux-keyring
- pacman --noconfirm -Syu --needed asciidoc make shellcheck m4
- echo -e "\e[0Ksection_end:`date +%s`:pacman\r\e[0K"
check:
stage: check
extends: .pacman_install
script:
- shellcheck common
- shellcheck arch-chroot.in genfstab.in pacstrap.in
- make shellcheck
test:
stage: check
extends: .pacman_install
script:
- make check

View File

@ -1,18 +1,20 @@
VER=26
PREFIX = /usr/local
PREFIX = /usr
BINPROGS = \
arch-chroot \
future-chroot \
genfstab \
pacstrap
MANS = \
doc/arch-chroot.8 \
doc/future-chroot.8 \
doc/genfstab.8 \
doc/pacstrap.8
BASH = bash
ZSHCOMP := $(wildcard completion/zsh/*)
BASHCOMP := $(wildcard completion/bash/*)
all: $(BINPROGS) man
man: $(MANS)
@ -23,7 +25,13 @@ _v_GEN_0 = @echo " GEN " $@;
edit = $(V_GEN) m4 -P $@.in >$@ && chmod go-w,+x $@
%: %.in common
future-chroot: future-chroot.in common
$(edit)
genfstab: genfstab.in fstab-helpers
$(edit)
pacstrap: pacstrap.in common
$(edit)
doc/%: doc/%.asciidoc doc/asciidoc.conf
@ -36,15 +44,18 @@ check: all
@for f in $(BINPROGS); do bash -O extglob -n $$f; done
@r=0; for t in test/test_*; do $(BASH) $$t || { echo $$t fail; r=1; }; done; exit $$r
install: all
install -dm755 $(DESTDIR)$(PREFIX)/bin
install -m755 $(BINPROGS) $(DESTDIR)$(PREFIX)/bin
install -Dm644 completion/_archinstallscripts.zsh $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_archinstallscripts
cd completion; for comp in *.bash; do \
install -Dm644 $$comp $(DESTDIR)$(PREFIX)/share/bash-completion/completions/$${comp%%.*}; \
done;
for manfile in $(MANS); do \
install -Dm644 $$manfile -t $(DESTDIR)$(PREFIX)/share/man/man$${manfile##*.}; \
done;
shellcheck: $(BINPROGS)
shellcheck -W 99 --color $(BINPROGS)
shellcheck -W 99 --color -x test/test_*
.PHONY: all clean install uninstall
install: all
install -d $(DESTDIR)$(PREFIX)/sbin
install -m 0755 $(BINPROGS) $(DESTDIR)$(PREFIX)/sbin
install -d $(DESTDIR)$(PREFIX)/share/zsh/site-functions
install -m 0644 $(ZSHCOMP) $(DESTDIR)$(PREFIX)/share/zsh/site-functions
install -d $(DESTDIR)$(PREFIX)/share/bash-completion/completions
install -m 0644 $(BASHCOMP) $(DESTDIR)$(PREFIX)/share/bash-completion/completions
install -d $(DESTDIR)$(PREFIX)/share/man/man8
install -m 0644 $(MANS) $(DESTDIR)$(PREFIX)/share/man/man8
.PHONY: all man clean check shellcheck install

View File

@ -1,12 +1,14 @@
# Arch Install Scripts
# Modify Arch Install Scripts
# Future Install Scripts
This is a small suite of scripts aimed at automating some menial
tasks when installing [Arch Linux](https://www.archlinux.org).
tasks when installing [Future Linux](https://www.futurelinux.xyz).
## Requirements
* GNU coreutils (>= v8.15)
* util-linux (>= 2.23)
* util-linux (>= 2.39)
* POSIX awk
* bash (>= 4.1)
* asciidoc (for generating man pages)

View File

@ -1,87 +0,0 @@
#!/bin/bash
shopt -s extglob
# m4_include() is recognized as a function definition
# shellcheck source=common disable=SC1073,SC1065,SC1064,SC1072
m4_include(common)
setup=chroot_setup
unshare=0
userspec=''
chroot_args=()
usage() {
cat <<EOF
usage: ${0##*/} [options] chroot_dir [command [arguments...]]
Options:
-N Run in unshare mode as a regular user
-u <user>[:group] Specify non-root user and group (optional) to use
-h Print this help message
If 'command' is unspecified, arch-chroot will launch /bin/bash.
Note that when using arch-chroot, the target chroot directory *should* be a
mountpoint. This ensures that tools such as pacman(8) or findmnt(8) have an
accurate hierarchy of the mounted filesystems within the chroot.
If your chroot target is not a mountpoint, you can bind mount the directory on
itself to make it one, i.e. 'mount --bind chroot_dir chroot_dir'.
EOF
}
if [[ -z $1 || $1 = @(-h|--help) ]]; then
usage
exit $(( $# ? 0 : 1 ))
fi
while getopts ':Nu:' flag; do
case $flag in
N)
setup=unshare_setup
unshare=1
;;
u)
userspec="$OPTARG"
;;
:)
die "%s: option requires an argument -- '%s'" "${0##*/}" "$OPTARG"
;;
?)
die "%s: invalid option -- '%s'" "${0##*/}" "$OPTARG"
;;
esac
done
shift $(( OPTIND - 1 ))
(( $# )) || die 'No chroot directory specified'
chrootdir="$1"; shift
if ! mountpoint -q "$chrootdir"; then
warning '%s is not a mountpoint, and thus may cause undesirable side effects. (See help for more info)' "$chrootdir"
fi
command=("$@")
arch-chroot() {
check_root
[[ -d "$chrootdir" ]] || die '%s: not a directory' "$chrootdir"
$setup "$chrootdir"
chroot_add_resolv_conf "$chrootdir" || die 'Failed to setup resolv.conf in chroot'
[[ $userspec ]] && chroot_args+=(--userspec="$userspec")
SHELL=/bin/bash $pid_unshare chroot "${chroot_args[@]}" -- "$chrootdir" "${command[@]}"
}
if (( unshare )); then
$mount_unshare bash -c "$(declare_all); arch-chroot"
else
arch-chroot
fi
# vim: et ts=2 sw=2 ft=sh:

459
common
View File

@ -1,284 +1,103 @@
#!/hint/bash
# shellcheck disable=SC2155,SC2064
# SPDX-License-Identifier: GPL-2.0-only
# shellcheck disable=SC2059 # $1 and $2 can contain the printf modifiers
# generated from util-linux source: libmount/src/utils.c
declare -A pseudofs_types=([anon_inodefs]=1
[apparmorfs]=1
[autofs]=1
[bdev]=1
[binder]=1
[binfmt_misc]=1
[bpf]=1
[cgroup]=1
[cgroup2]=1
[configfs]=1
[cpuset]=1
[debugfs]=1
[devfs]=1
[devpts]=1
[devtmpfs]=1
[dlmfs]=1
[dmabuf]=1
[drm]=1
[efivarfs]=1
[fuse]=1
[fuse.archivemount]=1
[fuse.avfsd]=1
[fuse.dumpfs]=1
[fuse.encfs]=1
[fuse.gvfs-fuse-daemon]=1
[fuse.gvfsd-fuse]=1
[fuse.lxcfs]=1
[fuse.rofiles-fuse]=1
[fuse.vmware-vmblock]=1
[fuse.xwmfs]=1
[fusectl]=1
[hugetlbfs]=1
[ipathfs]=1
[mqueue]=1
[nfsd]=1
[none]=1
[nsfs]=1
[overlay]=1
[pipefs]=1
[proc]=1
[pstore]=1
[ramfs]=1
[resctrl]=1
[rootfs]=1
[rpc_pipefs]=1
[securityfs]=1
[selinuxfs]=1
[smackfs]=1
[sockfs]=1
[spufs]=1
[sysfs]=1
[tmpfs]=1
[tracefs]=1
[vboxsf]=1
[virtiofs]=1)
# generated from: pkgfile -vbr '/fsck\..+' | awk -F. '{ print $NF }' | sort
declare -A fsck_types=([btrfs]=0 # btrfs doesn't need a regular fsck utility
[cramfs]=1
[erofs]=1
[exfat]=1
[ext2]=1
[ext3]=1
[ext4]=1
[f2fs]=1
[fat]=1
[jfs]=1
[minix]=1
[msdos]=1
[reiserfs]=1
[vfat]=1
[xfs]=1)
# shellcheck disable=SC2059
out() { printf "$1 $2\n" "${@:3}"; }
msg() { out "==>" "$@"; }
msg2() { out " ->" "$@"; }
warning() { out "==> WARNING:" "$@"; } >&2
error() { out "==> ERROR:" "$@"; } >&2
warning() { out "==> WARNING:" "$@"; } >&2
msg() { out "==>" "$@"; }
die() { error "$@"; exit 1; }
ignore_error() {
"$@" 2>/dev/null || return 0
}
in_array() {
local i
local -n _arr="$1"
for i in "${_arr[@]}"; do
[[ "$i" = "$1" ]] && return 0
done
return 1
}
rev_array() {
local -n _arr="$1"
mapfile -t _arr < <(printf '%s\n' "${_arr[@]}" | tac)
}
check_root() {
(( EUID == 0 )) || die 'This script must be run with root privileges'
}
resolve_link() {
local link="$1" root="$2" target
if [[ ! $root ]]; then
target="$(realpath -eq "$link")"
else
# This is tricky to do. We read from $link in a loop
# and prepend it with $root if it's not under it.
# This can't handle e.g. $root is /mnt and $link
# is /mnt/1 pointing to /mnt/2, which should actually
# be /mnt/mnt/2. Luckily these edge cases shouldn't
# bother most of the time.
root="$(realpath -e "$root")"
target="$link"
while [[ -L "$target" ]]; do
target="$(readlink -m "$target")"
if [[ "$target" != "$root"/* ]]; then
target="$root/${target#/}"
fi
done
# Normalize the path and make sure the resolved target exists
target="$(realpath -eq "$target")"
fi
printf '%s' "$target"
"$@" 2>/dev/null
return 0
}
chroot_add_mount() {
mount "$@" && CHROOT_ACTIVE_MOUNTS+=("$2")
mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}")
}
chroot_maybe_add_mount() {
local cond="$1"; shift
local cond=$1; shift
if eval "$cond"; then
chroot_add_mount "$@"
fi
}
chroot_setup() {
CHROOT_ACTIVE_MOUNTS=()
[[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap'
trap 'chroot_teardown' EXIT
chroot_add_mount --bind /dev "$1/dev" &&
chroot_add_mount devpts "$1/dev/pts" -t devpts -o gid=5,mode=0620 &&
chroot_add_mount proc $1/proc -t proc &&
chroot_add_mount sysfs $1/sys -t sysfs &&
chroot_add_mount tmpfs "$1/run" -t tmpfs &&
chroot_add_mount tmpfs "$1/dev/shm" -t tmpfs -o nosuid,nodev &&
ignore_error chroot_maybe_add_mount "[[ -d '$1/sys/firmware/efi/efivars' ]]" \
efivarfs "$1/sys/firmware/efi/efivars" -t efivarfs
}
chroot_teardown() {
if (( ${#CHROOT_ACTIVE_MOUNTS[@]} )); then
umount "${CHROOT_ACTIVE_MOUNTS[@]}"
fi
unset CHROOT_ACTIVE_MOUNTS
}
chroot_add_mount_lazy() {
mount "$@" && CHROOT_ACTIVE_LAZY+=("$2")
mount "$@" && CHROOT_ACTIVE_LAZY=("$2" "${CHROOT_ACTIVE_LAZY[@]}")
}
chroot_bind_device() {
touch "$2" && CHROOT_ACTIVE_FILES+=("$2")
touch "$2" && CHROOT_ACTIVE_FILES=("$2" "${CHROOT_ACTIVE_FILES[@]}")
chroot_add_mount "$1" "$2" --bind
}
chroot_add_link() {
ln -sf "$1" "$2" && CHROOT_ACTIVE_FILES+=("$2")
}
chroot_add_resolv_conf() {
local src="$(resolve_link /etc/resolv.conf)" dest="$1/etc/resolv.conf"
# If we don't have a source resolv.conf file, there's nothing useful we can do.
if [[ ! -f "$src" ]]; then
warning 'Cannot find a usable resolv.conf. DNS requests might fail in chroot'
return 0
fi
# If resolv.conf in the chroot is a symlink, we make a backup of it
# and create a plain file so we can bind mount to it.
# The backup is restore during chroot_teardown().
if [[ -L "$dest" ]]; then
mv "$dest" "$dest.orig"
fi
touch -a "$dest"
chroot_add_mount "$src" "$dest" --bind
}
chroot_setup() {
CHROOT_ACTIVE_MOUNTS=()
local root="$1"
local errtrap_old="$(trap -p ERR)" shellopts_old="$SHELLOPTS"
[[ $(trap -p EXIT) ]] && die 'An EXIT trap already exists (likely a bug)'
trap "chroot_teardown $root" EXIT
trap "$errtrap_old; die 'Failed to setup chroot %s' '$root'" ERR
set -e
chroot_add_mount proc "$root"/proc -t proc -o nosuid,noexec,nodev
chroot_add_mount sys "$root"/sys -t sysfs -o nosuid,noexec,nodev,ro
ignore_error chroot_maybe_add_mount "[[ -d '$root/sys/firmware/efi/efivars' ]]" \
efivarfs "$root"/sys/firmware/efi/efivars -t efivarfs -o nosuid,noexec,nodev
chroot_add_mount udev "$root"/dev -t devtmpfs -o mode=0755,nosuid
chroot_add_mount devpts "$root"/dev/pts -t devpts -o mode=0620,gid=5,nosuid,noexec
chroot_add_mount shm "$root"/dev/shm -t tmpfs -o mode=1777,nosuid,nodev
chroot_add_mount run "$root"/run -t tmpfs -o nosuid,nodev,mode=0755
chroot_add_mount tmp "$root"/tmp -t tmpfs -o mode=1777,strictatime,nodev,nosuid
[[ "$shellopts_old" = *'errexit'* ]] || set +e
if [[ $errtrap_old ]]; then
trap "$errtrap_old" ERR
else
trap - ERR
fi
}
chroot_teardown() {
local root="$1"
if (( ${#CHROOT_ACTIVE_MOUNTS[@]} )); then
rev_array CHROOT_ACTIVE_MOUNTS
umount "${CHROOT_ACTIVE_MOUNTS[@]}"
fi
unset CHROOT_ACTIVE_MOUNTS
if [[ -L "$root"/etc/resolv.conf.orig ]]; then
mv "$root"/etc/resolv.conf.orig "$root"/etc/resolv.conf
fi
ln -sf "$1" "$2" && CHROOT_ACTIVE_FILES=("$2" "${CHROOT_ACTIVE_FILES[@]}")
}
unshare_setup() {
CHROOT_ACTIVE_MOUNTS=() CHROOT_ACTIVE_LAZY=() CHROOT_ACTIVE_FILES=()
local root="$1"
local errtrap_old="$(trap -p ERR)" shellopts_old="$SHELLOPTS"
CHROOT_ACTIVE_MOUNTS=()
CHROOT_ACTIVE_LAZY=()
CHROOT_ACTIVE_FILES=()
[[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap'
trap 'unshare_teardown' EXIT
[[ $(trap -p EXIT) ]] && die 'An EXIT trap already exists (likely a bug)'
trap "unshare_teardown $root" EXIT
trap "$errtrap_old; die 'Failed to setup chroot %s' '$root'" ERR
set -e
chroot_add_mount_lazy "$root" "$root" --bind
chroot_add_mount proc "$root"/proc -t proc -o nosuid,noexec,nodev
chroot_add_mount_lazy /sys "$root"/sys --rbind
chroot_add_link "$root"/proc/self/fd "$root"/dev/fd
chroot_add_link "$root"/proc/self/fd/0 "$root"/dev/stdin
chroot_add_link "$root"/proc/self/fd/1 "$root"/dev/stdout
chroot_add_link "$root"/proc/self/fd/2 "$root"/dev/stderr
chroot_bind_device /dev/full "$root"/dev/full
chroot_bind_device /dev/null "$root"/dev/null
chroot_bind_device /dev/zero "$root"/dev/zero
chroot_bind_device /dev/random "$root"/dev/random
chroot_bind_device /dev/urandom "$root"/dev/urandom
chroot_bind_device /dev/tty "$root"/dev/tty
chroot_add_mount run "$root"/run -t tmpfs -o nosuid,nodev,mode=0755
chroot_add_mount tmp "$root"/tmp -t tmpfs -o mode=1777,strictatime,nodev,nosuid
[[ "$shellopts_old" = *'errexit'* ]] || set +e
if [[ $errtrap_old ]]; then
trap "$errtrap_old" ERR
else
trap - ERR
fi
chroot_add_mount_lazy "$1" "$1" --bind &&
chroot_add_mount proc "$1/proc" -t proc &&
chroot_add_mount sysfs "$1/sys" -t sysfs &&
chroot_add_link /proc/self/fd "$1/dev/fd" &&
chroot_add_link /proc/self/fd/0 "$1/dev/stdin" &&
chroot_add_link /proc/self/fd/1 "$1/dev/stdout" &&
chroot_add_link /proc/self/fd/2 "$1/dev/stderr" &&
chroot_bind_device /dev/full "$1/dev/full" &&
chroot_bind_device /dev/null "$1/dev/null" &&
chroot_bind_device /dev/random "$1/dev/random" &&
chroot_bind_device /dev/tty "$1/dev/tty" &&
chroot_bind_device /dev/urandom "$1/dev/urandom" &&
chroot_bind_device /dev/zero "$1/dev/zero" &&
chroot_add_mount tmpfs "$1/run" -t tmpfs
}
unshare_teardown() {
chroot_teardown "$1"
chroot_teardown
if (( ${#CHROOT_ACTIVE_LAZY[@]} )); then
rev_array CHROOT_ACTIVE_LAZY
umount --lazy "${CHROOT_ACTIVE_LAZY[@]}"
fi
unset CHROOT_ACTIVE_LAZY
if (( ${#CHROOT_ACTIVE_FILES[@]} )); then
rev_array CHROOT_ACTIVE_FILES
rm "${CHROOT_ACTIVE_FILES[@]}"
fi
unset CHROOT_ACTIVE_FILES
}
pid_unshare="unshare --fork --pid"
# shellcheck disable=SC2034
mount_unshare="$pid_unshare --mount --map-auto --map-root-user --setuid 0 --setgid 0"
# This outputs code for declaring all variables to stdout. For example, if
@ -297,173 +116,3 @@ declare_all() {
# Then declare functions
declare -pf
}
try_cast() (
_=$(( ${1#"$2"} ))
) 2>/dev/null
valid_number_of_base() {
local base="$1" len="${#2}" i
for (( i = 0; i < len; i++ )); do
try_cast "$base" "${2:i:1}" || return 1
done
return 0
}
mangle() {
local i chr out
local {a..f}='' {A..F}=''
for (( i = 0; i < ${#1}; i++ )); do
chr="${1:i:1}"
case $chr in
[[:space:]\\])
printf -v chr '%03o' "'$chr"
out+=\\
;;
esac
out+="$chr"
done
printf '%s' "$out"
}
unmangle() {
local i chr out len="$(( ${#1} - 4 ))"
local {a..f}='' {A..F}=''
for (( i = 0; i < len; i++ )); do
chr="${1:i:1}"
case $chr in
\\)
if valid_number_of_base 8 "${1:i+1:3}" ||
valid_number_of_base 16 "${1:i+1:3}"; then
printf -v chr '%b' "${1:i:4}"
(( i += 3 ))
fi
;;
esac
out+="$chr"
done
printf '%s' "$out${1:i}"
}
optstring_match_one_option() {
local options=() target="$2"
local -n _optstring_match="$1"
IFS=, read -ra options <<<"$_optstring_match"
if [[ "$target" != *'='* ]]; then
options=("${options[@]%%=*}")
fi
in_array options "$target"
}
optstring_get_options() {
local i options=()
local -n _ret="$1" _optstring_get="$2"
local -i got=0
IFS=, read -ra options <<<"$_optstring_get"
shift 2
for i in "${!options[@]}"; do
if optstring_match_one_option 'options[i]' "$1"; then
_ret+=(["${options[i]%%=*}"]="${options[i]//*=}")
got=1
fi
shift || break
done
(( got ))
}
optstring_from_array() {
local optstring
local -n _optarray="$1"
optstring="$(printf ',%s' "${_optarray[@]}")"
optstring="${optstring:1}" # Remove the leading comma
printf '%s' "$optstring"
}
optstring_normalize() {
local i options=()
local -n _optstring_norm="$1"
IFS=, read -ra options <<<"$_optstring_norm"
# remove empty fields
for i in "${!options[@]}"; do
[[ ${options[i]} ]] || unset 'options[i]'
done
# avoid empty strings, reset to "defaults"
if (( ! ${#options[@]} )); then
_optstring_norm="defaults"
else
_optstring_norm="$(optstring_from_array options)"
fi
}
optstring_remove_options() {
local i options=() target="$2"
local -n _optstring_remove="$1"
IFS=, read -ra options <<<"$_optstring_remove"
for i in "${!options[@]}"; do
optstring_match_one_option 'options[i]' "$target" && unset 'options[i]'
done
_optstring_remove="$(optstring_from_array options)"
}
optstring_append_one_option() {
local option="$2"
local -n _optstring_append="$1"
if ! optstring_match_one_option _optstring_append "$option"; then
_optstring_append+=",$option"
fi
optstring_normalize _optstring_append
}
optstring_prepend_one_option() {
local option="$2"
local -n _optstring_prepend="$1"
if ! optstring_match_one_option _optstring_prepend "$option"; then
_optstring_prepend="$option,$_optstring_prepend"
fi
optstring_normalize _optstring_prepend
}
dm_name_for_devnode() {
read -r dm_name <"/sys/class/block/${1#/dev/}/dm/name"
if [[ $dm_name ]]; then
printf '/dev/mapper/%s' "$dm_name"
else
# don't leave the caller hanging, just print the original name
# along with the failure.
error 'Failed to resolve device mapper name for: %s' "$1"
fi
}
fstype_is_pseudofs() {
(( pseudofs_types["$1"] )) || findmnt --pseudo "$1" &>/dev/null
}
fstype_has_fsck() {
(( fsck_types["$1"] == 0 )) && return 1
(( fsck_types["$1"] )) || command -v "fsck.$1" &>/dev/null
}
# vim: et ts=2 sw=2 ft=sh:

View File

@ -1,8 +1,8 @@
_arch_chroot() {
_future_chroot() {
compopt +o dirnames
local cur prev opts i
_init_completion -n : || return
opts="-N -u -h"
opts="-N -u -r -h"
for i in "${COMP_WORDS[@]:1:COMP_CWORD-1}"; do
if [[ -d ${i} ]]; then
@ -22,4 +22,4 @@ _arch_chroot() {
compopt -o dirnames
}
complete -F _arch_chroot arch-chroot
complete -F _future_chroot future-chroot

View File

@ -3,7 +3,7 @@ _genfstab() {
local cur prev words cword
_init_completion || return
local opts="-f -L -P -p -t -U -h"
local opts="-f -L -p -P -t -U -h"
case ${prev} in
-f)

View File

@ -0,0 +1,31 @@
#compdef future-chroot
# NOTE: nearly everything here is borrowed from the chroot completion
local -a args=(
'(-h --help)'{-h,--help}'[display help]'
'-N[Run in unshare mode as a regular user]'
'-u[The non-root user and optional group to use]: :->userspecs'
'-r[Do not change the resolv.conf within the chroot]'
'1:new root directory:_directories'
'*:::command:_normal'
)
local ret=1
_arguments $args && ret=0
# @todo user:group specs are probably used often enough to justify making a type
# function for this (see also `chown`, `cpio`, `rsync`, ...)
[[ $state == userspecs ]] &&
if compset -P '*:*:'; then
ret=1
elif compset -P '*:'; then
_groups && ret=0
elif compset -S ':*'; then
_users && ret=0
else
_users -qS : && ret=0
fi
return ret

13
completion/zsh/_genfstab Normal file
View File

@ -0,0 +1,13 @@
#compdef genfstab
local -a args=(
'(-h --help)'{-h,--help}'[display help]'
'-p[Avoid printing pseudofs mounts]'
'-f[Restrict output to mountpoints matching the prefix FILTER]'
'(-U -L)-t[Use TAG for source identifiers]:tag:(LABEL UUID PARTLABEL PARTUUID)'
'(-U -t)-L[Use labels for source identifiers]'
'(-L -t)-U[Use UUIDs for source identifiers]'
':*:_path_files -/'
)
_arguments $args

View File

@ -1,12 +1,20 @@
#compdef pacstrap genfstab arch-chroot
#compdef pacstrap
_pacstrap_args=(
'-h[display help]'
)
_pacstrap_args_nonh=(
'(-h --help)-c[Use the package cache on the host, rather than the target]'
'(--help -h)-i[Avoid auto-confirmation of package selections]'
'-C[Use an alternate config file for pacman]:config file:_files -/'
'-c[Use the package cache on the host, rather than the target]'
'-D[Skip pacman dependency checks]'
'-G[Avoid copying the host pacman keyring to the target]'
'-i[Prompt for package confirmation when needed (run interactively)]'
'-K[Initialize an empty pacman keyring in the target (implies -G)]'
'-M[Avoid copying the host mirrorlist to the target]'
'-N[Run in unshare mode as a regular user]'
'-P[Copy the host pacman config to the target]'
'-U[Use pacman -U to install packages]'
)
@ -51,17 +59,6 @@ _pacstrap_none(){
"$_longopts[@]" \
}
_genfstab_args=(
'-h[display help]'
)
_genfstab_args_nonh=(
'(--help -h)-p[Avoid printing pseudofs mounts]'
'(-U --help -h)-L[Use labels for source identifiers]'
'(-L --help -h)-U[Use UUIDs for source identifiers]'
)
_arch_chroot_args=( '-h[display help]' )
_longopts=( '--help[display help]' )
_pacstrap(){
@ -94,69 +91,10 @@ _pacstrap(){
fi
}
_genfstab(){
if [[ -z ${(M)words:#--help} && -z ${(M)words:#-*h} ]]; then
case $words[CURRENT] in
-p*|-L*|-U*)
_arguments -s : \
"$_genfstab_args_nonh[@]"
;;
-*)
_arguments -s : \
"$_genfstab_args[@]" \
"$_genfstab_args_nonh[@]" \
"$_longopts[@]"
;;
--*)
_arguments -s : \
"$_longopts[@]"
;;
*)
_arguments \
"$_genfstab_args[@]" \
"$_genfstab_args_nonh[@]" \
"$_longopts[@]" \
":*:_path_files -/"
;;
esac
else
return 1
fi
}
_arch_chroot(){
if [[ -z ${(M)words:#--help} && -z ${(M)words:#-*h} ]]; then
case $words[CURRENT] in
-*)
_arguments -s : \
"$_arch_chroot_args[@]" \
"$_longopts[@]" \
;;
--*)
_arguments -s : \
"$_longopts[@]"
;;
*)
_arguments \
':*:_path_files -/'
;;
esac
else
return 1
fi
}
_install_scripts(){
case "$service" in
pacstrap)
_pacstrap "$@"
;;
genfstab)
_genfstab "$@";;
arch-chroot)
_arch_chroot "$@";;
*)
_message "Error";;
_pacstrap "$@";;
esac
}

View File

@ -1,47 +0,0 @@
arch-chroot(8)
==============
Name
----
arch-chroot - enhanced chroot command
Synopsis
--------
arch-chroot [options] chroot_dir [command [arguments...]]
Description
-----------
arch-chroot wraps the linkman:chroot[1] command while ensuring that important
functionality is available, e.g. mounting '/dev', '/proc' and other API
filesystems, or exposing linkman:resolv.conf[5] to the chroot.
If 'command' is unspecified, arch-chroot will launch */bin/bash*.
[NOTE]
======
The target chroot directory *should* be a mountpoint. This ensures that tools
such as linkman:pacman[8] or linkman:findmnt[8] have an accurate hierarchy of
the mounted filesystems within the chroot. If your chroot target is not a
mountpoint, you can bind mount the directory on itself to make it a one, i.e.
'mount --bind chroot_dir chroot_dir'
======
Options
-------
*-N*::
Run in unshare mode. This will use linkman:unshare[1] to create a new
mount and user namespace, allowing regular users to create new system
installations.
*-u <user>[:group]*::
Specify non-root user and group (optional) to use.
*-h*::
Output syntax and command line options.
See Also
--------
linkman:chroot[1], linkman:proc[5], linkman:sysfs[5]

View File

@ -0,0 +1,53 @@
future-chroot(8)
==============
Name
----
future-chroot - enhanced chroot command
Synopsis
--------
future-chroot [options] chroot-dir [command] [arguments...]
Description
-----------
future-chroot wraps the linkman:chroot[1] command while ensuring that important
functionality is available, e.g. mounting '/dev/', '/proc' and other API
filesystems, or exposing linkman:resolv.conf[5] to the chroot.
If 'command' is unspecified, future-chroot will launch */bin/bash*.
[NOTE]
======
The target chroot-dir *should* be a mountpoint. This ensures that tools such as
linkman:pacman[8] or linkman:findmnt[8] have an accurate hierarchy of the
mounted filesystems within the chroot. If your chroot target is not a
mountpoint, you can bind mount the directory on itself to make it a mountpoint,
i.e.:
'mount --bind /your/chroot /your/chroot'
======
Options
-------
*-N*::
Run in unshare mode. This will use linkman:unshare[1] to create a new
mount and user namespace, allowing regular users to create new system
installations.
*-u <user>[:group]*::
Specify non-root user and optional group to use.
*-r*::
Do not change the resolv.conf within the chroot. This means that the resolver
might not work in the chroot, which could be the required state.
*-h*::
Output syntax and command line options.
See Also
--------
linkman:pacman[8]

View File

@ -26,12 +26,12 @@ Options
*-L*::
Use labels for source identifiers (shortcut for '-t LABEL').
*-P*::
Include pseudofs mounts.
*-p*::
Exclude pseudofs mounts (default behavior).
*-P*::
Include pseudofs mounts.
*-t* <tag>::
Use 'tag' for source identifiers (should be one of: 'LABEL', 'UUID',
'PARTLABEL', 'PARTUUID').
@ -45,4 +45,4 @@ Options
See Also
--------
linkman:fstab[5], linkman:file-hierarchy[7], linkman:filesystems[5]
linkman:pacman[8]

236
fstab-helpers Normal file
View File

@ -0,0 +1,236 @@
#!/hint/bash
# SPDX-License-Identifier: GPL-2.0-only
# generated from util-linux source: libmount/src/utils.c
declare -A pseudofs_types=([anon_inodefs]=1
[apparmorfs]=1
[autofs]=1
[bdev]=1
[binder]=1
[binfmt_misc]=1
[bpf]=1
[cgroup]=1
[cgroup2]=1
[configfs]=1
[cpuset]=1
[debugfs]=1
[devfs]=1
[devpts]=1
[devtmpfs]=1
[dlmfs]=1
[dmabuf]=1
[drm]=1
[efivarfs]=1
[fuse]=1
[fuse.archivemount]=1
[fuse.avfsd]=1
[fuse.dumpfs]=1
[fuse.encfs]=1
[fuse.gvfs-fuse-daemon]=1
[fuse.gvfsd-fuse]=1
[fuse.lxcfs]=1
[fuse.rofiles-fuse]=1
[fuse.vmware-vmblock]=1
[fuse.xwmfs]=1
[fusectl]=1
[hugetlbfs]=1
[ipathfs]=1
[mqueue]=1
[nfsd]=1
[none]=1
[nsfs]=1
[overlay]=1
[pipefs]=1
[proc]=1
[pstore]=1
[ramfs]=1
[resctrl]=1
[rootfs]=1
[rpc_pipefs]=1
[securityfs]=1
[selinuxfs]=1
[smackfs]=1
[sockfs]=1
[spufs]=1
[sysfs]=1
[tmpfs]=1
[tracefs]=1
[vboxsf]=1
[virtiofs]=1)
# generated from: pkgfile -vbr '/fsck\..+' | awk -F. '{ print $NF }' | sort
declare -A fsck_types=([btrfs]=0 # btrfs doesn't need a regular fsck utility
[cramfs]=1
[erofs]=1
[exfat]=1
[ext2]=1
[ext3]=1
[ext4]=1
[f2fs]=1
[fat]=1
[jfs]=1
[minix]=1
[msdos]=1
[reiserfs]=1
[vfat]=1
[xfs]=1)
# shellcheck disable=SC2059 # $1 and $2 can contain the printf modifiers
out() { printf "$1 $2\n" "${@:3}"; }
error() { out "==> ERROR:" "$@"; } >&2
die() { error "$@"; exit 1; }
try_cast() (
_=$(( $1#$2 ))
) 2>/dev/null
valid_number_of_base() {
local base=$1 len=${#2} i=
for (( i = 0; i < len; i++ )); do
try_cast "$base" "${2:i:1}" || return 1
done
return 0
}
mangle() {
local i= chr= out=
local {a..f}= {A..F}=
for (( i = 0; i < ${#1}; i++ )); do
chr=${1:i:1}
case $chr in
[[:space:]\\])
printf -v chr '%03o' "'$chr"
out+=\\
;;
esac
out+=$chr
done
printf '%s' "$out"
}
unmangle() {
local i= chr= out= len=$(( ${#1} - 4 ))
local {a..f}= {A..F}=
for (( i = 0; i < len; i++ )); do
chr=${1:i:1}
case $chr in
\\)
if valid_number_of_base 8 "${1:i+1:3}" ||
valid_number_of_base 16 "${1:i+1:3}"; then
printf -v chr '%b' "${1:i:4}"
(( i += 3 ))
fi
;;
esac
out+=$chr
done
printf '%s' "$out${1:i}"
}
optstring_match_option() {
local candidate pat patterns
IFS=, read -ra patterns <<<"$1"
for pat in "${patterns[@]}"; do
if [[ $pat = *=* ]]; then
# "key=val" will only ever match "key=val"
candidate=$2
else
# "key" will match "key", but also "key=anyval"
candidate=${2%%=*}
fi
[[ $pat = "$candidate" ]] && return 0
done
return 1
}
optstring_remove_option() {
local o options_ remove=$2 IFS=,
read -ra options_ <<<"${!1}"
for o in "${!options_[@]}"; do
optstring_match_option "$remove" "${options_[o]}" && unset 'options_[o]'
done
declare -g "$1=${options_[*]}"
}
optstring_normalize() {
local o options_ norm IFS=,
read -ra options_ <<<"${!1}"
# remove empty fields
for o in "${options_[@]}"; do
[[ $o ]] && norm+=("$o")
done
# avoid empty strings, reset to "defaults"
declare -g "$1=${norm[*]:-defaults}"
}
optstring_append_option() {
if ! optstring_has_option "$1" "$2"; then
declare -g "$1=${!1},$2"
fi
optstring_normalize "$1"
}
optstring_prepend_option() {
local options_=$1
if ! optstring_has_option "$1" "$2"; then
declare -g "$1=$2,${!1}"
fi
optstring_normalize "$1"
}
optstring_get_option() {
local _opts o
IFS=, read -ra _opts <<<"${!1}"
for o in "${_opts[@]}"; do
if optstring_match_option "$2" "$o"; then
declare -g "$o"
return 0
fi
done
return 1
}
optstring_has_option() {
local "${2%%=*}"
optstring_get_option "$1" "$2"
}
dm_name_for_devnode() {
read dm_name <"/sys/class/block/${1#/dev/}/dm/name"
if [[ $dm_name ]]; then
printf '/dev/mapper/%s' "$dm_name"
else
# don't leave the caller hanging, just print the original name
# along with the failure.
error 'Failed to resolve device mapper name for: %s' "$1"
fi
}
fstype_is_pseudofs() {
(( pseudofs_types["$1"] ))
}
fstype_has_fsck() {
(( fsck_types["$1"] ))
}

124
future-chroot.in Normal file
View File

@ -0,0 +1,124 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
shopt -s extglob
unshare=0
keepresolvconf=0
m4_include(common)
usage() {
cat <<EOF
usage: ${0##*/} chroot-dir [command] [arguments...]
-h Print this help message
-N Run in unshare mode as a regular user
-u <user>[:group] Specify non-root user and optional group to use
-r Do not change the resolv.conf within the chroot
If 'command' is unspecified, ${0##*/} will launch /bin/bash.
Note that when using future-chroot, the target chroot directory *should* be a
mountpoint. This ensures that tools such as pacman(8) or findmnt(8) have an
accurate hierarchy of the mounted filesystems within the chroot.
If your chroot target is not a mountpoint, you can bind mount the directory on
itself to make it a mountpoint, i.e. 'mount --bind /your/chroot /your/chroot'.
EOF
}
resolve_link() {
local target=$1
local root=$2
# If a root was given, make sure it ends in a slash.
[[ -n $root && $root != */ ]] && root=$root/
while [[ -L $target ]]; do
target=$(readlink -m "$target")
# If a root was given, make sure the target is under it.
# Make sure to strip any leading slash from target first.
[[ -n $root && $target != $root* ]] && target=$root${target#/}
done
printf %s "$target"
}
chroot_add_resolv_conf() {
local chrootdir=$1
local src
local dest="$chrootdir/etc/resolv.conf"
src=$(resolve_link /etc/resolv.conf)
# If we don't have a source resolv.conf file, there's nothing useful we can do.
[[ -e $src ]] || return 0
if [[ ! -e "$dest" && ! -h "$dest" ]]; then
# There may be no resolv.conf in the chroot. In this case, we'll just exit.
# The chroot environment must not be concerned with DNS resolution.
return 0
fi
chroot_add_mount "$src" "$dest" -c --bind
}
future-chroot() {
(( EUID == 0 )) || die 'This script must be run with root privileges'
[[ -d $chrootdir ]] || die "Can't create chroot on non-directory %s" "$chrootdir"
$setup "$chrootdir" || die "failed to setup chroot %s" "$chrootdir"
if (( ! keepresolvconf )); then
chroot_add_resolv_conf "$chrootdir" || die "failed to setup resolv.conf"
fi
if ! mountpoint -q "$chrootdir"; then
warning "$chrootdir is not a mountpoint. This may have undesirable side effects."
fi
chroot_args=()
[[ $userspec ]] && chroot_args+=(--userspec "$userspec")
SHELL=/bin/bash $pid_unshare chroot "${chroot_args[@]}" -- "$chrootdir" "${args[@]}"
}
while getopts ':hNu:r' flag; do
case $flag in
h)
usage
exit 0
;;
N)
unshare=1
;;
u)
userspec=$OPTARG
;;
r)
keepresolvconf=1
;;
:)
die '%s: option requires an argument -- '\''%s'\' "${0##*/}" "$OPTARG"
;;
?)
die '%s: invalid option -- '\''%s'\' "${0##*/}" "$OPTARG"
;;
esac
done
shift $(( OPTIND - 1 ))
(( $# )) || die 'No chroot directory specified'
chrootdir=$1
shift
args=("$@")
if (( unshare )); then
setup=unshare_setup
$mount_unshare bash -c "$(declare_all); future-chroot"
else
setup=chroot_setup
future-chroot
fi

View File

@ -1,60 +1,61 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
shopt -s extglob
# m4_include() is recognized as a function definition
# shellcheck source=common disable=SC1073,SC1065,SC1064,SC1072
m4_include(common)
bytag=src
pseudofs=0
m4_include(fstab-helpers)
write_source() {
local src spec comments=()
local src=$1 spec= label= uuid= comment=()
src="$(mangle "$1")"
local -A sources=([LABEL]="$(mangle "$(lsblk -rno LABEL "$1" 2>/dev/null)")"
[UUID]="$(lsblk -rno UUID "$1" 2>/dev/null)"
[PARTLABEL]="$(mangle "$(lsblk -rno PARTLABEL "$1" 2>/dev/null)")"
[PARTUUID]="$(lsblk -rno PARTUUID "$1" 2>/dev/null)"
)
label=$(lsblk -rno LABEL "$1" 2>/dev/null)
uuid=$(lsblk -rno UUID "$1" 2>/dev/null)
if [[ ${sources["$bytag"]} ]]; then
spec="$bytag"
comments+=("$src")
# bind mounts do not have a UUID!
case $bytag in
'')
[[ $uuid ]] && comment=("UUID=$uuid")
[[ $label ]] && comment+=("LABEL=$(mangle "$label")")
;;
LABEL)
spec=$label
[[ $uuid ]] && comment=("$src" "UUID=$uuid")
;;
UUID)
spec=$uuid
comment=("$src")
[[ $label ]] && comment+=("LABEL=$(mangle "$label")")
;;
*)
[[ $uuid ]] && comment=("$1" "UUID=$uuid")
[[ $label ]] && comment+=("LABEL=$(mangle "$label")")
[[ $bytag ]] && spec=$(lsblk -rno "$bytag" "$1" 2>/dev/null)
;;
esac
[[ $comment ]] && printf '# %s\n' "${comment[*]}"
if [[ $spec ]]; then
printf '%-20s' "$bytag=$(mangle "$spec")"
else
spec=src
fi
for tag in "${!sources[@]}"; do
if [[ ${sources["$tag"]} && "$tag" != "$spec" ]]; then
comments+=("$tag=${sources["$tag"]}")
fi
done
(( ${#comments[@]} )) && printf '# %s\n' "${comments[*]}"
if [[ "$spec" != "src" ]]; then
printf '%-20s' "$spec=${sources["$spec"]}"
else
printf '%-20s' "$src"
printf '%-20s' "$(mangle "$src")"
fi
}
optstring_apply_quirks() {
local fstype="$2"
local -n _optstring="$1"
local varname=$1 fstype=$2
# SELinux displays a 'seclabel' option in /proc/self/mountinfo. We can't know
# if the system we're generating the fstab for has any support for SELinux (as
# one might install Arch from a Fedora environment), so let's remove it.
optstring_remove_options _optstring seclabel
optstring_remove_option "$varname" seclabel
# Prune 'relatime' option for any pseudofs. This seems to be a rampant
# default which the kernel often exports even if the underlying filesystem
# doesn't support it. Example: https://bugs.archlinux.org/task/54554.
if fstype_is_pseudofs "$fstype"; then
optstring_remove_options _optstring relatime
if awk -v fstype="$fstype" '$1 == fstype { exit 1 }' /proc/filesystems; then
optstring_remove_option "$varname" relatime
fi
case $fstype in
@ -62,15 +63,25 @@ optstring_apply_quirks() {
# Having only one of subvol= and subvolid= is enough for mounting a btrfs subvolume
# And having subvolid= set prevents things like 'snapper rollback' to work, as it
# updates the subvolume in-place, leaving subvol= unchanged with a different subvolid.
if optstring_match_one_option _optstring subvol; then
optstring_remove_options _optstring subvolid
if optstring_has_option "$varname" subvol; then
optstring_remove_option "$varname" subvolid
fi
;;
f2fs)
# These are Kconfig options for f2fs. Kernels supporting the options will
# only provide the negative versions of these (e.g. noacl), and vice versa
# These are build-time or runtime-unchangeable options for f2fs.
# The former means that kernels supporting the options will only
# provide the negative versions of these (e.g. noacl), and vice versa
# for kernels without support.
optstring_remove_options _optstring noacl,acl,nouser_xattr,user_xattr
# The latter means that the options can only be specified/changed
# during the initial mount but not remount.
optstring_remove_option "$varname" noacl,acl,nouser_xattr,user_xattr,atgc
;;
vfat)
# Before Linux v3.8, "cp" is prepended to the value of the codepage.
if optstring_get_option "$varname" codepage && [[ $codepage = cp* ]]; then
optstring_remove_option "$varname" codepage
optstring_append_option "$varname" "codepage=${codepage#cp}"
fi
;;
esac
}
@ -85,13 +96,13 @@ usage: ${0##*/} [options] root
-p Exclude pseudofs mounts (default behavior)
-P Include pseudofs mounts
-t <tag> Use TAG for source identifiers (TAG should be one of: LABEL,
UUID, PARTLABEL, PARTUUID)
UUID, PARTLABEL, PARTUUID)
-U Use UUIDs for source identifiers (shortcut for -t UUID)
-h Print this help message
genfstab generates output suitable for addition to an fstab file based on
the devices mounted under the mountpoint specified by the given root.
genfstab generates output suitable for addition to an fstab file based on the
devices mounted under the mountpoint specified by the given root.
EOF
}
@ -103,12 +114,15 @@ fi
while getopts ':f:LPpt:U' flag; do
case $flag in
f)
prefixfilter="$OPTARG"
;;
L)
bytag=LABEL
;;
U)
bytag=UUID
;;
f)
prefixfilter=$OPTARG
;;
P)
pseudofs=1
;;
@ -116,46 +130,41 @@ while getopts ':f:LPpt:U' flag; do
pseudofs=0
;;
t)
bytag="${OPTARG^^}"
;;
U)
bytag=UUID
bytag=${OPTARG^^}
;;
:)
die "%s: option requires an argument -- '%s'" "${0##*/}" "$OPTARG"
die '%s: option requires an argument -- '\''%s'\' "${0##*/}" "$OPTARG"
;;
?)
die "%s: invalid option -- '%s'" "${0##*/}" "$OPTARG"
die '%s: invalid option -- '\''%s'\' "${0##*/}" "$OPTARG"
;;
esac
done
shift $(( OPTIND - 1 ))
(( $# )) || die 'No root directory specified'
root="$(realpath -mL "$1")"; shift
(( $# )) || die "No root directory specified"
root=$(realpath -mL "$1"); shift
if ! mountpoint -q "$root"; then
die '%s: not a mountpoint' "$root"
die "$root is not a mountpoint"
fi
# handle block devices
findmnt -Recvruno SOURCE,TARGET,FSTYPE,OPTIONS,FSROOT "$root" |
while read -r src target fstype opts fsroot; do
if (( ! pseudofs )) && fstype_is_pseudofs "$fstype"; then
while read -r src target fstype opts fsroot; do
if (( !pseudofs )) && fstype_is_pseudofs "$fstype"; then
continue
fi
[[ "$target" = "$prefixfilter"* ]] || continue
[[ $target = "$prefixfilter"* ]] || continue
# default 5th and 6th columns
dump=0 pass=2
src="$(unmangle "$src")"
target="$(unmangle "$target")"
target="${target#"$root/"}"
[[ "$target" != '/'* ]] && target="/$target"
src=$(unmangle "$src")
target=$(unmangle "$target")
target=${target#$root}
if (( ! foundroot )) && findmnt "$src" "$root" >/dev/null; then
if (( !foundroot )) && findmnt "$src" "$root" >/dev/null; then
# this is root. we can't possibly have more than one...
pass=1 foundroot=1
fi
@ -165,29 +174,19 @@ findmnt -Recvruno SOURCE,TARGET,FSTYPE,OPTIONS,FSROOT "$root" |
pass=0
fi
if [[ "$fsroot" != "/" && "$fstype" != "btrfs" ]]; then
if [[ $fsroot != / && $fstype != btrfs ]]; then
# it's a bind mount
mapfile -t bind_srcs < <(findmnt -uncevo TARGET "$src")
for bind_src in "${bind_srcs[@]}"; do
if [[ -d "$bind_src$fsroot" ]]; then
src="$bind_src$fsroot"
break
fi
done
src="${src#"$root/"}"
[[ "$src" != '/'* ]] && src="/$src"
if [[ "$src" = "$target" ]]; then
src=$(findmnt -funcevo TARGET "$src")$fsroot
src="/${src#$root/}"
if [[ $src -ef $target ]]; then
# hrmm, this is weird. we're probably looking at a file or directory
# that was bound into a chroot from the host machine. Ignore it,
# because this won't actually be a valid mount. Worst case, the user
# just re-adds it.
continue
fi
fstype=none
opts+=',bind'
opts+=,bind
pass=0
fi
@ -196,41 +195,44 @@ findmnt -Recvruno SOURCE,TARGET,FSTYPE,OPTIONS,FSROOT "$root" |
fuseblk)
# well-behaved FUSE filesystems will report themselves as fuse.$fstype.
# this is probably NTFS-3g, but let's just make sure.
if ! newtype="$(lsblk -no FSTYPE "$src")" || [[ -z $newtype ]]; then
if ! newtype=$(lsblk -no FSTYPE "$src") || [[ -z $newtype ]]; then
# avoid blanking out fstype, leading to an invalid fstab
error 'Failed to derive real filesystem type for FUSE device on %s' "$target"
else
fstype="$newtype"
fstype=$newtype
fi
;;
esac
optstring_apply_quirks opts "$fstype"
optstring_apply_quirks "opts" "$fstype"
# write one line
write_source "$src"
printf '\t%-10s' "$(mangle "$target")" "$fstype" "$opts"
printf '\t%-10s' "/$(mangle "${target#/}")" "$fstype" "$opts"
printf '\t%s %s' "$dump" "$pass"
printf '\n\n'
done
done < <(findmnt -Recvruno SOURCE,TARGET,FSTYPE,OPTIONS,FSROOT "$root")
# handle swaps devices
{
# ignore header
read -r
read
while read -r device type _ _ prio; do
options=defaults
if (( prio >= 0 )); then
options+=",pri=$prio"
options+=,pri=$prio
fi
# skip files marked deleted by the kernel
[[ "$device" = *'\040(deleted)' ]] && continue
[[ $device = *'\040(deleted)' ]] && continue
if [[ "$type" = "file" ]]; then
printf '%-20s' "${device#"${root%/}"}"
elif [[ "$device" = "/dev/dm-"+([0-9]) ]]; then
# skip devices not part of the prefix
[[ $device = "$prefixfilter"* ]] || continue
if [[ $type = file ]]; then
printf '%-20s' "${device#${root%/}}"
elif [[ $device = /dev/dm-+([0-9]) ]]; then
# device mapper doesn't allow characters we need to worry
# about being mangled, and it does the escaping of dashes
# for us in sysfs.
@ -239,8 +241,6 @@ done
write_source "$(unmangle "$device")"
fi
printf '\t%-10s\t%-10s\t%-10s\t0 0\n\n' none swap "$options"
printf '\t%-10s\t%-10s\t%-10s\t0 0\n\n' 'none' 'swap' "$options"
done
} </proc/swaps
# vim: et ts=2 sw=2 ft=sh:

View File

@ -1,4 +1,5 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
#
# Assumptions:
@ -10,20 +11,17 @@
shopt -s extglob
# m4_include() is recognized as a function definition
# shellcheck source=common disable=SC1073,SC1065,SC1064,SC1072
m4_include(common)
hostcache=0
copykeyring=1
initkeyring=0
copymirrorlist=1
copyconfig=0
pacman_config=/etc/pacman.conf
pacman_args=()
pacmode='-Sy'
setup=chroot_setup
pacmode=-Sy
unshare=0
copyconf=0
pacman_config=/etc/pacman.conf
m4_include(common)
usage() {
cat <<EOF
@ -39,16 +37,55 @@ usage: ${0##*/} [options] root [packages...]
-M Avoid copying the host's mirrorlist to the target
-N Run in unshare mode as a regular user
-P Copy the host's pacman config to the target
-U Use 'pacman -U' to install packages
-U Use pacman -U to install packages
-h Print this help message
pacstrap installs packages to the specified new root directory.
If no packages are given, pacstrap defaults to the 'base' metapackage.
pacstrap installs packages to the specified new root directory. If no packages
are given, pacstrap defaults to the "base" group.
EOF
}
pacstrap() {
(( EUID == 0 )) || die 'This script must be run with root privileges'
# create obligatory directories
msg 'Creating install root at %s' "$newroot"
# shellcheck disable=SC2174 # permissions are perfectly fine here
mkdir -m 0755 -p "$newroot"/var/{cache/pacman/pkg,lib/pacman,log} "$newroot"/{dev,run,etc/pacman.d}
# shellcheck disable=SC2174 # permissions are perfectly fine here
mkdir -m 1777 -p "$newroot"/tmp
# shellcheck disable=SC2174 # permissions are perfectly fine here
mkdir -m 0555 -p "$newroot"/{sys,proc}
# mount API filesystems
$setup "$newroot" || die "failed to setup chroot %s" "$newroot"
if [[ ! -d $newroot/etc/pacman.d/gnupg ]]; then
if (( initkeyring )); then
pacman-key --gpgdir "$newroot"/etc/pacman.d/gnupg --init
elif (( copykeyring )) && [[ -d /etc/pacman.d/gnupg ]]; then
# if there's a keyring on the host, copy it into the new root
cp -a --no-preserve=ownership /etc/pacman.d/gnupg "$newroot/etc/pacman.d/"
fi
fi
msg 'Installing packages to %s' "$newroot"
if ! $pid_unshare pacman -r "$newroot" "${pacman_args[@]}"; then
die 'Failed to install packages to new root'
fi
if (( copymirrorlist )); then
# install the host's mirrorlist onto the new root
cp -a /etc/pacman.d/mirrorlist "$newroot/etc/pacman.d/"
fi
if (( copyconf )); then
cp -a "$pacman_config" "$newroot/etc/pacman.conf"
fi
}
if [[ -z $1 || $1 = @(-h|--help) ]]; then
usage
exit $(( $# ? 0 : 1 ))
@ -57,20 +94,20 @@ fi
while getopts ':C:cDGiKMNPU' flag; do
case $flag in
C)
pacman_config="$OPTARG"
;;
c)
hostcache=1
pacman_config=$OPTARG
;;
D)
pacman_args+=(-dd)
;;
G)
copykeyring=0
c)
hostcache=1
;;
i)
interactive=1
;;
G)
copykeyring=0
;;
K)
initkeyring=1
;;
@ -78,96 +115,53 @@ while getopts ':C:cDGiKMNPU' flag; do
copymirrorlist=0
;;
N)
setup=unshare_setup
unshare=1
;;
P)
copyconfig=1
copyconf=1
;;
U)
pacmode='-U'
pacmode=-U
;;
:)
die "%s: option requires an argument -- '%s'" "${0##*/}" "$OPTARG"
die '%s: option requires an argument -- '\''%s'\' "${0##*/}" "$OPTARG"
;;
?)
die "%s: invalid option -- '%s'" "${0##*/}" "$OPTARG"
die '%s: invalid option -- '\''%s'\' "${0##*/}" "$OPTARG"
;;
esac
done
shift $(( OPTIND - 1 ))
(( $# )) || die 'No root directory specified'
newroot="$1"; shift
[[ -d "$newroot" ]] || die '%s: not a directory' "$newroot"
(( $# )) || die "No root directory specified"
newroot=$1
shift
pacman_args+=("$pacmode" "${@:-base}" --config="$pacman_config")
[[ -d $newroot ]] || die "%s is not a directory" "$newroot"
tmpfile="$(mktemp -t pacman.conf.XXXX)"
cp "$pacman_config" "$tmpfile"
sed -i 's/^DownloadUser/#&/' "$tmpfile"
pacman_config="$tmpfile"
pacman_args+=("$pacmode" "${@:-base}" --config="$pacman_config" --disable-sandbox)
if (( ! hostcache )); then
pacman_args+=(--cachedir="$newroot/var/cache/pacman/pkg")
fi
if (( ! interactive )); then
pacman_args+=(--noconfirm)
fi
set -e
gpgdir="$(pacman-conf --config="$pacman_config" GPGDir)"
cachedir="$(pacman-conf --config="$pacman_config" CacheDir)"
if (( copyconfig )); then
dbpath="$newroot$(pacman-conf --config="$pacman_config" DBPath)"
logfile="$newroot$(pacman-conf --config="$pacman_config" LogFile)"
cachedir_target="$newroot$cachedir"
gpgdir_target="$newroot$gpgdir"
pacman_args+=(--dbpath="$dbpath" --logfile="$logfile")
else
dbpath="$newroot"/var/lib/pacman
logfile="$newroot"/var/log/pacman.log
cachedir_target="$newroot"/var/cache/pacman/pkg
gpgdir_target="$newroot"/etc/pacman.d/gnupg
fi
if (( ! hostcache )); then
cachedir="$cachedir_target"
fi
pacman_args+=(--cachedir="$cachedir")
set +e
pacstrap() {
check_root
# create obligatory directories
msg 'Creating install root at %s' "$newroot"
mkdir -m 0755 -p "$dbpath" "$cachedir_target" "$(dirname "$logfile")" "$newroot"/{dev,run,etc/pacman.d}
mkdir -m 1777 -p "$newroot"/tmp
mkdir -m 0555 -p "$newroot"/{sys,proc}
# mount API filesystems
$setup "$newroot"
if [[ ! -d "$gpgdir_target" ]]; then
if (( initkeyring )); then
pacman-key --gpgdir "$gpgdir_target" --init
elif (( copykeyring )) && [[ -d "$gpgdir" ]]; then
# if there's a keyring on the host, copy it into the new root
cp -aT --no-preserve=ownership "$gpgdir" "$gpgdir_target"
fi
fi
msg 'Installing packages to %s' "$newroot"
$pid_unshare pacman --root "$newroot" "${pacman_args[@]}" || die 'Failed to install packages to new root'
if (( copymirrorlist )); then
# install the host's mirrorlist onto the new root
cp -a /etc/pacman.d/mirrorlist "$newroot"/etc/pacman.d/ || warning "Failed to copy the host's mirrorlist to new root"
fi
if (( copyconfig )); then
cp -a "$pacman_config" "$newroot"/etc/pacman.conf
fi
}
if (( unshare )); then
setup=unshare_setup
$mount_unshare bash -c "$(declare_all); pacstrap"
else
setup=chroot_setup
pacstrap
fi
# vim: et ts=2 sw=2 ft=sh:
# TODO: There is a trap check on exit. Need to rework the trap handling with
# hook-ins/callbacks to remove aux files
rm "$tmpfile"

View File

@ -1,6 +1,6 @@
#!/bin/bash
. "${1:-./common}"
. ./fstab-helpers
. ./test/common
ASSERT_streq ' deleted' "$(unmangle "$(mangle ' deleted')")"

View File

@ -1,6 +1,6 @@
#!/bin/bash
. "${1:-./common}"
. ./fstab-helpers
. ./test/common
optstring=rw,relatime,fd=29,pgrp=1,timeout=300,minproto=5,maxproto=5,direct
@ -26,8 +26,10 @@ EXPECT_success optstring_has_option optstring maxproto
EXPECT_failure optstring_get_option optstring proto
EXPECT_success optstring_get_option optstring maxproto
# shellcheck disable=SC2154 # set via the optstring helper above
ASSERT_streq "$maxproto" "5"
EXPECT_success optstring_get_option optstring timeout
# shellcheck disable=SC2154 # set via the optstring helper above
ASSERT_streq "$timeout" "300"
optstring_remove_option optstring pgrp

View File

@ -1,6 +1,6 @@
#!/bin/bash
. "${1:-./common}"
. ./fstab-helpers
. ./test/common
EXPECT_success valid_number_of_base 16 feedfacebeef