USB removable storage selector: USBKeyChooser
I think I have it:
Replacing grep -Hv 0 /sys/block/*/removable
by grep -Hv ^ATA\ *$ /sys/block/*/device/vendor
seem work:
export USBKEYS=($(
grep -Hv ^ATA\ *$ /sys/block/*/device/vendor |
sed s/device.vendor:.*$/device\\/uevent/ |
xargs grep -H ^DRIVER=sd |
sed s/device.uevent.*$/size/ |
xargs grep -Hv ^0$ |
cut -d / -f 4
))
for dev in ${USBKEYS[@]} ;do
echo $dev \"$(
sed -e s/\ *$//g </sys/block/$dev/device/model
)\" ;
done
Or even using readlink
to ensure this is USB could be more accurate...
export USBKEYS=($(
xargs -n1 readlink < <(echo /sys/block/*) |
sed -ne 's+^.*/usb[0-9].*/\([^/]*\)$+/sys/block/\1/device/uevent+p' |
xargs grep -H ^DRIVER=sd |
sed s/device.uevent.*$/size/ |
xargs grep -Hv ^0$ |
cut -d / -f 4
))
for dev in ${USBKEYS[@]} ;do
echo $dev \"$(
sed -e s/\ *$//g </sys/block/$dev/device/model
)\" ;
done
Rewind:
In this I
Ensure this is USB (or removable
Ensure this work as an hard drive (not a CD-Rom)
Ensure they have size greater than 0 (not an empty Card reader)
Golfed version:
US=($(cut -d/ -f4 <(grep -vl ^0$ $(sed s@device/.*@size@ <(grep -l ^DRIVER=sd $(
sed s+/device.*$+/dev*/ue*+ <(grep -Hv ^ATA\ *$ /sys/block/*/device/vendor)) <(:))) <(:))))
set | grep ^US=
This could be written
US=($(
cut -d/ -f4 <(
grep -vl ^0$ $(
sed s@device/.*@size@ <(
grep -l ^DRIVER=sd $(
sed -ne 's+^.*/usb[0-9].*/\([^/]*\)$+/sys/block/\1/dev*/ue*+p' <(
xargs -n1 readlink < <(echo /sys/block/*)
)
) /dev/null # equivalant but quicker than <(:)
)) /dev/null)))
With readlink
, golfed version become:
US=($(cut -d/ -f4 <(grep -vl ^0$ $(sed s@device/.*@size@ <(grep -l ^DRIVER=sd $(
sed -ne 's+^.*/usb[0-9].*/\([^/]*\)$+/sys/block/\1/dev*/ue*+p' <(
xargs -n1 readlink < <(echo /sys/block/*)) ) <(:))) <(:))))
In fine: usbKeyChooser
There is the final version of usbKeyChooser subroutine in my live installer:
#!/bin/bash
DIALOG=whiptail
usbKeyChoose() {
while [ ! -b /dev/$STICK ] ;do
USBKEYS=($(
xargs -n1 readlink < <(echo /sys/block/*) |
sed -ne 's+^.*/usb[0-9].*/\([^/]*\)$+/sys/block/\1/device/uevent+p' |
xargs grep -H ^DRIVER=sd |
sed s/device.uevent.*$/size/ |
xargs grep -Hv ^0$ |
cut -d / -f 4 ))
if [ ${#USBKEYS[@]} -eq 0 ];then
title="No key found"
else
title="Choose wich USB stick have to be installed"
fi
menu=(R "Re scan devices")
for dev in ${USBKEYS[@]} ;do
read model </sys/block/$dev/device/model
menu+=($dev "$model")
done
num=$($DIALOG --menu "$title" 21 72 14 "${menu[@]}" 2>&1 >/dev/tty)
if [ ! "$num" ] ; then
echo "User aborted."
exit 0;
fi
[ ! "$num" = "R" ] && [ "${USBKEYS[num]}" ] && STICK=${USBKEYS[num]}
done; }
usbKeyChoose
echo $STICK
I like this looping solution because they
- let insert many keys,
- wait for kernel registration,
- valid the choice,
- default to nothing and
- permit user abort.
Anyway, even if user did wrong ok
choice, next screen is another choice asking user for which image have to be written on key defaulting to create new image wich is a very long process where user could hit Ctrl+c
Yes, you can do that. It's more work than relying on a package manager — the main attraction of “portable” installations under Windows is not to have to fight the lack of a decent package manager.
You'll need to arrange for the programs to find their dependencies: data files, libraries, etc. Many programs support environment variables for that. Some check the directory where the binary is located, or relative directories like ../lib
, for companion files
Install the software under some root directory. Create the usual category directories under that root: bin
, lib
, man
, etc. To manage all the software, install each one independently and then use a program like Stow create a forest of symbolic links to link them to the category directories. See Keeping track of programs for an introduction to Stow. You'll thus have symbolic links like
bin/foo -> ../stow/foo-1.42/bin/foo
bin/foobar -> ../stow/foo-1.42/bin/foobar
man/man1/foo.1 -> ../../stow/foo-1.42/man/man1/foo.1
…
You'll want a script to set up environment variables. Put it at the root of your installation and use $0
to locate the script. Since a script can't influence its parent, the usual approach is to make the script produce output that can be evaluated by the calling shell. Let's call this script setup.sh
.
#!/bin/sh
set -e
root=$(dirname -- "$0")
cd -- "$root"
printf "PORTABLE_ROOT='%s'\\n" "${PWD}" | sed "s/'/'\\\\''/g"
prepend () {
eval "set -- \"\$1\" \"\$2\" \"${$1}\""
case :$3: in
*:$PORTABLE_ROOT/$2:*) :;; # already there (at any location)
:: echo '$1=$PORTABLE_ROOT/$2; export $1';; # the path was empty
*) echo '$1=$PORTABLE_ROOT/$2:$3; export $1';; # prepend
esac
}
prepend PATH bin
prepend MANPATH man
prepend LD_LIBRARY_PATH lib
prepend PERL5LIB lib/perl
prepend PYTHONPATH lib/python
…
(Warning: untested code)
To use the portable installation from a shell, run eval "`/path/to/setup.sh`"
.
Best Answer
Martin Monperrus wrote a wonderfully quick guide to auto-mounting on Linux using the
udev
package. Here's a copy of the ussefull bits but be sure to check the comments there tooNote the bits about
KERNEL=="sdb*",
andKERNEL=="sdc*",
are relotive and you may wish to useUUID
's to make sure that udev auto-mounts the correct drive to the correct directory path regardless of what USB port it gets re-plugged into. A quick search pulled up an Arch Linux forum post on using uuid instead of sdb* or sdc* error prone way of mounting. Once the drive auto-mounts properly then it should only require adding the properexport PATH=/mnt/media/some_usb/program/:$PATH
line to the shell's enviroment variables so that the program can be called by name for that user.