aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiloslav Trmac <mitr@volny.cz>2006-05-08 23:54:06 +0000
committerMiloslav Trmac <mitr@volny.cz>2006-05-08 23:54:06 +0000
commit3bd074fd404b4863d811d0a50e9ef484523c6b57 (patch)
tree9c4ca48303377ab77a8a00d10561ba1e8afbab28
parent0414be84b33e98510feb1d0e281b089ba16b349d (diff)
downloadinitscripts-3bd074fd404b4863d811d0a50e9ef484523c6b57.tar
initscripts-3bd074fd404b4863d811d0a50e9ef484523c6b57.tar.gz
initscripts-3bd074fd404b4863d811d0a50e9ef484523c6b57.tar.bz2
initscripts-3bd074fd404b4863d811d0a50e9ef484523c6b57.tar.xz
initscripts-3bd074fd404b4863d811d0a50e9ef484523c6b57.zip
Fix handling of mount points with white space (#186713):
- src/fstab-decode.c, src/fstab-decode.8: New files. - src/Makefile: Build and install fstab-decode. - initscripts.spec: Add fstab-decode to %files - rc.d/init.d/functions (fstab_decode_str): New function. (__umount_loop, __umount_loopback_loop): Factor out from copy&pasted copies. (action): Fix command quoting. - rc.d/rc.sysinit: Correctly quote and decode mount points. - rc.d/init.d/halt: Use __umount_* and fstab-decode. (action): Rename from runcmd. Fix command quoting. - rc.d/init.d/netfs: Use __umount_*.
-rw-r--r--initscripts.spec1
-rwxr-xr-xrc.d/init.d/functions61
-rwxr-xr-xrc.d/init.d/halt110
-rwxr-xr-xrc.d/init.d/netfs79
-rwxr-xr-xrc.d/rc.sysinit21
-rw-r--r--src/Makefile4
-rw-r--r--src/fstab-decode.845
-rw-r--r--src/fstab-decode.c86
8 files changed, 247 insertions, 160 deletions
diff --git a/initscripts.spec b/initscripts.spec
index de6cd80b..3d8129ac 100644
--- a/initscripts.spec
+++ b/initscripts.spec
@@ -188,6 +188,7 @@ rm -rf $RPM_BUILD_ROOT
/bin/usleep
%attr(4755,root,root) /usr/sbin/usernetctl
/sbin/consoletype
+/sbin/fstab-decode
/sbin/genhostid
/sbin/getkey
%attr(2755,root,root) /sbin/netreport
diff --git a/rc.d/init.d/functions b/rc.d/init.d/functions
index 74fd3d05..f1844d54 100755
--- a/rc.d/init.d/functions
+++ b/rc.d/init.d/functions
@@ -68,6 +68,11 @@ else
INITLOG_ARGS=
fi
+# Interpret escape sequences in an fstab entry
+fstab_decode_str() {
+ fstab-decode echo "$1"
+}
+
# Check if $pid (could be plural) are running
checkpid() {
local i
@@ -78,6 +83,60 @@ checkpid() {
return 1
}
+# __umount_loop awk_program fstab_file first_msg retry_msg umount_args
+# awk_program should process fstab_file and return a list of fstab-encoded
+# paths; it doesn't have to handle comments in fstab_file.
+__umount_loop() {
+ local remaining sig=
+ local retry=3
+
+ remaining=$(LC_ALL=C awk "/^#/ {next} $1" "$2" | sort -r)
+ while [ -n "$remaining" -a "$retry" -gt 0 ]; do
+ if [ "$retry" -eq 3 ]; then
+ action "$3" fstab-decode umount $5 $remaining
+ else
+ action "$4" fstab-decode umount $5 $remaining
+ fi
+ sleep 2
+ remaining=$(LC_ALL=C awk "/^#/ {next} $1" "$2" | sort -r)
+ [ -z "$remaining" ] && break
+ fstab-decode /sbin/fuser -k -m $sig $remaining >/dev/null
+ sleep 5
+ retry=$(($retry -1))
+ sig=-9
+ done
+}
+
+# Similar to __umount loop above, specialized for loopback devices
+__umount_loopback_loop() {
+ local remaining devremaining sig=
+ local retry=3
+
+ remaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts)
+ devremaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts)
+ while [ -n "$remaining" -a "$retry" -gt 0 ]; do
+ if [ "$retry" -eq 3 ]; then
+ action $"Unmounting loopback filesystems: " \
+ fstab-decode umount $remaining
+ else
+ action $"Unmounting loopback filesystems (retry):" \
+ fstab-decode umount $remaining
+ fi
+ for dev in $devremaining ; do
+ losetup $dev > /dev/null 2>&1 && \
+ action $"Detaching loopback device $dev: " \
+ losetup -d $dev
+ done
+ remaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts)
+ devremaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts)
+ [ -z "$remaining" ] && break
+ fstab-decode /sbin/fuser -k -m $sig $remaining >/dev/null
+ sleep 5
+ retry=$(($retry -1))
+ sig=-9
+ done
+}
+
# __proc_pids {program} [pidfile]
# Set $pid to pids from /var/run* for {program}. $pid should be declared
# local in the caller.
@@ -442,7 +501,7 @@ action() {
echo -n "$STRING " > /etc/rhgb/temp/rhgb-console
fi
shift
- $* && success $"$STRING" || failure $"$STRING"
+ "$@" && success $"$STRING" || failure $"$STRING"
rc=$?
echo
if [ "${RHGB_STARTED:-}" != "" -a -w /etc/rhgb/temp/rhgb-console ]; then
diff --git a/rc.d/init.d/halt b/rc.d/init.d/halt
index 25fba6f7..d1ff19bf 100755
--- a/rc.d/init.d/halt
+++ b/rc.d/init.d/halt
@@ -11,24 +11,17 @@
NOLOCALE=1
. /etc/init.d/functions
-runcmd() {
+action() {
echo -n "$1 "
shift
if [ "$BOOTUP" = "color" ]; then
- $* && echo_success || echo_failure
+ "$@" && echo_success || echo_failure
else
- $*
+ "$@"
fi
echo
}
-halt_get_remaining() {
- awk '$2 ~ /^\/$|^\/proc|^\/dev/{next}
- $3 == "tmpfs" || $3 == "proc" {print $2 ; next}
- /(^#|loopfs|autofs|sysfs|^none|^\/dev\/ram|^\/dev\/root)/ {next}
- {print $2}' /proc/mounts
-}
-
# See how we were called.
case "$0" in
*halt)
@@ -57,9 +50,9 @@ esac
# Kill all processes.
[ "${BASH+bash}" = bash ] && enable kill
-runcmd $"Sending all processes the TERM signal..." /sbin/killall5 -15
+action $"Sending all processes the TERM signal..." /sbin/killall5 -15
sleep 5
-runcmd $"Sending all processes the KILL signal..." /sbin/killall5 -9
+action $"Sending all processes the KILL signal..." /sbin/killall5 -9
# Write to wtmp file before unmounting /var
/sbin/halt -w
@@ -67,13 +60,13 @@ runcmd $"Sending all processes the KILL signal..." /sbin/killall5 -9
# Save mixer settings, here for lack of a better place.
grep -q "\(alsa\)" /proc/devices
if [ $? = 0 -a -x /usr/sbin/alsactl ]; then
- runcmd $"Saving mixer settings" alsactl store
+ action $"Saving mixer settings" alsactl store
fi
# Save random seed
touch /var/lib/random-seed
chmod 600 /var/lib/random-seed
-runcmd $"Saving random seed: " dd if=/dev/urandom of=/var/lib/random-seed count=1 bs=512 2>/dev/null
+action $"Saving random seed: " dd if=/dev/urandom of=/var/lib/random-seed count=1 bs=512 2>/dev/null
# Sync the system clock.
ARC=0
@@ -118,87 +111,38 @@ case "$SRM" in
;;
esac
-runcmd $"Syncing hardware clock to system time" /sbin/hwclock $CLOCKFLAGS
+action $"Syncing hardware clock to system time" /sbin/hwclock $CLOCKFLAGS
# Try to unmount tmpfs filesystems to avoid swapping them in. Ignore failures.
tmpfs=$(awk '$2 ~ /^\/($|proc|dev)/ { next; }
$3 == "tmpfs" { print $2; }' /proc/mounts | sort -r)
-[ -n "$tmpfs" ] && umount $tmpfs 2>/dev/null
+[ -n "$tmpfs" ] && fstab-decode umount $tmpfs 2>/dev/null
# Turn off swap, then unmount file systems.
[ -f /proc/swaps ] && SWAPS=`awk '! /^Filename/ { print $1 }' /proc/swaps`
-[ -n "$SWAPS" ] && runcmd $"Turning off swap: " swapoff $SWAPS
+[ -n "$SWAPS" ] && action $"Turning off swap: " swapoff $SWAPS
-[ -x /sbin/quotaoff ] && runcmd $"Turning off quotas: " /sbin/quotaoff -aug
+[ -x /sbin/quotaoff ] && action $"Turning off quotas: " /sbin/quotaoff -aug
# Unmount file systems, killing processes if we have to.
# Unmount loopback stuff first
-remaining=`awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts`
-devremaining=`awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts`
-[ -n "$remaining" ] && {
- sig=
- retry=3
- while [ -n "$remaining" -a "$retry" -gt 0 ]
- do
- if [ "$retry" -lt 3 ]; then
- runcmd $"Unmounting loopback filesystems (retry):" umount $remaining
- else
- runcmd $"Unmounting loopback filesystems: " umount $remaining
- fi
- for dev in $devremaining ; do
- losetup $dev > /dev/null 2>&1 && \
- runcmd $"Detaching loopback device $dev: " losetup -d $dev
- done
- remaining=`awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts`
- devremaining=`awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts`
- [ -z "$remaining" ] && break
- /sbin/fuser -k -m $sig $remaining >/dev/null
- sleep 5
- retry=$(($retry -1))
- sig=-9
- done
-}
+__umount_loopback_loop
# Unmount RPC pipe file systems
-sig=
-retry=3
-remaining=`awk '$3 ~ /^rpc_pipefs$/ || $3 ~ /^rpc_svc_gss_pipefs$/ {print $2}' /proc/mounts`
-
-while [ -n "$remaining" -a "$retry" -gt 0 ]
-do
- if [ "$retry" -lt 3 ]; then
- runcmd $"Unmounting pipe file systems (retry): " umount -f $remaining
- else
- runcmd $"Unmounting pipe file systems: " umount -f $remaining
- fi
- sleep 2
- remaining=`awk '$3 ~ /^rpc_pipefs$/ || $3 ~ /^rpc_svc_gss_pipefs$/ {print $2}' /proc/mounts`
- [ -z "$remaining" ] && break
- /sbin/fuser -k -m $sig $remaining >/dev/null
- sleep 5
- retry=$(($retry-1))
- sig=-9
-done
-
-sig=
-retry=3
-remaining=`halt_get_remaining | sort -r`
+__umount_loop '$3 ~ /^rpc_pipefs$/ || $3 ~ /^rpc_svc_gss_pipefs$/ {print $2}' \
+ /proc/mounts \
+ $"Unmounting pipe file systems: " \
+ $"Unmounting pipe file systems (retry): " \
+ -f
+
+LANG=C __umount_loop '$2 ~ /^\/$|^\/proc|^\/dev/{next}
+ $3 == "tmpfs" || $3 == "proc" {print $2 ; next}
+ /(loopfs|autofs|sysfs|^none|^\/dev\/ram|^\/dev\/root)/ {next}
+ {print $2}' /proc/mounts \
+ $"Unmounting file systems: " \
+ $"Unmounting file systems (retry): " \
+ -f
-while [ -n "$remaining" -a "$retry" -gt 0 ]
-do
- if [ "$retry" -lt 3 ]; then
- LANG=C runcmd $"Unmounting file systems (retry): " umount -f $remaining
- else
- LANG=C runcmd $"Unmounting file systems: " umount -f $remaining
- fi
- sleep 2
- remaining=`halt_get_remaining | sort -r`
- [ -z "$remaining" ] && break
- /sbin/fuser -k -m $sig $remaining >/dev/null
- sleep 5
- retry=$(($retry-1))
- sig=-9
-done
[ -f /proc/bus/usb/devices ] && umount /proc/bus/usb
# remove the crash indicator flag
@@ -207,7 +151,7 @@ rm -f /.autofsck
# Try all file systems other than root and RAM disks, one last time.
mount | awk '!/( \/ |^\/dev\/root|^\/dev\/ram| \/proc )/ { print $3 }' | sort -r | \
while read line; do
- umount -f $line
+ fstab-decode umount -f $line
done
if [ -x /sbin/halt.local ]; then
@@ -217,7 +161,7 @@ fi
# Remount read only anything that's left mounted.
# echo $"Remounting remaining filesystems readonly"
mount | awk '{ print $3 }' | while read line; do
- mount -n -o ro,remount $line
+ fstab-decode mount -n -o ro,remount $line
done
# Now halt or reboot.
diff --git a/rc.d/init.d/netfs b/rc.d/init.d/netfs
index faab107e..59693d11 100755
--- a/rc.d/init.d/netfs
+++ b/rc.d/init.d/netfs
@@ -89,71 +89,20 @@ case "$1" in
;;
stop)
# Unmount loopback stuff first
- remaining=`LC_ALL=C awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts`
- devremaining=`LC_ALL=C awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts`
- [ -n "$remaining" ] && {
- sig=
- retry=3
- while [ -n "$remaining" -a "$retry" -gt 0 ]
- do
- if [ "$retry" -lt 3 ]; then
- action $"Unmounting loopback filesystems (retry):" umount $remaining
- else
- action $"Unmounting loopback filesystems: " umount $remaining
- fi
- for dev in $devremaining ; do
- losetup $dev >/dev/null 2>&1 && \
- action $"Detaching loopback device $dev: " losetup -d $dev
- done
- remaining=`LC_ALL=C awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts`
- devremaining=`LC_ALL=C awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts`
- [ -z "$remaining" ] && break
- /sbin/fuser -k -m $sig $remaining >/dev/null
- sleep 5
- retry=$(($retry -1))
- sig=-9
- done
- }
- [ -n "$NETDEVMTAB" ] && {
- sig=
- retry=3
- remaining=`LC_ALL=C awk '!/^#/ && $4 ~ /_netdev/ && $2 != "/" {print $2}' /etc/mtab`
- while [ -n "$remaining" -a "$retry" -gt 0 ]
- do
- if [ "$retry" -lt 3 ]; then
- action $"Unmounting network block filesystems (retry): " umount -a -O _netdev
- else
- action $"Unmounting network block filesystems: " umount -a -O _netdev
- fi
- sleep 2
- remaining=`LC_ALL=C awk '!/^#/ && $4 ~ /_netdev/ && $2 != "/" {print $2}' /etc/mtab`
- [ -z "$remaining" ] && break
- /sbin/fuser -k -m $sig $remaining >/dev/null
- sleep 5
- retry=$(($retry - 1))
- sig=-9
- done
- }
- [ -n "$NFSMTAB" ] && {
- sig=
- retry=3
- remaining=`LC_ALL=C awk '$3 ~ /^nfs/ && $2 != "/" {print $2}' /proc/mounts`
- while [ -n "$remaining" -a "$retry" -gt 0 ]
- do
- if [ "$retry" -lt 3 ]; then
- action $"Unmounting NFS filesystems (retry): " umount -f -l $remaining
- else
- action $"Unmounting NFS filesystems: " umount -f -l $remaining
- fi
- sleep 2
- remaining=`LC_ALL=C awk '$3 ~ /^nfs/ && $2 != "/" {print $2}' /proc/mounts`
- [ -z "$remaining" ] && break
- /sbin/fuser -k -m $sig $remaining >/dev/null
- sleep 5
- retry=$(($retry - 1))
- sig=-9
- done
- }
+ __umount_loopback_loop
+ if [ -n "$NETDEVMTAB" ]; then
+ __umount_loop '$4 ~ /_netdev/ && $2 != "/" {print $2}' \
+ /etc/mtab \
+ $"Unmounting network block filesystems: " \
+ $"Unmounting network block filesystems (retry): "
+ fi
+ if [ -n "$NFSMTAB" ]; then
+ __umount_loop '$3 ~ /^nfs/ && $2 != "/" {print $2}' \
+ /proc/mounts \
+ $"Unmounting NFS filesystems: " \
+ $"Unmounting NFS filesystems (retry): " \
+ "-f -l"
+ fi
[ -n "$SMBMTAB" ] && action $"Unmounting SMB filesystems: " umount -a -t smbfs
[ -n "$CIFSMTAB" ] && action $"Unmounting CIFS filesystems: " umount -a -t cifs
[ -n "$NCPMTAB" ] && action $"Unmounting NCP filesystems: " umount -a -t ncpfs
diff --git a/rc.d/rc.sysinit b/rc.d/rc.sysinit
index 96e79c82..c0195319 100755
--- a/rc.d/rc.sysinit
+++ b/rc.d/rc.sysinit
@@ -29,11 +29,11 @@ fi
. /etc/init.d/functions
# Check SELinux status
-selinuxfs=`LC_ALL=C awk '/ selinuxfs / { print $2 }' /proc/mounts`
+selinuxfs="$(fstab_decode_str `LC_ALL=C awk '/ selinuxfs / { print $2 }' /proc/mounts`)"
SELINUX_STATE=
if [ -n "$selinuxfs" ] && [ "`cat /proc/self/attr/current`" != "kernel" ]; then
- if [ -r $selinuxfs/enforce ] ; then
- SELINUX_STATE=`cat $selinuxfs/enforce`
+ if [ -r "$selinuxfs/enforce" ] ; then
+ SELINUX_STATE=`cat "$selinuxfs/enforce"`
else
# assume enforcing if you can't read it
SELINUX_STATE=1
@@ -48,7 +48,7 @@ disable_selinux() {
echo "*** Warning -- SELinux is active"
echo "*** Disabling security enforcement for system recovery."
echo "*** Run 'setenforce 1' to reenable."
- echo "0" > $selinuxfs/enforce
+ echo "0" > "$selinuxfs/enforce"
}
relabel_selinux() {
@@ -64,14 +64,14 @@ relabel_selinux() {
*** Relabelling could take a very long time, depending on file ***
*** system size and speed of hard drives. ***
"
- echo "0" > $selinuxfs/enforce
+ echo "0" > "$selinuxfs/enforce"
/sbin/fixfiles restore > /dev/null 2>&1
rm -f /.autorelabel
if [ ! -z "$REBOOTFLAG" ]; then
echo $"Automatic reboot in progress."
reboot -f
fi
- echo $SELINUX_STATE > $selinuxfs/enforce
+ echo $SELINUX_STATE > "$selinuxfs/enforce"
if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then
chvt 8
fi
@@ -431,15 +431,16 @@ if [ X"$_RUN_QUOTACHECK" = X1 -a -x /sbin/quotacheck ]; then
if [ -x /sbin/convertquota ]; then
# try to convert old quotas
for mountpt in `LC_ALL=C awk '$4 ~ /quota/{print $2}' /etc/mtab` ; do
+ mountpt="$(fstab_decode_str "$mountpt")"
if [ -f "$mountpt/quota.user" ]; then
action $"Converting old user quota files: " \
- /sbin/convertquota -u $mountpt && \
- rm -f $mountpt/quota.user
+ /sbin/convertquota -u "$mountpt" && \
+ rm -f "$mountpt/quota.user"
fi
if [ -f "$mountpt/quota.group" ]; then
action $"Converting old group quota files: " \
- /sbin/convertquota -g $mountpt && \
- rm -f $mountpt/quota.group
+ /sbin/convertquota -g "$mountpt" && \
+ rm -f "$mountpt/quota.group"
fi
done
fi
diff --git a/src/Makefile b/src/Makefile
index 78276fad..84d6d439 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,7 +1,7 @@
CFLAGS+=$(RPM_OPT_FLAGS) -Wall -D_GNU_SOURCE
PROGS=usernetctl doexec netreport testd usleep ipcalc initlog \
- getkey ppp-watch consoletype genhostid rename_device
+ fstab-decode getkey ppp-watch consoletype genhostid rename_device
PPPWATCH_OBJS=ppp-watch.o shvar.o
INITLOG_OBJS=initlog.o process.o
USLEEP_OBJS=usleep.o
@@ -20,6 +20,7 @@ install:
install -m 4755 usernetctl $(ROOT)/usr/sbin/usernetctl
install -m 2755 netreport $(ROOT)/sbin/netreport
install -m 755 ipcalc $(ROOT)/bin/ipcalc
+ install -m 755 fstab-decode $(ROOT)/sbin/fstab-decode
install -m 755 genhostid $(ROOT)/sbin/genhostid
install -m 755 initlog $(ROOT)/sbin/initlog
install -m 755 getkey $(ROOT)/sbin/getkey
@@ -32,6 +33,7 @@ install:
install -m 644 getkey.1 $(ROOT)$(mandir)/man1
install -m 644 netreport.1 $(ROOT)$(mandir)/man1
install -m 644 usleep.1 $(ROOT)$(mandir)/man1
+ install -m 644 fstab-decode.8 $(ROOT)$(mandir)/man8
install -m 644 usernetctl.8 $(ROOT)$(mandir)/man8
install -m 644 ppp-watch.8 $(ROOT)$(mandir)/man8
install -m 644 ipcalc.1 $(ROOT)$(mandir)/man1
diff --git a/src/fstab-decode.8 b/src/fstab-decode.8
new file mode 100644
index 00000000..216dee86
--- /dev/null
+++ b/src/fstab-decode.8
@@ -0,0 +1,45 @@
+.\" A man page for fstab-decode(8).
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+.\"
+.\" This copyrighted material is made available to anyone wishing to use,
+.\" modify, copy, or redistribute it subject to the terms and conditions of the
+.\" GNU General Public License v.2.
+.\"
+.\" This program is distributed in the hope that it will be useful, but WITHOUT
+.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+.\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+.\" more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+.\"
+.\" Author: Miloslav Trmac <mitr@redhat.com>
+.TH fstab-decode 8 "May 2006"
+
+.SH NAME
+fstab-decode \- run a command with fstab-encoded arguments
+
+.SH SYNOPSIS
+\fB fstab-decode\fR \fICOMMAND\fR [\fIARGUMENT\fR]...
+
+.SH DESCRIPTION
+.B fstab-decode
+decodes escapes in the specified \FIARGUMENT\fRs
+and uses them to run \fICOMMAND\fR.
+The argument escaping uses the same rules as path escaping in
+\fB/etc/fstab\fR,
+.B /etc/mtab
+and \fB/proc/mtab\fR.
+
+.SH EXIT STATUS
+.B fstab-decode
+exits with status 127 if
+.I COMMAND
+can't be run.
+Otherwise it exits with the status returned by \fICOMMAND\fR.
+
+.SH EXAMPLES
+
+.B fstab-decode umount $(awk '$3 == "vfat" { print $2 }' /etc/fstab)
diff --git a/src/fstab-decode.c b/src/fstab-decode.c
new file mode 100644
index 00000000..4a162dfe
--- /dev/null
+++ b/src/fstab-decode.c
@@ -0,0 +1,86 @@
+/* fstab-decode(8).
+
+Copyright (c) 2006 Red Hat, Inc. All rights reserved.
+
+This copyrighted material is made available to anyone wishing to use, modify,
+copy, or redistribute it subject to the terms and conditions of the GNU General
+Public License v.2.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
+Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+Author: Miloslav Trmac <mitr@redhat.com> */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Decode the fstab-encoded string in place. */
+static void
+decode(char *s)
+{
+ const char *src;
+ char *dest;
+
+ src = s;
+ dest = s;
+ while (*src != '\0') {
+ if (*src != '\\')
+ *dest = *src++;
+ else {
+ static const struct repl {
+ char orig[4];
+ size_t len;
+ char new;
+ } repls[] = {
+#define R(X, Y) { X, sizeof(X) - 1, Y }
+ R("\\", '\\'),
+ R("011", '\t'),
+ R("012", '\n'),
+ R("040", ' '),
+ R("134", '\\')
+#undef R
+ };
+
+ size_t i;
+
+ for (i = 0; i < sizeof (repls) / sizeof (repls[0]);
+ i++) {
+ if (memcmp(src + 1, repls[i].orig,
+ repls[i].len) == 0) {
+ *dest = repls[i].new;
+ src += 1 + repls[i].len;
+ goto found;
+ }
+ }
+ *dest = *src++;
+ found:
+ ;
+ }
+ dest++;
+ }
+ *dest = '\0';
+}
+
+int
+main (int argc, char *argv[])
+{
+ size_t i;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: fstab-decode command [arguments]\n");
+ return EXIT_FAILURE;
+ }
+ for (i = 2; i < (size_t)argc; i++)
+ decode(argv[i]);
+ execvp(argv[1], argv + 1);
+ fprintf(stderr, "fstab-decode: %s: %s\n", argv[1], strerror(errno));
+ return 127;
+}