operating-systemembeddedrtosqnx

Picking which QNX partition to boot into automatically


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.


Solution

  • 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