英文:
Picking which QNX partition to boot into automatically
问题
我目前有一个嵌入式设备,其中有一个带有3个QNX 6.5.0SP1分区的闪存卡 - 两个可引导分区(文件系统类型79),一个数据分区(文件系统类型78)。我想根据数据分区上的某种标志(可能是一个touch
命令创建的文件),在关机前通过用户交互来编程选择要引导的两个可引导分区中的哪一个。这种做法可行吗?理想情况下,选择的分区的文件系统在引导后会被挂载到根目录。
我尝试修改.boot
文件,但我相信在执行交给.boot
之前,分区已经被引导了。我相信我需要修改IPL,但我不确定如何在IPL期间从任何文件系统中读取数据。
英文:
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.
答案1
得分: 1
最简单的解决方案是通过确保只有一个带有.diskroot
文件的“活动”可引导分区,该文件指示diskboot
将其挂载为/
。切换过程如下:使用fdisk boot
将新的根分区标记为可引导;然后将/.diskroot
移动到该分区。
如果要求可引导分区不可写入,您需要为系统设计一个替代的启动脚本,该脚本启动关键驱动程序并执行自己的挂载操作,因为diskboot
不支持复杂的挂载行为(它不支持重复的.diskroot
挂载点)。您可以使用mkifs将更新的脚本链接到.boot
文件的替代品中。
关键参考文档:
最后,作为帮助,我可以提供这个Shell脚本“fsscan”,这是我们公司在QNX 6.3时代用于此目的的脚本。该脚本会查找具有与IFS中包含的“bootkey”文件匹配的“.bootkey”文件的分区;该文件的内容是一个简短的版本和日期戳。这样,我们就可以仅使用fdisk boot
选择引导分区,它会找到并挂载匹配的根分区。
#/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."
注意:此脚本需要在.boot
IFS中包含完整的Shell和一些UNIX文本处理实用程序。QNX努力使其默认IFS尽可能小;这对我们的应用程序来说不是一个限制。
mount
umount
sleep
sh
awk
sed
ls
cat
echo
df
grep
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论