I currently have an embedded device with a flash card that has 3 QNX 6.5.0SP1 partitions - two bootable partitions (fs type 79), one data partition (fs type 78). I would like to programmatically choose which of these two bootable partitions to boot into, based on a flag of some sort on the data partition (perhaps a touch
'd file) set by user interaction before shutdown. Is this possible? Ideally, the end result would have the chosen partition's file system mounted to root once booted.
I have tried modifying the .boot
file, but I believe the partition has already been booted by the time execution is handed to .boot
. I believe I need to modify the IPL, but I'm unsure how to read from any file system during the IPL.
The simplest solution is to mark the "active" bootable partion by ensuring it's the only one with a .diskroot
file that instructs diskboot
to mount it as /
. The switching process would be: use fdisk boot
to mark the new root partition as bootable; then mv /.diskroot
to it.
If it is a strict requirement that the bootable partitions are not writable, you'll need to design a replacement boot script for your system that starts up the key drivers and does its own mounting, as diskboot
does not support complex mounting behaviour (it does not support duplicate .diskroot mount points). Your updated script can be linked in to a replacment for the .boot
file using mkifs.
Key reference documentation:
Finally, as a leg up, I can offer this shell script "fsscan" my company used to use for this purpose back in the QNX 6.3 days. This script looks for a partition with a ".bootkey" file that matches a "bootkey" file included in the IFS; the contents of this file were a short version and date stamp. This let us select a boot partition with nothing but fdisk boot
, and it would find and mount the matching root partition.
#/proc/boot/sh
# fsscan for QNX - scans for and mounts filesystems
# includes analysis of .diskroot for QNX filesystems for use at boot.
# Options
do_mount=0
build_fstab=1
parse_diskroot=0
commit_string=""
keyfile="/proc/boot/bootkey"
## Parse commandline
while getopts "mndck:" opt ; do
case $opt in
m)
do_mount=1
;;
n)
build_fstab=0
;;
d)
parse_diskroot=1
;;
k)
keyfile="$OPTARG"
;;
c)
commit_string="commit=none"
;;
esac
done
if [ -r "$keyfile" ]; then
keydata=`cat $keyfile`
else
keyfile=""
fi
echo "Scanning available disk partitions..."
if [ "$build_fstab" -eq 1 ]; then
echo "# fstab build by fsscan on `date`" > /etc/fstab
fi
# Get QNX devices
# We use two passes to figure out what to do. First pass pre-mounts devices
# and locates .bootkey, second pass manages other .diskroots.
UD=`ls /dev/ud*t79 /dev/ud*t78 /dev/ud*t77 2>/dev/null`
HD=`ls /dev/hd*t79 /dev/hd*t78 /dev/hd*t77 2>/dev/null`
QDEVS="$UD $HD"
# First pass
did_mount=""
was_mounted=""
for device in $QDEVS; do
disk=`echo $device | sed -e "s/\/dev\/[hu]d\(.*\)t7[789]/\1/"`
type=`echo $device | sed -n -e "s/\/dev\/\([hu]\)d.*t7[789]/\1/p"`
id=`echo $device | sed -n -e "s/\/dev\/[hu]d.*t\(7[789]\)/\1/p"`
mountopts="rw"
if [ ! -z "$commit_string" ]; then
mountopts="$mountopts,$commit_string"
fi
# Check if already mounted
mountpt=`df $device | awk "\\$1 == \"$device\" {print \\$6}"`
is_mounted=0
if [ -z "$mountpt" ]; then
num=$((80 - $id))
mountpt="/fs/${type}d$disk-qnx4-$num"
if [ "$do_mount" -eq 1 ]; then
echo "Found QNX filesystem at $device, mounting as $mountpt"
mount -t qnx4 -o $mountopts $device $mountpt
is_mounted=1
did_mount="$did_mount $device"
fi;
else
is_mounted=1
was_mounted="$was_mounted $device"
echo "Found QNX filesystem at $device already mounted as $mountpt"
fi
if [ "$is_mounted" -eq 1 ]; then
if [ -n "$keyfile" -a "$parse_diskroot" -eq 1 -a -r $mountpt/.diskroot -a -r $mountpt/.bootkey ]; then
# Check boot key.
fskeydata=`cat $mountpt/.bootkey`
if [ "$keydata" = "$fskeydata" ]; then
# Handle diskroot RIGHT NOW
diskroot=`awk 'BEGIN { mp = "/" }
(NR == 1) && /\// { mp = $0; }
/^[ \t]*mount[ \t]*=/ { split($0,parts,/=/); mp = parts[2]; gsub(/^[ \t]*/,"",mp); gsub(/[ \t]*$/,"",mp); }
END { print mp; }' <$mountpt/.diskroot`
# echo "$device: Diskroot mountpoint is '$diskroot'"
if [ -z "$diskroot" ]; then
diskroot="/"
fi
# Check for existing partition there
if df $diskroot | awk "\$6 != \"$diskroot\" {exit 0} {exit 1}"; then
echo "Relocating QNX filesystem with matching key at $device to $diskroot"
umount $mountpt
if [ "$do_mount" -eq 1 ]; then
mount -t qnx4 -o $mountopts $device $diskroot
fi
mountpt="$diskroot"
fi
fi
fi;
else
echo "Found QNX filesystem at $device, mountable as $mountpt"
fi
done;
#echo "Did mount: '$did_mount' Was mounted: '$was_mounted'"
# Second pass
for device in $QDEVS; do
disk=`echo $device | sed -e "s/\/dev\/[hu]d\(.*\)t7[789]/\1/"`
type=`echo $device | sed -n -e "s/\/dev\/\([hu]\)d.*t7[789]/\1/p"`
id=`echo $device | sed -n -e "s/\/dev\/[hu]d.*t\(7[789]\)/\1/p"`
mountopts="rw"
if [ ! -z "$commit_string" ]; then
mountopts="$mountopts,$commit_string"
fi
# Check if already mounted
mountpt=`df $device | awk "\\$1 == \"$device\" {print \\$6}"`
if echo $was_mounted | grep -q $device || echo $did_mount | grep -q $device; then
# Process diskroot
#echo "Considering $device for diskroot"
# Read .diskroot
if [ "$parse_diskroot" -eq 1 -a -r $mountpt/.diskroot ]; then
diskroot=`awk 'BEGIN { mp = "/" }
(NR == 1) && /\// { mp = $0; }
/^[ \t]*mount[ \t]*=/ { split($0,parts,/=/); mp = parts[2]; gsub(/^[ \t]*/,"",mp); gsub(/[ \t]*$/,"",mp); }
END { print mp; }' <$mountpt/.diskroot`
# echo "$device: Diskroot mountpoint is '$diskroot'"
if [ -z "$diskroot" ]; then
diskroot="/"
fi
# echo "Using '$diskroot' for $device"
# Check for existing partition there
if df $diskroot | awk "\$6 != \"$diskroot\" {exit 0} {exit 1}"; then
echo "Relocating QNX filesystem at $device to $diskroot"
echo "umount $mountpt"
umount $mountpt
if [ "$do_mount" -eq 1 ]; then
echo "mount -t qnx4 -o $mountopts $device $diskroot"
mount -t qnx4 -o $mountopts $device $diskroot
fi
mountpt="$diskroot"
fi
fi
else
# Check is now mounted == bootkey
if [ -z "$mountpt" ]; then
num=$((80 - $id))
mountpt="/fs/${type}d$disk-qnx4-$num"
fi
fi
if [ "$build_fstab" -eq 1 ]; then
echo "$device $mountpt qnx4 $mountopts 0 0" >> /etc/fstab
fi;
done;
# Grab DOS devices.
lastdisk=""
for id in 1 4 6 11 12; do
for device in `ls /dev/hd*t$id /dev/hd*t$id.* /dev/ud*t$id /dev/ud*t$id.* 2>/dev/null`; do
disk=`echo $device | sed -e "s/\/dev\/\([hu]d.*\)t$id.*/\1/"`
# Check if already mounted
mountpt=`df $device | awk "\\$1 == \"$device\" {print \\$6}"`
mountopts="rw"
if [ -z "$mountpt" ]; then
is_mounted=0
# Find mountpoint
if [ "X$lastdisk" != "X$disk" ]; then
lastdisk="$disk"
num=0
fi
while [ -z "$mountpt" ]; do
num=$(($num + 1))
mountpt="/fs/$disk-dos-$num"
if [ -e "$mountpt" ]; then
mountpt=""
fi
done;
if [ "$do_mount" -eq 1 ]; then
echo "Found DOS filesystem at $device, mounting as $mountpt"
mount -t dos -o $mountopts $device $mountpt
else
echo "Found DOS filesystem at $device, mountable as $mountpt"
fi
else
echo "Found DOS filesystem at $device, already mounted as $mountpt"
fi
if [ "$build_fstab" -eq 1 ]; then
echo "$device $mountpt dos $mountopts 0 0" >> /etc/fstab
fi
done;
done;
echo "Partition scan complete."
NB: this script requires a full shell and some UNIX text processing utilities to be included in the .boot IFS. QNX worked hard to keep their default IFS as small as possible; this wasn't a limitation for our application.
mount
umount
sleep
sh
awk
sed
ls
cat
echo
df
grep