On Sun, 2009-11-29 at 13:56 +0100, Marco d'Itri wrote:
> On Nov 28, Bastian Blank <wa...@debian.org> wrote:
> 
> > The Linux image packages needs to do some modifications to core
> > configuration files like fstab in the future to allow newer kernels to
> > work. To do this and the planned further extension I intend to make all
> > linux image packages depend on python.
> This is not justified.
> I will be happy to rewrite in perl whatever you need.

Find attached an initial attempt to use shell only. Let me know if you
are interested.

The script is configurable, so a sysadmin can decide to re-rewrite fstab
using DM/LVM names rather than UUID, or volume LABEL, or legacy /dev/hd*
names.

Known bugs/limitation:
 * Should accept command line arguments
 * Some devices may need to be blacklisted
 * What about removable media? (UUID of media in CDROM? ouch)
 * Should actually write fstab ;)

I have hesitated to probe the current /dev or to use blkid... I can
change that easily.

I think this script should have a companion, to insert/update a comments
line above each fstab entry (à-la Debian-Installer)

Franklin
#!/bin/sh
set -e
# update-fstab-persistent-names - Rewrite current fstab
# (Using your prefered device naming).
#
# Copyright 2009, Frank Lin PIAT <fp...@klabs.be>
# Licensed under GPLv2 or later
#
# Known bugs/limitation
#  * Should actually _write_ fstab ;)
#  * Doesn't accept command line arguments
#  * Some devices may need to be blacklisted
#  * What about removable media?


# ====== User configurable variables ====== #

# Prefered device naming scheme to use in fstab. **Order matters**.
#    dm         : use /dev/grpname/logvolname for LVM volumes
#               : or /dev/mapper/dmname for CRYPT and other.
#    uuid       : use UUID=cafecafe (based on the FS's volume UUID)
#    label      : use LABEL=foo (based on the FS's volume name)
#    plaindev   : use legacy /dev/ devices.
PREFERED_NAME='dm uuid label plaindev'

# Rewrite existing LABEL=foo lines in fstab
REWRITE_LABELS=1

# Rewrite existing UUID=foo lines in fstab
REWRITE_UUIDS=1

# ====== End of user configurable variables ====== #

# Let's declare some functions...

# Initialise a sed file to rewrite fstab, based on device major/minor IDs.
# (this temporary sed file search and replace all possible names for the
# local devices, with a fake unique ID "#DEVICE=X.Y" where X and Y are 
# the device's major and minor numbers)
generate_simple_fstab_sed() {

        # Sed rule to rewrite /dev/* entry as #DEVICE=X:Y
        find /dev/ \( -type b -o -type l \)  \
                        \! -path '/dev/.udev/*' \! -path '/dev/.static/*' \
                        -iregex '^[a-z0-9./_-]*$' -printf '%Y\t%p\n' \
                | sed -n -e 's/^b\t\(.*\)/\1/p' \
                | while read s ; do
                        printf 's\t^%s\>\t#DEVICE=%d:%d\t\n' \
                                "$s" \
                                "$(stat -L -c '0x%t' "$s")" \
                                "$(stat -L -c '0x%T' "$s")"
                done

        # Sed rule to rewrite existing LABELS=* entry as #DEVICE=X:Y
        if [ "$REWRITE_LABELS" = "1" -a -d /dev/disk/by-label ]; then
                find /dev/disk/by-label/ -type l -iregex '^[a-z0-9./_-]*$' \
                        | while read s ; do \
                                printf 's\t^%s\>\t#DEVICE=%d:%d\t\n' \
                                        "LABEL=$(basename $s)" \
                                        "$(stat -L -c '0x%t' "$s")" \
                                        "$(stat -L -c '0x%T' "$s")"
                        done
        fi

        # Sed rule to rewrite existing UUID=* entry as #DEVICE=X:Y
        if [ "$REWRITE_UUIDS" = "1" -a -d /dev/disk/by-uuid ]; then
                find /dev/disk/by-uuid/ -type l -iregex '^[a-z0-9./_-]*$' \
                        | while read s ; do \
                                printf 's\t^%s\>\t#DEVICE=%d:%d\tg\n' \
                                        "UUID=$(basename $s)" \
                                        "$(stat -L -c '0x%t' "$s")" \
                                        "$(stat -L -c '0x%T' "$s")"
                        done
        fi
}



