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")
30 #PGR-16e: reorganized configuration section
31 #--------------------------------------------------------------------------
35 #PGR During LFS-Ch5 stage1 build when $LFS is defined externally
37 SHOWRESULT
=yes # default answer to 'Show it?'
40 SCRIPTPATH
=$LFS/$SNAME ;;
42 #PGR During LFS-Ch6 stage2 build
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 ;;
49 #PGR After LFS-Ch6 stage 2 complete, general ops
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 ;;
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
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 ...]
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
132 BACKUPPATH
=$SCRIPTPATH/backups
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
145 # ...allows subshells started by this script to handle those filenames properly
147 if [ ".$1" = ".--cwd" ]; then
149 TEMPDIR
=$
(pwd)/$SNAME.$$
151 TEMPDIR
=${TMPDIR:-/tmp}/$SNAME.$$
153 TEMPFILE
=$TEMPDIR/$SNAME
155 function novice
() # $1: string to return
157 if [ "$EXPERT" = no
]; then
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 \)" |
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."
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"
230 echo $E "$ID for \`$(basename "$1" ".
$SUFFIX")'," |
sed "s:^:# :" >> "$2"
231 echo "# created by $LNAME $VERSION.$SUBVER on $(date)" >> "$2"
233 if grep -q "?" "$TEMPFILE.new" "$TEMPFILE.del"; then
235 echo '" # some filenames contain newlines expressed by ${NL}' >> "$2"
238 if [ -s "$TEMPFILE.del" ]; then
239 echo "## WARNING!" >> "$2"
241 echo "## This is a list of files that seem to have been deleted during installation:" >> "$2"
243 cat "$TEMPFILE.del" | translate_filenames
"#" |
sed "s:^# rm...:## :" |
sort >> "$2"
245 echo "## End of WARNING" >> "$2"
248 echo "$SNAME --xcheck" '"$(basename "$0")"' >> "$2"
249 echo 'echo -n "Ok to start de-installation? "' >> "$2"
251 echo 'if [ ".$REPLY" != ".y" -a ".$REPLY" != ".yes" ]; then' >> "$2"
252 echo ' echo "No, aborted."' >> "$2"
255 echo -n ' echo -n "Removing \`$(basename "$0")' >> "$2"
256 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"
262 #PGR updated syntax for POSIX-200112 standard (klugey, I know)
263 sort -t : -k1.9
-r "$TEMPFILE.rm" >> "$2" # puts files before directory
265 echo 'chmod -x "$0"' >> "$2"
266 echo 'echo "done."' >> "$2"
267 echo 'echo -n "Remove script, too? "' >> "$2"
269 echo 'if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then' >> "$2"
270 echo ' rm "$0"' >> "$2"
272 echo ' echo "It has been made non-executable instead."' >> "$2"
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."
290 elif [ -z "$VIEWPROG" ]; then
291 echo -n "Can't show it, press enter. "
294 echo -n "Show it? [$SHOWRESULT] "
296 REPLY
=${REPLY:-$SHOWRESULT}
297 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
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")
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
352 if [ -z "$FILES" ]; then
356 if [ "$DEPENDENCIES" ]; then
357 echo $E "$DEPENDENCIES"
364 function permissions
() # $1: script
366 COL
="\([^ ]\+\)\( \+\)" # a column (with delimiter)
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"
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
394 */*) echo $E "Will not handle \`$1' (containing a slash)!"
400 function chkscript
() # $1: ANYNAME
403 if [ ! -f "$SCRIPTPATH/$1" ]; then
404 echo $E "\`$SCRIPTPATH/$1' does not exist!"
406 elif sed -n "3p" "$SCRIPTPATH/$1" |
grep -q "$ID"; then
409 echo $E "\`$SCRIPTPATH/$1' does not seem to be a de-installation script!"
414 function chkbakpath
()
416 if [ ! -d "$BACKUPPATH" ]; then
417 echo -n "Ok to create backup directory $BACKUPPATH? $(novice '[no/yes]')"
419 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
420 mkdir
-p "$BACKUPPATH" ||
exit 1
428 function check_paths
() # $@: directories to check
433 /*) if [ ! -d "$p" ]; then
434 echo $E "Warning: \`$p' does not exist!"
438 *) echo $E "Will not accept \`$p' (not an absolute path)!"
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
463 echo "function $SNAME ()"
465 echo ' if [ ".$1" = ".--cd" ]; then'
466 echo " cd \"$SCRIPTPATH\""
468 echo " command $SNAME" '"$@"'
471 echo "export -f $SNAME"
473 if [ ".$PROFILEVAR" = ".*default*" ]; then
477 case "$PROFILEVAR" in *[^a-zA-Z0-9_
]* |
[0-9]* | _
)
478 echo "$SNAME --profile: \`$PROFILEVAR' is not a valid variable name." >&2
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
495 *\'*) echo $E "$1" |
sed -e "s:':'\\\'':g" -e "1s:^:':" -e '$s:$:'\'':'
502 function option_list
() # $@: command line
507 --watch) WATCHDIRS
=""
509 OPTIONS
=$
((OPTIONS |
1))
511 --ignore) IGNOREDIRS
=""
513 OPTIONS
=$
((OPTIONS |
2))
520 *) if [ -z "$CURROPT" ]; then
522 elif [ $CURROPT = --watch ]; then
523 WATCHDIRS
="$WATCHDIRS $(quote "$p")"
524 elif [ $CURROPT = --ignore ]; then
525 IGNOREDIRS
="$IGNOREDIRS $(quote "$p")"
533 WATCHDIRS
=${WATCHDIRS# }
534 IGNOREDIRS
=${IGNOREDIRS# }
537 function prune_statement
() # $@: directories to ignore
541 PRUNE
="$PRUNE -path $(quote "$p") -prune -o"
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."
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:^.::")
567 function finish_installation
() # $1: ANYNAME
569 chmod u
+x
"$SCRIPTPATH/$1"
570 rm "$SCRIPTPATH/$1.$SUFFIX"
571 rm -f "$SCRIPTPATH/$1.$PIOOPT"
573 show_result
"$SCRIPTPATH/$1"
576 function check_directories
()
578 if [ -z "$WATCHDIRS" ]; then
579 echo "Nothing to watch."
583 eval check_paths
"$WATCHDIRS $IGNOREDIRS"
585 if [ $?
-ne 0 -a $OPTIONS -ne 0 ]; then
586 echo -n "Continue anyway? $(novice '[no/yes]')"
588 if [ ".$REPLY" != ".y" -a ".$REPLY" != ".yes" ]; then
594 eval prune_statement
"$IGNOREDIRS"
597 function cleanup
() # $@: files to delete
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
613 HEADER
="Use of libraries found in \`$3'."
615 HEADER
="Use of \`$2' found in \`$3'."
618 NOREGEX
=$
(noregex
"$2")
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" |
628 [^
$WSPACE]*) FILE
=$REPLY
630 *) [ "$HEADER" ] && echo && echo $E "$HEADER" && HEADER
=""
631 [ "$FILE" ] && echo $E "$FILE" && FILE
=""
638 function dependencies
() # $1: search pattern
640 NOREGEX
=$
(noregex
"$1")
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 ;" |
663 function touch_script
() # $1: script, $2: save/restore
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"
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
683 touch_script
"$1" save
685 if grep -q "^#: $3: " "$1"; then
688 elif grep -q "^#: " "$1"; then
692 MAGIC
="^[$WSPACE]*\$"
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"
707 if [ "$PRESERVE" = yes ]; then
708 touch_script
"$1" restore
713 function edit_script
() # $1: script
715 touch_script
"$1" save
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]')"
730 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
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]')"
745 if [ ".$REPLY" != ".y" -a ".$REPLY" != ".yes" ]; then
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"
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."
765 if [ ! -x "$1" ]; then
767 echo "$1 made executable again."
770 echo "Oops! $ID $1 doesn't exist anymore."
771 # Yes, backup is restored even if deinstall script is missing.
774 echo "Restore returned error code $?"
777 echo "$BACKUPPATH/$2.$BACKUPEXT doesn't exist."
781 #PGR-16f: compare current files to contents of backup
785 mkdir
$TEMPDIR/CHECK
#branch for temporary restore
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."
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+,.:_-]."
805 if echo "\t" |
grep -q "t"; then
807 elif echo -E "\t" |
grep -q "t"; then
810 echo "Warning: Your \`echo' can't handle backslash-escaped characters literally."
814 trap 'trap "" SIGINT; rm -rf "$TEMPDIR"' EXIT
815 trap 'echo "interrupted!"; exit 1' SIGINT
818 if [ ".$1" = ".--ls" ]; then
820 cd "$SCRIPTPATH" && $LSPROG -- "$2"*
822 elif [ ".$1" = ".--lsbak" ]; then
825 cd "$BACKUPPATH" && $LSPROG -- "$2"*
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 {} "$@"
834 elif [ ".$2" = ".--lib" -a $# -le 3 ]; then
835 ANYNAME
=${1#"$SCRIPTPATH/"}
837 lddlib
"$SCRIPTPATH/$ANYNAME" "$3" "$ANYNAME"
842 3) ANYNAME
=${1#"$SCRIPTPATH/"}
843 DEPNAME
=${3#"$SCRIPTPATH/"}
845 --requires) chkscript
"$ANYNAME"
847 depend
"$SCRIPTPATH/$ANYNAME" "$DEPNAME" "$DEPEND"
850 --uses) chkscript
"$ANYNAME"
852 depend
"$SCRIPTPATH/$ANYNAME" "$DEPNAME" "$USE_OF"
855 --supports) chkscript
"$ANYNAME"
857 depend
"$SCRIPTPATH/$ANYNAME" "$DEPNAME" "$USED_BY"
865 2) ANYNAME
=${2#"$SCRIPTPATH/"}
867 --xcheck) chkscript
"$ANYNAME"
868 xcheck
"$SCRIPTPATH/$ANYNAME" "$ANYNAME"
871 --remove) chkscript
"$ANYNAME"
874 exec "$SCRIPTPATH/$ANYNAME"
876 --backup) chkscript
"$ANYNAME"
878 backup
"$SCRIPTPATH/$ANYNAME" "$ANYNAME"
881 #PGR added "restore" command so we don't have to run tar from / and chmod
882 --restore) chkname
"$ANYNAME"
884 restore
"$SCRIPTPATH/$ANYNAME" "$ANYNAME"
887 #PGR added "check" command to validate current files & backup
888 --check) chkname
"$ANYNAME"
895 --list) chkscript
"$ANYNAME"
896 permissions
"$SCRIPTPATH/$ANYNAME"
899 --files) chkscript
"$ANYNAME"
900 files
"$SCRIPTPATH/$ANYNAME" |
tr "\0" "\n"
903 --files0) chkscript
"$ANYNAME"
904 files
"$SCRIPTPATH/$ANYNAME"
907 --edit) chkscript
"$ANYNAME"
908 edit_script
"$SCRIPTPATH/$ANYNAME"
911 --find) find_script
"$2"
914 --dirs) chkname
"$ANYNAME"
924 --cd) echo "Option --cd isn't available, use \`cd $SCRIPTPATH' instead."
936 --help) echo "$USAGE"
939 --version) echo "$SNAME - $LNAME $VERSION.$SUBVER"
960 # called first time ever
961 if [ ! -d "$SCRIPTPATH" ]; then
962 echo -n "Ok to create script directory $SCRIPTPATH? $(novice '[no/yes]')"
964 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
965 mkdir
-p "$SCRIPTPATH" ||
exit 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:^.::")
989 echo $E "Observing the installation of \`$ANYNAME'."
991 until [ "$REPLY" ]; do
992 echo -n "What shall $SNAME do now (s/r/f/q)? $(novice '[Press enter for help]')"
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"
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
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]')"
1027 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
1028 echo -n "State information may be out of date. Please confirm: $(novice '[no/yes]')"
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"
1036 finish_installation
"$ANYNAME"
1045 # revoke installation
1046 elif [ "$REPLY" = "r" ]; then
1047 echo $E -n "Revoking the installation of \`$ANYNAME'... Sure? $(novice '[no/yes]')"
1049 if [ ".$REPLY" = ".y" -o ".$REPLY" = ".yes" ]; then
1050 rm "$SCRIPTPATH/$ANYNAME.$SUFFIX"
1051 rm -f "$SCRIPTPATH/$ANYNAME.$PIOOPT"
1054 echo "Nothing done."
1060 echo "Nothing done."
1069 if [ -e "$SCRIPTPATH/$ANYNAME" ]; then
1070 echo $E "\`$ANYNAME' seems to be installed."
1071 echo "What about removing the script first?"
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"
1082 if [ -f "$SCRIPTPATH/$ANYNAME.$SUFFIX" ]; then
1083 #PGR-16a: make sure before and after timestamps aren't the same
1091 echo "Nothing done."