forked from idlemoor/slackrepo
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathinstallfunctions.sh
executable file
·403 lines (374 loc) · 14.6 KB
/
installfunctions.sh
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
#!/bin/bash
# Copyright 2014 David Spencer, Baildon, West Yorkshire, U.K.
# All rights reserved. For licence details, see the file 'LICENCE'.
#-------------------------------------------------------------------------------
# installfunctions.sh - package install functions for slackrepo
# install_deps
# uninstall_deps
# install_packages
# uninstall_packages
# is_installed
# dotprofilizer
#-------------------------------------------------------------------------------
function install_deps
# Install dependencies of $itemid (but NOT $itemid itself)
# $1 = itemid
# Return status:
# 0 = all installs succeeded
# 1 = any install failed
{
local itemid="$1"
local mydep
local allinstalled='y'
if [ -n "${FULLDEPS[$itemid]}" ]; then
log_normal -a "Installing dependencies ..."
for mydep in ${FULLDEPS[$itemid]}; do
install_packages "$mydep" || allinstalled='n'
done
# If any installs failed, uninstall them all and return an error:
if [ "$allinstalled" = 'n' ]; then
for mydep in ${FULLDEPS[$itemid]}; do
uninstall_packages "$mydep"
done
return 1
fi
fi
return 0
}
#-------------------------------------------------------------------------------
function uninstall_deps
# Uninstall dependencies of $itemid (but NOT $itemid itself)
# $1 = itemid
# Return status always 0
{
local itemid="$1"
local mydep
if [ -n "${FULLDEPS[$itemid]}" ]; then
[ "$OPT_CHROOT" = 'n' ] && log_normal -a "Uninstalling dependencies ..."
for mydep in ${FULLDEPS[$itemid]}; do
uninstall_packages "$mydep"
done
fi
return 0
}
#-------------------------------------------------------------------------------
function install_packages
# Run installpkg if the package is not already installed
# $* = itemids and/or package pathnames
# Return status:
# 0 = installed ok or already installed
# 1 = any install failed or not found (bail out after first error)
{
local arg
for arg in $*; do
if [ -f "$arg" ]; then
pkgbase="${arg##*/}"
pkgnam="${pkgbase%-*-*-*}"
local -a pkgnams=( "$pkgnam" )
local -a pkglist=( "$arg" )
local itemid=$(db_get_pkgnam_itemid "${pkgnams[0]}")
else
local itemid="$arg"
local itemdir="${ITEMDIR[$itemid]}"
[ -z "$itemdir" ] && { log_error -a "install_packages cannot find item ${itemid}"; return 1; }
local -a pkgnams=( $(db_get_itemid_pkgnams "$itemid") )
local -a pkglist=()
for pn in "${pkgnams[@]}"; do
# Don't look in TMP_OUTPUT (if you want that, specify them as pathnames)
if [ "$OPT_DRY_RUN" = 'y' ]; then
for p in "$TMP_DRYREPO"/"$itemdir"/"${pn}"-*.t?z; do
if [ -e "$p" ]; then
# cross-check p's pkgnam against pn (e.g. the geany/geany-plugins problem)
ppb="${p##*/}"
ppn="${ppb%-*-*-*}"
[ "$ppn" = "$pn" ] && pkglist+=( "$p" )
fi
done
fi
if [ "${#pkglist[@]}" = 0 ]; then
for p in "$SR_PKGREPO"/"$itemdir"/"${pn}"-*.t?z; do
if [ -e "$p" ]; then
ppb="${p##*/}"
ppn="${ppb%-*-*-*}"
[ "$ppn" = "$pn" ] && pkglist+=( "$p" )
fi
done
fi
done
if [ "${#pkglist[@]}" = 0 ]; then
log_error -a "${itemid}: Can't find any packages to install"
# if the packages have gone, we'd better wipe the db entries
db_del_rev "${itemid}"
db_del_itemid_pkgnam "$itemid"
return 1
fi
fi
if [ -n "${HINT_GROUPADD[$itemid]}" ] || [ -n "${HINT_USERADD[$itemid]}" ]; then
log_info -a "Adding groups and users:"
if [ -n "${HINT_GROUPADD[$itemid]}" ]; then
log_info -a " ${HINT_GROUPADD[$itemid]}"
eval $(echo "${HINT_GROUPADD[$itemid]}" | sed "s#groupadd #${CHROOTCMD}${SUDO}groupadd #g")
fi
if [ -n "${HINT_USERADD[$itemid]}" ]; then
log_info -a " ${HINT_USERADD[$itemid]}"
eval $(echo "${HINT_USERADD[$itemid]}" | sed "s#useradd #${CHROOTCMD}${SUDO}useradd #g")
fi
fi
for pkgpath in "${pkglist[@]}"; do
pkgbase="${pkgpath##*/}"
pkgid="${pkgbase%.t?z}"
pkgnam="${pkgbase%-*-*-*}"
is_installed "$pkgpath"
istat=$?
if [ "$istat" = 0 ]; then
# already installed, same version/arch/build/tag
log_normal -a "$R_INSTALLED is already installed"
KEEPINSTALLED[$pkgnam]="$pkgid"
elif [ "$istat" = 2 ]; then
# nothing similar currently installed
> "$MYTMP"/installpkglog
teelist="$MAINLOG $MYTMP/installpkglog"
[ -n "$ITEMLOG" ] && teelist="$teelist $ITEMLOG"
set -o pipefail
ROOT=${MY_CHRDIR:-/} ${SUDO}installpkg --terse "$pkgpath" 2>&1 | tee -a $teelist
pstat=$?
set +o pipefail
if [ "$pstat" != 0 ]; then
log_error -a "${itemid}: installpkg $pkgbase failed (status $pstat)"
log_info -t "$(<"$MYTMP"/installpkglog)"
return 1
else
tersename="${pkgbase%.t?z}:"
logtext=$(cat "$MYTMP"/installpkglog | \
grep -v "^${tersename:0:72} .*] *$" | \
grep -v -F -e 'Reloading system message bus configuration...' \
-e 'kbuildsycoca4 running...')
if [ -n "$logtext" ]; then
log_warning -a -s "${itemid}: Possible error message from doinst.sh or installpkg"
fi
fi
[ "$OPT_INSTALL" = 'y' -o "${HINT_INSTALL[$itemid]}" = 'y' ] && KEEPINSTALLED[$pkgnam]="$pkgid"
else
# istat=1 (already installed, different version/arch/build/tag)
# or istat=3 (broken /var/log/packages) or istat=whatever
[ "$istat" = 1 ] && log_normal -a "Upgrading $R_INSTALLED ..."
[ "$istat" = 3 ] && log_warning -n "Attempting to upgrade or reinstall $R_INSTALLED ..."
if [ "$OPT_VERBOSE" = 'y' ]; then
set -o pipefail
ROOT=${MY_CHRDIR:-/} ${SUDO}upgradepkg --reinstall "$pkgpath" 2>&1 | tee -a "$ITEMLOG"
pstat=$?
set +o pipefail
else
ROOT=${MY_CHRDIR:-/} ${SUDO}upgradepkg --reinstall "$pkgpath" >> "$ITEMLOG" 2>&1
pstat=$?
fi
[ "$pstat" = 0 ] || { log_error -a "${itemid}: upgradepkg $pkgbase failed (status $pstat)"; return 1; }
KEEPINSTALLED[$pkgnam]="$pkgid"
fi
dotprofilizer "$pkgpath"
done
done
return 0
}
#-------------------------------------------------------------------------------
function uninstall_packages
# Run removepkg, and do extra cleanup
# Usage: uninstall_packages [-f] itemid
# -f = (optionally) force uninstall. This is intended for use prior to building.
# (Many packages don't build properly if a prior version is installed.)
# Return status: always 0
# If KEEPINSTALLED[pkgnam] is set, the package WILL NOT be removed UNLESS -f is specified.
# If there is an install hint, the packages WILL NOT be removed UNLESS -f is specified.
# If OPT_INSTALL is set, the packages WILL be removed.
# Extra cleanup is only performed for 'vanilla' uninstalls.
# If OPT_CHROOT is set, the packages will not be removed, but a bit of cleanup will be done.
{
local force='n'
if [ "$1" = '-f' ]; then
force='y'
shift
fi
local itemid="$1"
local itemdir="${ITEMDIR[$itemid]}"
local -a pkglist
local pkgpath
local etcnewfiles etcdirs e
if [ "$OPT_CHROOT" != 'n' ]; then
# Don't bother uninstalling, the chroot has already been destroyed,
# but we need to run 'depmod' if we have removed a kernel module.
if [ "${HINT_KERNEL[$itemid]}" = 'kernelmodule' ]; then
${SUDO}depmod -a
elif [ -n "${HINT_CLEANUP[$itemid]}" ]; then
# For backwards compatibility, look for 'depmod' in the cleanup hints.
IFS=';'
for cleancmd in ${HINT_CLEANUP[$itemid]}; do
if [ "${cleancmd:0:7}" = 'depmod ' ]; then
eval "${SUDO}${cleancmd}" >> "$ITEMLOG" 2>&1
elif [ "${cleancmd:0:6}" = 'unset ' ]; then
eval "${cleancmd}" >> "$ITEMLOG" 2>&1
fi
done
unset IFS
fi
# Look for the package(s).
pkgnams=( $(db_get_itemid_pkgnams "$itemid") )
for pkgnam in "${pkgnams[@]}"; do
# we don't care about exact match so use a dummy -version-arch-build_tag
is_installed "$pkgnam"-v-a-b_t
istat=$?
if [ "$istat" = 2 ]; then
# Not installed, carry on quietly
continue
else
if [ "${HINT_KERNEL[$itemid]}" = 'kernelmodule' ]; then
${SUDO}depmod -a
elif [ -n "${HINT_CLEANUP[$itemid]}" ]; then
# For backwards compatibility, look for 'depmod' in the cleanup hints.
IFS=';'
for cleancmd in ${HINT_CLEANUP[$itemid]}; do
if [ "${cleancmd:0:7}" = 'depmod ' ]; then
eval "${SUDO}${cleancmd}" >> "$ITEMLOG" 2>&1
elif [ "${cleancmd:0:6}" = 'unset ' ]; then
eval "${cleancmd}" >> "$ITEMLOG" 2>&1
fi
done
unset IFS
fi
fi
done
return 0
fi
# Don't remove a package that has an install hint, unless -f was specified.
[ "${HINT_INSTALL[$itemid]}" = 'y' ] && [ "$force" != 'y' ] && return 0
# Look for the package(s).
pkgnams=( $(db_get_itemid_pkgnams "$itemid") )
for pkgnam in "${pkgnams[@]}"; do
# we don't care about exact match so use a dummy -version-arch-build_tag
is_installed "$pkgnam"-v-a-b_t
istat=$?
if [ "$istat" = 2 ]; then
# Not installed, carry on quietly
continue
else
# Don't remove a package flagged with KEEPINSTALLED, unless -f was specified.
[ -n "${KEEPINSTALLED[$pkgnam]}" ] && [ "$force" != 'y' ] && continue
if [ "$OPT_INSTALL" = 'y' ] || [ -n "${KEEPINSTALLED[$pkgnam]}" ] || \
[ "$force" = 'y' ] || [ "${HINT_INSTALL[$itemid]}" = 'y' ]; then
# Conventional gentle removepkg :-)
log_normal -a "Uninstalling $R_INSTALLED ..."
ROOT=${MY_CHRDIR:-/} ${SUDO}removepkg "$R_INSTALLED" >> "$ITEMLOG" 2>&1
else
# Violent removal :D
# Save a list of potential detritus in /etc
etcnewfiles=$(grep '^etc/.*\.new$' "${MY_CHRDIR}"/var/log/packages/"$R_INSTALLED")
etcdirs=$(grep '^etc/.*/$' "${MY_CHRDIR}"/var/log/packages/"$R_INSTALLED")
# Run removepkg
#### if verbose, maybe we should show this on the console, but it's usually big and annoying
log_normal -a "Uninstalling $R_INSTALLED ..."
ROOT=${MY_CHRDIR:-/} ${SUDO}removepkg "$R_INSTALLED" >> "$ITEMLOG" 2>&1
# Remove any surviving detritus (we now keep files without .new because
# of openrc and inittab, but overlayfs is the real long-term solution)
for etcnewfile in $etcnewfiles; do
rm -f /"$etcnewfile" 2>/dev/null
done
for e in $etcdirs; do
if [ -d /"$e" ]; then
find /"$e" -type d -depth -exec rmdir --ignore-fail-on-non-empty {} \; 2>/dev/null
fi
done
# If it was a kernel module, we need to run depmod
if [ "${HINT_KERNEL[$pkgnam]}" != 'kernelmodule' ]; then
${SUDO}depmod -a
fi
# Do this last so it can mend things the package broke.
# The cleanup hint can contain any required shell commands, for example:
# * Reinstalling Slackware packages that conflict with the item's packages
# (use the provided helper script: s_reinstall pkgnam...)
# * Unsetting environment variables set in an /etc/profile.d script
# (e.g. unset LD_PRELOAD)
# * Removing specific files and directories that removepkg doesn't remove
# * Running sed -i (e.g. to remove entries from /etc/shells, ld.so.conf)
# * Running ldconfig
# * [obsolete] Running depmod to remove references to removed kernel modules
# Be very careful with semicolons, IFS splitting is dumb.
if [ -n "${HINT_CLEANUP[$itemid]}" ]; then
IFS=';'
for cleancmd in ${HINT_CLEANUP[$itemid]}; do
log_info "Cleanup: $cleancmd"
if [ "${cleancmd:0:6}" = 'unset ' ]; then
# unset has to be run in this process (obvsly)
eval "${cleancmd}" >> "$ITEMLOG" 2>&1
else
# Everything else will need sudo if you're not root.
eval "${SUDO}${cleancmd}" >> "$ITEMLOG" 2>&1
fi
done
unset IFS
fi
fi
fi
done
return 0
}
#-------------------------------------------------------------------------------
function is_installed
# Check whether a package is currently installed
# $1 = pathname of a package file
# Sets the installed package name/version/arch/build in R_INSTALLED
# Return status:
# 0 = installed, with same version/arch/build/tag
# 1 = installed, but with different version/arch/build/tag
# 2 = not installed
# 3 = /var/log/packages is broken (multiple packages)
{
local pkgbase="${1##*/}"
local pkgid="${pkgbase%.t?z}"
local pkgnam="${pkgbase%-*-*-*}"
R_INSTALLED=''
if ls "${MY_CHRDIR}"/var/log/packages/"$pkgnam"-* 1>/dev/null 2>/dev/null; then
for instpkg in "${MY_CHRDIR}"/var/log/packages/"$pkgnam"-*; do
instid="${instpkg##*/}"
instnam="${instid%-*-*-*}"
if [ "$instnam" = "$pkgnam" ]; then
if [ -n "$R_INSTALLED" ]; then
log_warning -n "Your /var/log/packages is broken."
log_warning -n "Please review these files:"
log_warning -n " $instpkg"
log_warning -n " /var/log/packages/$R_INSTALLED"
return 3
fi
R_INSTALLED="$instid"
elif [ "${instid%-upgraded}" != "$instid" ]; then
log_warning -n "Your /var/log/packages is broken."
log_warning -n "Please review these files:"
log_warning -n " $instpkg"
fi
done
[ "$R_INSTALLED" = "$pkgid" ] && return 0
[ -n "$R_INSTALLED" ] && return 1
fi
return 2
}
#-------------------------------------------------------------------------------
function dotprofilizer
# Execute the /etc/profile.d scriptlets that came with a specific package
# $1 = path of package
# Return status: always 0
{
local pkgpath="$1"
local varlogpkg script
# examine /var/log/packages/xxxx because it's quicker than looking inside a .t?z
varlogpkg="${MY_CHRDIR}"/var/log/packages/$(basename "${pkgpath/%.t?z/}")
if grep -q -E '^etc/profile\.d/.*\.sh(\.new)?' "$varlogpkg"; then
while read -r script; do
if [ -f "${MY_CHRDIR}"/"$script" ]; then
log_info -a " Running profile script: /$script"
. "${MY_CHRDIR}"/"$script"
elif [ -f "${MY_CHRDIR}"/"$script".new ]; then
log_info -a " Running profile script: /$script.new"
. "${MY_CHRDIR}"/"$script".new
fi
done < <(grep '^etc/profile\.d/.*\.sh' "$varlogpkg" | sed 's/.new$//')
fi
return
}