Compare commits

...

43 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
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
19 changed files with 452 additions and 431 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,29 +0,0 @@
name: Differential ShellCheck
on:
push:
branches:
- master
pull_request:
branches:
- master
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- name: Repository checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Differential ShellCheck
uses: redhat-plumbers-in-action/differential-shellcheck@v4
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,14 +1,14 @@
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
@ -25,10 +25,16 @@ _v_GEN_0 = @echo " GEN " $@;
edit = $(V_GEN) m4 -P $@.in >$@ && chmod go-w,+x $@
%: %.in common
future-chroot: future-chroot.in common
$(edit)
doc/%: doc/%.asciidoc doc/asciidoc.conf doc/footer.asciidoc
genfstab: genfstab.in fstab-helpers
$(edit)
pacstrap: pacstrap.in common
$(edit)
doc/%: doc/%.asciidoc doc/asciidoc.conf
$(V_GEN) a2x --no-xmllint --asciidoc-opts="-f doc/asciidoc.conf" -d manpage -f manpage -D doc $<
clean:
@ -43,8 +49,8 @@ shellcheck: $(BINPROGS)
shellcheck -W 99 --color -x test/test_*
install: all
install -d $(DESTDIR)$(PREFIX)/bin
install -m 0755 $(BINPROGS) $(DESTDIR)$(PREFIX)/bin
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

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)

273
common
View File

@ -1,82 +1,11 @@
# 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)
#!/hint/bash
# SPDX-License-Identifier: GPL-2.0-only
# shellcheck disable=SC2059 # $1 and $2 can contain the printf modifiers
out() { printf "$1 $2\n" "${@:3}"; }
error() { out "==> ERROR:" "$@"; } >&2
warning() { out "==> WARNING:" "$@"; } >&2
msg() { out "==>" "$@"; }
msg2() { out " ->" "$@";}
die() { error "$@"; exit 1; }
ignore_error() {
@ -84,14 +13,6 @@ ignore_error() {
return 0
}
in_array() {
local i
for i in "${@:2}"; do
[[ $1 = "$i" ]] && return 0
done
return 1
}
chroot_add_mount() {
mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}")
}
@ -108,15 +29,15 @@ chroot_setup() {
[[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap'
trap 'chroot_teardown' EXIT
chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev &&
chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro &&
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 -o nosuid,noexec,nodev &&
chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid &&
chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec &&
chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev &&
chroot_add_mount /run "$1/run" --bind --make-private &&
chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid
efivarfs "$1/sys/firmware/efi/efivars" -t efivarfs
}
chroot_teardown() {
@ -132,7 +53,7 @@ chroot_add_mount_lazy() {
chroot_bind_device() {
touch "$2" && CHROOT_ACTIVE_FILES=("$2" "${CHROOT_ACTIVE_FILES[@]}")
chroot_add_mount $1 "$2" --bind
chroot_add_mount "$1" "$2" --bind
}
chroot_add_link() {
@ -147,20 +68,19 @@ unshare_setup() {
trap 'unshare_teardown' EXIT
chroot_add_mount_lazy "$1" "$1" --bind &&
chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev &&
chroot_add_mount_lazy /sys "$1/sys" --rbind &&
chroot_add_link "$1/proc/self/fd" "$1/dev/fd" &&
chroot_add_link "$1/proc/self/fd/0" "$1/dev/stdin" &&
chroot_add_link "$1/proc/self/fd/1" "$1/dev/stdout" &&
chroot_add_link "$1/proc/self/fd/2" "$1/dev/stderr" &&
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 run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 &&
chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid
chroot_add_mount tmpfs "$1/run" -t tmpfs
}
unshare_teardown() {
@ -196,158 +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_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"] ))
}

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

@ -1,10 +1,11 @@
#compdef arch-chroot
#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'
)

View File

@ -1,18 +0,0 @@
Bugs
----
Bugs can be reported on the bug tracker 'https://bugs.archlinux.org' in the Arch
Linux category and title prefixed with [arch-install-scripts] or via
mailto:arch-projects@archlinux.org[].
Authors
-------
Maintainers:
* Dave Reisner <dreisner@archlinux.org>
* Eli Schwartz <eschwartz@archlinux.org>
For additional contributors, use `git shortlog -s` on the arch-install-scripts.git
repository.

View File

@ -1,21 +1,21 @@
arch-chroot(8)
future-chroot(8)
==============
Name
----
arch-chroot - enhanced chroot command
future-chroot - enhanced chroot command
Synopsis
--------
arch-chroot [options] chroot-dir [command] [arguments...]
future-chroot [options] chroot-dir [command] [arguments...]
Description
-----------
arch-chroot wraps the linkman:chroot[1] command while ensuring that important
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, arch-chroot will launch */bin/bash*.
If 'command' is unspecified, future-chroot will launch */bin/bash*.
[NOTE]
======
@ -40,6 +40,10 @@ Options
*-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.
@ -47,5 +51,3 @@ See Also
--------
linkman:pacman[8]
include::footer.asciidoc[]

View File

@ -46,5 +46,3 @@ See Also
--------
linkman:pacman[8]
include::footer.asciidoc[]

View File

@ -62,5 +62,3 @@ See Also
--------
linkman:pacman[8]
include::footer.asciidoc[]

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"] ))
}

View File

@ -1,11 +1,12 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
shopt -s extglob
m4_include(common)
setup=chroot_setup
unshare=0
keepresolvconf=0
m4_include(common)
usage() {
cat <<EOF
@ -14,10 +15,11 @@ 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 arch-chroot, the target chroot directory *should* be a
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.
@ -46,47 +48,58 @@ resolve_link() {
chroot_add_resolv_conf() {
local chrootdir=$1
local src=$(resolve_link /etc/resolv.conf)
local dest=$(resolve_link "$chrootdir/etc/resolv.conf" "$chrootdir")
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 ]]; then
# There are two reasons the destination might not exist:
#
# 1. There may be no resolv.conf in the chroot. In this case, $dest won't exist,
# and it will be equal to $1/etc/resolv.conf. In this case, we'll just exit.
# The chroot environment must not be concerned with DNS resolution.
#
# 2. $1/etc/resolv.conf is (or resolves to) a broken link. The environment
# clearly intends to handle DNS resolution, but something's wrong. Maybe it
# normally creates the target at boot time. We'll (try to) take care of it by
# creating a dummy file at the target, so that we have something to bind to.
# Case 1.
[[ $dest = $chrootdir/etc/resolv.conf ]] && return 0
# Case 2.
install -Dm644 /dev/null "$dest" || return 1
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" --bind
chroot_add_mount "$src" "$dest" -c --bind
}
while getopts ':hNu:' flag; do
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)
setup=unshare_setup
unshare=1
;;
u)
userspec=$OPTARG
;;
r)
keepresolvconf=1
;;
:)
die '%s: option requires an argument -- '\''%s'\' "${0##*/}" "$OPTARG"
;;
@ -101,27 +114,11 @@ shift $(( OPTIND - 1 ))
chrootdir=$1
shift
arch-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"
chroot_add_resolv_conf "$chrootdir" || die "failed to setup resolv.conf"
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[@]}"
}
args=("$@")
if (( unshare )); then
$mount_unshare bash -c "$(declare_all); arch-chroot"
setup=unshare_setup
$mount_unshare bash -c "$(declare_all); future-chroot"
else
arch-chroot
setup=chroot_setup
future-chroot
fi

