Solved Problems with gpart in script

I am trying to write a script to automate imaging some USB flash drives. The idea is to run the script with the argument for the block device of the USB drive, then let the script remove partitioning, create partitions, then copy over a disk image.
Here is the script:

Code:
#!/bin/sh
echo $1
echo /dev/$1
echo /dev/${1}p1

clearpartition () {
gpart destroy -F $1
 }
makebootpart () {
gpart create -s gpt $1
gpart add -t ms-basic-data -s 3782213632b $1
}
makebootimg () { dd if=zroot/shared/iso/EMU_STICK.img of=/dev/${1}p1 bs=1M conv=sync status=progress; }
makedatapart () {
gpart add -t ms-basic-data $1
mkexfatfs -n UTILS /dev/${1}p2
}

clearpartition
makebootpart
makebootimg
makedatapart

The first few lines were for testing, so I would know that when I passed the name of the block device, it would register properly. I had simply listed the commands, but after getting errors, I thought I'd try building functions. That didn't work either. Here is the results:

Code:
root@BQ751T2:/ # /usr/local/bin/emucreate.sh da0
da0
/dev/da0
/dev/da0p1
gpart: Invalid number of arguments.
gpart: Invalid number of arguments.
gpart: Invalid number of arguments.

If I manually run the commands in the shell, everything works.
Can anyone tell me what I'm doing wrong?
 
Probably you can add something like device=$1 to the top of your script, and then reference $device instead of $1 in your functions. That, or you need to call the functions with args, e.g. clearpartition $1.
 
You are calling your functions without any arguments, so inside the functions, "$1" is undefined.

Both of the suggestions above will confirm this...
This pointed me in a right direction.
Probably you can add something like device=$1 to the top of your script, and then reference $device instead of $1 in your functions. That, or you need to call the functions with args, e.g. clearpartition $1.
I setup a variable based on the argument. This is working. Thanks!
 
I would execute the script with the absolute path of the character device.

/usr/local/bin/emucreate.sh /dev/da0 /zroot/shared/iso/EMU_STICK.img

I would also encourage the use of full paths for each executable just be explicit and shit.

You also don't need to include the 'b' suffix. You may also be better off specifying the size in a human-readable format after rounding up, too. (e.g. 4G)

I usually like to start each shell function with some type of assertion and type checking to make sure things go as expected. When things don't it's easy to see determine what's going wrong.

I haven't tested these functions, but hopefully it helps.

Bash:
clearpartition() {
    if [ -z "$DEV" ]; then
        /bin/echo '<$1: DEV>'; return 127;
    fi
    if [ ! -c "$DEV" ]; then
        /bin/echo "Device not found: ${DEV}"; return 1;
    fi
    /sbin/gpart destroy -F ${DEV} || return 127
}

makebootpart() {
    local DEV="$1";
    if [ -z "$DEV" ]; then
        /bin/echo '<$1: DEV>'; return 1;
    fi
    if [ ! -c "$DEV" ]; then
        /bin/echo "Character device not found: ${DEV}"; return 1;
    fi
    /sbin/gpart create -s GPT ${DEV} || return 127
    /sbin/gpart add -t ms-basic-data -s 4G ${DEV} || return 127
}

makebootimg() {
    local IMG="$1";
    if [ -z "$IMG" ]; then
        /bin/echo '<$1: IMG>'; return 1;
    fi
    if [ ! -f "$IMG" ]; then
        /bin/echo "File not found: ${IMG}"; return 1;
    fi
   
    local DEV="$2";
    if [ -z "$DEV" ]; then
        /bin/echo '<$2: DEV>'; return 1;
    fi
    if [ ! -c "$DEV" ]; then
        /bin/echo "Character device not found: ${DEV}"; return 1;
    fi


    /bin/dd if=${IMG} of=${DEV}p1 bs=1m conv=noerror,sync status=progress;
}

