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