blob: 8f97d2d59822f6eca68460931ee89f810a1acb40 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
#!/usr/bin/env bash
# Copyright 2016-2018 Luke Shumaker
# This work is free. You can redistribute it and/or modify it under the
# terms of the Do What The Fuck You Want To Public License, Version 2,
# as published by Sam Hocevar. See the COPYING file for more details.
# The user should not call this script directly.
declare -r workdir=/var/lib/pristine-etc
watchdirs=(
/etc
/usr/share/holo/files
/usr/lib/sysusers.d
)
readonly watchdirs
pacman-watched-name-ver-dirs() {
local dir dirs
dirs=()
for dir in "${watchdirs[@]}"; do
if [[ -d "$dir" ]]; then
dirs+=("$dir")
fi
done
LC_ALL=C pacman -Qo "${dirs[@]}" | sed -r 's| is owned by | |' |
awk '{i=$2" "$3; a[i]=a[i]" "$1} END{for(i in a){print i " " a[i]}}'
}
pacman-all-name-arch() {
LC_ALL=C pacman -Qni | tr $'\n' $'\r' | sed 's/\r\r/\n/g' | sed -r 's|(.*\r)?Name\s*:\s*(\S+)(\r.*)?\rArchitecture\s*:\s*(\S+)\r.*|\2 \4|'
}
pacman-watched-name-arch-ver-dirs() {
join <(pacman-all-name-arch|sort) <(pacman-watched-name-ver-dirs|sort)
}
commit() (
msg="$1"
cd "$workdir"
if ! [[ -d etc.git ]]; then
mkdir -p chroot/etc
(cd chroot/etc && etckeeper init -d "$PWD")
mv chroot/etc/.git etc.git
fi
rm -rf etc; ln -sfT chroot/etc etc # for compatibility with old installs
rm -rf chroot
mkdir chroot
cd chroot
err=false
files=()
while IFS=' ' read -r pkgname arch pkgver dirs; do
file=("/var/cache/pacman/pkg/$pkgname-$pkgver-$arch".pkg.tar.*)
if ! test -f "$file"; then
printf "ERROR: no cached package for %s %s %s\n" "$pkgname" "$pkgver" "$arch"
err=true
fi
files+=("$file $dirs")
done < <(pacman-watched-name-arch-ver-dirs)
if $err; then
return 1
fi
for filespec in "${files[@]}"; do
read file dirs_str <<<"$filespec"
read -a dirs <<<"$dirs_str"
printf " -> %s\n" "$file"
bsdtar xpvf "$file" "${dirs[@]#/}"
done
ln -srT ../etc.git etc/.git
# The holo libalpm hook runs before the systemd-sysusers
# libalpm hook; but ignore that and run systemd-sysusers
# first, because I said so.
if type systemd-sysusers &>/dev/null; then
systemd-sysusers --root=.
fi
if type holo &>/dev/null; then
plugins=($(cat etc/holorc etc/holorc.d/* 2>/dev/null|sed -rn 's,^plugin ([a-z0-9][a-z0-9-]*)(=.*)?$,\1,p'))
mkdir -p -- run usr/lib "${plugins[@]/#/usr/share/holo/}"
ln -sT /usr/lib/holo usr/lib/holo
if [ -f /etc/os-release ]; then
ln -sT /etc/os-release usr/lib/os-release
else
ln -sT /usr/lib/os-release usr/lib/os-release
fi
HOLO_ROOT_DIR=. holo apply
fi
if type pwck &>/dev/null; then
pwck --root "$PWD" --sort
fi
if type grpck &>/dev/null; then
grpck --root "$PWD" --sort
fi
cd etc/
etckeeper update-ignore -d "$PWD"
if etckeeper unclean -d "$PWD"; then
etckeeper commit -d "$PWD" "$msg"
fi
)
pull() (
cd /etc
git remote add pristine "${workdir}/chroot/etc" &>/dev/null || true
git fetch pristine
)
lock() {
local fd=$1
local file=$2
eval "exec $fd>"'"$file"'
flock "${@:3}" "$fd"
}
unlock() {
local fd=$1
exec {fd}>&-
}
main() {
set -e -o pipefail
umask 0022
if ! lock 7 "${workdir}/chroot.lock" -n; then
return 0
fi
while true; do
lock 8 "${workdir}/spool.lock"
if ! [[ -f "${workdir}/spool" ]]; then
return 0
fi
msg="$(cat "${workdir}/spool")"
rm -f "${workdir}/spool"
unlock 8
commit "$msg"
pull
done
}
main "$@"
|