Beginning public development of xorriso-dd-target
This commit is contained in:
parent
ea863307a4
commit
fe46a2d983
469
xorriso-dd-target/xorriso-dd-target
Executable file
469
xorriso-dd-target/xorriso-dd-target
Executable file
@ -0,0 +1,469 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2019
|
||||
# Nio Wiklund alias sudodus <nio dot wiklund at gmail dot com>
|
||||
# Thomas Schmitt <scdbackup@gmx.net>
|
||||
# Provided under GPL version 2 or later.
|
||||
|
||||
# Check whether we are on GNU/Linux
|
||||
if uname -s | grep -v '^Linux' >/dev/null
|
||||
then
|
||||
echo "This program is entirely specialized on Linux kernel device names." >&2
|
||||
echo "Found to be on: '$(uname -s)'" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Accept sudo-executable commands only in well known directories.
|
||||
# (Listed with increasing priority.)
|
||||
lsblk_cmd=
|
||||
dd_cmd=
|
||||
if test "$(whoami)" = "root"
|
||||
then
|
||||
sudo_x_dir_list="/usr/bin /bin /usr/sbin /sbin"
|
||||
else
|
||||
sudo_x_dir_list="/usr/sbin /sbin /usr/bin /bin"
|
||||
fi
|
||||
for i in $sudo_x_dir_list
|
||||
do
|
||||
if test -x "$i"/lsblk
|
||||
then
|
||||
lsblk_cmd="$i"/lsblk
|
||||
fi
|
||||
if test -x "$i"/dd
|
||||
then
|
||||
dd_cmd="$i"/dd
|
||||
fi
|
||||
if test -x "$i"/umount
|
||||
then
|
||||
umount_cmd="$i"/umount
|
||||
fi
|
||||
done
|
||||
if test -z "$lsblk_cmd"
|
||||
then
|
||||
echo "No executable program lsblk found in: $sudo_x_dir_list" >&2
|
||||
exit 5
|
||||
fi
|
||||
|
||||
print_usage() {
|
||||
echo "usage: $0 [options] [device_name [device_name ...]]"
|
||||
echo
|
||||
echo "Looks on GNU/Linux for USB and Memory Card devices and evaluates"
|
||||
echo "whether the found devices are plausible targets for image copying."
|
||||
echo "If no device names and no -list_all are given, then a plain list of"
|
||||
echo "advisable device names is printed to stdout. One per line."
|
||||
echo "Device names must not begin by '-' and must be single words. They must"
|
||||
echo "not contain '/'. E.g. 'sdc' is valid, '/dev/sdc' is not valid."
|
||||
echo "If devices names are given, then they get listed with advice shown."
|
||||
echo "If one of the given device names gets not advised, the exit value is 1."
|
||||
echo
|
||||
echo "Only if option -DO_WRITE is given and -list_all is not, and if exactly"
|
||||
echo "one advisable device is listed, it really gets overwritten by the"
|
||||
echo "file content of the given -image_file. In this case the exit value"
|
||||
echo "is zero if writing succeeded, non-zero else."
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -list_all Print list of all found devices with advice, vendor"
|
||||
echo " and model, One per line. Ignore any device names."
|
||||
echo " Ignore -DO_WRITE."
|
||||
echo " -with_vendor_model Print vendor and model with each submitted device."
|
||||
echo
|
||||
echo " -max_size n[M|G|T] Set upper byte size limit for advisable devices."
|
||||
echo " Plain numbers get rounded down to full millions."
|
||||
echo " Suffix: M = million, G = billion, T = trillion."
|
||||
echo " Be generous to avoid problems with GB < GiB."
|
||||
echo " -min_size n[M|G|T] Set lower byte size limit for advisable devices."
|
||||
echo " After processing like with -max_size, one million"
|
||||
echo " gets added to the size limit."
|
||||
echo " -look_for_iso Demand presence of an ISO 9660 filesystem. If so,"
|
||||
echo " any further filesystem type is acceptable on that"
|
||||
echo " device. Else only ISO 9660 and VFAT are accepted."
|
||||
echo " -with_sudo Run '$lsblk_cmd -o FSTYPE' by sudo."
|
||||
echo " If so, consider to enable this without password."
|
||||
echo " If no filesystems are detected and the program"
|
||||
echo " has no superuser power, the device is not advised."
|
||||
echo " If -DO_WRITE is given, run umount and dd by sudo."
|
||||
echo " -image_file PATH Set the path of the image file which shall be"
|
||||
echo " written to a device. Its size will be set as"
|
||||
echo " -min_size."
|
||||
echo " -DO_WRITE Write the given -image_file to the one advisable"
|
||||
echo " device that is found. If more than one such device"
|
||||
echo " is found, then they get listed but no writing"
|
||||
echo " happens. In this case, re-run with one of the"
|
||||
echo " advised device names to get a real write run."
|
||||
echo
|
||||
echo " -help Print this text to stdout and then end the program."
|
||||
echo "Examples:"
|
||||
echo " $0 -with_sudo -list_all"
|
||||
echo " $0 sdc"
|
||||
echo " $0 -with_sudo -image_file debian-live-10.0.0-amd64-xfce.iso -DO_WRITE"
|
||||
echo
|
||||
}
|
||||
|
||||
# Roughly convert human readable sizes and plain numbers to 1 / million
|
||||
round_down_div_million() {
|
||||
sed -e 's/\.[0-9]*//' -e 's/[0-9][0-9][0-9][0-9][0-9][0-9]$//' \
|
||||
-e 's/[Mm]//' -e 's/[Gg]/000/' -e 's/[Tt]/000000/'
|
||||
}
|
||||
|
||||
### Assessing arguments and setting up the job
|
||||
|
||||
# Settings
|
||||
reset_job() {
|
||||
list_all=
|
||||
show_reasons=
|
||||
look_for_iso=
|
||||
devs=
|
||||
devs_named=
|
||||
max_size=
|
||||
with_vendor_model=
|
||||
with_sudo=
|
||||
image_file=
|
||||
do_write=
|
||||
|
||||
# Status
|
||||
sudo_cmd=
|
||||
have_su_power=
|
||||
}
|
||||
|
||||
arg_interpreter() {
|
||||
next_is=
|
||||
for i in "$@"
|
||||
do
|
||||
# The next_is option parameter readers get programmed by the -options
|
||||
if test "$next_is" = "max_size"
|
||||
then
|
||||
max_size="$(echo "$i" | round_down_div_million)"
|
||||
next_is=
|
||||
elif test "$next_is" = "min_size"
|
||||
then
|
||||
min_size="$(echo "$i" | round_down_div_million)"
|
||||
min_size="$(expr $min_size + 1)"
|
||||
next_is=
|
||||
elif test "$next_is" = "image_file"
|
||||
then
|
||||
image_file="$i"
|
||||
min_size="$(stat -c '%s' "$i" | round_down_div_million)"
|
||||
if test -z "$min_size"
|
||||
then
|
||||
echo "WARNING: Cannot obtain size of -image_file '$i'" >&2
|
||||
else
|
||||
min_size="$(expr $min_size + 1)"
|
||||
fi
|
||||
next_is=
|
||||
elif test "$i" = "-list_all"
|
||||
then
|
||||
list_all=y
|
||||
with_vendor_model=y
|
||||
show_reasons=y
|
||||
elif test "$i" = "-max_size"
|
||||
then
|
||||
next_is="max_size"
|
||||
elif test "$i" = "-min_size"
|
||||
then
|
||||
next_is="min_size"
|
||||
elif test "$i" = "-with_vendor_model"
|
||||
then
|
||||
with_vendor_model=y
|
||||
elif test "$i" = "-look_for_iso"
|
||||
then
|
||||
look_for_iso=y
|
||||
elif test "$i" = "-with_sudo"
|
||||
then
|
||||
with_sudo=y
|
||||
elif test "$i" = "-image_file"
|
||||
then
|
||||
next_is="image_file"
|
||||
elif test "$i" = "-DO_WRITE"
|
||||
then
|
||||
do_write=y
|
||||
elif test "$i" = "-help"
|
||||
then
|
||||
print_usage
|
||||
exit 0
|
||||
elif echo "$i" | grep -v '^-' >/dev/null
|
||||
then
|
||||
devs_named=y
|
||||
devs="$devs $i"
|
||||
show_reasons=y
|
||||
else
|
||||
echo "$0 : Unknown option: $i" >&2
|
||||
echo >&2
|
||||
print_usage >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Predict superuser power. Possibly enable sudo with lsblk -o FSTYPE and dd.
|
||||
if test "$(whoami)" = "root"
|
||||
then
|
||||
have_su_power=y
|
||||
elif test -n "$with_sudo"
|
||||
then
|
||||
sudo_cmd=sudo
|
||||
have_su_power=y
|
||||
fi
|
||||
}
|
||||
|
||||
## Evaluation of available devices and suitability
|
||||
list_devices() {
|
||||
if test -n "$list_all"
|
||||
then
|
||||
devs=
|
||||
fi
|
||||
if test -z "$devs"
|
||||
then
|
||||
# Obtain list of top-level names which do not look like CD or floppy.
|
||||
devs=$($lsblk_cmd -d -n -o NAME | grep -v '^sr[0-9]' | grep -v '^fd[0-9]')
|
||||
fi
|
||||
|
||||
not_advised=0
|
||||
for name in $devs
|
||||
do
|
||||
# Collect reasons
|
||||
tasty=
|
||||
yucky=
|
||||
reasons=
|
||||
good_trans=
|
||||
good_fs=
|
||||
bad_fs=
|
||||
|
||||
# Unwanted device name patterns
|
||||
if (echo "$name" | grep '^sd[a-z][1-9]' >/dev/null) \
|
||||
|| (echo "$name" | grep '^mmcblk.*p[0-9]' >/dev/null) \
|
||||
|| (echo "$name" | grep '^nvme.*p[0-9]' >/dev/null)
|
||||
then
|
||||
yucky=y
|
||||
reasons="${reasons}looks_like_disk_partition- "
|
||||
fi
|
||||
if echo "$name" | grep '^sr[0-9]' >/dev/null
|
||||
then
|
||||
yucky=y
|
||||
reasons="${reasons}looks_like_cd_drive- "
|
||||
fi
|
||||
|
||||
# >>> recognize the device from which Debian Live booted
|
||||
|
||||
# Connection type. Normally by lsblk TRAN, but in case of mmcblk artificial.
|
||||
if echo "$name" | grep '^mmcblk[0-9]' >/dev/null
|
||||
then
|
||||
transports="mmcblk"
|
||||
elif echo "$name" | fgrep "/" >/dev/null
|
||||
then
|
||||
echo "NOTE: The device name must not contain '/' characters" >&2
|
||||
transports=not_an_expected_name
|
||||
reasons="${reasons}name_with_slash- "
|
||||
else
|
||||
transports=$($lsblk_cmd -n -o TRAN /dev/"$name")
|
||||
fi
|
||||
if test -z "$transports"
|
||||
then
|
||||
transports=lsblk_failed_tran
|
||||
fi
|
||||
for trans in $transports
|
||||
do
|
||||
if test "$trans" = "usb" -o "$trans" = "mmcblk"
|
||||
then
|
||||
good_trans="${trans}+"
|
||||
tasty=y
|
||||
elif test -n "$trans"
|
||||
then
|
||||
yucky=y
|
||||
if test "$transports" = "not_an_expected_name"
|
||||
then
|
||||
dummy=dummy
|
||||
else
|
||||
if echo "$reasons" | fgrep -v "not_usb" >/dev/null
|
||||
then
|
||||
reasons="${reasons}not_usb- "
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Wanted or unwanted filesystem types
|
||||
fstypes=$($sudo_cmd $lsblk_cmd -n -o FSTYPE /dev/"$name")
|
||||
if test "$?" -gt 0
|
||||
then
|
||||
fstypes="lsblk_fstype_error"
|
||||
fi
|
||||
# Get overview of filesystems
|
||||
has_iso=
|
||||
has_vfat=
|
||||
has_other=
|
||||
for fstype in $fstypes
|
||||
do
|
||||
if test "$fstype" = "iso9660"
|
||||
then
|
||||
has_iso=y
|
||||
if echo "$good_fs" | fgrep -v "has_$fstype" >/dev/null
|
||||
then
|
||||
good_fs="${good_fs}has_${fstype}+ "
|
||||
fi
|
||||
elif test "$fstype" = "vfat"
|
||||
then
|
||||
has_vfat=y
|
||||
if echo "$good_fs" | fgrep -v "has_$fstype" >/dev/null
|
||||
then
|
||||
good_fs="${good_fs}has_${fstype}+ "
|
||||
fi
|
||||
elif test -n "$fstype"
|
||||
then
|
||||
has_other=y
|
||||
if echo "$bad_fs" | fgrep -v "has_$fstype" >/dev/null
|
||||
then
|
||||
bad_fs="${bad_fs}has_${fstype}- "
|
||||
fi
|
||||
fi
|
||||
done
|
||||
# Decide whether the found filesystems look dispensible enough
|
||||
reasons="${reasons}${good_fs}${bad_fs}"
|
||||
if test "${bad_fs}${good_fs}" = "" -a -z "$have_su_power"
|
||||
then
|
||||
yucky=y
|
||||
reasons="${reasons}no_fs_while_not_su- "
|
||||
elif test -n "$look_for_iso"
|
||||
then
|
||||
if test -n "$has_iso"
|
||||
then
|
||||
tasty=y
|
||||
reasons="${reasons}look_for_iso++ "
|
||||
else
|
||||
yucky=y
|
||||
reasons="${reasons}no_iso9660- "
|
||||
fi
|
||||
elif test -n "$has_other"
|
||||
then
|
||||
yucky=y
|
||||
else
|
||||
tasty=y
|
||||
fi
|
||||
|
||||
# Optional tests for size
|
||||
if test -n "$max_size" -o -n "$min_size"
|
||||
then
|
||||
size=$($lsblk_cmd -n -b -o SIZE /dev/"$name" | head -1 | round_down_div_million)
|
||||
if test -z "$size"
|
||||
then
|
||||
yucky=y
|
||||
reasons="${reasons}lsblk_no_size- "
|
||||
fi
|
||||
fi
|
||||
if test -n "$max_size" -a -n "$size"
|
||||
then
|
||||
if test "$size" -gt "$max_size"
|
||||
then
|
||||
yucky=y
|
||||
reasons="${reasons}size_too_large- "
|
||||
fi
|
||||
fi
|
||||
if test -n "$min_size" -a -n "$size"
|
||||
then
|
||||
if test "$size" -lt "$min_size"
|
||||
then
|
||||
yucky=y
|
||||
reasons="${reasons}size_too_small- "
|
||||
fi
|
||||
fi
|
||||
|
||||
# Now decide overall and report
|
||||
descr=
|
||||
if test -n "$with_vendor_model"
|
||||
then
|
||||
descr=": "$($lsblk_cmd -n -o VENDOR,MODEL /dev/"$name" | tr '\n\r' ' ' | tr -s ' ')
|
||||
fi
|
||||
if test -n "$yucky"
|
||||
then
|
||||
if test -n "$show_reasons"
|
||||
then
|
||||
echo "$name : NO : $reasons$descr"
|
||||
fi
|
||||
not_advised=1
|
||||
else
|
||||
if test -n "$show_reasons"
|
||||
then
|
||||
echo "$name : YES : $good_trans $reasons$descr"
|
||||
else
|
||||
echo "$name"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return 0;
|
||||
}
|
||||
|
||||
write_image() {
|
||||
|
||||
echo "--- not activated yet ---"
|
||||
|
||||
if test -z "$umount_cmd"
|
||||
then
|
||||
echo "No executable program umount found in: $sudo_x_dir_list" >&2
|
||||
return 6
|
||||
fi
|
||||
partitions=$($lsblk_cmd -n -p -o NAME /dev/"$2" | grep -v '^'/dev/"$2"'$' \
|
||||
| sed -e 's/[^a-zA-Z0-9_+@:.,/-]//g' | tr '\n\r' ' ')
|
||||
echo "Would do: $sudo_cmd $umount_cmd /dev/"$2" $partitions"
|
||||
|
||||
if test -z "$dd_cmd"
|
||||
then
|
||||
echo "No executable program dd found in: $sudo_x_dir_list" >&2
|
||||
return 6
|
||||
fi
|
||||
echo "Would do: $sudo_cmd $dd_cmd if='${1}' bs=1M of=/dev/${2} ; sync"
|
||||
|
||||
echo "--- not activated yet ---"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
reset_job
|
||||
arg_interpreter "$@"
|
||||
list_devices
|
||||
if test -n "$list_all"
|
||||
then
|
||||
dummy=dummy
|
||||
elif test -n "$do_write"
|
||||
then
|
||||
with_vendor_model=
|
||||
show_reasons=
|
||||
candidates=$(list_devices | tr '\n\r' ' ')
|
||||
num=$(echo $candidates | wc -w)
|
||||
if test "$num" -eq 1
|
||||
then
|
||||
if test -n "$image_file"
|
||||
then
|
||||
write_image "$image_file" $candidates
|
||||
exit $?
|
||||
else
|
||||
echo "Would write to /dev/$candidates if an -image_file were given." >&2
|
||||
exit 0
|
||||
fi
|
||||
elif test "$num" -gt 1
|
||||
then
|
||||
echo "WILL NOT WRITE ! More than one candidate found for target device:" >&2
|
||||
show_reasons=y
|
||||
with_vendor_model=y
|
||||
devs="$candidates"
|
||||
list_devices >&2
|
||||
echo "HINT: Re-run with one of the names {$(echo $candidates | sed -e 's/ /,/g')} as additional argument." >&2
|
||||
exit 3
|
||||
else
|
||||
if test -n "$devs_named"
|
||||
then
|
||||
echo "NO CANDIDATE FOR TARGET DEVICE AMONG THE GIVEN NAMES !" >&2
|
||||
echo "Overall available devices:"
|
||||
else
|
||||
echo "NO CANDIDATE FOR TARGET DEVICE FOUND !" >&2
|
||||
fi
|
||||
list_all=y
|
||||
show_reasons=y
|
||||
with_vendor_model=y
|
||||
list_devices >&2
|
||||
exit 4
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$devs"
|
||||
then
|
||||
exit $not_advised
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user