View File

@ -1,8 +1,9 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
shopt -s extglob
m4_include(common)
m4_include(fstab-helpers)
write_source() {
local src=$1 spec= label= uuid= comment=()
@ -149,8 +150,7 @@ if ! mountpoint -q "$root"; then
fi
# handle block devices
findmnt -Recvruno SOURCE,TARGET,FSTYPE,OPTIONS,FSROOT "$root" |
while read -r src target fstype opts fsroot; do
while read -r src target fstype opts fsroot; do
if (( !pseudofs )) && fstype_is_pseudofs "$fstype"; then
continue
fi
@ -211,7 +211,7 @@ findmnt -Recvruno SOURCE,TARGET,FSTYPE,OPTIONS,FSROOT "$root" |
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
{
@ -227,6 +227,9 @@ done
# skip files marked deleted by the kernel
[[ $device = *'\040(deleted)' ]] && continue
# 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
@ -241,5 +244,3 @@ done
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,19 +11,18 @@
shopt -s extglob
m4_include(common)
hostcache=0
copykeyring=1
initkeyring=0
copymirrorlist=1
pacman_args=()
pacmode=-Sy
setup=chroot_setup
unshare=0
copyconf=0
pacman_config=/etc/pacman.conf
m4_include(common)
usage() {
cat <<EOF
usage: ${0##*/} [options] root [packages...]
@ -47,6 +47,45 @@ 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 ))
@ -76,7 +115,6 @@ while getopts ':C:cDGiKMNPU' flag; do
copymirrorlist=0
;;
N)
setup=unshare_setup
unshare=1
;;
P)
@ -96,8 +134,17 @@ done
shift $(( OPTIND - 1 ))
(( $# )) || die "No root directory specified"
newroot=$1; shift
pacman_args+=("$pacmode" "${@:-base}" --config="$pacman_config")
newroot=$1
shift
[[ -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")
@ -107,48 +154,14 @@ if (( ! interactive )); then
pacman_args+=(--noconfirm)
fi
[[ -d $newroot ]] || die "%s is not a directory" "$newroot"
pacstrap() {
(( EUID == 0 )) || die 'This script must be run with root privileges'
# create obligatory directories
msg 'Creating install root at %s' "$newroot"
mkdir -m 0755 -p "$newroot"/var/{cache/pacman/pkg,lib/pacman,log} "$newroot"/{dev,run,etc/pacman.d}
mkdir -m 1777 -p "$newroot"/tmp
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 (( 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