自动选择要引导的QNX分区

huangapple go评论83阅读模式
英文:

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=&quot;&quot;
keyfile=&quot;/proc/boot/bootkey&quot;

## Parse commandline
while getopts &quot;mndck:&quot; opt ; do
	case $opt in
		m)
			do_mount=1
		;;
		n)
			build_fstab=0
		;;
		d)
			parse_diskroot=1
		;;
		k)
			keyfile=&quot;$OPTARG&quot;
		;;
		c)
			commit_string=&quot;commit=none&quot;
		;;
	esac
done

if [ -r &quot;$keyfile&quot; ]; then
    keydata=`cat $keyfile`
else
    keyfile=&quot;&quot;
fi    


echo &quot;Scanning available disk partitions...&quot;

if [ &quot;$build_fstab&quot; -eq 1 ]; then
    echo &quot;# fstab build by fsscan on `date`&quot; &gt; /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&gt;/dev/null`
HD=`ls /dev/hd*t79 /dev/hd*t78 /dev/hd*t77 2&gt;/dev/null`

QDEVS=&quot;$UD $HD&quot;

# First pass
did_mount=&quot;&quot;
was_mounted=&quot;&quot;
for device in $QDEVS; do
	disk=`echo $device | sed -e &quot;s/\/dev\/[hu]d\(.*\)t7[789]/\1/&quot;`	
	type=`echo $device | sed -n -e &quot;s/\/dev\/\([hu]\)d.*t7[789]/\1/p&quot;`	
	id=`echo $device | sed -n -e &quot;s/\/dev\/[hu]d.*t\(7[789]\)/\1/p&quot;`	

    mountopts=&quot;rw&quot;
    if [ ! -z &quot;$commit_string&quot; ]; then
    	mountopts=&quot;$mountopts,$commit_string&quot;
    fi
    
    # Check if already mounted
    mountpt=`df $device | awk &quot;\\$1 == \&quot;$device\&quot; {print \\$6}&quot;`

    is_mounted=0
    
    if [ -z &quot;$mountpt&quot; ]; then                
		num=$((80 - $id))
		mountpt=&quot;/fs/${type}d$disk-qnx4-$num&quot;		
		
        if [ &quot;$do_mount&quot; -eq 1 ]; then 
            
            echo &quot;Found QNX filesystem at $device, mounting as $mountpt&quot;   	    
            mount -t qnx4 -o $mountopts $device $mountpt
            is_mounted=1
            did_mount=&quot;$did_mount $device&quot;
        fi;
	
    else
        is_mounted=1        
        was_mounted=&quot;$was_mounted $device&quot;        
        echo &quot;Found QNX filesystem at $device already mounted as $mountpt&quot;
    fi
    
    if [ &quot;$is_mounted&quot; -eq 1 ]; then         
        if [ -n &quot;$keyfile&quot; -a &quot;$parse_diskroot&quot; -eq 1 -a -r $mountpt/.diskroot -a -r $mountpt/.bootkey ]; then
            # Check boot key.
            fskeydata=`cat $mountpt/.bootkey`
            if [ &quot;$keydata&quot; = &quot;$fskeydata&quot; ]; then
                # Handle diskroot RIGHT NOW
           	    diskroot=`awk &#39;BEGIN { mp = &quot;/&quot; }
(NR == 1) &amp;&amp; /\// { mp = $0; }
/^[ \t]*mount[ \t]*=/ { split($0,parts,/=/); mp = parts[2]; gsub(/^[ \t]*/,&quot;&quot;,mp); gsub(/[ \t]*$/,&quot;&quot;,mp);  }
END { print mp; }&#39; &lt;$mountpt/.diskroot`

#					echo &quot;$device: Diskroot mountpoint is &#39;$diskroot&#39;&quot;   	           	    
          	    
           	    if [ -z &quot;$diskroot&quot; ]; then   	        
           	        diskroot=&quot;/&quot;
           	    fi
           	    
           	    # Check for existing partition there
           	    if df $diskroot | awk &quot;\$6 != \&quot;$diskroot\&quot; {exit 0} {exit 1}&quot;; then
           	        echo &quot;Relocating QNX filesystem with matching key at $device to $diskroot&quot;
           	        umount $mountpt
           	        if [ &quot;$do_mount&quot; -eq 1 ]; then
           	            mount -t qnx4 -o $mountopts $device $diskroot
           	        fi
           	        mountpt=&quot;$diskroot&quot;
                fi   	                      
            fi                
        fi;   
    else
   	        echo &quot;Found QNX filesystem at $device, mountable as $mountpt&quot;   	            	
    fi    
    
done;

#echo &quot;Did mount: &#39;$did_mount&#39;   Was mounted: &#39;$was_mounted&#39;&quot;

