lfs-uefi: fix efivar-37 FTBFS
[linux_from_scratch_hints.git] / pio-files / pio
blob0944286464255b009ae8f9ba7bc4e65347de312b
1 #!/bin/bash
2 # Package Installation Observer, pio
3 #PGR was here for minor config changes
4 #PGR SUBVER=16a: added restore command, added a deliberate delay
5 #PGR SUBVER=16b: changed "files" function to include "touched" files in
6 # lists and backups. Important!
7 #PGR SUBVER=16c: added --color to ls, shortened backup file extension
8 #PGR SUBVER=16d: find wants -maxdepth before -type (some versions)
9 #PGR SUBVER=16e: reorganized configuration section for easier bootstrapping
10 #PGR SUBVER=16f: functionalized restore code, added "check" command
11 #PGR SUBVER=17: re-identified, changed hyphenated commands
12 #PGR SUBVER=17a: tar: ignore zero-blocks, don't pass tar "/"
13 #PGR SUBVER=17b: in write_script, sort used an obsolete POSIX syntax
14 #PGR SUBVER=17c: find syntax for -perm changed
15 #PGR SUBVER=17d: added /srv to WATCHed DIRectorieS
17 # Once upon a time there was git, the Guarded Installation Tool, by Ingo
18 # Brueckl (ib@wupperonline.de) 14.11.1996. I found it useful for LFS
19 # builds & added a few functions. Then Linus made a kernel development
20 # management tool he chose to call git. So I changed this script to
21 # avoid potential confusion. pio is still almost entirely Ingo's git.
22 # Some functionality has been changed. That's my responsibility.
25 LNAME="Package Installation Observer"
26 SNAME=$(basename "$0")
27 VERSION=2
28 SUBVER=17d
30 #PGR-16e: reorganized configuration section
31 #--------------------------------------------------------------------------
32 CFG=3
33 case $CFG in
35 #PGR During LFS-Ch5 stage1 build when $LFS is defined externally
36 VIEWPROG="less -c"
37 SHOWRESULT=yes # default answer to 'Show it?'
38 WATCHDIRS=$LFS
39 IGNOREDIRS=
40 SCRIPTPATH=$LFS/$SNAME ;;
42 #PGR During LFS-Ch6 stage2 build
43 VIEWPROG=cat
44 SHOWRESULT=yes # default answer to 'Show it?'
45 WATCHDIRS="/bin /boot /dev /etc /lib /opt /sbin /srv /usr /var"
46 IGNOREDIRS="/usr/local/src /usr/local/$SNAME /var/log"
47 SCRIPTPATH=/usr/local/$SNAME ;;
48 3)
49 #PGR After LFS-Ch6 stage 2 complete, general ops
50 VIEWPROG="less -c"
51 SHOWRESULT=yes # default answer to 'Show it?'
52 WATCHDIRS="/bin /boot /dev /etc /lib /opt /sbin /srv /usr /var"
53 #PGR if cups is installed, ignore cups changes
54 [ -d /etc/cups ] && cups="/etc/cups" || cups=""
55 [ -d /var/spool/fcron ] && fcron="/var/spool/fcron" || fcron=""
56 IGNOREDIRS="/usr/local/src /usr/local/$SNAME /var/log $cups $fcron"
57 SCRIPTPATH=/usr/local/$SNAME ;;
58 esac
60 #PGR-16c: use color
61 LSPROG="ls --color=auto -dCv" # program used to list de-installation scripts
62 #PGR-16c: shorten extension
63 BACKUPEXT=tgz # file extension used for backups
64 FINDCASE=-i # will cause --find to ignore case
65 PROFILEVAR=*default* # empty, *default*, or individual variable name
66 PRESERVE=yes # preserve the de-installation script's timestamps
67 EXPERT=no # non-experts get some additional help
68 EDITPROG=${EDITOR:-vi} # program used to edit de-installation scripts
69 BACKUPPIPE="tar --no-recursion --null -T - -czf" # program used to back up
70 #PGR-17b: ignore zero blocks
71 RESTOREPIPE="tar -xzif" #restore parms
72 #--------------------------------------------------------------------------
73 # end of configuration section
75 #PGR-17: eliminated hyphenated commands
76 USAGE="Usage:
77 $SNAME PKG
78 $SNAME command
79 [--cd] [--deps] [--help] [--profile] [--version]
80 $SNAME command [argument]
81 [--cwd [...]] [--ls [PKG*]] [--lsbak [PKG*]] [--dirs [PKG*]]
82 $SNAME command argument
83 [--edit PKG] [--remove PKG] [--backup PKG] [--restore PKG]
84 [--check PKG] [--files PKG] [--files0 PKG] [--list PKG]
85 [--xcheck PKG] [--find FILENAME]
86 $SNAME PKG command argument
87 [PKG --requires PKG2] [PKG --uses PKG2] [PKG --supports PKG2]
88 $SNAME [PKG] --lib [LIBNAME]
89 $SNAME [PKG] [--watch DIR1 DIR2 ...] [--ignore DIR1 DIR2 ...]
91 i.e.
92 PKG observe installation start/finish of PKG
93 --backup PKG create a backup of the files in PKG
94 --cd change the current directory to $SCRIPTPATH
95 --check PKG check current files against backup
96 --cwd [...] execute with arguments given in [...], but create all
97 working files in ./ (only works as first option)
98 --deps show all dependencies and usages
99 --dirs [PKG] show the defaults for --watch and --ignore or the
100 values used for the (current) installation of PKG
101 --edit PKG edit PKG's script preserving the file's timestamp
102 --files PKG list the files in PKG
103 --files0 PKG list the files in PKG with null-terminated names
104 --find FILENAME tell which PKG installed files matching FILENAME
105 --help display this help and exit
106 --ignore DIRn paths excluded from being watched during installation
107 --lib [LIBNAME] tell which programs use libraries matching LIBNAME
108 --list PKG list information about the files in PKG
109 --ls [PKG] list all de-installation scripts matching PKG*
110 --lsbak [PKG] list all backups matching PKG*
111 --profile print definitions required for option --cd and for a
112 variable containing $SCRIPTPATH
113 --remove PKG call the de-installation script for PKG
114 --requires PKG2 note the dependency on PKG2
115 --restore PKG restore files from backup PKG
116 --supports PKG2 note the exclusive use by PKG2
117 --uses PKG2 note the advantage because of PKG2
118 --version output version information and exit
119 --watch DIRn paths to be watched during installation
120 --xcheck PKG cross-check contents of PKG against all other
121 (executable) de-installation scripts to find out
122 whether a file has been installed more than once"
124 TRY="Try \`$SNAME --help' for more information."
126 ID="De-installation script"
127 #PGR-17: use unhyphenated synonyms
128 DEPEND="requires"
129 USE_OF="uses"
130 USED_BY="supports"
132 BACKUPPATH=$SCRIPTPATH/backups
134 SOFAR=so-far
135 SUFFIX=pre-inst
136 PIOOPT=pio-opts
138 OPTIONS=0 # a bitmap flag for options, bit 0: --watch, bit 1: --ignore
140 WSPACE=$(echo -e " \t")
141 eval "$(echo -e 'NL="\n"')"
142 # newlines in filenames will be expressed by ${NL} in de-installation scripts
143 # the following...
144 export NL
145 # ...allows subshells started by this script to handle those filenames properly
147 if [ ".$1" = ".--cwd" ]; then
148 shift
149 TEMPDIR=$(pwd)/$SNAME.$$
150 else
151 TEMPDIR=${TMPDIR:-/tmp}/$SNAME.$$
153 TEMPFILE=$TEMPDIR/$SNAME
155 function novice () # $1: string to return
157 if [ "$EXPERT" = no ]; then
158 echo "$1 "
159 else
160 echo ""
164 function change_filenames ()
166 # split lines separated by \0
167 # change <newline> temporarily into \0,
168 # question mark into //Q,
169 # and \0 into question mark
171 tr "\0\n" "\n\0" | sed "s:?://Q:g" | tr "\0" "?"
174 function restore_filename ()
176 # reverse what change_filenames did
178 tr "?" "\n" | sed "s://Q:?:g"
181 function find_filenames ()
183 eval "find $WATCHDIRS $PRUNE \"\$@\" \( -type d -printf "d" -print0 -o \
184 -printf "f" -print0 \)" |
185 change_filenames
188 function translate_filenames () # $1: inserted as first character in line
190 # escape special characters,
191 # change question mark into ${NL},
192 # change //Q into question mark,
193 # translate file type into 'rm -f' or 'rmdir'
194 # and put double quotes around the filename if (possibly) necessary
196 sed -e 's:["$\\`]:\\&:g' -e 's:?:${NL}:g' -e "s://Q:?:g" \
197 -e "s:^f:$1 rm -f :" -e "s:^d:$1 rmdir :" \
198 -e 's:^\(.\{8\}\) \(.*[^a-zA-Z0-9+,./:_-].*\)$:\1"\2":'
201 function create_tempdir ()
203 mkdir "$TEMPDIR" && chmod go-w "$TEMPDIR" && rm -rf "$TEMPDIR"/{,.[^.],..?}*
204 if [ $? -ne 0 ]; then
205 echo "Fatal error while creating working directory."
206 exit 1
208 TMPDIR=$TEMPDIR
209 export TMPDIR
212 function write_script () # $1: pre-inst, $2: script, $3: quiet?
214 # detect new or modified files
215 find_filenames -cnewer "$1" | sort > "$TEMPFILE.new"
217 # detect files that have been deleted
218 find_filenames | sort > "$TEMPFILE.all"
219 comm -23 "$1" "$TEMPFILE.all" > "$TEMPFILE.del"
221 # handle files that have been newly created
222 comm -13 "$1" "$TEMPFILE.new" | translate_filenames " " > "$TEMPFILE.rm"
224 # handle previously existing files that have been changed
225 comm -12 "$1" "$TEMPFILE.new" | translate_filenames "#" >> "$TEMPFILE.rm"
227 # now create the de-installation script
228 echo "#!/bin/bash" > "$2"
229 echo "#" >> "$2"
230 echo $E "$ID for \`$(basename "$1" ".$SUFFIX")'," | sed "s:^:# :" >> "$2"
231 echo "# created by $LNAME $VERSION.$SUBVER on $(date)" >> "$2"
232 echo >> "$2"
233 if grep -q "?" "$TEMPFILE.new" "$TEMPFILE.del"; then
234 echo 'NL="' >> "$2"
235 echo '" # some filenames contain newlines expressed by ${NL}' >> "$2"
236 echo >> "$2"
238 if [ -s "$TEMPFILE.del" ]; then
239 echo "## WARNING!" >> "$2"
240 echo "##" >> "$2"
241 echo "## This is a list of files that seem to have been deleted during installation:" >> "$2"
242 echo "##" >> "$2"
243 cat "$TEMPFILE.del" | translate_filenames "#" | sed "s:^# rm...:## :" | sort >> "$2"
244 echo "##" >> "$2"
245 echo "## End of WARNING" >> "$2"
246 echo >> "$2"
248 echo "$SNAME --xcheck" '"$(basename "$0")"' >> "$2"
249 echo 'echo -n "Ok to start de-installation? "' >> "$2"
250 echo "read" >> "$2"
251 echo 'if [ ".$REPLY" != ".y" -a ".$REPLY" != ".yes" ]; then' >> "$2"
252 echo ' echo "No, aborted."' >> "$2"
253 echo " exit" >> "$2"
254 echo "else" >> "$2"
255 echo -n ' echo -n "Removing \`$(basename "$0")' >> "$2"
256 echo "'... \"" >> "$2"
257 echo "fi" >> "$2"
258 echo >> "$2"
259 echo "# The following statements will completely remove the installation," >> "$2"
260 echo "# files already existing prior to the installation are commented out." >> "$2"
261 echo >> "$2"
262 #PGR updated syntax for POSIX-200112 standard (klugey, I know)
263 sort -t : -k1.9 -r "$TEMPFILE.rm" >> "$2" # puts files before directory
264 echo >> "$2"
265 echo 'chmod -x "$0"' >> "$2"
266 echo 'echo "done."' >> "$2"
267 echo 'echo -n "Remove script, too? "' >> "$2"
268 echo "read" >> "$2"
269 echo 'if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then' >> "$2"
270 echo ' rm "$0"' >> "$2"
271 echo "else" >> "$2"
272 echo ' echo "It has been made non-executable instead."' >> "$2"
273 echo "fi" >> "$2"
275 # we're done
276 if [ -z "$3" ]; then
277 trap "" SIGINT
278 echo "done."
279 if [ -s "$TEMPFILE.del" ]; then
280 echo "See it for warnings!"
285 function show_result () # $1: script
287 if [ ! -s "$1" ]; then
288 echo "Nothing to show."
289 return 1
290 elif [ -z "$VIEWPROG" ]; then
291 echo -n "Can't show it, press enter. "
292 read
293 else
294 echo -n "Show it? [$SHOWRESULT] "
295 read
296 REPLY=${REPLY:-$SHOWRESULT}
297 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
298 $VIEWPROG "$1"
301 return 0
304 function extract_filenames () # $1: search pattern for beginning of line
306 NFNAME="[^$WSPACE\";]\+" # normal (unquoted) filenames
307 QFNAME='".*"' # double quoted filenames
309 sed "s:$1\($NFNAME\|$QFNAME\)\([$WSPACE;].*\)\?\$: \1:"
312 function xcheck () # $1: script, $2: ANYNAME
314 echo $E -n "Checking \`$(basename "$1")'... "
316 # separate files to be removed
317 grep "^ *rm -f " "$1" | extract_filenames "^ *rm -f \+" |
318 sort > "$TEMPFILE.check"
320 # separate files commented out
321 #PGR-16d: -maxdepth order problem with some versions of find
322 # find "$SCRIPTPATH" -maxdepth 1 -type f -perm +u+x -print0 |
323 #PGR-17c: syntax for -perm changed
324 find "$SCRIPTPATH" -maxdepth 1 -type f -perm /u+x -print0 |
325 xargs -0re grep -h '^#[^"]*rm -f ' | extract_filenames '^#[^"]*rm -f \+' |
326 sort > "$TEMPFILE.against"
328 # detect files being installed more than once
329 FILES=$(comm -12 "$TEMPFILE.check" "$TEMPFILE.against")
331 # check result
332 if [ "$FILES" ]; then
333 echo -e "\nSome files seem to have been installed more than once!\n"
334 grep -F "$FILES" "$1"
335 echo -e "conflict(s) with:\n"
336 INUM=$(find "$1" -printf "%i")
337 #PGR-16d: -maxdepth order problem with some versions of find
338 # find "$SCRIPTPATH" -maxdepth 1 -type f -perm +u+x -not -inum $INUM \
339 #PGR-17c: syntax for -perm changed
340 find "$SCRIPTPATH" -maxdepth 1 -type f -perm /u+x -not -inum $INUM \
341 -exec grep -F "$FILES" {} \; -printf "(in %P)\n\n"
344 SCRIPT=$(echo $E -n "$2" | change_filenames)
345 DEPENDENCIES=$(dependencies "$SCRIPT")
347 if [ -z "$FILES" -a -z "$DEPENDENCIES" ]; then
348 echo "done."
349 return 0
352 if [ -z "$FILES" ]; then
353 echo -e "\n"
356 if [ "$DEPENDENCIES" ]; then
357 echo $E "$DEPENDENCIES"
358 echo
361 return 1
364 function permissions () # $1: script
366 COL="\([^ ]\+\)\( \+\)" # a column (with delimiter)
368 IFSold=$IFS
369 IFS=$(echo -e "\t")
371 for c in " " "#"; do
372 grep "^$c *rm... " "$1" | extract_filenames "^$c *rm... \+" | tr "\n" "\0" |
373 xargs -0re sh -c 'eval ls -ldbF "$@"' -- |
374 sed "s:^$COL$COL$COL$COL$COL$COL$COL$COL:\1\t\3\t\5\t\7\t$c\t:"
375 done | sort -r -k 6 -t "$IFS" |
376 while read -r p n o g c f; do
377 printf "%s %3s %-8s %-8s %s %s\n" $p $n $o $g "$c" "$f"
378 done
380 IFS=$IFSold
383 function files () # $1: script
385 #PGR-16b: don't ignore changed previously existing files
386 # grep "^ *rm... " "$1" | extract_filenames "^ *rm... \+" | sed "s:^ ::" |
387 grep "^[ #] *rm... " "$1" | extract_filenames "^[ #] *rm... \+" | sed "s:^ ::" |
388 tr "\n" "\0" | xargs -0re sh -c 'eval find "$@" -maxdepth 0 -print0' --
391 function chkname () # $1: ANYNAME
393 case "$1" in
394 */*) echo $E "Will not handle \`$1' (containing a slash)!"
395 exit 1
397 esac
400 function chkscript () # $1: ANYNAME
402 chkname "$1"
403 if [ ! -f "$SCRIPTPATH/$1" ]; then
404 echo $E "\`$SCRIPTPATH/$1' does not exist!"
405 exit 1
406 elif sed -n "3p" "$SCRIPTPATH/$1" | grep -q "$ID"; then
407 return 0
408 else
409 echo $E "\`$SCRIPTPATH/$1' does not seem to be a de-installation script!"
410 exit 1
414 function chkbakpath ()
416 if [ ! -d "$BACKUPPATH" ]; then
417 echo -n "Ok to create backup directory $BACKUPPATH? $(novice '[no/yes]')"
418 read
419 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
420 mkdir -p "$BACKUPPATH" || exit 1
421 else
422 echo "No, aborted."
423 exit 1
428 function check_paths () # $@: directories to check
430 RC=0
431 for p in "$@"; do
432 case "$p" in
433 /*) if [ ! -d "$p" ]; then
434 echo $E "Warning: \`$p' does not exist!"
435 RC=1
438 *) echo $E "Will not accept \`$p' (not an absolute path)!"
439 exit 1
441 esac
442 done
443 return $RC
446 function find_script () # $1: string to search
448 NOREGEX=$(echo $E -n "f$1" | change_filenames | translate_filenames " " |
449 sed -e "s:^.\{9\}::" -e 's:"$::' -e 's:[][^$\\.*]:\\&:g')
450 NFNAME="[^$WSPACE\";]*$NOREGEX" # string inside normal (unquoted) filenames
451 QFNAME="\".*$NOREGEX.*\"" # string inside double quoted filenames
453 cd "$SCRIPTPATH" || return 1
454 #PGR-16d: -maxdepth order problem with some versions of find
455 # find -maxdepth 1 -type f -perm +u+x -printf "%P\0" |
456 #PGR-17c: syntax for -perm changed
457 find -maxdepth 1 -type f -perm /u+x -printf "%P\0" |
458 xargs -0re grep $FINDCASE "^[ #] *rm... \+\($NFNAME\|$QFNAME\)" /dev/null
461 function profile ()
463 echo "function $SNAME ()"
464 echo "{"
465 echo ' if [ ".$1" = ".--cd" ]; then'
466 echo " cd \"$SCRIPTPATH\""
467 echo " else"
468 echo " command $SNAME" '"$@"'
469 echo " fi"
470 echo "}"
471 echo "export -f $SNAME"
473 if [ ".$PROFILEVAR" = ".*default*" ]; then
474 PROFILEVAR=$SNAME
477 case "$PROFILEVAR" in *[^a-zA-Z0-9_]* | [0-9]* | _)
478 echo "$SNAME --profile: \`$PROFILEVAR' is not a valid variable name." >&2
479 exit 1
481 esac
483 if [ "$PROFILEVAR" ]; then
484 echo "$PROFILEVAR=\"$SCRIPTPATH\""
485 echo "export $PROFILEVAR"
489 function quote () # $1: file or path name
491 # put single quotes around the name
492 # after replacing all ' by '\'' if necessary
494 case "$1" in
495 *\'*) echo $E "$1" | sed -e "s:':'\\\'':g" -e "1s:^:':" -e '$s:$:'\'':'
497 *) echo $E "'$1'"
499 esac
502 function option_list () # $@: command line
504 CURROPT=""
505 for p in "$@"; do
506 case "$p" in
507 --watch) WATCHDIRS=""
508 CURROPT=--watch
509 OPTIONS=$((OPTIONS | 1))
511 --ignore) IGNOREDIRS=""
512 CURROPT=--ignore
513 OPTIONS=$((OPTIONS | 2))
515 -*) echo $TRY
516 exit 1
518 "") continue
520 *) if [ -z "$CURROPT" ]; then
521 CURROPT=none
522 elif [ $CURROPT = --watch ]; then
523 WATCHDIRS="$WATCHDIRS $(quote "$p")"
524 elif [ $CURROPT = --ignore ]; then
525 IGNOREDIRS="$IGNOREDIRS $(quote "$p")"
526 else
527 echo $TRY
528 exit 1
531 esac
532 done
533 WATCHDIRS=${WATCHDIRS# }
534 IGNOREDIRS=${IGNOREDIRS# }
537 function prune_statement () # $@: directories to ignore
539 PRUNE=""
540 for p in "$@"; do
541 PRUNE="$PRUNE -path $(quote "$p") -prune -o"
542 done
543 PRUNE=$(echo $E "$PRUNE" | sed "s:[][*?]:\\\&:g")
546 function default_dirs ()
548 echo $E "--watch ${WATCHDIRS:-\"\"}"
549 echo $E "--ignore ${IGNOREDIRS:-\"\"}"
552 function dirs () # $1: ANYNAME
554 if [ ! -f "$SCRIPTPATH/$1.$SUFFIX" ]; then
555 echo $E "A guarded installation of \`$1' isn't in progress."
556 return 1
557 else
558 if [ -f "$SCRIPTPATH/$1.$PIOOPT" ]; then
559 WATCHDIRS=$(grep "^w" "$SCRIPTPATH/$1.$PIOOPT" | sed "s:^.::")
560 IGNOREDIRS=$(grep "^i" "$SCRIPTPATH/$1.$PIOOPT" | sed "s:^.::")
562 default_dirs
563 return 0
567 function finish_installation () # $1: ANYNAME
569 chmod u+x "$SCRIPTPATH/$1"
570 rm "$SCRIPTPATH/$1.$SUFFIX"
571 rm -f "$SCRIPTPATH/$1.$PIOOPT"
572 trap SIGINT
573 show_result "$SCRIPTPATH/$1"
576 function check_directories ()
578 if [ -z "$WATCHDIRS" ]; then
579 echo "Nothing to watch."
580 exit 1
583 eval check_paths "$WATCHDIRS $IGNOREDIRS"
585 if [ $? -ne 0 -a $OPTIONS -ne 0 ]; then
586 echo -n "Continue anyway? $(novice '[no/yes]')"
587 read
588 if [ ".$REPLY" != ".y" -a ".$REPLY" != ".yes" ]; then
589 echo "No, aborted."
590 exit 1
594 eval prune_statement "$IGNOREDIRS"
597 function cleanup () # $@: files to delete
599 trap "" SIGINT
600 echo "interrupted!"
601 rm -f "$@"
602 exit 1
605 function noregex () # $1: pattern
607 echo $E ".$1" | sed -e "s:^.::" -e 's:[][^$\\.*]:\\&:g'
610 function lddlib () # $1: script, $2: search pattern, $3: ANYNAME
612 if [ -z "$2" ]; then
613 HEADER="Use of libraries found in \`$3'."
614 else
615 HEADER="Use of \`$2' found in \`$3'."
618 NOREGEX=$(noregex "$2")
619 FILE=""
621 grep "^. *rm -f " "$1" | extract_filenames "^. *rm -f \+" |
622 grep -v "^ /dev/\|^ /proc/" | tr "\n" "\0" |
623 xargs -0re sh -c 'eval ldd "$@"' -- /dev/null 2> /dev/null |
624 grep $FINDCASE "^[^$WSPACE]\|$NOREGEX" |
626 while read -r; do
627 case "$REPLY" in
628 [^$WSPACE]*) FILE=$REPLY
630 *) [ "$HEADER" ] && echo && echo $E "$HEADER" && HEADER=""
631 [ "$FILE" ] && echo $E "$FILE" && FILE=""
632 echo $E "$REPLY"
634 esac
635 done
638 function dependencies () # $1: search pattern
640 NOREGEX=$(noregex "$1")
641 if [ "$1" ]; then
642 NOREGEX="$NOREGEX\$"
645 MAGIC="#: \($DEPEND\|$USE_OF\|$USED_BY\): "
647 cd "$SCRIPTPATH" || return 1
648 #PGR-16d: -maxdepth order problem with some versions of find
649 # find -maxdepth 1 -type f -perm +u+x -printf "%P\0" |
650 #PGR-17c: syntax for -perm changed
651 find -maxdepth 1 -type f -perm /u+x -printf "%P\0" |
652 xargs -0re grep "^${MAGIC}${NOREGEX}" /dev/null |
653 # change all question marks in front of :$MAGIC and
654 # those in all lines not containing :$MAGIC to //Q
655 # (which protects them against restore_filename)
656 # then extract $DEPEND, $USE_OF or $USED_BY from :$MAGIC
657 sed -e ":loop" -e "s;?\(.*:$MAGIC\);//Q\1;" -e "t loop" \
658 -e "/:$MAGIC/ !s:?://Q:g" \
659 -e "s;:$MAGIC; \1 ;" |
660 restore_filename
663 function touch_script () # $1: script, $2: save/restore
665 case $2 in
666 save) touch -r "$1" "$TEMPFILE.mtime"
668 restore) if [ "$1" -nt "$TEMPFILE.mtime" -o \
669 "$1" -ot "$TEMPFILE.mtime" ]; then
670 touch -mr "$TEMPFILE.mtime" "$1"
673 esac
676 function depend () # $1: script, $2: DEPNAME, $3: string
678 SCRIPT=$(echo $E -n "$2" | change_filenames)
680 if grep -q "^#: $3: $(noregex "$SCRIPT")\$" "$1"; then
681 return 0
682 else
683 touch_script "$1" save
684 N="\\$NL"
685 if grep -q "^#: $3: " "$1"; then
686 MAGIC="^#: $3: "
687 EXTRA=""
688 elif grep -q "^#: " "$1"; then
689 MAGIC="^#: "
690 EXTRA=""
691 else
692 MAGIC="^[$WSPACE]*\$"
693 EXTRA=$N
696 # determine the line number behind the last $MAGIC line
697 # and insert '#: $3: $SCRIPT' there
698 LNR=$(sed -n "/$MAGIC/,\$ { /$MAGIC/ !{ =; q; }; }" "$1")
699 sed "$((LNR)) i${N}#: $3: ${SCRIPT}${EXTRA}" "$1" > "$TEMPFILE.copy"
701 if [ $? -eq 0 -a -s "$TEMPFILE.copy" ]; then
702 cp "$TEMPFILE.copy" "$1"
703 else
704 return 1
707 if [ "$PRESERVE" = yes ]; then
708 touch_script "$1" restore
713 function edit_script () # $1: script
715 touch_script "$1" save
716 $EDITPROG "$1"
717 touch_script "$1" restore
720 function no_other_pre_inst_file ()
722 #PGR-16d: -maxdepth order problem with some versions of find
723 FILES=$(find "$SCRIPTPATH" -maxdepth 1 -type f -name "*.$SUFFIX")
725 if [ "$FILES" ]; then
726 echo "Other installation(s) still in progress:"
727 cd "$SCRIPTPATH" && ls -CdbF *."$SUFFIX"
728 echo -n "Continue anyway? $(novice '[no/yes]')"
729 read
730 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
731 return 0
732 else
733 return 1
735 else
736 return 0
740 function backup () # $1: script, $2: ANYNAME
742 if [ -e "$BACKUPPATH/$2.$BACKUPEXT" ]; then
743 echo -n "Backup already exists. Ok to overwrite? $(novice '[no/yes]')"
744 read
745 if [ ".$REPLY" != ".y" -a ".$REPLY" != ".yes" ]; then
746 echo "No, aborted."
747 exit 1
750 # PGR passing it "/", i.e. when package contains a root-level directory,
751 # would cause it to backup a "null member".
752 # files "$1" | $BACKUPPIPE "$BACKUPPATH/$2.$BACKUPEXT"
753 files "$1" | sed -e '/^\/$/d' | $BACKUPPIPE "$BACKUPPATH/$2.$BACKUPEXT"
754 echo "Done."
757 #PGR-16a: functionalized restore code
758 function restore () # $1: script $2: ANYNAME
760 if [ -e "$BACKUPPATH/$2.$BACKUPEXT" ]; then
761 (cd / && $RESTOREPIPE "$BACKUPPATH/$2.$BACKUPEXT")
762 if [ $? -eq 0 ]; then
763 echo "Files restored successfully."
764 if [ -e "$1" ]; then
765 if [ ! -x "$1" ]; then
766 chmod u+x "$1"
767 echo "$1 made executable again."
769 else
770 echo "Oops! $ID $1 doesn't exist anymore."
771 # Yes, backup is restored even if deinstall script is missing.
773 else
774 echo "Restore returned error code $?"
776 else
777 echo "$BACKUPPATH/$2.$BACKUPEXT doesn't exist."
781 #PGR-16f: compare current files to contents of backup
782 function check ()
784 create_tempdir
785 mkdir $TEMPDIR/CHECK #branch for temporary restore
786 cd $TEMPDIR/CHECK
787 $RESTOREPIPE "$BACKUPPATH/$1.$BACKUPEXT"
788 for i in `find $TEMPDIR/CHECK -type f -exec echo {} \;`
790 file=${i#$TEMPDIR/CHECK}
791 cmp -s $i $file || echo $file "changed."
792 done
796 # start of main program
799 case "$SNAME" in *[^a-zA-Z0-9+,.:_-]*)
800 echo "Please call me under a name only containing characters [a-zA-Z0-9+,.:_-]."
801 exit 1
803 esac
805 if echo "\t" | grep -q "t"; then
806 E=""
807 elif echo -E "\t" | grep -q "t"; then
808 E="-E"
809 else
810 echo "Warning: Your \`echo' can't handle backslash-escaped characters literally."
811 E=""
814 trap 'trap "" SIGINT; rm -rf "$TEMPDIR"' EXIT
815 trap 'echo "interrupted!"; exit 1' SIGINT
816 create_tempdir
818 if [ ".$1" = ".--ls" ]; then
819 chkname "$2"
820 cd "$SCRIPTPATH" && $LSPROG -- "$2"*
821 exit
822 elif [ ".$1" = ".--lsbak" ]; then
823 chkname "$2"
824 chkbakpath
825 cd "$BACKUPPATH" && $LSPROG -- "$2"*
826 exit
827 elif [ ".$1" = ".--lib" -a $# -le 2 ]; then
828 #PGR-16d: -maxdepth order problem with some versions of find
829 # find "$SCRIPTPATH" -maxdepth 1 -type f -perm +u+x -print0 |
830 #PGR-17c: syntax for -perm changed
831 find "$SCRIPTPATH" -maxdepth 1 -type f -perm /u+x -print0 |
832 xargs -0re -i $SNAME {} "$@"
833 exit
834 elif [ ".$2" = ".--lib" -a $# -le 3 ]; then
835 ANYNAME=${1#"$SCRIPTPATH/"}
836 chkscript "$ANYNAME"
837 lddlib "$SCRIPTPATH/$ANYNAME" "$3" "$ANYNAME"
838 exit
841 case $# in
842 3) ANYNAME=${1#"$SCRIPTPATH/"}
843 DEPNAME=${3#"$SCRIPTPATH/"}
844 case "$2" in
845 --requires) chkscript "$ANYNAME"
846 chkscript "$DEPNAME"
847 depend "$SCRIPTPATH/$ANYNAME" "$DEPNAME" "$DEPEND"
848 exit
850 --uses) chkscript "$ANYNAME"
851 chkscript "$DEPNAME"
852 depend "$SCRIPTPATH/$ANYNAME" "$DEPNAME" "$USE_OF"
853 exit
855 --supports) chkscript "$ANYNAME"
856 chkscript "$DEPNAME"
857 depend "$SCRIPTPATH/$ANYNAME" "$DEPNAME" "$USED_BY"
858 exit
860 *) chkname "$1"
861 option_list "$@"
863 esac
865 2) ANYNAME=${2#"$SCRIPTPATH/"}
866 case "$1" in
867 --xcheck) chkscript "$ANYNAME"
868 xcheck "$SCRIPTPATH/$ANYNAME" "$ANYNAME"
869 exit
871 --remove) chkscript "$ANYNAME"
872 rm -rf "$TEMPDIR"
873 export -n TMPDIR
874 exec "$SCRIPTPATH/$ANYNAME"
876 --backup) chkscript "$ANYNAME"
877 chkbakpath
878 backup "$SCRIPTPATH/$ANYNAME" "$ANYNAME"
879 exit
881 #PGR added "restore" command so we don't have to run tar from / and chmod
882 --restore) chkname "$ANYNAME"
883 chkbakpath
884 restore "$SCRIPTPATH/$ANYNAME" "$ANYNAME"
885 exit
887 #PGR added "check" command to validate current files & backup
888 --check) chkname "$ANYNAME"
889 chkbakpath
890 rm -rf "$TEMPDIR"
891 export -n TMPDIR
892 check "$ANYNAME"
893 exit
895 --list) chkscript "$ANYNAME"
896 permissions "$SCRIPTPATH/$ANYNAME"
897 exit 0
899 --files) chkscript "$ANYNAME"
900 files "$SCRIPTPATH/$ANYNAME" | tr "\0" "\n"
901 exit 0
903 --files0) chkscript "$ANYNAME"
904 files "$SCRIPTPATH/$ANYNAME"
905 exit 0
907 --edit) chkscript "$ANYNAME"
908 edit_script "$SCRIPTPATH/$ANYNAME"
909 exit
911 --find) find_script "$2"
912 exit
914 --dirs) chkname "$ANYNAME"
915 dirs "$ANYNAME"
916 exit
918 *) echo $TRY
919 exit 1
921 esac
923 1) case "$1" in
924 --cd) echo "Option --cd isn't available, use \`cd $SCRIPTPATH' instead."
925 exit 1
927 --deps) dependencies
928 exit
930 --dirs) default_dirs
931 exit 0
933 --profile) profile
934 exit 0
936 --help) echo "$USAGE"
937 exit 0
939 --version) echo "$SNAME - $LNAME $VERSION.$SUBVER"
940 exit 0
942 -*) echo $TRY
943 exit 1
945 *) chkname "$1"
947 esac
949 *) case "$1" in
950 -* | "") echo $TRY
951 exit 1
953 *) chkname "$1"
954 option_list "$@"
956 esac
958 esac
960 # called first time ever
961 if [ ! -d "$SCRIPTPATH" ]; then
962 echo -n "Ok to create script directory $SCRIPTPATH? $(novice '[no/yes]')"
963 read
964 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
965 mkdir -p "$SCRIPTPATH" || exit 1
966 else
967 echo "No, aborted."
968 exit 1
972 ANYNAME=$1
974 # installation in progress
975 if [ -f "$SCRIPTPATH/$ANYNAME.$SUFFIX" ]; then
977 if [ -f "$SCRIPTPATH/$ANYNAME.$PIOOPT" ]; then
978 if [ $((OPTIONS & 1)) -eq 0 ]; then
979 WATCHDIRS=$(grep "^w" "$SCRIPTPATH/$ANYNAME.$PIOOPT" | sed "s:^.::")
981 if [ $((OPTIONS & 2)) -eq 0 ]; then
982 IGNOREDIRS=$(grep "^i" "$SCRIPTPATH/$ANYNAME.$PIOOPT" | sed "s:^.::")
986 check_directories
988 # ask what to do
989 echo $E "Observing the installation of \`$ANYNAME'."
990 REPLY=""
991 until [ "$REPLY" ]; do
992 echo -n "What shall $SNAME do now (s/r/f/q)? $(novice '[Press enter for help]')"
993 read
994 if [ ".$REPLY" != ".s" -a ".$REPLY" != ".r" -a \
995 ".$REPLY" != ".f" -a ".$REPLY" != ".q" ]; then
996 echo " s ... show state of installation"
997 echo " r ... revoke installation"
998 echo " f ... finish installation"
999 echo " q ... quit"
1000 REPLY=""
1002 done
1004 # finish installation
1005 if [ "$REPLY" = "f" ]; then
1006 echo $E -n "Creating de-installation script \`$SCRIPTPATH/$ANYNAME'... "
1007 trap 'cleanup "$SCRIPTPATH/$ANYNAME"' SIGINT
1008 write_script "$SCRIPTPATH/$ANYNAME.$SUFFIX" "$SCRIPTPATH/$ANYNAME"
1009 finish_installation "$ANYNAME"
1011 # state of installation
1012 elif [ "$REPLY" = "s" ]; then
1013 echo $E -n "Analyzing the state of installation of \`$ANYNAME'... "
1014 write_script "$SCRIPTPATH/$ANYNAME.$SUFFIX" "$TEMPFILE.script" -q
1015 grep "^##" "$TEMPFILE.script" > "$TEMPDIR/$ANYNAME.$SOFAR"
1016 if [ -s "$TEMPDIR/$ANYNAME.$SOFAR" ]; then
1017 echo >> "$TEMPDIR/$ANYNAME.$SOFAR"
1019 permissions "$TEMPFILE.script" >> "$TEMPDIR/$ANYNAME.$SOFAR" 2>&1
1020 echo "done."
1021 show_result "$TEMPDIR/$ANYNAME.$SOFAR"
1023 # enable quick finish of installation
1024 if [ $? -eq 0 ]; then
1025 echo -n "Use state information and finish installation now? $(novice '[no/yes]')"
1026 read
1027 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
1028 echo -n "State information may be out of date. Please confirm: $(novice '[no/yes]')"
1029 read
1030 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
1031 echo $E -n "Creating de-installation script \`$SCRIPTPATH/$ANYNAME'... "
1032 trap 'cleanup "$SCRIPTPATH/$ANYNAME"' SIGINT
1033 mv "$TEMPFILE.script" "$SCRIPTPATH/$ANYNAME"
1034 trap "" SIGINT
1035 echo "done."
1036 finish_installation "$ANYNAME"
1037 else
1038 echo "No."
1040 else
1041 echo "No."
1045 # revoke installation
1046 elif [ "$REPLY" = "r" ]; then
1047 echo $E -n "Revoking the installation of \`$ANYNAME'... Sure? $(novice '[no/yes]')"
1048 read
1049 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
1050 rm "$SCRIPTPATH/$ANYNAME.$SUFFIX"
1051 rm -f "$SCRIPTPATH/$ANYNAME.$PIOOPT"
1052 echo "Done."
1053 else
1054 echo "Nothing done."
1055 exit 1
1058 # quit
1059 else
1060 echo "Nothing done."
1061 exit 1
1064 # new installation
1065 else
1067 check_directories
1069 if [ -e "$SCRIPTPATH/$ANYNAME" ]; then
1070 echo $E "\`$ANYNAME' seems to be installed."
1071 echo "What about removing the script first?"
1072 exit 1
1073 elif no_other_pre_inst_file; then
1074 echo $E -n "Preparing to observe the installation of \`$ANYNAME'... "
1075 trap 'cleanup "$SCRIPTPATH/$ANYNAME".{"$SUFFIX","$PIOOPT"}' SIGINT
1076 find_filenames | sort > "$SCRIPTPATH/$ANYNAME.$SUFFIX"
1077 if [ $OPTIONS -ne 0 ]; then
1078 echo $E "$WATCHDIRS" | sed "s:^:w:" > "$SCRIPTPATH/$ANYNAME.$PIOOPT"
1079 echo $E "$IGNOREDIRS" | sed "s:^:i:" >> "$SCRIPTPATH/$ANYNAME.$PIOOPT"
1081 trap "" SIGINT
1082 if [ -f "$SCRIPTPATH/$ANYNAME.$SUFFIX" ]; then
1083 #PGR-16a: make sure before and after timestamps aren't the same
1084 sleep 2
1085 echo "done."
1086 else
1087 echo "failed!"
1088 exit 1
1090 else
1091 echo "Nothing done."
1092 exit 1
1096 exit 0