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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
|
#!/bin/bash
#
# Copyright 2023-2025 Jeremy Hansen <jebrhansen -at- gmail.com>
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# -----------------------------------------------------------------------------
# Create a chroot from a maintained and updated Slackware stable base to allow
# easy testing of SlackBuild scripts in a clean environment. Ensure that base
# is updated every time this script is ran along with updating sbopkg and
# running sqg to update all queues. Offer to remove chroot files when exiting
# the chroot.
# Supports passing "cleanup" to remove any existing chroots and their files.
# Supports passing "update" to update the base image with slackpkg and sbopkg
# and then exiting without starting the chroot.
# TODO
# Currently empty
# -----------------------------------------------------------------------------
# --------------------------Global Settings Beginning--------------------------
# Set where you want the chroot located and the base name of the folder
CHROOT_LOCATION=/tmp/
CHROOT_TEMPLATE_BASE="chroot"
# Set variables for the base image and location of the local Slackware mirror
VERSION=15.0
SLACKWARE_BASE=/share/gothrough/sbo-build/$VERSION
LOCAL_MIRROR=/share/gothrough/slackware-mirrors/slackware64-$VERSION/
# To allow you to open GUI programs from within the chroot, you need to
# allow "remote" access to the x server. This could possibly open up
# security issues, but it is limited to non-network local connections.
# Change to "no" if you want this disabled or pass ACCESS=no to the script.
ACCESS=${ACCESS:-yes}
# ---------------------------Global Settings Ending----------------------------
# --------------------------Custom Commands Beginning--------------------------
# This will allow you to add custom aliases or functions into the chroot
# Make sure you escape single quotes and variables and that all commands are on
# their own lines
custom_cmd='
# Check all listed deps in a .info to see if they are installed
alias checkdeps=". *.info; for i in \$REQUIRES; do ls /var/log/packages/*SBo* | cut -d/ -f5 | rev | cut -d- -f4- | rev | grep ^\$i$; done"
'
# ---------------------------Custom Commands Ending----------------------------
# Check that we're root
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
fi
# Provide an easy cleanup for older tmp files and exit
if [ "$1" == "cleanup" ]; then
for i in "$CHROOT_LOCATION"/"$CHROOT_TEMPLATE_BASE".*; do
if [ -d "$i" ]; then
echo "Found $i"
else
echo "No chroots to clean up."
exit 2
fi
if mountpoint -q "$i"/chroot/dev/pts; then
printf "\tUnmounting %s/chroot/dev/pts\n" "$i"
umount "$i"/chroot/dev/pts
fi
for j in dev proc sys; do
if mountpoint -q "$i"/chroot/$j; then
printf "\tUnmounting %s/chroot/%s\n" "$i" "$j"
umount "$i"/chroot/$j
fi
done
if mountpoint -q "$i"/chroot/etc/resolv.conf; then
printf "\tUnmounting %s/chroot/etc/resolv.conf\n" "$i"
umount "$i"/chroot/etc/resolv.conf
fi
if mountpoint -q "$i"/chroot/var/lib/dbus/machine-id; then
printf "\tUnmounting %s/chroot/var/lib/dbus/machine-id\n" "$i"
umount "$i"/chroot/var/lib/dbus/machine-id
fi
# umount overlayfs
if mountpoint -q "$i"/chroot; then
printf "\tUnmounting %s/chroot/%s/chroot\n" "$i" "$j"
umount "$i"/chroot
fi
# Remove dirs
if [ -d "$i" ]; then
printf "\tRemoving %s.\n" "$i"
rm -r "$i"
fi
done
echo "Cleanup complete"
exit
fi
# Track the latest updates to prevent attempting to update system
# packages and rebuilding sbopkg's queues
touch $SLACKWARE_BASE/last-base-update
# Make sure the base image is up-to-date
if [ "$(head -n1 $LOCAL_MIRROR/ChangeLog.txt)" != "$(cat $SLACKWARE_BASE/last-base-update)" ]; then
for i in "$LOCAL_MIRROR"/patches/packages/*.t?z; do
if [ ! -e "$SLACKWARE_BASE"/var/lib/pkgtools/packages/"$(basename "${i%.*}")" ]; then
ROOT=$SLACKWARE_BASE upgradepkg --install-new "$i"
fi
done
echo "Slackware has been updated with local mirror."
head -n1 $LOCAL_MIRROR/ChangeLog.txt > $SLACKWARE_BASE/last-base-update
else
echo "Slackware is up-to-date with the local mirror."
fi
# Set up directories for the chroot
echo "Creating required directories for the overlay"
TMPDIR=$(mktemp -d "$CHROOT_LOCATION"/"$CHROOT_TEMPLATE_BASE".XXXXX)
mkdir "$TMPDIR"/{changes,tmp,chroot}
# Mount the overlayfs
echo "Mounting the overlay"
mount -t overlay overlay -olowerdir="$SLACKWARE_BASE",upperdir="$TMPDIR"/changes,workdir="$TMPDIR"/tmp "$TMPDIR"/chroot
# Bind mount the pertinent system dirs
echo "Binding required directories"
mkdir -p "$TMPDIR"/changes/{dev,proc,sys}
for i in dev proc sys; do
mount -o bind /$i "$TMPDIR"/chroot/$i
done
# Mount /dev/pts for sudo
mkdir -p "$TMPDIR"/changes/dev/pts
mount -o bind /dev/pts "$TMPDIR"/chroot/dev/pts
# Give the chroot internet
echo "Setting up internet"
mount -o bind /etc/resolv.conf "$TMPDIR"/chroot/etc/resolv.conf
chroot "$TMPDIR"/chroot /bin/bash -c "/usr/sbin/update-ca-certificates --fresh > /dev/null"
# Setting up DBUS binding required for certain apps
echo "Binding DBUS to local machine"
touch "$TMPDIR"/chroot/var/lib/dbus/machine-id
mount -o bind /var/lib/dbus/machine-id "$TMPDIR"/chroot/var/lib/dbus/machine-id
# Update sbopkg (if installed) and queues
# Do it in the chroot to prevent GPG errors, but copy files back to the
# base image so we only need to do it during updates.
if [ -e "$SLACKWARE_BASE"/usr/sbin/sbopkg ]; then
echo "Checking for SBo updates for sbopkg"
# Get the latest changelog date from server
SERVDATE="$(wget -qO- https://slackbuilds.org/slackbuilds/15.0/ChangeLog.txt | head -n1)"
if [ -z "$SERVDATE" ]; then
echo "Upstream address did not provide a changelog."
echo "Please validate internet is working and address is correct"
echo "This will continue in 5 seconds. Ctrl+C if you'd like to exit."
sleep 5
fi
# Get latest changelog date on local copy
LOCALDATE="$(head -n1 $SLACKWARE_BASE/var/lib/sbopkg/SBo/15.0/ChangeLog.txt)"
# If they don't match, update sbopkg and run sqg. Copy updates back to base image.
if [ "$SERVDATE" != "$LOCALDATE" ]; then
chroot "$TMPDIR"/chroot /bin/bash -c "/usr/sbin/sbopkg -r; /usr/sbin/sqg -a"
rsync -a --delete "$TMPDIR"/chroot/var/lib/sbopkg/ "$SLACKWARE_BASE"/var/lib/sbopkg
rsync -a --delete "$TMPDIR"/chroot/root/.gnupg "$SLACKWARE_BASE"/root/
else
echo "sbopkg is up-to-date."
fi
fi
# Only set up X server access and launch the chroot if update isn't passed
if [ "$1" != "update" ]; then
# Checking if we can add local connection access
if [ "$ACCESS" == "yes" ]; then
echo "Setting up X server access"
echo "STATUS: $(xhost +local:hosts)"
fi
# Check if there are custom commands to add by checking for text
if [[ "$custom_cmd" =~ [a-zA-Z] ]]; then
echo "Adding custom commands to chroot's /etc/profile.d/chroot_custom_cmds.sh"
echo "$custom_cmd" > "$TMPDIR"/chroot/etc/profile.d/chroot_custom_cmds.sh
chmod +x "$TMPDIR"/chroot/etc/profile.d/chroot_custom_cmds.sh
fi
# Let's save the following in the root of the chroot structure to allow
# the user to enter into that chroot from another prompt and/or if they
# accidentally leave the chroot.
# Then we'll just execute the file to actually enter the chroot.
cat << EOH > "$TMPDIR"/start-chroot.sh
#!/bin/bash
# Time to actually chroot and do our work
# Need to type 'exit' to leave the chroot and start the cleanup
# Use custom PS1 so we know we're in the chroot
echo "Entering chroot. Please type \"exit\" to exit it."
echo "You can add files to the chroot by placing them in $TMPDIR/chroot/"
chroot "$TMPDIR"/chroot env PS1="\[\e[41m\]\u\[\e[49m\]@\[\e[33m\]$(basename "$TMPDIR")\[\e[0m\]:\w$ " bash -l
EOH
# Start the chroot
bash "$TMPDIR"/start-chroot.sh
fi
# Start cleanup
# Undo bind mounts
umount "$TMPDIR"/chroot/dev/pts
for i in dev proc sys; do
umount "$TMPDIR"/chroot/$i
done
umount "$TMPDIR"/chroot/etc/resolv.conf
umount "$TMPDIR"/chroot/var/lib/dbus/machine-id
# umount overlayfs
umount "$TMPDIR"/chroot
# Only ask to delete chroot if update isn't passed, otherwise delete without asking
if [ "$1" != "update" ]; then
# Ask if tmp dirs should be removed
# Could be kept to review filesystem changes
echo -n "Would you like to remove the unneeded overlay directories? y/N "
read -r answer
# If anything other than y, rm them
if ! /usr/bin/grep -qi "y" <<< "$answer"; then
echo "Temp overlay dirs will not be removed. They can be found at $TMPDIR."
else
rm -r "$TMPDIR"
fi
else
rm -r "$TMPDIR"
fi
|