# Second pass
for device in $QDEVS; do
	disk=`echo $device | sed -e &quot;s/\/dev\/[hu]d\(.*\)t7[789]/\1/&quot;`	
	type=`echo $device | sed -n -e &quot;s/\/dev\/\([hu]\)d.*t7[789]/\1/p&quot;`	
	id=`echo $device | sed -n -e &quot;s/\/dev\/[hu]d.*t\(7[789]\)/\1/p&quot;`	

    mountopts=&quot;rw&quot;
	if [ ! -z &quot;$commit_string&quot; ]; then
		mountopts=&quot;$mountopts,$commit_string&quot;
	fi
    
    # Check if already mounted
    mountpt=`df $device | awk &quot;\\$1 == \&quot;$device\&quot; {print \\$6}&quot;`

    if echo $was_mounted | grep -q $device || echo $did_mount | grep -q $device; then
        # Process diskroot
		#echo &quot;Considering $device for diskroot&quot;
   	    # Read .diskroot
   	    if [ &quot;$parse_diskroot&quot; -eq 1 -a -r $mountpt/.diskroot ]; then
       	    diskroot=`awk &#39;BEGIN { mp = &quot;/&quot; }
(NR == 1) &amp;&amp; /\// { mp = $0; }
/^[ \t]*mount[ \t]*=/ { split($0,parts,/=/); mp = parts[2]; gsub(/^[ \t]*/,&quot;&quot;,mp); gsub(/[ \t]*$/,&quot;&quot;,mp);  }
END { print mp; }&#39; &lt;$mountpt/.diskroot`

#			echo &quot;$device: Diskroot mountpoint is &#39;$diskroot&#39;&quot;   	           	    
      	    
       	    if [ -z &quot;$diskroot&quot; ]; then   	        
       	        diskroot=&quot;/&quot;
       	    fi
       	    
#			echo &quot;Using &#39;$diskroot&#39; for $device&quot;   	           	    
			       	    
       	    # Check for existing partition there
       	    if df $diskroot | awk &quot;\$6 != \&quot;$diskroot\&quot; {exit 0} {exit 1}&quot;; then
       	        echo &quot;Relocating QNX filesystem at $device to $diskroot&quot;
       	        echo &quot;umount $mountpt&quot;
       	        umount $mountpt
       	        if [ &quot;$do_mount&quot; -eq 1 ]; then
           	        echo &quot;mount -t qnx4 -o $mountopts $device $diskroot&quot;       	        
       	            mount -t qnx4 -o $mountopts $device $diskroot
       	        fi
       	        mountpt=&quot;$diskroot&quot;
            fi   	        
   	    fi   	       	    
    else
        # Check is now mounted == bootkey
        if [ -z &quot;$mountpt&quot; ]; then                
   			num=$((80 - $id))
   			mountpt=&quot;/fs/${type}d$disk-qnx4-$num&quot;
        fi
    fi

    if [ &quot;$build_fstab&quot; -eq 1 ]; then
        echo &quot;$device 	$mountpt 	qnx4 	$mountopts 	0 	0&quot; &gt;&gt; /etc/fstab
    fi;
done;           	    



# Grab DOS devices.
lastdisk=&quot;&quot;
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&gt;/dev/null`; do
		disk=`echo $device | sed -e &quot;s/\/dev\/\([hu]d.*\)t$id.*/\1/&quot;`	

        # Check if already mounted
        mountpt=`df $device | awk &quot;\\$1 == \&quot;$device\&quot; {print \\$6}&quot;`
	    mountopts=&quot;rw&quot;

		
        if [ -z &quot;$mountpt&quot; ]; then                
            is_mounted=0
            
            # Find mountpoint
    		if [ &quot;X$lastdisk&quot; != &quot;X$disk&quot; ]; then
    			lastdisk=&quot;$disk&quot;
    			num=0
    		fi
            
            while [ -z &quot;$mountpt&quot; ]; do
                num=$(($num + 1))
       			mountpt=&quot;/fs/$disk-dos-$num&quot;
        		if [ -e &quot;$mountpt&quot; ]; then
        		    mountpt=&quot;&quot;
        		fi
            done;

    	    if [ &quot;$do_mount&quot; -eq 1 ]; then
   	    	    echo &quot;Found DOS filesystem at $device, mounting as $mountpt&quot;
    	        mount -t dos -o $mountopts $device $mountpt
    	    else
   	    	    echo &quot;Found DOS filesystem at $device, mountable as $mountpt&quot;
    	    fi
	        		            
        else
		    echo &quot;Found DOS filesystem at $device, already mounted as $mountpt&quot;        
		fi
		
		if [ &quot;$build_fstab&quot; -eq 1 ]; then
	        echo &quot;$device 	$mountpt dos 	$mountopts 	0 	0&quot; &gt;&gt; /etc/fstab
	    fi	    
	done;
done;

    
echo &quot;Partition scan complete.&quot;

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

huangapple
  • 本文由 发表于 2023年8月8日 22:30:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76860535.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定