[Ovirt-devel] [PATCH node-image] edit-livecd: add -o OUTPUT.iso option, required

Jim Meyering jim at meyering.net
Wed Dec 3 12:45:34 UTC 2008


The new -o OUTPUT.iso option is now required.

Allow the '-p CODE' option to  specify bourne shell code, not just
a file/script.  This permits a common idiom: to avoid writing a
separate shell script for a simple task, and instead include a
quoted multi-line snippet in the invoking script, e.g.,

edit-livecd ...other-options... -p '
    d=etc/foo
    mkdir -p $d &&
    touch $d/file
'
Also,
in the boot params substitution,
  - use @ rather than / in the sed
  - warn if the selected string contains @

Update -h (help) output, and add examples.

Evaluate $CODE in a subshell (safer and doesn't rely on pushd,popd).

Guard against uninitialized ID_FS_LABEL.

Don't use "function" keyword.

Fail if there are any extra command-line arguments.

Ensure that $PWD and $CD are double-eval safe (else fail),
so that we don't have to quote them everywhere.

Ensure that a $CODE (renamed from $PROG) definition doesn't
leak in from the environment.
---
 edit-livecd |  117 ++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 75 insertions(+), 42 deletions(-)

diff --git a/edit-livecd b/edit-livecd
index ce9e65b..6d6498a 100755
--- a/edit-livecd
+++ b/edit-livecd
@@ -34,38 +34,49 @@ usage() {
 Usage: $ME -i LiveCD.iso [-b bootparams] [-p program]
   -b BOOTPARAMS  optional parameters appended to the kernel command line
   -i LIVECD.iso  LiveCD ISO to edit (default: $NODEIMG_DEFAULT)
-  -p PROGRAM     Arbitrary program/script that is run inside of the livecd root
-            filesystem.  This script is not run in a chroot environment so
-            it can access the host filesystem.  The program should be executable
-            If program is omitted the script will pause and allow the user in
-            another terminal to edit the filesystem manually.  After enter is
-            pushed the script will re-package up the ISO.
+  -o OUTPUT.iso  specify the output file (required)
+  -p CODE        Arbitrary CODE that is eval'd while 'cd'd into the root of
+                   the livecd root filesystem.  Note; the code is not run in
+                   a chroot environment, so it can access the host filesystem.
+                   If this option is omitted, this program pauses and allows
+                   the user (in another terminal) to modify the filesystem
+                   manually.  Type <enter> when done, and the script
+                   re-packages the ISO.
   -h             display this help and exit

+EXAMPLES
+
   Example Script:
     #!/bin/sh
     touch etc/sysconfig/foo
+  Save as foo and make executable:
+    chmod a+x foo
+  Run this to create a file /etc/sysconfig/foo in the livecd filesystem
+  (note the use of "\$PWD/foo", not "./foo", since it will be run from a
+   different directory):
+
+    $ME -i input.iso -o /tmp/result.iso -p "\$PWD/foo"
+
+  or, equivalently, but without a separate script:
+
+    $ME -i input.iso -o /tmp/result.iso -p 'touch etc/sysconfig/foo'

-  This will create a file /etc/sysconfig/foo in the livecd filesystem.
 EOF
 }

-# FIXME: instead of requiring a PROGRAM, allow arbitrary shell code,
-# so we can invoke $0 -p 'touch etc/sysconfig/foo' ...
-# This means that if you *do* have a program in the current directory
-# running "$0 -p ./my-script" won't work, since it'll be run with
-# a different working dir.  However, *this* will:
-# $0 -p "$PWD/my-script"
-
 # exit after any error:
 set -e

+CODE=
+OUTPUT_FILE=
+
 err=0 help=0
-while getopts :b:i:p:h c; do
+while getopts :b:hi:o:p: c; do
     case $c in
         i) CD=$OPTARG;;
         b) PARAMS=$OPTARG;;
-        p) PROG=$OPTARG;;
+        o) OUTPUT_FILE=$OPTARG;;
+        p) CODE=$OPTARG;;
         h) help=1;;
         '?') err=1; warn "invalid option: \`-$OPTARG'";;
         :) err=1; warn "missing argument to \`-$OPTARG' option";;
@@ -75,39 +86,59 @@ done
 test $err = 1 && { try_h; exit 1; }
 test $help = 1 && { usage; exit 0; }

+# Require "-o OUTPUT_FILE"
+test -z "$OUTPUT_FILE" \
+  && { warn "no output file specified; use -o FILE.iso"; try_h; exit 1; }
+
+# Fail if there are any extra command-line arguments.
+if test $OPTIND -le $#; then
+  bad_arg=$(eval "echo \$$OPTIND")
+  warn "extra argument '$bad_arg'"; try_h; exit 1
+fi
+
 # first, check to see we are root
 if [ $( id -u ) -ne 0 ]; then
     die "Must run as root"
 fi

