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
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
15 SOURCE_VERSION=@SOURCE_VERSION@
16 OFFICIAL_BUILD=@OFFICIAL_BUILD@
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
24 # old -> new variable names
25 if [ -z "$DEBUG_XORG_PACKAGE" ] && [ -n "$DEBUG_XFREE86_PACKAGE" ]; then
26 DEBUG_XORG_PACKAGE="$DEBUG_XFREE86_PACKAGE"
28 if [ -z "$DEBUG_XORG_DEBCONF" ] && [ -n "$DEBUG_XFREE86_DEBCONF" ]; then
29 DEBUG_XORG_DEBCONF="$DEBUG_XFREE86_DEBCONF"
32 # initial sanity checks
33 if [ -z "$THIS_PACKAGE" ]; then
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.
43 exit $SHELL_LIB_USAGE_ERROR
46 if [ -z "$THIS_SCRIPT" ]; then
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.
57 exit $SHELL_LIB_USAGE_ERROR
60 if [ "$1" = "reconfigure" ] || [ -n "$DEBCONF_RECONFIGURE" ]; then
66 if ([ "$1" = "install" ] || [ "$1" = "configure" ]) && [ -z "$2" ]; then
70 if [ -z "$RECONFIGURE" ] && [ -z "$FIRSTINST" ]; then
75 message \"Received signal. Aborting $THIS_PACKAGE package $THIS_SCRIPT script.\";\
77 exit 1" HUP INT QUIT TERM
80 # syntax: reject_nondigits [ operand ... ]
82 # scan operands (typically shell variables whose values cannot be trusted) for
83 # characters other than decimal digits and barf if any are found
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
96 reject_unlikely_path_chars () {
97 # syntax: reject_unlikely_path_chars [ operand ... ]
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
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
124 # pretty-print messages of arbitrary length
125 reject_nondigits "$COLUMNS"
126 echo "$*" | fmt -t -w ${COLUMNS:-$DEFCOLUMNS} >&2
130 # syntax: observe message ...
132 # issue observational message suitable for logging someday when support for
134 if [ -n "$DEBUG_XORG_PACKAGE" ]; then
135 message "$THIS_PACKAGE $THIS_SCRIPT note: $*"
140 # syntax: warn message ...
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: $*"
148 # syntax: die message ...
150 # exit script with error message
151 message "$THIS_PACKAGE $THIS_SCRIPT error: $*"
152 exit $SHELL_LIB_THROWN_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."
169 exit $SHELL_LIB_INTERNAL_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
187 # run $UPDATECMDS in $FONTDIRS
189 local dir cmd shortcmd x_font_dir_prefix
191 x_font_dir_prefix="/usr/share/fonts/X11"
193 if [ -z "$UPDATECMDS" ]; then
194 usage_error "font_update() called but \$UPDATECMDS not set"
196 if [ -z "$FONTDIRS" ]; then
197 usage_error "font_update() called but \$FONTDIRS not set"
200 reject_unlikely_path_chars "$UPDATECMDS"
201 reject_unlikely_path_chars "$FONTDIRS"
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
208 observe "running $shortcmd in $dir font directory"
210 if [ "$shortcmd" = "update-fonts-alias" ]; then
211 cmd_opts=--x11r7-layout
213 if [ "$shortcmd" = "update-fonts-dir" ]; then
214 cmd_opts=--x11r7-layout
216 if [ "$shortcmd" = "update-fonts-scale" ]; then
217 cmd_opts=--x11r7-layout
219 $cmd $cmd_opts $dir || warn "$cmd $cmd_opts $dir" \
220 "failed; font directory data may not" \
223 warn "$cmd not found; not updating corresponding $dir font" \
228 warn "$dir is not a directory; not updating font directory data"
233 remove_conffile_prepare () {
234 # syntax: remove_conffile_prepare filename official_md5sum ...
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.
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.
247 local conffile current_checksum
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
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"
276 remove_conffile_lookup () {
277 # syntax: remove_conffile_lookup package filename
279 # Lookup the md5sum of a conffile in dpkg's database, and prepare for removal
280 # if it matches the actual file's md5sum.
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.
285 local package conffile old_md5sum
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
297 if ! [ -e "$conffile" ]; then
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"
307 remove_conffile_commit () {
308 # syntax: remove_conffile_commit filename
310 # Complete the removal of a conffile "filename" that has become obsolete.
312 # Call this function from a postinst script after having used
313 # remove_conffile_prepare() in the preinst.
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
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"
333 remove_conffile_rollback () {
334 # syntax: remove_conffile_rollback filename
336 # Roll back the removal of a conffile "filename".
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
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
353 # if the temporary file created by remove_conffile_prepare() exists, move it
355 if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then
356 observe "rolling back removal of obsolete conffile $conffile"
357 mv "$conffile.$THIS_PACKAGE-tmp" "$conffile"
361 replace_conffile_with_symlink_prepare () {
362 # syntax: replace_conffile_with_symlink_prepare oldfilename newfilename \
363 # official_md5sum ...
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.
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.
377 local conffile current_checksum
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
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"
400 replace_conffile_with_symlink_commit () {
401 # syntax: replace_conffile_with_symlink_commit oldfilename
403 # Complete the removal of a conffile "oldfilename" that has been
404 # replaced by a symlink.
406 # Call this function from a postinst script after having used
407 # replace_conffile_with_symlink_prepare() in the preinst.
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
420 remove_conffile_commit "$conffile"
423 replace_conffile_with_symlink_rollback () {
424 # syntax: replace_conffile_with_symlink_rollback oldfilename newfilename
426 # Roll back the replacing of a conffile "oldfilename" with symlink to
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
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
448 remove_conffile_rollback "$_oldconffile"
449 if [ -f "$newconffile" ]; then
455 # syntax: run command [ argument ... ]
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.
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.
468 if [ $# -lt 1 ]; then
469 usage_error "run() called with wrong number of arguments; expected at" \
471 exit $SHELL_LIB_USAGE_ERROR
476 if [ ${retval:-0} -ne 0 ]; then
477 observe "command \"$*\" exited with status $retval"
481 make_symlink_sane () {
482 # syntax: make_symlink_sane symlink target
484 # Ensure that the symbolic link symlink exists, and points to target.
486 # If symlink does not exist, create it and point it at target.
488 # If symlink exists but is not a symbolic link, back it up.
490 # If symlink exists, is a symbolic link, but points to the wrong location, fix
493 # If symlink exists, is a symbolic link, and already points to target, do
496 # This function wouldn't be needed if ln had an -I, --idempotent option.
498 # Validate arguments.
499 if [ $# -ne 2 ]; then
500 usage_error "make_symlink_sane() called with wrong number of arguments;" \
502 exit $SHELL_LIB_USAGE_ERROR
505 # We could just use the positional parameters as-is, but that makes things
512 if [ -L "$symlink" ] && [ "$(readlink "$symlink")" = "$target" ]; then
513 observe "link from $symlink to $target already exists"
515 observe "creating symbolic link from $symlink to $target"
516 mkdir -p "${target%/*}" "${symlink%/*}"
517 ln -s -b -S ".dpkg-old" "$target" "$symlink"
521 migrate_dir_to_symlink () {
522 # syntax: migrate_dir_to_symlink old_location new_location
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
529 # We have to do it ourselves.
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
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.
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.
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
551 # We could just use the positional parameters as-is, but that makes things
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"
567 warn "backing up symbolic link $old as $old.dpkg-old"
568 mv -b "$old" "$old.dpkg-old"
572 # Does old location exist, but is not a directory?
573 if [ -e "$old" ] && ! [ -d "$old" ]; then
575 warn "backing up non-directory $old as $old.dpkg-old"
576 mv -b "$old" "$old.dpkg-old"
579 observe "migrating $old to $new"
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
586 observe "removing symbolic link $new which points to $old"
590 warn "backing up symbolic link $new as $new.dpkg-old"
591 mv -b "$new" "$new.dpkg-old"
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"
601 # Create new directory if it does not yet exist.
602 if ! [ -e "$new" ]; then
603 observe "creating $new"
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"
614 # Remove files at old location.
615 observe "removing $old"
618 # Create symlink from old location to new location.
619 make_symlink_sane "$old" "$new"
622 # vim:set ai et sw=2 ts=2 tw=80:
624 # GOBSTOPPER: The X Strike Force shell library ends here.