home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/wishx
-
- # /dev/ide/c0b0t0ux
-
-
- set partType(00) "Empty"
- set partType(01) "DOS 12-bit FAT"
- set partType(02) "XENIX root"
- set partType(03) "XENIX usr"
- set partType(04) "DOS 16-bit <32M"
- set partType(05) "Extended"
- set partType(06) "DOS 16-bit >=32M"
- set partType(07) "OS/2 HPFS"
- set partType(08) "AIX"
- set partType(09) "AIX bootable"
- set partType(0a) "OS/2 Boot Manag"
- set partType(0b) "Win95 FAT32"
- set partType(0c) "Win95 FAT32 LBA"
- set partType(0e) "Win95 FAT16 LBA"
- set partType(0f) "Win95 Extended"
- set partType(40) "Venix 80286"
- set partType(51) "Novell?"
- set partType(52) "Microport"
- set partType(63) "GNU HURD"
- set partType(64) "Novell Netware"
- set partType(65) "Novell Netware"
- set partType(75) "PC/IX"
- set partType(80) "Old MINIX"
- set partType(81) "Linux/MINIX"
- set partType(82) "Linux swap"
- set partType(83) "Linux native"
- set partType(85) "Linux extended"
- set partType(93) "Amoeba"
- set partType(94) "Amoeba BBT"
- set partType(a5) "BSD/386"
- set partType(a6) "OpenBSD"
- set partType(a7) "NEXTSTEP"
- set partType(b7) "BSDI fs"
- set partType(b8) "BSDI swap"
- set partType(c7) "Syrinx"
- set partType(db) "CP/M"
- set partType(e1) "DOS access"
- set partType(e3) "DOS R/O"
- set partType(f2) "DOS secondary"
- set partType(ff) "BBT"
-
- proc ExtendedPartition {drive fileName sector part} {
- global db extendedStart partType
-
- set br [ReadSector $fileName $sector]
-
- binary scan $br "@510h4" magic
- if {$magic != "55aa"} {
- # error "bad MBR"
- }
-
- set foundExtended 0
- set foundPartition 0
-
- for {set i 0} {$i < 4} {incr i} {
- set addr [expr {446 + $i*16}]
-
- binary scan $br "@${addr}ccccH2cccii" \
- boot head sect cyl \
- id endHead endSect endCyl \
- start num
-
- switch $id {
- "00" {
- continue
- }
-
- "05" -
- "85" -
- "0f" {
- if {$foundExtended} {
- # puts "bad extended"
- continue
- }
-
- set foundExtended 1
-
- ExtendedPartition $drive $fileName \
- [expr {$extendedStart + $start}] \
- [expr {$part + 1}]
- continue
- }
-
- "default" {
- if {$foundPartition} {
- # puts "bad partition"
- continue
- }
- set foundPartition 1
- }
- }
-
- # puts "$drive$part $partType($id)"
-
- lappend db(hostRawDisk.$drive.partitions) $part
- set db(hostRawDisk.$drive.$part.start) [expr {$sector + $start}]
- set db(hostRawDisk.$drive.$part.end) [expr {$sector + $start + $num}]
- set db(hostRawDisk.$drive.$part.id) $id
- if {[info exists partType($id)]} {
- set db(hostRawDisk.$drive.$part.type) $partType($id)
- } else {
- set db(hostRawDisk.$drive.$part.type) "Unknown"
- }
- set db(rawDisk.$drive.$part.access) ro
- }
- }
-
- proc PartitionTable {drive fileName} {
- global db extendedStart partType
-
- set br [ReadSector $fileName 0]
-
- binary scan $br "@510h4" magic
- if {$magic != "55aa"} {
- # error "bad MBR"
- }
-
- for {set part 1} {$part <= 4} {incr part} {
- set addr [expr {430 + $part*16}]
-
- binary scan $br "@${addr}ccccH2cccii" \
- boot head sect cyl \
- id endHead endSect endCyl \
- start num
-
- switch $id {
- "00" {
- continue
- }
-
- "05" -
- "85" -
- "0f" {
- # primary extended partition
- set extendedStart $start
- ExtendedPartition $drive $fileName $start 5
- }
-
- "default" {
- }
- }
-
- # puts "$drive$part $partType($id)"
-
- lappend db(hostRawDisk.$drive.partitions) $part
- set db(hostRawDisk.$drive.$part.start) $start
- set db(hostRawDisk.$drive.$part.end) [expr {$start + $num}]
- set db(hostRawDisk.$drive.$part.id) $id
- if {[info exists partType($id)]} {
- set db(hostRawDisk.$drive.$part.type) $partType($id)
- } else {
- set db(hostRawDisk.$drive.$part.type) "Unknown"
- }
- set db(rawDisk.$drive.$part.access) ro
- }
- }
-
-
- ##
- ## This proc fills in the following info.
- ##
- ##
- ## db(hostRawDisk.drives) : List of detected ro or rw drives
- ## db(hostRawDisk.<drive>.userAccess) { np none ro rw }
- ## db(hostRawDisk.<drive>.partitions)
- ## db(hostRawDisk.<drive>.<partition>.start)
- ## db(hostRawDisk.<drive>.<partition>.end)
- ## db(hostRawDisk.<drive>.<partition>.id)
- ## db(hostRawDisk.<drive>.<partition>.type)
- ##
- ## db(rawDisk.<drive>.used)
- ## db(rawDisk.<drive>.<partition>.access) { none ro rw }
- ##
-
- proc GetRawDiskInfo {drive} {
- global db
-
- set db(rawDisk.$drive.used) 0
- set fileName [file join /dev $drive]
-
- if {![file exists $fileName]} {
- set db(hostRawDisk.$drive.userAccess) np
- return
- }
-
- if {[info exists db(hostRawDisk.$drive.partitions)]} {
- unset db(hostRawDisk.$drive.partitions)
- }
-
- if [catch {PartitionTable $drive $fileName} err] {
- # puts $err
- if {[info exists db(hostRawDisk.$drive.partitions)]} {
- unset db(hostRawDisk.$drive.partitions)
- }
- }
-
- if {[info exists db(hostRawDisk.$drive.partitions)]} {
- set db(hostRawDisk.$drive.partitions) \
- [lsort -integer -increasing $db(hostRawDisk.$drive.partitions)]
- }
-
- if {[file readable $fileName] && [file writable $fileName]} {
- set db(hostRawDisk.$drive.userAccess) rw
- } elseif {[file readable $fileName]} {
- set db(hostRawDisk.$drive.userAccess) ro
- } else {
- set db(hostRawDisk.$drive.userAccess) none
- return
- }
-
- if {![info exists db(hostRawDisk.$drive.partitions)]} {
- set db(hostRawDisk.$drive.userAccess) np
- return
- }
-
- lappend db(hostRawDisk.drives) $drive
-
- # min is some big num
- set min 1000000
-
- foreach p $db(hostRawDisk.$drive.partitions) {
- if {$db(hostRawDisk.$drive.$p.start) < $min} {
- set min $db(hostRawDisk.$drive.$p.start)
- }
- }
-
- if {$min != 0} {
- # If the beginning of the disk is not already included in a partition,
- # create an additional special range for it
- set db(hostRawDisk.$drive.partitions) [linsert $db(hostRawDisk.$drive.partitions) 0 0]
- set db(hostRawDisk.$drive.0.start) 0
- set db(hostRawDisk.$drive.0.end) $min
- set db(hostRawDisk.$drive.0.id) "MBR"
- set db(hostRawDisk.$drive.0.type) "MBR"
-
- set db(rawDisk.$drive.0.access) ro
- }
-
- set db(rawDisk.$drive.used) 1
- }
-
- # Perform half of a range overlapping check on 2 ranges
- # Return 1 if we should care about overlapping
- proc RawDisk_CheckHalfOverlappingRange {r1 r2} {
- global db
-
- if {($db(${r1}.start) <= $db(${r2}.start)) && ($db(${r2}.start) < $db(${r1}.end))} {
- # r2 starts in r1
- if {$db(${r2}.end) > $db(${r1}.end)} {
- # r2 ends out of r1
- return 1
- }
-
- # r2 ends in r1
- if {[RawDisk_IsExtendedRange $r1]} {
- # r1 is the extended partition
- # This special case is handled when we save the safe raw disk file
- return 0
- }
-
- # r1 is not the extended partition
- return 1
- }
-
- # r2 does not start in r1
- return 0
- }
-
- # Perform a range overlapping check on 2 ranges
- # Return 1 if we should care about overlapping
- proc RawDisk_CheckOverlappingRange {r1 r2} {
- if { [RawDisk_CheckHalfOverlappingRange $r1 $r2]
- || [RawDisk_CheckHalfOverlappingRange $r2 $r1]} {
- return 1
- }
- return 0
- }
-
- # Determine if a range corresponds to an extended partition
- proc RawDisk_IsExtendedRange {r} {
- global db
-
- if { ($db(${r}.id) == "05")
- || ($db(${r}.id) == "85")
- || ($db(${r}.id) == "0F")} {
- return 1
- }
- return 0
- }
-
- # Sort the range set increasing starting sector order
- # Return the sorted list
- proc RawDisk_SortRanges {drive} {
- global db
-
- # Bubble sort
- set partitionList $db(hostRawDisk.${drive}.partitions)
- set sortedList $partitionList
- for {set i 0} {$i < [llength $sortedList]} {incr i 1} {
- for {set j [expr $i + 1]} {$j < [llength $sortedList]} {incr j 1} {
- set partition_i [lindex $sortedList $i]
- set partition_j [lindex $sortedList $j]
- if {$db(hostRawDisk.${drive}.${partition_i}.start) > $db(hostRawDisk.${drive}.${partition_j}.start)} {
- set sortedList [lreplace $sortedList $i $i $partition_j]
- set sortedList [lreplace $sortedList $j $j $partition_i]
- }
- }
- }
- return $sortedList
- }
-
- # Write a range to the safe raw disk file
- # Note: NO_ACCESS is assumed for all ranges not specified in the file
- # Return 1 if success
- proc RawDisk_WriteRange {fd start end type} {
- switch $type {
- "none" {
- set typeStr "NO_ACCESS"
- }
- "ro" {
- set typeStr "RDONLY"
- }
- "rw" {
- set typeStr "ACCESS"
- }
- }
-
- # Externally, the end sector is included, internally it is not
- set end [expr $end - 1]
- puts -nonewline $fd "$typeStr $start $end\n"
- return 1
- }
-
- # If the hole is valid, write its intersection with the extended
- # partition to the safe raw disk file
- # Return 1 if success
- proc RawDisk_WriteHole {fd drive ext holeStart holeEnd} {
- global db
-
- if {$holeStart >= $holeEnd} {
- # There is no hole
- return 1
- }
-
- # There is a valid hole
- # Compute its intersection with the extended partition
- if {($holeEnd <= $db(hostRawDisk.${drive}.${ext}.start)) || ($db(hostRawDisk.${drive}.${ext}.end) <= $holeStart)} {
- # The intersection is empty
- return 1
- }
-
- # The intersection exists
- puts -nonewline $fd "\# Extended partition hole\n"
-
- return [RawDisk_WriteRange $fd [max $holeStart $db(hostRawDisk.${drive}.${ext}.start)] [min $holeEnd $db(hostRawDisk.${drive}.${ext}.end)] $db(rawDisk.${drive}.${ext}.access)]
- }
-
- # Create a safe raw disk file
- # Return 1 if everything is ok
- proc RawDisk_Save {drive fileName} {
- global db
-
- if {[catch {set fd [open $fileName w]} err]} {
- DialogWin .error "Configuration Wizard Error" \
- "Failed to open $db(directory)$db(OS.name).$drive: $err" {} 0 OK
- return 0
- }
-
- puts -nonewline $fd "DEVICE /dev/$drive\n\n"
-
- # This is required by the following algorithm
- set sortedList [RawDisk_SortRanges $drive]
-
- # Find the index of the extended partition, because it
- # is a special case: it represents only the holes between the logical
- # partitions it contains.
- #
- # Note: We must do this in a separate loop because otherwise, nothing
- # ensures that the extended partition will be seen before its content.
- set ext ""
- foreach range $sortedList {
- if {[RawDisk_IsExtendedRange hostRawDisk.${drive}.${range}]} {
- set ext $range
- break
- }
- }
-
- set holeStart 0
- foreach range $sortedList {
- # Deal with the next hole
- if {$ext != ""} {
- if {$range == $ext} {
- # Skip the extended partition
- continue
- }
-
- set holeEnd $db(hostRawDisk.${drive}.${range}.start)
- if {[RawDisk_WriteHole $fd $drive $ext $holeStart $holeEnd] == 0} {
- close $fd
- return 0
- }
- # 2 partitions could start at the same sector, with the second one
- # being smaller than the first one. Thanks to max, this quantity
- # can only increase
- set holeStart [max $holeStart $db(hostRawDisk.${drive}.${range}.end)]
- }
-
- if {$db(hostRawDisk.${drive}.${range}.type) != ""} {
- puts -nonewline $fd "\# Partition type: $db(hostRawDisk.${drive}.${range}.type)\n"
- }
- if {[RawDisk_WriteRange $fd $db(hostRawDisk.${drive}.${range}.start) $db(hostRawDisk.${drive}.${range}.end) $db(rawDisk.${drive}.${range}.access)] == 0} {
- close $fd
- return 0
- }
- }
- # Deal with the last hole
- if {$ext != ""} {
- # Ideally, we should use the number of sectors on the disk here. This
- # info is not easily available. Fortunately, this value will do just
- # fine for what we want to do
- set holeEnd $db(hostRawDisk.${drive}.${ext}.end)
- if {[RawDisk_WriteHole $fd $drive $ext $holeStart $holeEnd] == 0} {
- close $fd
- return 0
- }
- }
- close $fd
- return 1
- }
-
-