72efa950d3276968f8405e8fecc32ea5a4572e77
[framework/uifw/xorg/lib/libdri2.git] / debian / xsfbs / xsfbs.sh
1 # $Id$
2
3 # This is the X Strike Force shell library for X Window System package
4 # maintainer scripts.  It serves to define shell functions commonly used by
5 # such packages, and performs some error checking necessary for proper operation
6 # of those functions.  By itself, it does not "do" much; the maintainer scripts
7 # invoke the functions defined here to accomplish package installation and
8 # removal tasks.
9
10 # If you are reading this within a Debian package maintainer script (e.g.,
11 # /var/lib/dpkg)info/PACKAGE.{config,preinst,postinst,prerm,postrm}), you can
12 # skip past this library by scanning forward in this file to the string
13 # "GOBSTOPPER".
14
15 SOURCE_VERSION=@SOURCE_VERSION@
16 OFFICIAL_BUILD=@OFFICIAL_BUILD@
17
18 # Use special abnormal exit codes so that problems with this library are more
19 # easily tracked down.
20 SHELL_LIB_INTERNAL_ERROR=86
21 SHELL_LIB_THROWN_ERROR=74
22 SHELL_LIB_USAGE_ERROR=99
23
24 # old -> new variable names
25 if [ -z "$DEBUG_XORG_PACKAGE" ] && [ -n "$DEBUG_XFREE86_PACKAGE" ]; then
26   DEBUG_XORG_PACKAGE="$DEBUG_XFREE86_PACKAGE"
27 fi
28 if [ -z "$DEBUG_XORG_DEBCONF" ] && [ -n "$DEBUG_XFREE86_DEBCONF" ]; then
29   DEBUG_XORG_DEBCONF="$DEBUG_XFREE86_DEBCONF"
30 fi
31
32 # initial sanity checks
33 if [ -z "$THIS_PACKAGE" ]; then
34   cat >&2 <<EOF
35 Error: package maintainer script attempted to use shell library without
36 definining \$THIS_PACKAGE shell variable.  Please report the package name,
37 version, and the text of this error message to the Debian Bug Tracking System.
38 Visit <http://www.debian.org/Bugs/Reporting> on the World Wide Web for
39 instructions, read the file /usr/share/doc/debian/bug-reporting.txt from the
40 "doc-debian" package, or install the "reportbug" package and use the command of
41 the same name to file a report against version $SOURCE_VERSION of this package.
42 EOF
43   exit $SHELL_LIB_USAGE_ERROR
44 fi
45
46 if [ -z "$THIS_SCRIPT" ]; then
47   cat >&2 <<EOF
48 Error: package maintainer script attempted to use shell library without
49 definining \$THIS_SCRIPT shell variable.  Please report the package name,
50 version, and the text of this error message to the Debian Bug Tracking System.
51 Visit <http://www.debian.org/Bugs/Reporting> on the World Wide Web for
52 instructions, read the file /usr/share/doc/debian/bug-reporting.txt from the
53 "doc-debian" package, or install the "reportbug" package and use the command of
54 the same name to file a report against version $SOURCE_VERSION of the
55 "$THIS_PACKAGE" package.
56 EOF
57   exit $SHELL_LIB_USAGE_ERROR
58 fi
59
60 ARCHITECTURE="$(dpkg --print-installation-architecture)"
61
62 if [ "$1" = "reconfigure" ] || [ -n "$DEBCONF_RECONFIGURE" ]; then
63   RECONFIGURE="true"
64 else
65   RECONFIGURE=
66 fi
67
68 if ([ "$1" = "install" ] || [ "$1" = "configure" ]) && [ -z "$2" ]; then
69   FIRSTINST="yes"
70 fi
71
72 if [ -z "$RECONFIGURE" ] && [ -z "$FIRSTINST" ]; then
73   UPGRADE="yes"
74 fi
75
76 trap "message;\
77       message \"Received signal.  Aborting $THIS_PACKAGE package $THIS_SCRIPT script.\";\
78       message;\
79       exit 1" HUP INT QUIT TERM
80
81 reject_nondigits () {
82   # syntax: reject_nondigits [ operand ... ]
83   #
84   # scan operands (typically shell variables whose values cannot be trusted) for
85   # characters other than decimal digits and barf if any are found
86   while [ -n "$1" ]; do
87     # does the operand contain anything but digits?
88     if ! expr "$1" : "[[:digit:]]\+$" > /dev/null 2>&1; then
89       # can't use die(), because it wraps message() which wraps this function
90       echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_nondigits() encountered" \
91            "possibly malicious garbage \"$1\"" >&2
92       exit $SHELL_LIB_THROWN_ERROR
93     fi
94     shift
95   done
96 }
97
98 reject_whitespace () {
99   # syntax: reject_whitespace [ operand ]
100   #
101   # scan operand (typically a shell variable whose value cannot be trusted) for
102   # whitespace characters and barf if any are found
103   if [ -n "$1" ]; then
104     # does the operand contain any whitespace?
105     if expr "$1" : "[[:space:]]" > /dev/null 2>&1; then
106       # can't use die(), because I want to avoid forward references
107       echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_whitespace() encountered" \
108            "possibly malicious garbage \"$1\"" >&2
109       exit $SHELL_LIB_THROWN_ERROR
110     fi
111   fi
112 }
113
114 reject_unlikely_path_chars () {
115   # syntax: reject_unlikely_path_chars [ operand ... ]
116   #
117   # scan operands (typically shell variables whose values cannot be trusted) for
118   # characters unlikely to be seen in a path and which the shell might
119   # interpret and barf if any are found
120   while [ -n "$1" ]; do
121     # does the operand contain any funny characters?
122     if expr "$1" : '.*[!$&()*;<>?|].*' > /dev/null 2>&1; then
123       # can't use die(), because I want to avoid forward references
124       echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_unlikely_path_chars()" \
125            "encountered possibly malicious garbage \"$1\"" >&2
126       exit $SHELL_LIB_THROWN_ERROR
127     fi
128     shift
129   done
130 }
131
132 # Query the terminal to establish a default number of columns to use for
133 # displaying messages to the user.  This is used only as a fallback in the
134 # event the COLUMNS variable is not set.  ($COLUMNS can react to SIGWINCH while
135 # the script is running, and this cannot, only being calculated once.)
136 DEFCOLUMNS=$(stty size 2> /dev/null | awk '{print $2}') || true
137 if ! expr "$DEFCOLUMNS" : "[[:digit:]]\+$" > /dev/null 2>&1; then
138   DEFCOLUMNS=80
139 fi
140
141 message () {
142   # pretty-print messages of arbitrary length
143   reject_nondigits "$COLUMNS"
144   echo "$*" | fmt -t -w ${COLUMNS:-$DEFCOLUMNS} >&2
145 }
146
147 observe () {
148   # syntax: observe message ...
149   #
150   # issue observational message suitable for logging someday when support for
151   # it exists in dpkg
152   if [ -n "$DEBUG_XORG_PACKAGE" ]; then
153     message "$THIS_PACKAGE $THIS_SCRIPT note: $*"
154   fi
155 }
156
157 warn () {
158   # syntax: warn message ...
159   #
160   # issue warning message suitable for logging someday when support for
161   # it exists in dpkg; also send to standard error
162   message "$THIS_PACKAGE $THIS_SCRIPT warning: $*"
163 }
164
165 die () {
166   # syntax: die message ...
167   #
168   # exit script with error message
169   message "$THIS_PACKAGE $THIS_SCRIPT error: $*"
170   exit $SHELL_LIB_THROWN_ERROR
171 }
172
173 internal_error () {
174   # exit script with error; essentially a "THIS SHOULD NEVER HAPPEN" message
175   message "internal error: $*"
176   if [ -n "$OFFICIAL_BUILD" ]; then
177     message "Please report a bug in the $THIS_SCRIPT script of the" \
178             "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \
179             "Tracking System.  Include all messages above that mention the" \
180             "$THIS_PACKAGE package.  Visit " \
181             "<http://www.debian.org/Bugs/Reporting> on the World Wide Web for" \
182             "instructions, read the file" \
183             "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \
184             "package, or install the reportbug package and use the command of" \
185             "the same name to file a report."
186   fi
187   exit $SHELL_LIB_INTERNAL_ERROR
188 }
189
190 usage_error () {
191   message "usage error: $*"
192   message "Please report a bug in the $THIS_SCRIPT script of the" \
193           "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \
194           "Tracking System.  Include all messages above that mention the" \
195           "$THIS_PACKAGE package.  Visit " \
196           "<http://www.debian.org/Bugs/Reporting> on the World Wide Web for" \
197           "instructions, read the file" \
198           "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \
199           "package, or install the reportbug package and use the command of" \
200           "the same name to file a report."
201   exit $SHELL_LIB_USAGE_ERROR
202 }
203
204
205 maplink () {
206   # returns what symlink should point to; i.e., what the "sane" answer is
207   # Keep this in sync with the debian/*.links files.
208   # This is only needed for symlinks to directories.
209   #
210   # XXX: Most of these look wrong in the X11R7 world and need to be fixed.
211   # If we've stopped using this function, fixing it might enable us to re-enable
212   # it again and catch more errors.
213   case "$1" in
214     /etc/X11/xkb/compiled) echo /var/lib/xkb ;;
215     /etc/X11/xkb/xkbcomp) echo /usr/X11R6/bin/xkbcomp ;;
216     /usr/X11R6/lib/X11/app-defaults) echo /etc/X11/app-defaults ;;
217     /usr/X11R6/lib/X11/fs) echo /etc/X11/fs ;;
218     /usr/X11R6/lib/X11/lbxproxy) echo /etc/X11/lbxproxy ;;
219     /usr/X11R6/lib/X11/proxymngr) echo /etc/X11/proxymngr ;;
220     /usr/X11R6/lib/X11/rstart) echo /etc/X11/rstart ;;
221     /usr/X11R6/lib/X11/twm) echo /etc/X11/twm ;;
222     /usr/X11R6/lib/X11/xdm) echo /etc/X11/xdm ;;
223     /usr/X11R6/lib/X11/xinit) echo /etc/X11/xinit ;;
224     /usr/X11R6/lib/X11/xkb) echo /etc/X11/xkb ;;
225     /usr/X11R6/lib/X11/xserver) echo /etc/X11/xserver ;;
226     /usr/X11R6/lib/X11/xsm) echo /etc/X11/xsm ;;
227     /usr/bin/X11) echo ../X11R6/bin ;;
228     /usr/bin/rstartd) echo ../X11R6/bin/rstartd ;;
229     /usr/include/X11) echo ../X11R6/include/X11 ;;
230     /usr/lib/X11) echo ../X11R6/lib/X11 ;;
231     *) internal_error "maplink() called with unknown path \"$1\"" ;;
232   esac
233 }
234
235 analyze_path () {
236   # given a supplied set of pathnames, break each one up by directory and do an
237   # ls -dl on each component, cumulatively; i.e.
238   # analyze_path /usr/X11R6/bin -> ls -dl /usr /usr/X11R6 /usr/X11R6/bin
239   # Thanks to Randolph Chung for this clever hack.
240
241   local f g
242
243   while [ -n "$1" ]; do
244     reject_whitespace "$1"
245     g=
246     message "Analyzing $1:"
247     for f in $(echo "$1" | tr / \  ); do
248       if [ -e /$g$f ]; then
249         ls -dl /$g$f /$g$f.dpkg-* 2> /dev/null || true
250         g=$g$f/
251       else
252         message "/$g$f: nonexistent; directory contents of /$g:"
253         ls -l /$g
254         break
255       fi
256     done
257     shift
258   done
259 }
260
261 find_culprits () {
262   local f p dpkg_info_dir possible_culprits smoking_guns bad_packages package \
263     msg
264
265   reject_whitespace "$1"
266   message "Searching for overlapping packages..."
267   dpkg_info_dir=/var/lib/dpkg/info
268   if [ -d $dpkg_info_dir ]; then
269     if [ "$(echo $dpkg_info_dir/*.list)" != "$dpkg_info_dir/*.list" ]; then
270       possible_culprits=$(ls -1 $dpkg_info_dir/*.list | egrep -v \
271         "(xbase-clients|x11-common|xfs|xlibs)")
272       if [ -n "$possible_culprits" ]; then
273         smoking_guns=$(grep -l "$1" $possible_culprits || true)
274         if [ -n "$smoking_guns" ]; then
275           bad_packages=$(printf "\\n")
276           for f in $smoking_guns; do
277             # too bad you can't nest parameter expansion voodoo
278             p=${f%*.list}      # strip off the trailing ".list"
279             package=${p##*/}   # strip off the directories
280             bad_packages=$(printf "%s\n%s" "$bad_packages" "$package")
281           done
282           msg=$(cat <<EOF
283 The following packages appear to have file overlaps with the X.Org packages;
284 these packages are either very old, or in violation of Debian Policy.  Try
285 upgrading each of these packages to the latest available version if possible:
286 for example, with the command "apt-get install".  If no newer version of a
287 package is available, you will have to remove it; for example, with the command
288 "apt-get remove".  If even the latest available version of the package has
289 this file overlap, please file a bug against that package with the Debian Bug
290 Tracking System.  You may want to refer the package maintainer to section 12.8
291 of the Debian Policy manual.
292 EOF
293 )
294           message "$msg"
295           message "The overlapping packages are: $bad_packages"
296         else
297           message "no overlaps found."
298         fi
299       fi
300     else
301       message "cannot search; no matches for $dpkg_info_dir/*.list."
302     fi
303   else
304     message "cannot search; $dpkg_info_dir does not exist."
305   fi
306 }
307
308 # we require a readlink command or shell function
309 if ! which readlink > /dev/null 2>&1; then
310   message "The readlink command was not found.  Please install version" \
311           "1.13.1 or later of the debianutils package."
312   readlink () {
313     # returns what symlink in $1 actually points to
314     perl -e '$l = shift; exit 1 unless -l $l; $r = readlink $l; exit 1 unless $r; print "$r\n"' "$1"
315   }
316 fi
317
318 check_symlink () {
319   # syntax: check_symlink symlink
320   #
321   # See if specified symlink points where it is supposed to.  Return 0 if it
322   # does, and 1 if it does not.
323   #
324   # Primarily used by check_symlinks_and_warn() and check_symlinks_and_bomb().
325
326   local symlink
327
328   # validate arguments
329   if [ $# -ne 1 ]; then
330     usage_error "check_symlink() called with wrong number of arguments;" \
331                 "expected 1, got $#"
332     exit $SHELL_LIB_USAGE_ERROR
333   fi
334
335   symlink="$1"
336
337   if [ "$(maplink "$symlink")" = "$(readlink "$symlink")" ]; then
338     return 0
339   else
340     return 1
341   fi
342 }
343
344 check_symlinks_and_warn () {
345   # syntax: check_symlinks_and_warn symlink ...
346   #
347   # For each argument, check for symlink sanity, and warn if it isn't sane.
348   #
349   # Call this function from a preinst script in the event $1 is "upgrade" or
350   # "install".
351
352   local errmsg symlink
353
354   # validate arguments
355   if [ $# -lt 1 ]; then
356     usage_error "check_symlinks_and_warn() called with wrong number of" \
357                 "arguments; expected at least 1, got $#"
358     exit $SHELL_LIB_USAGE_ERROR
359   fi
360
361   while [ -n "$1" ]; do
362     symlink="$1"
363     if [ -L "$symlink" ]; then
364       if ! check_symlink "$symlink"; then
365         observe "$symlink symbolic link points to wrong location" \
366                 "$(readlink "$symlink"); removing"
367         rm "$symlink"
368       fi
369     elif [ -e "$symlink" ]; then
370       errmsg="$symlink exists and is not a symbolic link; this package cannot"
371       errmsg="$errmsg be installed until this"
372       if [ -f "$symlink" ]; then
373         errmsg="$errmsg file"
374       elif [ -d "$symlink" ]; then
375         errmsg="$errmsg directory"
376       else
377         errmsg="$errmsg thing"
378       fi
379       errmsg="$errmsg is removed"
380       die "$errmsg"
381     fi
382     shift
383   done
384 }
385
386 check_symlinks_and_bomb () {
387   # syntax: check_symlinks_and_bomb symlink ...
388   #
389   # For each argument, check for symlink sanity, and bomb if it isn't sane.
390   #
391   # Call this function from a postinst script.
392
393   local problem symlink
394
395   # validate arguments
396   if [ $# -lt 1 ]; then
397     usage_error "check_symlinks_and_bomb() called with wrong number of"
398                 "arguments; expected at least 1, got $#"
399     exit $SHELL_LIB_USAGE_ERROR
400   fi
401
402   while [ -n "$1" ]; do
403     problem=
404     symlink="$1"
405     if [ -L "$symlink" ]; then
406       if ! check_symlink "$symlink"; then
407         problem=yes
408         warn "$symlink symbolic link points to wrong location" \
409              "$(readlink "$symlink")"
410       fi
411     elif [ -e "$symlink" ]; then
412       problem=yes
413       warn "$symlink is not a symbolic link"
414     else
415       problem=yes
416       warn "$symlink symbolic link does not exist"
417     fi
418     if [ -n "$problem" ]; then
419       analyze_path "$symlink" "$(readlink "$symlink")"
420       find_culprits "$symlink"
421       die "bad symbolic links on system"
422     fi
423     shift
424   done
425 }
426
427 font_update () {
428   # run $UPDATECMDS in $FONTDIRS
429
430   local dir cmd shortcmd x_font_dir_prefix
431
432   x_font_dir_prefix="/usr/share/fonts/X11"
433
434   if [ -z "$UPDATECMDS" ]; then
435     usage_error "font_update() called but \$UPDATECMDS not set"
436   fi
437   if [ -z "$FONTDIRS" ]; then
438     usage_error "font_update() called but \$FONTDIRS not set"
439   fi
440
441   reject_unlikely_path_chars "$UPDATECMDS"
442   reject_unlikely_path_chars "$FONTDIRS"
443
444   for dir in $FONTDIRS; do
445     if [ -d "$x_font_dir_prefix/$dir" ]; then
446       for cmd in $UPDATECMDS; do
447         if which "$cmd" > /dev/null 2>&1; then
448           shortcmd=${cmd##*/}
449           observe "running $shortcmd in $dir font directory"
450           cmd_opts=
451           if [ "$shortcmd" = "update-fonts-alias" ]; then
452             cmd_opts=--x11r7-layout
453           fi
454           if [ "$shortcmd" = "update-fonts-dir" ]; then
455             cmd_opts=--x11r7-layout
456           fi
457           if [ "$shortcmd" = "update-fonts-scale" ]; then
458             cmd_opts=--x11r7-layout
459           fi
460           $cmd $cmd_opts $dir || warn "$cmd $cmd_opts $dir" \
461                               "failed; font directory data may not" \
462                               "be up to date"
463         else
464           warn "$cmd not found; not updating corresponding $dir font" \
465                "directory data"
466         fi
467       done
468     else
469       warn "$dir is not a directory; not updating font directory data"
470     fi
471   done
472 }
473
474 remove_conffile_prepare () {
475   # syntax: remove_conffile_prepare filename official_md5sum ...
476   #
477   # Check a conffile "filename" against a list of canonical MD5 checksums.
478   # If the file's current MD5 checksum matches one of the "official_md5sum"
479   # operands provided, then prepare the conffile for removal from the system.
480   # We defer actual deletion until the package is configured so that we can
481   # roll this operation back if package installation fails.
482   #
483   # Call this function from a preinst script in the event $1 is "upgrade" or
484   # "install" and verify $2 to ensure the package is being upgraded from a
485   # version (or installed over a version removed-but-not-purged) prior to the
486   # one in which the conffile was obsoleted.
487
488   local conffile current_checksum
489
490   # validate arguments
491   if [ $# -lt 2 ]; then
492     usage_error "remove_conffile_prepare() called with wrong number of" \
493                 "arguments; expected at least 2, got $#"
494     exit $SHELL_LIB_USAGE_ERROR
495   fi
496
497   conffile="$1"
498   shift
499
500   # does the conffile even exist?
501   if [ -e "$conffile" ]; then
502     # calculate its checksum
503     current_checksum=$(md5sum < "$conffile" | sed 's/[[:space:]].*//')
504     # compare it to each supplied checksum
505     while [ -n "$1" ]; do
506       if [ "$current_checksum" = "$1" ]; then
507         # we found a match; move the confffile and stop looking
508         observe "preparing obsolete conffile $conffile for removal"
509         mv "$conffile" "$conffile.$THIS_PACKAGE-tmp"
510         break
511       fi
512       shift
513     done
514   fi
515 }
516
517 remove_conffile_lookup () {
518   # syntax: remove_conffile_lookup package filename
519   #
520   # Lookup the md5sum of a conffile in dpkg's database, and prepare for removal
521   # if it matches the actual file's md5sum.
522   #
523   # Call this function when you would call remove_conffile_prepare but only
524   # want to check against dpkg's status database instead of known checksums.
525
526   local package conffile old_md5sum
527
528   # validate arguments
529   if [ $# -ne 2 ]; then
530     usage_error "remove_conffile_lookup() called with wrong number of" \
531                 "arguments; expected 1, got $#"
532     exit $SHELL_LIB_USAGE_ERROR
533   fi
534
535   package="$1"
536   conffile="$2"
537
538   if ! [ -e "$conffile" ]; then
539     return
540   fi
541   old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$package" | \
542     awk '{ if (match($0, "^ '"$conffile"' ")) print $2}')"
543   if [ -n "$old_md5sum" ]; then
544     remove_conffile_prepare "$conffile" "$old_md5sum"
545   fi
546 }
547
548 remove_conffile_commit () {
549   # syntax: remove_conffile_commit filename
550   #
551   # Complete the removal of a conffile "filename" that has become obsolete.
552   #
553   # Call this function from a postinst script after having used
554   # remove_conffile_prepare() in the preinst.
555
556   local conffile
557
558   # validate arguments
559   if [ $# -ne 1 ]; then
560     usage_error "remove_conffile_commit() called with wrong number of" \
561                 "arguments; expected 1, got $#"
562     exit $SHELL_LIB_USAGE_ERROR
563   fi
564
565   conffile="$1"
566
567   # if the temporary file created by remove_conffile_prepare() exists, remove it
568   if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then
569     observe "committing removal of obsolete conffile $conffile"
570     rm "$conffile.$THIS_PACKAGE-tmp"
571   fi
572 }
573
574 remove_conffile_rollback () {
575   # syntax: remove_conffile_rollback filename
576   #
577   # Roll back the removal of a conffile "filename".
578   #
579   # Call this function from a postrm script in the event $1 is "abort-upgrade"
580   # or "abort-install" is  after having used remove_conffile_prepare() in the
581   # preinst.
582
583   local conffile
584
585   # validate arguments
586   if [ $# -ne 1 ]; then
587     usage_error "remove_conffile_rollback() called with wrong number of" \
588                 "arguments; expected 1, got $#"
589     exit $SHELL_LIB_USAGE_ERROR
590   fi
591
592   conffile="$1"
593
594   # if the temporary file created by remove_conffile_prepare() exists, move it
595   # back
596   if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then
597     observe "rolling back removal of obsolete conffile $conffile"
598     mv "$conffile.$THIS_PACKAGE-tmp" "$conffile"
599   fi
600 }
601
602 replace_conffile_with_symlink_prepare () {
603   # syntax: replace_conffile_with_symlink_prepare oldfilename newfilename \
604   # official_md5sum ...
605   #
606   # Check a conffile "oldfilename" against a list of canonical MD5 checksums.
607   # If the file's current MD5 checksum matches one of the "official_md5sum"
608   # operands provided, then prepare the conffile for removal from the system.
609   # We defer actual deletion until the package is configured so that we can
610   # roll this operation back if package installation fails. Otherwise copy it
611   # to newfilename and let dpkg handle it through conffiles mechanism.
612   #
613   # Call this function from a preinst script in the event $1 is "upgrade" or
614   # "install" and verify $2 to ensure the package is being upgraded from a
615   # version (or installed over a version removed-but-not-purged) prior to the
616   # one in which the conffile was obsoleted.
617
618   local conffile current_checksum
619
620   # validate arguments
621   if [ $# -lt 3 ]; then
622     usage_error "replace_conffile_with_symlink_prepare() called with wrong" \
623                 " number of arguments; expected at least 3, got $#"
624     exit $SHELL_LIB_USAGE_ERROR
625   fi
626
627   oldconffile="$1"
628   shift
629   newconffile="$1"
630   shift
631
632   remove_conffile_prepare "$_oldconffile" "$@"
633   # If $oldconffile still exists, then md5sums didn't match.
634   # Copy it to new one.
635   if [ -f "$oldconffile" ]; then
636     cp "$oldconffile" "$newconffile"
637   fi
638
639 }
640
641 replace_conffile_with_symlink_commit () {
642   # syntax: replace_conffile_with_symlink_commit oldfilename
643   #
644   # Complete the removal of a conffile "oldfilename" that has been
645   # replaced by a symlink.
646   #
647   # Call this function from a postinst script after having used
648   # replace_conffile_with_symlink_prepare() in the preinst.
649
650   local conffile
651
652   # validate arguments
653   if [ $# -ne 1 ]; then
654     usage_error "replace_conffile_with_symlink_commit() called with wrong" \
655                 "number of arguments; expected 1, got $#"
656     exit $SHELL_LIB_USAGE_ERROR
657   fi
658
659   conffile="$1"
660
661   remove_conffile_commit "$conffile"
662 }
663
664 replace_conffile_with_symlink_rollback () {
665   # syntax: replace_conffile_with_symlink_rollback oldfilename newfilename
666   #
667   # Roll back the replacing of a conffile "oldfilename" with symlink to
668   # "newfilename".
669   #
670   # Call this function from a postrm script in the event $1 is "abort-upgrade"
671   # or "abort-install" and verify $2 to ensure the package failed to upgrade
672   # from a version (or install over a version removed-but-not-purged) prior
673   # to the one in which the conffile was obsoleted.
674   # You should have  used replace_conffile_with_symlink_prepare() in the
675   # preinst.
676
677   local conffile
678
679   # validate arguments
680   if [ $# -ne 2 ]; then
681     usage_error "replace_conffile_with_symlink_rollback() called with wrong" \
682                 "number of arguments; expected 2, got $#"
683     exit $SHELL_LIB_USAGE_ERROR
684   fi
685
686   oldconffile="$1"
687   newconffile="$2"
688
689   remove_conffile_rollback "$_oldconffile"
690   if [ -f "$newconffile" ]; then
691     rm "$newconffile"
692   fi
693 }
694
695 run () {
696   # syntax: run command [ argument ... ]
697   #
698   # Run specified command with optional arguments and report its exit status.
699   # Useful for commands whose exit status may be nonzero, but still acceptable,
700   # or commands whose failure is not fatal to us.
701   #
702   # NOTE: Do *not* use this function with db_get or db_metaget commands; in
703   # those cases the return value of the debconf command *must* be checked
704   # before the string returned by debconf is used for anything.
705
706   local retval
707
708   # validate arguments
709   if [ $# -lt 1 ]; then
710     usage_error "run() called with wrong number of arguments; expected at" \
711                 "least 1, got $#"
712     exit $SHELL_LIB_USAGE_ERROR
713   fi
714
715   "$@" || retval=$?
716
717   if [ ${retval:-0} -ne 0 ]; then
718     observe "command \"$*\" exited with status $retval"
719   fi
720 }
721
722 register_x_lib_dir_with_ld_so () {
723   # syntax: register_x_lib_dir_with_ld_so
724   #
725   # Configure the dynamic loader ld.so to search /usr/X11R6/lib for shared
726   # libraries.
727   #
728   # Call this function from the postinst script of a package that places a
729   # shared library in /usr/X11R6/lib, before invoking ldconfig.
730
731   local dir ldsoconf
732
733   dir="/usr/X11R6/lib"
734   ldsoconf="/etc/ld.so.conf"
735
736   # is the line not already present?
737   if ! fgrep -qsx "$dir" "$ldsoconf"; then
738     observe "adding $dir directory to $ldsoconf"
739     echo "$dir" >> "$ldsoconf"
740   fi
741 }
742
743 deregister_x_lib_dir_with_ld_so () {
744   # syntax: deregister_x_lib_dir_with_ld_so
745   #
746   # Configure dynamic loader ld.so to not search /usr/X11R6/lib for shared
747   # libraries, if and only if no shared libaries remain there.
748   #
749   # Call this function from the postrm script of a package that places a shared
750   # library in /usr/X11R6/lib, in the event "$1" is "remove", and before
751   # invoking ldconfig.
752
753   local dir ldsoconf fgrep_status cmp_status
754
755   dir="/usr/X11R6/lib"
756   ldsoconf="/etc/ld.so.conf"
757
758   # is the line present?
759   if fgrep -qsx "$dir" "$ldsoconf"; then
760     # are there any shared objects in the directory?
761     if [ "$(echo "$dir"/lib*.so.*.*)" = "$dir/lib*.so.*.*" ]; then
762       # glob expansion produced nothing, so no shared libraries are present
763       observe "removing $dir directory from $ldsoconf"
764       # rewrite the file (very carefully)
765       set +e
766       fgrep -svx "$dir" "$ldsoconf" > "$ldsoconf.dpkg-tmp"
767       fgrep_status=$?
768       set -e
769       case $fgrep_status in
770         0|1) ;; # we don't actually care if any lines matched or not
771         *) die "error reading \"$ldsoconf\"; fgrep exited with status" \
772           "$fgrep_status" ;;
773       esac
774       set +e
775       cmp -s "$ldsoconf.dpkg-tmp" "$ldsoconf"
776       cmp_status=$?
777       set -e
778       case $cmp_status in
779         0) rm "$ldsoconf.dpkg-tmp" ;; # files are identical
780         1) mv "$ldsoconf.dpkg-tmp" "$ldsoconf" ;; # files differ
781         *) die "error comparing \"$ldsoconf.dpkg-tmp\" to \"$ldsoconf\";" \
782           "cmp exited with status $cmp_status" ;;
783       esac
784     fi
785   fi
786 }
787
788 make_symlink_sane () {
789   # syntax: make_symlink_sane symlink target
790   #
791   # Ensure that the symbolic link symlink exists, and points to target.
792   #
793   # If symlink does not exist, create it and point it at target.
794   #
795   # If symlink exists but is not a symbolic link, back it up.
796   #
797   # If symlink exists, is a symbolic link, but points to the wrong location, fix
798   # it.
799   #
800   # If symlink exists, is a symbolic link, and already points to target, do
801   # nothing.
802   #
803   # This function wouldn't be needed if ln had an -I, --idempotent option.
804
805   # Validate arguments.
806   if [ $# -ne 2 ]; then
807     usage_error "make_symlink_sane() called with wrong number of arguments;" \
808       "expected 2, got $#"
809     exit $SHELL_LIB_USAGE_ERROR
810   fi
811
812   # We could just use the positional parameters as-is, but that makes things
813   # harder to follow.
814   local symlink target
815
816   symlink="$1"
817   target="$2"
818
819   if [ -L "$symlink" ] && [ "$(readlink "$symlink")" = "$target" ]; then
820       observe "link from $symlink to $target already exists"
821   else
822     observe "creating symbolic link from $symlink to $target"
823     mkdir -p "${target%/*}" "${symlink%/*}"
824     ln -s -b -S ".dpkg-old" "$target" "$symlink"
825   fi
826 }
827
828 migrate_dir_to_symlink () {
829   # syntax: migrate_dir_to_symlink old_location new_location
830   #
831   # Per Debian Policy section 6.5.4, "A directory will never be replaced by a
832   # symbolic link to a directory or vice versa; instead, the existing state
833   # (symlink or not) will be left alone and dpkg will follow the symlink if
834   # there is one."
835   #
836   # We have to do it ourselves.
837   #
838   # This function moves the contents of old_location, a directory, into
839   # new_location, a directory, then makes old_location a symbolic link to
840   # new_location.
841   #
842   # old_location need not exist, but if it does, it must be a directory (or a
843   # symlink to a directory).  If it is not, it is backed up.  If new_location
844   # exists already and is not a directory, it is backed up.
845   #
846   # This function should be called from a package's preinst so that other
847   # packages unpacked after this one --- but before this package's postinst runs
848   # --- are unpacked into new_location even if their payloads contain
849   # old_location filespecs.
850
851   # Validate arguments.
852   if [ $# -ne 2 ]; then
853     usage_error "migrate_dir_to_symlink() called with wrong number of"
854                 "arguments; expected 2, got $#"
855     exit $SHELL_LIB_USAGE_ERROR
856   fi
857
858   # We could just use the positional parameters as-is, but that makes things
859   # harder to follow.
860   local new old
861
862   old="$1"
863   new="$2"
864
865   # Is old location a symlink?
866   if [ -L "$old" ]; then
867     # Does it already point to new location?
868     if [ "$(readlink "$old")" = "$new" ]; then
869       # Nothing to do; migration has already been done.
870       observe "migration of $old to $new already done"
871       return 0
872     else
873       # Back it up.
874       warn "backing up symbolic link $old as $old.dpkg-old"
875       mv -b "$old" "$old.dpkg-old"
876     fi
877   fi
878
879   # Does old location exist, but is not a directory?
880   if [ -e "$old" ] && ! [ -d "$old" ]; then
881       # Back it up.
882       warn "backing up non-directory $old as $old.dpkg-old"
883       mv -b "$old" "$old.dpkg-old"
884   fi
885
886   observe "migrating $old to $new"
887
888   # Is new location a symlink?
889   if [ -L "$new" ]; then
890     # Does it point the wrong way, i.e., back to where we're migrating from?
891     if [ "$(readlink "$new")" = "$old" ]; then
892       # Get rid of it.
893       observe "removing symbolic link $new which points to $old"
894       rm "$new"
895     else
896       # Back it up.
897       warn "backing up symbolic link $new as $new.dpkg-old"
898       mv -b "$new" "$new.dpkg-old"
899     fi
900   fi
901
902   # Does new location exist, but is not a directory?
903   if [ -e "$new" ] && ! [ -d "$new" ]; then
904     warn "backing up non-directory $new as $new.dpkg-old"
905     mv -b "$new" "$new.dpkg-old"
906   fi
907
908   # Create new directory if it does not yet exist.
909   if ! [ -e "$new" ]; then
910     observe "creating $new"
911     mkdir -p "$new"
912   fi
913
914   # Copy files in old location to new location.  Back up any filenames that
915   # already exist in the new location with the extension ".dpkg-old".
916   observe "copying files from $old to $new"
917   if ! (cd "$old" && cp -a -b -S ".dpkg-old" . "$new"); then
918     die "error(s) encountered while copying files from $old to $new"
919   fi
920
921   # Remove files at old location.
922   observe "removing $old"
923   rm -r "$old"
924
925   # Create symlink from old location to new location.
926   make_symlink_sane "$old" "$new"
927 }
928
929 # vim:set ai et sw=2 ts=2 tw=80:
930
931 # GOBSTOPPER: The X Strike Force shell library ends here.