Git init
[framework/uifw/xorg/proto/x11proto-xf86dga.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_unlikely_path_chars () {
97   # syntax: reject_unlikely_path_chars [ operand ... ]
98   #
99   # scan operands (typically shell variables whose values cannot be trusted) for
100   # characters unlikely to be seen in a path and which the shell might
101   # interpret and barf if any are found
102   while [ -n "$1" ]; do
103     # does the operand contain any funny characters?
104     if expr "$1" : '.*[!$&()*;<>?|].*' > /dev/null 2>&1; then
105       # can't use die(), because I want to avoid forward references
106       echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_unlikely_path_chars()" \
107            "encountered possibly malicious garbage \"$1\"" >&2
108       exit $SHELL_LIB_THROWN_ERROR
109     fi
110     shift
111   done
112 }
113
114 # Query the terminal to establish a default number of columns to use for
115 # displaying messages to the user.  This is used only as a fallback in the
116 # event the COLUMNS variable is not set.  ($COLUMNS can react to SIGWINCH while
117 # the script is running, and this cannot, only being calculated once.)
118 DEFCOLUMNS=$(stty size 2> /dev/null | awk '{print $2}') || true
119 if ! expr "$DEFCOLUMNS" : "[[:digit:]]\+$" > /dev/null 2>&1; then
120   DEFCOLUMNS=80
121 fi
122
123 message () {
124   # pretty-print messages of arbitrary length
125   reject_nondigits "$COLUMNS"
126   echo "$*" | fmt -t -w ${COLUMNS:-$DEFCOLUMNS} >&2
127 }
128
129 observe () {
130   # syntax: observe message ...
131   #
132   # issue observational message suitable for logging someday when support for
133   # it exists in dpkg
134   if [ -n "$DEBUG_XORG_PACKAGE" ]; then
135     message "$THIS_PACKAGE $THIS_SCRIPT note: $*"
136   fi
137 }
138
139 warn () {
140   # syntax: warn message ...
141   #
142   # issue warning message suitable for logging someday when support for
143   # it exists in dpkg; also send to standard error
144   message "$THIS_PACKAGE $THIS_SCRIPT warning: $*"
145 }
146
147 die () {
148   # syntax: die message ...
149   #
150   # exit script with error message
151   message "$THIS_PACKAGE $THIS_SCRIPT error: $*"
152   exit $SHELL_LIB_THROWN_ERROR
153 }
154
155 internal_error () {
156   # exit script with error; essentially a "THIS SHOULD NEVER HAPPEN" message
157   message "internal error: $*"
158   if [ -n "$OFFICIAL_BUILD" ]; then
159     message "Please report a bug in the $THIS_SCRIPT script of the" \
160             "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \
161             "Tracking System.  Include all messages above that mention the" \
162             "$THIS_PACKAGE package.  Visit " \
163             "<http://www.debian.org/Bugs/Reporting> on the World Wide Web for" \
164             "instructions, read the file" \
165             "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \
166             "package, or install the reportbug package and use the command of" \
167             "the same name to file a report."
168   fi
169   exit $SHELL_LIB_INTERNAL_ERROR
170 }
171
172 usage_error () {
173   message "usage error: $*"
174   message "Please report a bug in the $THIS_SCRIPT script of the" \
175           "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \
176           "Tracking System.  Include all messages above that mention the" \
177           "$THIS_PACKAGE package.  Visit " \
178           "<http://www.debian.org/Bugs/Reporting> on the World Wide Web for" \
179           "instructions, read the file" \
180           "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \
181           "package, or install the reportbug package and use the command of" \
182           "the same name to file a report."
183   exit $SHELL_LIB_USAGE_ERROR
184 }
185
186 font_update () {
187   # run $UPDATECMDS in $FONTDIRS
188
189   local dir cmd shortcmd x_font_dir_prefix
190
191   x_font_dir_prefix="/usr/share/fonts/X11"
192
193   if [ -z "$UPDATECMDS" ]; then
194     usage_error "font_update() called but \$UPDATECMDS not set"
195   fi
196   if [ -z "$FONTDIRS" ]; then
197     usage_error "font_update() called but \$FONTDIRS not set"
198   fi
199
200   reject_unlikely_path_chars "$UPDATECMDS"
201   reject_unlikely_path_chars "$FONTDIRS"
202
203   for dir in $FONTDIRS; do
204     if [ -d "$x_font_dir_prefix/$dir" ]; then
205       for cmd in $UPDATECMDS; do
206         if which "$cmd" > /dev/null 2>&1; then
207           shortcmd=${cmd##*/}
208           observe "running $shortcmd in $dir font directory"
209           cmd_opts=
210           if [ "$shortcmd" = "update-fonts-alias" ]; then
211             cmd_opts=--x11r7-layout
212           fi
213           if [ "$shortcmd" = "update-fonts-dir" ]; then
214             cmd_opts=--x11r7-layout
215           fi
216           if [ "$shortcmd" = "update-fonts-scale" ]; then
217             cmd_opts=--x11r7-layout
218           fi
219           $cmd $cmd_opts $dir || warn "$cmd $cmd_opts $dir" \
220                               "failed; font directory data may not" \
221                               "be up to date"
222         else
223           warn "$cmd not found; not updating corresponding $dir font" \
224                "directory data"
225         fi
226       done
227     else
228       warn "$dir is not a directory; not updating font directory data"
229     fi
230   done
231 }
232
233 remove_conffile_prepare () {
234   # syntax: remove_conffile_prepare filename official_md5sum ...
235   #
236   # Check a conffile "filename" against a list of canonical MD5 checksums.
237   # If the file's current MD5 checksum matches one of the "official_md5sum"
238   # operands provided, then prepare the conffile for removal from the system.
239   # We defer actual deletion until the package is configured so that we can
240   # roll this operation back if package installation fails.
241   #
242   # Call this function from a preinst script in the event $1 is "upgrade" or
243   # "install" and verify $2 to ensure the package is being upgraded from a
244   # version (or installed over a version removed-but-not-purged) prior to the
245   # one in which the conffile was obsoleted.
246
247   local conffile current_checksum
248
249   # validate arguments
250   if [ $# -lt 2 ]; then
251     usage_error "remove_conffile_prepare() called with wrong number of" \
252                 "arguments; expected at least 2, got $#"
253     exit $SHELL_LIB_USAGE_ERROR
254   fi
255
256   conffile="$1"
257   shift
258
259   # does the conffile even exist?
260   if [ -e "$conffile" ]; then
261     # calculate its checksum
262     current_checksum=$(md5sum < "$conffile" | sed 's/[[:space:]].*//')
263     # compare it to each supplied checksum
264     while [ -n "$1" ]; do
265       if [ "$current_checksum" = "$1" ]; then
266         # we found a match; move the confffile and stop looking
267         observe "preparing obsolete conffile $conffile for removal"
268         mv "$conffile" "$conffile.$THIS_PACKAGE-tmp"
269         break
270       fi
271       shift
272     done
273   fi
274 }
275
276 remove_conffile_lookup () {
277   # syntax: remove_conffile_lookup package filename
278   #
279   # Lookup the md5sum of a conffile in dpkg's database, and prepare for removal
280   # if it matches the actual file's md5sum.
281   #
282   # Call this function when you would call remove_conffile_prepare but only
283   # want to check against dpkg's status database instead of known checksums.
284
285   local package conffile old_md5sum
286
287   # validate arguments
288   if [ $# -ne 2 ]; then
289     usage_error "remove_conffile_lookup() called with wrong number of" \
290                 "arguments; expected 1, got $#"
291     exit $SHELL_LIB_USAGE_ERROR
292   fi
293
294   package="$1"
295   conffile="$2"
296
297   if ! [ -e "$conffile" ]; then
298     return
299   fi
300   old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$package" | \
301     awk '{ if (match($0, "^ '"$conffile"' ")) print $2}')"
302   if [ -n "$old_md5sum" ]; then
303     remove_conffile_prepare "$conffile" "$old_md5sum"
304   fi
305 }
306
307 remove_conffile_commit () {
308   # syntax: remove_conffile_commit filename
309   #
310   # Complete the removal of a conffile "filename" that has become obsolete.
311   #
312   # Call this function from a postinst script after having used
313   # remove_conffile_prepare() in the preinst.
314
315   local conffile
316
317   # validate arguments
318   if [ $# -ne 1 ]; then
319     usage_error "remove_conffile_commit() called with wrong number of" \
320                 "arguments; expected 1, got $#"
321     exit $SHELL_LIB_USAGE_ERROR
322   fi
323
324   conffile="$1"
325
326   # if the temporary file created by remove_conffile_prepare() exists, remove it
327   if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then
328     observe "committing removal of obsolete conffile $conffile"
329     rm "$conffile.$THIS_PACKAGE-tmp"
330   fi
331 }
332
333 remove_conffile_rollback () {
334   # syntax: remove_conffile_rollback filename
335   #
336   # Roll back the removal of a conffile "filename".
337   #
338   # Call this function from a postrm script in the event $1 is "abort-upgrade"
339   # or "abort-install" is  after having used remove_conffile_prepare() in the
340   # preinst.
341
342   local conffile
343
344   # validate arguments
345   if [ $# -ne 1 ]; then
346     usage_error "remove_conffile_rollback() called with wrong number of" \
347                 "arguments; expected 1, got $#"
348     exit $SHELL_LIB_USAGE_ERROR
349   fi
350
351   conffile="$1"
352
353   # if the temporary file created by remove_conffile_prepare() exists, move it
354   # back
355   if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then
356     observe "rolling back removal of obsolete conffile $conffile"
357     mv "$conffile.$THIS_PACKAGE-tmp" "$conffile"
358   fi
359 }
360
361 replace_conffile_with_symlink_prepare () {
362   # syntax: replace_conffile_with_symlink_prepare oldfilename newfilename \
363   # official_md5sum ...
364   #
365   # Check a conffile "oldfilename" against a list of canonical MD5 checksums.
366   # If the file's current MD5 checksum matches one of the "official_md5sum"
367   # operands provided, then prepare the conffile for removal from the system.
368   # We defer actual deletion until the package is configured so that we can
369   # roll this operation back if package installation fails. Otherwise copy it
370   # to newfilename and let dpkg handle it through conffiles mechanism.
371   #
372   # Call this function from a preinst script in the event $1 is "upgrade" or
373   # "install" and verify $2 to ensure the package is being upgraded from a
374   # version (or installed over a version removed-but-not-purged) prior to the
375   # one in which the conffile was obsoleted.
376
377   local conffile current_checksum
378
379   # validate arguments
380   if [ $# -lt 3 ]; then
381     usage_error "replace_conffile_with_symlink_prepare() called with wrong" \
382                 " number of arguments; expected at least 3, got $#"
383     exit $SHELL_LIB_USAGE_ERROR
384   fi
385
386   oldconffile="$1"
387   shift
388   newconffile="$1"
389   shift
390
391   remove_conffile_prepare "$_oldconffile" "$@"
392   # If $oldconffile still exists, then md5sums didn't match.
393   # Copy it to new one.
394   if [ -f "$oldconffile" ]; then
395     cp "$oldconffile" "$newconffile"
396   fi
397
398 }
399
400 replace_conffile_with_symlink_commit () {
401   # syntax: replace_conffile_with_symlink_commit oldfilename
402   #
403   # Complete the removal of a conffile "oldfilename" that has been
404   # replaced by a symlink.
405   #
406   # Call this function from a postinst script after having used
407   # replace_conffile_with_symlink_prepare() in the preinst.
408
409   local conffile
410
411   # validate arguments
412   if [ $# -ne 1 ]; then
413     usage_error "replace_conffile_with_symlink_commit() called with wrong" \
414                 "number of arguments; expected 1, got $#"
415     exit $SHELL_LIB_USAGE_ERROR
416   fi
417
418   conffile="$1"
419
420   remove_conffile_commit "$conffile"
421 }
422
423 replace_conffile_with_symlink_rollback () {
424   # syntax: replace_conffile_with_symlink_rollback oldfilename newfilename
425   #
426   # Roll back the replacing of a conffile "oldfilename" with symlink to
427   # "newfilename".
428   #
429   # Call this function from a postrm script in the event $1 is "abort-upgrade"
430   # or "abort-install" and verify $2 to ensure the package failed to upgrade
431   # from a version (or install over a version removed-but-not-purged) prior
432   # to the one in which the conffile was obsoleted.
433   # You should have  used replace_conffile_with_symlink_prepare() in the
434   # preinst.
435
436   local conffile
437
438   # validate arguments
439   if [ $# -ne 2 ]; then
440     usage_error "replace_conffile_with_symlink_rollback() called with wrong" \
441                 "number of arguments; expected 2, got $#"
442     exit $SHELL_LIB_USAGE_ERROR
443   fi
444
445   oldconffile="$1"
446   newconffile="$2"
447
448   remove_conffile_rollback "$_oldconffile"
449   if [ -f "$newconffile" ]; then
450     rm "$newconffile"
451   fi
452 }
453
454 run () {
455   # syntax: run command [ argument ... ]
456   #
457   # Run specified command with optional arguments and report its exit status.
458   # Useful for commands whose exit status may be nonzero, but still acceptable,
459   # or commands whose failure is not fatal to us.
460   #
461   # NOTE: Do *not* use this function with db_get or db_metaget commands; in
462   # those cases the return value of the debconf command *must* be checked
463   # before the string returned by debconf is used for anything.
464
465   local retval
466
467   # validate arguments
468   if [ $# -lt 1 ]; then
469     usage_error "run() called with wrong number of arguments; expected at" \
470                 "least 1, got $#"
471     exit $SHELL_LIB_USAGE_ERROR
472   fi
473
474   "$@" || retval=$?
475
476   if [ ${retval:-0} -ne 0 ]; then
477     observe "command \"$*\" exited with status $retval"
478   fi
479 }
480
481 make_symlink_sane () {
482   # syntax: make_symlink_sane symlink target
483   #
484   # Ensure that the symbolic link symlink exists, and points to target.
485   #
486   # If symlink does not exist, create it and point it at target.
487   #
488   # If symlink exists but is not a symbolic link, back it up.
489   #
490   # If symlink exists, is a symbolic link, but points to the wrong location, fix
491   # it.
492   #
493   # If symlink exists, is a symbolic link, and already points to target, do
494   # nothing.
495   #
496   # This function wouldn't be needed if ln had an -I, --idempotent option.
497
498   # Validate arguments.
499   if [ $# -ne 2 ]; then
500     usage_error "make_symlink_sane() called with wrong number of arguments;" \
501       "expected 2, got $#"
502     exit $SHELL_LIB_USAGE_ERROR
503   fi
504
505   # We could just use the positional parameters as-is, but that makes things
506   # harder to follow.
507   local symlink target
508
509   symlink="$1"
510   target="$2"
511
512   if [ -L "$symlink" ] && [ "$(readlink "$symlink")" = "$target" ]; then
513       observe "link from $symlink to $target already exists"
514   else
515     observe "creating symbolic link from $symlink to $target"
516     mkdir -p "${target%/*}" "${symlink%/*}"
517     ln -s -b -S ".dpkg-old" "$target" "$symlink"
518   fi
519 }
520
521 migrate_dir_to_symlink () {
522   # syntax: migrate_dir_to_symlink old_location new_location
523   #
524   # Per Debian Policy section 6.5.4, "A directory will never be replaced by a
525   # symbolic link to a directory or vice versa; instead, the existing state
526   # (symlink or not) will be left alone and dpkg will follow the symlink if
527   # there is one."
528   #
529   # We have to do it ourselves.
530   #
531   # This function moves the contents of old_location, a directory, into
532   # new_location, a directory, then makes old_location a symbolic link to
533   # new_location.
534   #
535   # old_location need not exist, but if it does, it must be a directory (or a
536   # symlink to a directory).  If it is not, it is backed up.  If new_location
537   # exists already and is not a directory, it is backed up.
538   #
539   # This function should be called from a package's preinst so that other
540   # packages unpacked after this one --- but before this package's postinst runs
541   # --- are unpacked into new_location even if their payloads contain
542   # old_location filespecs.
543
544   # Validate arguments.
545   if [ $# -ne 2 ]; then
546     usage_error "migrate_dir_to_symlink() called with wrong number of"
547                 "arguments; expected 2, got $#"
548     exit $SHELL_LIB_USAGE_ERROR
549   fi
550
551   # We could just use the positional parameters as-is, but that makes things
552   # harder to follow.
553   local new old
554
555   old="$1"
556   new="$2"
557
558   # Is old location a symlink?
559   if [ -L "$old" ]; then
560     # Does it already point to new location?
561     if [ "$(readlink "$old")" = "$new" ]; then
562       # Nothing to do; migration has already been done.
563       observe "migration of $old to $new already done"
564       return 0
565     else
566       # Back it up.
567       warn "backing up symbolic link $old as $old.dpkg-old"
568       mv -b "$old" "$old.dpkg-old"
569     fi
570   fi
571
572   # Does old location exist, but is not a directory?
573   if [ -e "$old" ] && ! [ -d "$old" ]; then
574       # Back it up.
575       warn "backing up non-directory $old as $old.dpkg-old"
576       mv -b "$old" "$old.dpkg-old"
577   fi
578
579   observe "migrating $old to $new"
580
581   # Is new location a symlink?
582   if [ -L "$new" ]; then
583     # Does it point the wrong way, i.e., back to where we're migrating from?
584     if [ "$(readlink "$new")" = "$old" ]; then
585       # Get rid of it.
586       observe "removing symbolic link $new which points to $old"
587       rm "$new"
588     else
589       # Back it up.
590       warn "backing up symbolic link $new as $new.dpkg-old"
591       mv -b "$new" "$new.dpkg-old"
592     fi
593   fi
594
595   # Does new location exist, but is not a directory?
596   if [ -e "$new" ] && ! [ -d "$new" ]; then
597     warn "backing up non-directory $new as $new.dpkg-old"
598     mv -b "$new" "$new.dpkg-old"
599   fi
600
601   # Create new directory if it does not yet exist.
602   if ! [ -e "$new" ]; then
603     observe "creating $new"
604     mkdir -p "$new"
605   fi
606
607   # Copy files in old location to new location.  Back up any filenames that
608   # already exist in the new location with the extension ".dpkg-old".
609   observe "copying files from $old to $new"
610   if ! (cd "$old" && cp -a -b -S ".dpkg-old" . "$new"); then
611     die "error(s) encountered while copying files from $old to $new"
612   fi
613
614   # Remove files at old location.
615   observe "removing $old"
616   rm -r "$old"
617
618   # Create symlink from old location to new location.
619   make_symlink_sane "$old" "$new"
620 }
621
622 # vim:set ai et sw=2 ts=2 tw=80:
623
624 # GOBSTOPPER: The X Strike Force shell library ends here.