home *** CD-ROM | disk | FTP | other *** search
/ Chip: Linux Special / CorelLinux_CHIP.iso / VMware / bin / vmware-wizard / rawdisk.tcl < prev    next >
Encoding:
Tcl/Tk script  |  1999-11-08  |  12.4 KB  |  436 lines

  1. #!/usr/bin/wishx
  2.  
  3. # /dev/ide/c0b0t0ux
  4.  
  5.  
  6. set partType(00) "Empty"
  7. set partType(01) "DOS 12-bit FAT"
  8. set partType(02) "XENIX root"
  9. set partType(03) "XENIX usr"
  10. set partType(04) "DOS 16-bit <32M"
  11. set partType(05) "Extended"
  12. set partType(06) "DOS 16-bit >=32M"
  13. set partType(07) "OS/2 HPFS"
  14. set partType(08) "AIX"
  15. set partType(09) "AIX bootable"
  16. set partType(0a) "OS/2 Boot Manag"
  17. set partType(0b) "Win95 FAT32"
  18. set partType(0c) "Win95 FAT32 LBA"
  19. set partType(0e) "Win95 FAT16 LBA"
  20. set partType(0f) "Win95 Extended"
  21. set partType(40) "Venix 80286"
  22. set partType(51) "Novell?"
  23. set partType(52) "Microport"
  24. set partType(63) "GNU HURD"
  25. set partType(64) "Novell Netware"
  26. set partType(65) "Novell Netware"
  27. set partType(75) "PC/IX"
  28. set partType(80) "Old MINIX"
  29. set partType(81) "Linux/MINIX"
  30. set partType(82) "Linux swap"
  31. set partType(83) "Linux native"
  32. set partType(85) "Linux extended"
  33. set partType(93) "Amoeba"
  34. set partType(94) "Amoeba BBT"
  35. set partType(a5) "BSD/386"
  36. set partType(a6) "OpenBSD"
  37. set partType(a7) "NEXTSTEP"
  38. set partType(b7) "BSDI fs"
  39. set partType(b8) "BSDI swap"
  40. set partType(c7) "Syrinx"
  41. set partType(db) "CP/M"
  42. set partType(e1) "DOS access"
  43. set partType(e3) "DOS R/O"
  44. set partType(f2) "DOS secondary"
  45. set partType(ff) "BBT"
  46.  
  47. proc ExtendedPartition {drive fileName sector part} {
  48.     global db extendedStart partType
  49.     
  50.     set br [ReadSector $fileName $sector]
  51.     
  52.     binary scan $br "@510h4" magic
  53.     if {$magic != "55aa"} {
  54.         # error "bad MBR"
  55.     }
  56.     
  57.     set foundExtended 0
  58.     set foundPartition 0
  59.     
  60.     for {set i 0} {$i < 4} {incr i} {
  61.         set addr [expr {446 + $i*16}]
  62.         
  63.         binary scan $br "@${addr}ccccH2cccii" \
  64.             boot head sect cyl \
  65.             id endHead endSect endCyl \
  66.             start num
  67.  
  68.         switch $id {
  69.             "00" {
  70.                 continue
  71.             }
  72.  
  73.             "05" -
  74.             "85" -
  75.             "0f" {
  76.                 if {$foundExtended} {
  77.                     # puts "bad extended"
  78.                     continue
  79.                 }
  80.  
  81.                 set foundExtended 1
  82.                 
  83.                 ExtendedPartition $drive $fileName \
  84.                     [expr {$extendedStart + $start}] \
  85.                     [expr {$part + 1}]
  86.                 continue
  87.             }
  88.  
  89.             "default" {
  90.                 if {$foundPartition} {
  91.                     # puts "bad partition"
  92.                     continue
  93.                 }
  94.                 set foundPartition 1
  95.             }
  96.         }
  97.  
  98.         # puts "$drive$part $partType($id)"
  99.         
  100.         lappend db(hostRawDisk.$drive.partitions) $part
  101.         set db(hostRawDisk.$drive.$part.start) [expr {$sector + $start}]
  102.         set db(hostRawDisk.$drive.$part.end) [expr {$sector + $start + $num}]
  103.         set db(hostRawDisk.$drive.$part.id) $id
  104.         if {[info exists partType($id)]} {
  105.             set db(hostRawDisk.$drive.$part.type) $partType($id)
  106.         } else {
  107.             set db(hostRawDisk.$drive.$part.type) "Unknown"
  108.         }
  109.         set db(rawDisk.$drive.$part.access) ro
  110.     }
  111. }
  112.  
  113. proc PartitionTable {drive fileName} {
  114.     global db extendedStart partType
  115.  
  116.     set br [ReadSector $fileName 0]
  117.     
  118.     binary scan $br "@510h4" magic
  119.     if {$magic != "55aa"} {
  120.         # error "bad MBR"
  121.     }
  122.  
  123.     for {set part 1} {$part <= 4} {incr part} {
  124.         set addr [expr {430 + $part*16}]
  125.         
  126.         binary scan $br "@${addr}ccccH2cccii" \
  127.             boot head sect cyl \
  128.             id endHead endSect endCyl \
  129.             start num
  130.  
  131.         switch $id {
  132.             "00" {
  133.                 continue
  134.             }
  135.  
  136.             "05" -
  137.             "85" -
  138.             "0f" {
  139.                 # primary extended partition
  140.                 set extendedStart $start
  141.                 ExtendedPartition $drive $fileName $start 5
  142.             }
  143.             
  144.             "default" {
  145.             }
  146.         }
  147.         
  148.         # puts "$drive$part $partType($id)"
  149.  
  150.         lappend db(hostRawDisk.$drive.partitions) $part
  151.         set db(hostRawDisk.$drive.$part.start) $start
  152.         set db(hostRawDisk.$drive.$part.end) [expr {$start + $num}]
  153.         set db(hostRawDisk.$drive.$part.id) $id
  154.         if {[info exists partType($id)]} {
  155.             set db(hostRawDisk.$drive.$part.type) $partType($id)
  156.         } else {
  157.             set db(hostRawDisk.$drive.$part.type) "Unknown"
  158.         }
  159.         set db(rawDisk.$drive.$part.access) ro
  160.     }
  161. }
  162.  
  163.  
  164. ##
  165. ## This proc fills in the following info.
  166. ##
  167. ##
  168. ## db(hostRawDisk.drives) : List of detected ro or rw drives
  169. ## db(hostRawDisk.<drive>.userAccess)    { np none ro rw }
  170. ## db(hostRawDisk.<drive>.partitions)
  171. ## db(hostRawDisk.<drive>.<partition>.start)
  172. ## db(hostRawDisk.<drive>.<partition>.end)
  173. ## db(hostRawDisk.<drive>.<partition>.id)
  174. ## db(hostRawDisk.<drive>.<partition>.type)
  175. ##
  176. ## db(rawDisk.<drive>.used)
  177. ## db(rawDisk.<drive>.<partition>.access)     { none ro rw }
  178. ##
  179.  
  180. proc GetRawDiskInfo {drive} {
  181.     global db
  182.  
  183.     set db(rawDisk.$drive.used) 0
  184.     set fileName [file join /dev $drive]
  185.  
  186.     if {![file exists $fileName]} {
  187.         set db(hostRawDisk.$drive.userAccess) np
  188.         return
  189.     }
  190.  
  191.     if {[info exists db(hostRawDisk.$drive.partitions)]} {
  192.         unset db(hostRawDisk.$drive.partitions)
  193.     }
  194.  
  195.     if [catch {PartitionTable $drive $fileName} err] {
  196.         # puts $err
  197.         if {[info exists db(hostRawDisk.$drive.partitions)]} {
  198.             unset db(hostRawDisk.$drive.partitions)
  199.         }
  200.     }
  201.     
  202.     if {[info exists db(hostRawDisk.$drive.partitions)]} {
  203.         set db(hostRawDisk.$drive.partitions) \
  204.             [lsort -integer -increasing $db(hostRawDisk.$drive.partitions)]
  205.     }
  206.  
  207.     if {[file readable $fileName] && [file writable $fileName]} {
  208.         set db(hostRawDisk.$drive.userAccess) rw
  209.     } elseif {[file readable $fileName]} {
  210.         set db(hostRawDisk.$drive.userAccess) ro
  211.     } else {
  212.         set db(hostRawDisk.$drive.userAccess) none
  213.         return
  214.     }
  215.  
  216.     if {![info exists db(hostRawDisk.$drive.partitions)]} {
  217.         set db(hostRawDisk.$drive.userAccess) np
  218.         return
  219.     }
  220.     
  221.     lappend db(hostRawDisk.drives) $drive
  222.     
  223.     # min is some big num
  224.     set min 1000000
  225.  
  226.     foreach p $db(hostRawDisk.$drive.partitions) {
  227.         if {$db(hostRawDisk.$drive.$p.start) < $min} {
  228.             set min $db(hostRawDisk.$drive.$p.start)
  229.         }
  230.     }
  231.  
  232.     if {$min != 0} {
  233.         # If the beginning of the disk is not already included in a partition,
  234.         # create an additional special range for it
  235.         set db(hostRawDisk.$drive.partitions) [linsert $db(hostRawDisk.$drive.partitions) 0 0]
  236.         set db(hostRawDisk.$drive.0.start) 0
  237.         set db(hostRawDisk.$drive.0.end) $min
  238.         set db(hostRawDisk.$drive.0.id) "MBR"
  239.         set db(hostRawDisk.$drive.0.type) "MBR"
  240.  
  241.         set db(rawDisk.$drive.0.access) ro
  242.     }
  243.  
  244.     set db(rawDisk.$drive.used) 1
  245. }
  246.  
  247. # Perform half of a range overlapping check on 2 ranges
  248. # Return 1 if we should care about overlapping
  249. proc RawDisk_CheckHalfOverlappingRange {r1 r2} {
  250.     global db
  251.  
  252.     if {($db(${r1}.start) <= $db(${r2}.start)) && ($db(${r2}.start) < $db(${r1}.end))} {
  253.         # r2 starts in r1
  254.     if {$db(${r2}.end) > $db(${r1}.end)} {
  255.             # r2 ends out of r1
  256.             return 1
  257.         }
  258.       
  259.         # r2 ends in r1
  260.         if {[RawDisk_IsExtendedRange $r1]} {
  261.             # r1 is the extended partition
  262.             # This special case is handled when we save the safe raw disk file
  263.             return 0
  264.     }
  265.  
  266.     # r1 is not the extended partition
  267.     return 1
  268.     }
  269.  
  270.     # r2 does not start in r1
  271.     return 0
  272. }
  273.  
  274. # Perform a range overlapping check on 2 ranges
  275. # Return 1 if we should care about overlapping
  276. proc RawDisk_CheckOverlappingRange {r1 r2} {
  277.     if {   [RawDisk_CheckHalfOverlappingRange $r1 $r2]
  278.         || [RawDisk_CheckHalfOverlappingRange $r2 $r1]} {
  279.         return 1
  280.     }
  281.     return 0
  282. }
  283.  
  284. # Determine if a range corresponds to an extended partition
  285. proc RawDisk_IsExtendedRange {r} {
  286.     global db
  287.  
  288.     if {   ($db(${r}.id) == "05")
  289.         || ($db(${r}.id) == "85")
  290.         || ($db(${r}.id) == "0F")} {
  291.         return 1
  292.     }
  293.     return 0
  294. }
  295.  
  296. # Sort the range set increasing starting sector order
  297. # Return the sorted list
  298. proc RawDisk_SortRanges {drive} {
  299.     global db
  300.  
  301.     # Bubble sort
  302.     set partitionList $db(hostRawDisk.${drive}.partitions)
  303.     set sortedList $partitionList
  304.     for {set i 0} {$i < [llength $sortedList]} {incr i 1} {
  305.         for {set j [expr $i + 1]} {$j < [llength $sortedList]} {incr j 1} {
  306.             set partition_i [lindex $sortedList $i]
  307.             set partition_j [lindex $sortedList $j]
  308.             if {$db(hostRawDisk.${drive}.${partition_i}.start) > $db(hostRawDisk.${drive}.${partition_j}.start)} {
  309.                 set sortedList [lreplace $sortedList $i $i $partition_j]
  310.                 set sortedList [lreplace $sortedList $j $j $partition_i]
  311.             }
  312.         }
  313.     }
  314.     return $sortedList
  315. }
  316.  
  317. # Write a range to the safe raw disk file
  318. # Note: NO_ACCESS is assumed for all ranges not specified in the file
  319. # Return 1 if success
  320. proc RawDisk_WriteRange {fd start end type} {
  321.     switch $type {
  322.         "none" {
  323.             set typeStr "NO_ACCESS"
  324.         }
  325.         "ro" {
  326.             set typeStr "RDONLY"
  327.         }
  328.         "rw" {
  329.             set typeStr "ACCESS"
  330.         }
  331.     }
  332.  
  333.     # Externally, the end sector is included, internally it is not
  334.     set end [expr $end - 1]
  335.     puts -nonewline $fd "$typeStr $start $end\n"
  336.     return 1
  337. }
  338.  
  339. # If the hole is valid, write its intersection with the extended
  340. # partition to the safe raw disk file
  341. # Return 1 if success
  342. proc RawDisk_WriteHole {fd drive ext holeStart holeEnd} {
  343.     global db
  344.  
  345.     if {$holeStart >= $holeEnd} {
  346.         # There is no hole
  347.         return 1
  348.     }
  349.  
  350.     # There is a valid hole
  351.     # Compute its intersection with the extended partition
  352.     if {($holeEnd <= $db(hostRawDisk.${drive}.${ext}.start)) || ($db(hostRawDisk.${drive}.${ext}.end) <= $holeStart)} {
  353.         # The intersection is empty
  354.         return 1
  355.     }
  356.  
  357.     # The intersection exists
  358.     puts -nonewline $fd "\# Extended partition hole\n"
  359.  
  360.     return [RawDisk_WriteRange $fd [max $holeStart $db(hostRawDisk.${drive}.${ext}.start)] [min $holeEnd $db(hostRawDisk.${drive}.${ext}.end)] $db(rawDisk.${drive}.${ext}.access)]
  361. }
  362.  
  363. # Create a safe raw disk file
  364. # Return 1 if everything is ok
  365. proc RawDisk_Save {drive fileName} {
  366.     global db
  367.  
  368.     if {[catch {set fd [open $fileName w]} err]} {
  369.         DialogWin .error "Configuration Wizard Error" \
  370.             "Failed to open $db(directory)$db(OS.name).$drive: $err" {} 0 OK
  371.         return 0
  372.     }
  373.  
  374.     puts -nonewline $fd "DEVICE /dev/$drive\n\n"
  375.  
  376.     # This is required by the following algorithm
  377.     set sortedList [RawDisk_SortRanges $drive]
  378.  
  379.     # Find the index of the extended partition, because it
  380.     # is a special case: it represents only the holes between the logical
  381.     # partitions it contains.
  382.     #
  383.     # Note: We must do this in a separate loop because otherwise, nothing
  384.     # ensures that the extended partition will be seen before its content.
  385.     set ext ""
  386.     foreach range $sortedList {
  387.         if {[RawDisk_IsExtendedRange hostRawDisk.${drive}.${range}]} {
  388.             set ext $range
  389.             break
  390.     }
  391.     }
  392.  
  393.     set holeStart 0
  394.     foreach range $sortedList {
  395.         # Deal with the next hole
  396.         if {$ext != ""} {
  397.             if {$range == $ext} {
  398.             # Skip the extended partition
  399.                 continue
  400.         }
  401.  
  402.             set holeEnd $db(hostRawDisk.${drive}.${range}.start)
  403.         if {[RawDisk_WriteHole $fd $drive $ext $holeStart $holeEnd] == 0} {
  404.                 close $fd
  405.             return 0
  406.         }
  407.         # 2 partitions could start at the same sector, with the second one
  408.             # being smaller than the first one. Thanks to max, this quantity
  409.             # can only increase
  410.         set holeStart [max $holeStart $db(hostRawDisk.${drive}.${range}.end)]
  411.         }
  412.  
  413.         if {$db(hostRawDisk.${drive}.${range}.type) != ""} {
  414.             puts -nonewline $fd "\# Partition type: $db(hostRawDisk.${drive}.${range}.type)\n"
  415.     }
  416.         if {[RawDisk_WriteRange $fd $db(hostRawDisk.${drive}.${range}.start) $db(hostRawDisk.${drive}.${range}.end) $db(rawDisk.${drive}.${range}.access)] == 0} {
  417.             close $fd
  418.         return 0
  419.     }
  420.     }
  421.     # Deal with the last hole
  422.     if {$ext != ""} {
  423.         # Ideally, we should use the number of sectors on the disk here. This
  424.         # info is not easily available. Fortunately, this value will do just
  425.         # fine for what we want to do
  426.         set holeEnd $db(hostRawDisk.${drive}.${ext}.end)
  427.         if {[RawDisk_WriteHole $fd $drive $ext $holeStart $holeEnd] == 0} {
  428.             close $fd
  429.         return 0
  430.         }
  431.     }
  432.     close $fd
  433.     return 1
  434. }
  435.  
  436.