makedatapart() {
    local IMG="$1";
    if [ -z "$IMG" ]; then
        /bin/echo '<$1: IMG>'; return 1;
    fi
    if [ ! -f "$IMG" ]; then
        /bin/echo "File not found: ${IMG}"; return 1;
    fi
   
    local DEV="$2";
    if [ -z "$DEV" ]; then
        /bin/echo '<$2: DEV>'; return 1;
    fi
    if [ ! -c "$DEV" ]; then
        /bin/echo "Character device not found: ${DEV}"; return 1;
    fi

    /sbin/gpart add -t ms-basic-data [-s <BS>] ${DEV} || return 1
    /sbin/mkexfatfs -n UTILS ${DEV}p2 || return 1
}

clearpartition "$1" || exit $?
makebootpart "$1" || exit $?
makebootimg "$1" "$2" || exit $?
makedatapart "$1" "$2" || exit $?
 
Be careful when running these types of scripts. You probablly want to add a confirm dialog to make sure you don't destroy an other disk by accident.

I would execute the script with the absolute path of the character device.

/usr/local/bin/emucreate.sh /dev/da0 /zroot/shared/iso/EMU_STICK.img

I would also encourage the use of full paths for each executable just be explicit and shit.

You also don't need to include the 'b' suffix. You may also be better off specifying the size in a human-readable format after rounding up, too. (e.g. 4G)

I usually like to start each shell function with some type of assertion and type checking to make sure things go as expected. When things don't it's easy to see determine what's going wrong.

I haven't tested these functions, but hopefully it helps.

Bash:
clearpartition() {
    if [ -z "$DEV" ]; then
        /bin/echo '<$1: DEV>'; return 127;
    fi
    if [ ! -c "$DEV" ]; then
        /bin/echo "Device not found: ${DEV}"; return 1;
    fi
    /sbin/gpart destroy -F ${DEV} || return 127
}

makebootpart() {
    local DEV="$1";
    if [ -z "$DEV" ]; then
        /bin/echo '<$1: DEV>'; return 1;
    fi
    if [ ! -c "$DEV" ]; then
        /bin/echo "Character device not found: ${DEV}"; return 1;
    fi
    /sbin/gpart create -s GPT ${DEV} || return 127
    /sbin/gpart add -t ms-basic-data -s 4G ${DEV} || return 127
}

makebootimg() {
    local IMG="$1";
    if [ -z "$IMG" ]; then
        /bin/echo '<$1: IMG>'; return 1;
    fi
    if [ ! -f "$IMG" ]; then
        /bin/echo "File not found: ${IMG}"; return 1;
    fi
  
    local DEV="$2";
    if [ -z "$DEV" ]; then
        /bin/echo '<$2: DEV>'; return 1;
    fi
    if [ ! -c "$DEV" ]; then
        /bin/echo "Character device not found: ${DEV}"; return 1;
    fi


    /bin/dd if=${IMG} of=${DEV}p1 bs=1m conv=noerror,sync status=progress;
}

makedatapart() {
    local IMG="$1";
    if [ -z "$IMG" ]; then
        /bin/echo '<$1: IMG>'; return 1;
    fi
    if [ ! -f "$IMG" ]; then
        /bin/echo "File not found: ${IMG}"; return 1;
    fi
  
    local DEV="$2";
    if [ -z "$DEV" ]; then
        /bin/echo '<$2: DEV>'; return 1;
    fi
    if [ ! -c "$DEV" ]; then
        /bin/echo "Character device not found: ${DEV}"; return 1;
    fi

    /sbin/gpart add -t ms-basic-data [-s <BS>] ${DEV} || return 1
    /sbin/mkexfatfs -n UTILS ${DEV}p2 || return 1
}

clearpartition "$1" || exit $?
makebootpart "$1" || exit $?
makebootimg "$1" "$2" || exit $?
makedatapart "$1" "$2" || exit $?
Thanks for the tips. I just needed something quick for now. I want to eventually put in code to scan for USB drives and present USB drives and only USB drives to be selected for the script.

You also don't need to include the 'b' suffix. You may also be better off specifying the size in a human-readable format after rounding up, too. (e.g. 4G)
Interestingly enough, when I tried just the value, it assumed a larger integer, and gave me a message about insufficient space. I want this partition to be exactly the size of the image. Eventually I'll put it in to check the size of the image file so that if the image file changes in size, I won't have to recode the whole script!
 
Back
Top