-# FIXME: don't use which: with bash, it's a separate program
-# FIXME: When failing due to a missing required program, tell the user why.
-which mkisofs mksquashfs sed > /dev/null 2>&1
+# Check for some prerequisites.
+# "type" prints "PROG not found" if it's not in $PATH.
+type mkisofs
+type mksquashfs
+type sed
+
+sane_name()
+{
+  case $1 in
+    *[^a-zA-Z0-9._,+:/@%=-]*) false;;
+    *) true;;
+  esac
+}
+
+# Fail if names we'll use contain white space or shell meta-characters
+sane_name "$PWD" || die "invalid working directory name: $PWD"
+sane_name "$CD" || die "invalid ISO name: $CD"

 WDIR=`mktemp -d $PWD/livecd.XXXXXXXXXX`
-# FIXME: fail if $WDIR contains white space or shell meta-characters
-# FIXME: do the same for $CD.
-
-ISO="${CD##*/}"
-ISO="${ISO%.iso}-custom.iso"

-function addExit() {
+addExit() {
     EXIT="$@ ; $EXIT"
     trap "$EXIT" EXIT HUP TERM INT QUIT
 }

-function mnt() {
+mnt() {
     local margs="$1" ; shift
     local mp="$WDIR/$1"
     for D in "$@" ; do
         mkdir -v -p "$WDIR/$D"
     done
-    mount -v $margs "$mp"
+    eval mount -v $margs "$mp"
     addExit "df | grep $mp > /dev/null 2>&1 && umount -v $mp"
 }

 addExit "rm -rf $WDIR"

+ID_FS_LABEL= # initialize, in case vol_id fails
 eval "$(/lib/udev/vol_id $CD)"
 LABEL=$ID_FS_LABEL

@@ -120,21 +151,21 @@ mnt "-t squashfs $WDIR/cd/LiveOS/squashfs.img -o ro,loop" sq
 # create writable copy of the new filesystem for the CD
 cp -a $WDIR/cd $WDIR/cd-w

-# create writable copy of the filesystem for the new compressed squashfs filesystem
+# create writable copy of the filesystem for the new compressed
+# squashfs filesystem
 cp -a $WDIR/sq $WDIR/sq-w

 # mount ext3 filesystem
 mnt "-t auto $WDIR/sq-w/LiveOS/ext3fs.img -o rw,loop" ex

 echo ">>> Updating CD content"
-if [ -n "$PROG" ]; then
-    cp -av $PROG $WDIR/ex
-    pushd $WDIR/ex
-    set +e
-    ./$(basename $PROG)
-    set -e
-    popd
-    rm -f $WDIR/ex/$PROG
+if [ -n "$CODE" ]; then
+    (
+      cd $WDIR/ex
+      set +e
+      eval "$CODE"
+      set -e
+    )
 else
     echo "***"
     echo "*** Pausing to allow manual changes.  Press any key to continue."
@@ -147,7 +178,7 @@ fi
 while :; do
   echo ">>> Unmounting ext3fs"
   umount $WDIR/ex && break
-  echo ">>> Unmounting ext3fs failed"
+  echo ">>> Unmounting the working file system copy failed"
   echo "***"
   echo "*** Did you forget to 'cd' out of $WDIR/ex?"
   echo "***"
@@ -160,13 +191,15 @@ echo ">>> Compressing filesystem"
 mksquashfs $WDIR/sq-w/ $WDIR/cd-w/LiveOS/squashfs.img -noappend

 echo ">>> Recomputing MD5 sums"
-( cd $WDIR/cd-w && find . -type f -not -name md5sum.txt -not -path '*/isolinux/*' -print0 | xargs -0 -- md5sum > md5sum.txt )
+( cd $WDIR/cd-w && find . -type f -not -name md5sum.txt \
+    -not -path '*/isolinux/*' -print0 | xargs -0 -- md5sum > md5sum.txt )

 if [ -n "$PARAMS" ]; then
-    # FIXME: make the script fail -- or maybe try to
-    # find a usable sed delimiter if $PARAMS contains a slash
+    case $PARAMS in
+      *@*) warn "PARAMS contains the @ sed delimiter, be sure it's escaped";;
+    esac
     echo ">>> Appending boot parameters"
-    sed -i 's/^  append .*$/& '"$PARAMS/" "$WDIR/cd-w/isolinux/isolinux.cfg"
+    sed -i 's@^  append .*$@& '"$PARAMS@" "$WDIR/cd-w/isolinux/isolinux.cfg"
 fi

 echo ">>> Creating ISO image $ISO"
@@ -176,7 +209,7 @@ mkisofs \
     -b isolinux/isolinux.bin \
     -c isolinux/boot.cat \
     -no-emul-boot -boot-load-size 4 -boot-info-table \
-    -o "$ISO" \
+    -o "$OUTPUT_FILE" \
     $WDIR/cd-w

 # The trap ... callbacks will unmount everything.
--
1.6.1.rc1.279.g45d11




More information about the ovirt-devel mailing list