# create a list of device-major-minor -> /dev/vg/lv for LVM.
use_dm_legacy() {
        which vgs 2>&1 > /dev/null || return 0

        LVM_VGS="$(vgs --all -o vg_name --noheadings | sed -e 's#^\s*#/dev/#')"
        [ ! "$LVM_VGS" ] && return 0

        find $LVM_VGS -maxdepth 1 -type l -iregex '^[a-z0-9./_-]*$' \
                | while read s ; do \
                        printf 's\t#DEVICE=%d:%d\t%s\t\n' \
                                "$(stat -L -c '0x%t' "$s")" \
                                "$(stat -L -c '0x%T' "$s")" \
                                "$s"
                done
}

# create a list of device-major-minor -> /dev/vg/lv
# or -> /dev/mapper/name for dmsetup (LVM/DM/CRYPT...)
use_dm_new() {
        which dmsetup 2>&1 > /dev/null || return 0

        dmsetup info -c --noheadings --separator="$(printf "\t")" \
                        -o major,minor,name,vg_name,lv_name \
                | while read maj min name vg lv ; do
                        if [ "$vg" -a "$lv" -a -b /dev/$vg/$lv ] ; then
                                DEV=/dev/$vg/$lv
                        else
                                DEV=/dev/mapper/$name
                        fi

                        if [ -b $DEV ]; then
                               printf "s\t#DEVICE=%d:%d\t%s\t\n" $maj $min $DEV
                        fi
               done
}

# Disaptcher to create a list of device-major-minor -> /dev/vg/lv
# or -> /dev/mapper/diskmappername, depending on dmsetup version.
use_dm() {
        which dmsetup 2>&1 > /dev/null || return 0

        # Lenny's dmsetup don't provide "lv_name"
        if dmsetup --noheadings info -c -o lv_name >/dev/null 2>&1; then
                use_dm_new
        else
                use_dm_legacy
        fi
}

# create a list of device-major-minor -> uuid
use_uuid() {
        [ ! -d /dev/disk/by-uuid ] && return 0

        find /dev/disk/by-uuid/ -type l -iregex '^[a-z0-9./_-]*$' \
                | while read s ; do \
                        printf 's\t#DEVICE=%d:%d\t%s\t\n' \
                                "$(stat -L -c '0x%t' "$s")" \
                                "$(stat -L -c '0x%T' "$s")" \
                                "UUID=$(basename $s)"
                done
}

# create a list of device-major-minor -> label
use_label() {
        [ ! -d /dev/disk/by-label ] && return 0

        find /dev/disk/by-label/ -type l -iregex '^[a-z0-9./_-]*$' \
                | while read s ; do \
                        printf 's\t#DEVICE=%d:%d\t%s\t\n' \
                                "$(stat -L -c '0x%t' "$s")" \
                                "$(stat -L -c '0x%T' "$s")" \
                                "LABEL=$(basename $s)"
                done
}

# create a list of device-major-minor -> /dev
use_plaindev() {
        find /dev/ -maxdepth 1 -type b '!' -path '/dev/.udev/*' \
                | grep -v '/dev/dm-' \
                | while read s ; do \
                        printf 's\t#DEVICE=%d:%d\t%s\t\n' \
                                "$(stat -L -c '0x%t' "$s")" \
                                "$(stat -L -c '0x%T' "$s")" \
                                "$s"
                done
}

# Drop remaining entries which have no sane equivalement.
use_dropunknown() {
        echo '/#DEVICE=/d'
}

# Drop null rules
use_dropnullrules() {
        echo '/^s\t^\([^\t]\+\)\\>\t\1\t/d'
}

# ====== End of Function declaration ====== #


WDIR="$(mktemp -d -t $(basename $0).XXX)"
trap 'if [ "$WDIR" ]; then rm -f $WDIR/* ; rmdir $WDIR ; fi' EXIT
#Don't purge to debug#WDIR="/tmp/this-is-a-test"


# Initialise a sed file to rewrite fstab
generate_simple_fstab_sed > $WDIR/fstab.sed

# Now, let's poke the sed file to use sensible devices names
# instead of the fake "#DEVICE=X.Y".
i=1
last_tweak=".0.orig"
for p in $PREFERED_NAME dropunknown dropnullrules ; do
        case $p in
                dm|uuid|label|plaindev|dropunknown|dropnullrules)
                        sedtweak=$WDIR/tweak_${i}_Use_$p.sed
                        use_$p > $sedtweak
                        sed -i$last_tweak -f $sedtweak $WDIR/fstab.sed
                        last_tweak=".$i.$p"
                        ;;
                *)
                        echo "Error: Invalid preference value \"$p\" for option 
PREFFERED_NAME" 1>&2
                        ;;
        esac
        i=$((i + 1))
done

# And Finaly...
sed -f $WDIR/fstab.sed /etc/fstab

Reply via email to