diff options
author | Miloslav Trmac <mitr@volny.cz> | 2006-05-08 23:54:06 +0000 |
---|---|---|
committer | Miloslav Trmac <mitr@volny.cz> | 2006-05-08 23:54:06 +0000 |
commit | 3bd074fd404b4863d811d0a50e9ef484523c6b57 (patch) | |
tree | 9c4ca48303377ab77a8a00d10561ba1e8afbab28 | |
parent | 0414be84b33e98510feb1d0e281b089ba16b349d (diff) | |
download | initscripts-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.spec | 1 | ||||
-rwxr-xr-x | rc.d/init.d/functions | 61 | ||||
-rwxr-xr-x | rc.d/init.d/halt | 110 | ||||
-rwxr-xr-x | rc.d/init.d/netfs | 79 | ||||
-rwxr-xr-x | rc.d/rc.sysinit | 21 | ||||
-rw-r--r-- | src/Makefile | 4 | ||||
-rw-r--r-- | src/fstab-decode.8 | 45 | ||||
-rw-r--r-- | src/fstab-decode.c | 86 |
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; +} |