home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / nieuûytki / mountdos10 / mountdos.e < prev    next >
Text File  |  1996-01-28  |  13KB  |  489 lines

  1. OPT REG=5
  2. OPT PREPROCESS
  3. OPT OSVERSION=37
  4.  
  5. /*
  6.  * MS-Dos partitiontable lister and Cross-Dos mounter for PC-HD's.
  7.  *
  8.  * (c) K.P. van Beem (patrick@aobh.xs4all.nl or 2:280/464.2)
  9.  *
  10.  * Based on information gained from the source of the Linux FDisk, by
  11.  * A. V. Le Blanc (LeBlanc@mcc.ac.uk).
  12.  * This program is free software.  You can redistribute it and/or
  13.  * modify it under the terms of the GNU General Public License as
  14.  * published by the Free Software Foundation.
  15.  *
  16.  * Version 1.0, 28-1-96, Initial version.
  17.  */
  18.  
  19. #define VERSION '$VER: MountDos 1.0 (28.1.96) PD, (c) K.P. van Beem.\n'
  20.  
  21. MODULE 'devices/trackdisk', 'exec/io', 'exec/ports'
  22. MODULE 'dos/dos', 'dos/dostags'
  23. MODULE 'utility/tagitem'
  24. MODULE 'icon', 'workbench/workbench', 'workbench/startup'
  25.  
  26.  
  27.  
  28. /******************* Globals **********************/
  29.  
  30. #define TEMPLATE      'DEVICE,UNIT/N,LIST/S,GENERATE/S,MOUNT/S,QUIET/S'
  31. #define ARG_DEVICE    arg_ptrs[0]
  32. #define ARG_UNIT      arg_ptrs[1]
  33. #define ARG_LIST      arg_ptrs[2]
  34. #define ARG_GENERATE  arg_ptrs[3]
  35. #define ARG_MOUNT     arg_ptrs[4]
  36. #define ARG_QUIET     arg_ptrs[5]
  37. #define NUMARGS                6
  38.  
  39. #define TMPFILENAME   'T:MountDosTmpMountlist'
  40.  
  41. #define EXTENDED          5
  42. #define SECTOR_SIZE       512
  43. #define PART_TABLE_FLAG   $55AA
  44. -> Actually $AA55, but ix86's are realy weird. They swap multiple-byte values.
  45.  
  46. -> Byte values. Highest two bits of sector are added to cylinder.
  47. #define SECTOR(s)     (s AND $3F)
  48. #define CYLINDER(s,c) (c OR Shl(s AND $C0,2))
  49.  
  50.  
  51. -> This is how an MS-Dos partition entry looks like:
  52. OBJECT partition
  53.   boot_ind    :CHAR   -> 0x80 - active
  54.   head        :CHAR   -> starting head
  55.   sector      :CHAR   -> starting sector
  56.   cyl         :CHAR   -> starting cylinder
  57.   sys_ind     :CHAR   -> What partition type
  58.   end_head    :CHAR   -> end head
  59.   end_sector  :CHAR   -> end sector
  60.   end_cyl     :CHAR   -> end cylinder
  61.   start_sect  :LONG   -> starting sector counting from 0
  62.   nr_sects    :LONG   -> nr of sectors in partition
  63. ENDOBJECT
  64.  
  65. -> Global return-code
  66. DEF rc       = RETURN_OK            -> Exceptionhandler will correct this.
  67.  
  68. -> Program arguments
  69. DEF rargs    = NIL
  70. DEF arg_ptrs = NIL : PTR TO LONG
  71. DEF device, unit                    -> Device and unit we work on
  72.  
  73. -> Device handling
  74. DEF tio      = NIL :PTR TO ioexttd  -> Trackdisk io blok.
  75.  
  76. -> Count number of partitions found, for unique naming of mount-entries
  77. DEF dosparts, ndosparts
  78.  
  79.  
  80. /****************** Automatic exceptions **********************/
  81. -> What can go wrong...
  82. RAISE "CTLC"  IF CtrlC()             = TRUE,
  83.       "DEV"   IF OpenDevice()       <> NIL,
  84.       "DOS"   IF ReadArgs()          = NIL,
  85.       "IO"    IF DoIO()             <> NIL,
  86.       "LIB"   IF OpenLibrary()       = NIL,
  87.       "RES"   IF CreateIORequest()   = NIL,
  88.       "RES"   IF CreateMsgPort()     = NIL,
  89.       "STAC"  IF FreeStack()         < 1000
  90.  
  91.  
  92.  
  93. /****************** Main prog **********************/
  94.  
  95. PROC main() HANDLE
  96.  
  97.   -> Device handling
  98.   DEF tmp     = NIL                 -> MsgPort for the trackdisk.device
  99.   DEF topen   = FALSE               -> Flag if the trackdisk.device is opened.
  100.  
  101.   -> WB args
  102.   DEF arg :PTR TO wbarg, dobj :PTR TO diskobject, wm :PTR TO wbstartup
  103.   DEF olddir, item
  104.  
  105.  
  106.   -> Check the parameters we got, first, initial and default values.
  107.   NEW arg_ptrs[NUMARGS]
  108.   device := 'scsi.device'
  109.   IF wbmessage
  110.     -> Started from workbench
  111.     iconbase  := OpenLibrary('icon.library', 0)
  112.     wm        := wbmessage
  113.     arg       := wm.arglist
  114.     IF wm.numargs > 1 THEN arg++        -> We are called with a project.
  115.     olddir    := CurrentDir(arg.lock)
  116.     dobj      := GetDiskObject(arg.name)
  117.     IF dobj
  118.       IF FindToolType(dobj.tooltypes,'LIST')     THEN ARG_LIST     := TRUE
  119.       IF FindToolType(dobj.tooltypes,'GENERATE') THEN ARG_GENERATE := TRUE
  120.       IF FindToolType(dobj.tooltypes,'MOUNT')    THEN ARG_MOUNT    := TRUE
  121.       IF FindToolType(dobj.tooltypes,'QUIET')    THEN ARG_QUIET    := TRUE
  122.       item := FindToolType(dobj.tooltypes,'DEVICE')
  123.       IF item
  124.         device := String(StrLen(item))
  125.         StrCopy(device, item)
  126.       ENDIF
  127.       item := FindToolType(dobj.tooltypes,'UNIT')
  128.       IF item THEN unit := Val(item)
  129.       FreeDiskObject(dobj)
  130.     ENDIF
  131.     CurrentDir(olddir)
  132.   ELSE
  133.     -> Started from CLI
  134.     rargs  := ReadArgs(TEMPLATE, arg_ptrs, NIL)
  135.     IF ARG_DEVICE THEN device := ARG_DEVICE
  136.     IF ARG_UNIT   THEN unit   := Long(ARG_UNIT)
  137.   ENDIF
  138.  
  139.   -> No options?
  140.   IF (ARG_GENERATE=0) AND (ARG_MOUNT=0) AND (ARG_LIST=0)
  141.     PrintF(VERSION+6)
  142.     PrintF('Type: ''MountDos ?'' for an option summary.\n')
  143.     Raise(0)
  144.   ENDIF
  145.  
  146.   -> Redirect output if option quiet is specified
  147.   IF (ARG_QUIET = TRUE)
  148.     conout := stdout := Open('NIL:', MODE_NEWFILE)
  149.   ENDIF
  150.  
  151.   -> Trackdisk initialisation
  152.   tmp   := CreateMsgPort()
  153.   tio   := CreateIORequest(tmp, SIZEOF ioexttd)
  154.   OpenDevice(device, unit, tio, 0)
  155.   topen := TRUE
  156.  
  157.   -> Actions to perform <-
  158.  
  159.   IF ARG_LIST
  160.     list_table()
  161.   ENDIF
  162.  
  163.   IF ARG_GENERATE
  164.     dosparts := ndosparts := 0
  165.     generate()
  166.   ENDIF
  167.  
  168.   IF ARG_MOUNT
  169.     mount()
  170.   ENDIF
  171.  
  172.  
  173. EXCEPT DO
  174.  
  175.   /* Inspect the error (if any) */
  176.   IF exception <> 0
  177.     rc := RETURN_FAIL
  178.     SELECT exception
  179.       CASE "DEV"
  180.         PrintF('Unable to open device ''\s'', unit \d.\n', device, unit)
  181.       CASE "DOS"
  182.         PrintFault(IoErr(), NIL)
  183.       CASE "CTLC"
  184.         PrintF('Ctrl-C detected.\n')
  185.       CASE "IO"
  186.         PrintF('Device IO-error $\h.\n', tio.iostd.error)
  187.       CASE "LIB"
  188.         PrintF('Unable to open a needed library.\n')
  189.       CASE "MEM"
  190.         PrintF('Unable to allocate memory.\n')
  191.       CASE "RES"
  192.         PrintF('Unable to allocate needed resources.\n')
  193.       CASE "STAC"
  194.         PrintF('Stack overflow.\n')
  195.       DEFAULT
  196.         PrintF('Unknown exception: $\h.\n', exception)
  197.     ENDSELECT
  198.   ENDIF
  199.  
  200.   /* Clean-up */
  201.   IF topen          THEN CloseDevice    (tio)
  202.   IF tio            THEN DeleteIORequest(tio)
  203.   IF tmp            THEN DeleteMsgPort  (tmp)
  204.  
  205.   IF iconbase       THEN CloseLibrary   (iconbase)
  206.   IF rargs          THEN FreeArgs       (rargs)
  207.  
  208. ENDPROC rc
  209.  
  210.  
  211.  
  212. /************ Read a partition-table block from disk *************/
  213. PROC readblock(buffer, block)
  214.  
  215.   tio.iostd.command   := CMD_READ
  216.   tio.iostd.data      := buffer
  217.   tio.iostd.length    := SECTOR_SIZE
  218.   tio.iostd.offset    := Mul(block,SECTOR_SIZE)
  219.   tio.iostd.flags     := IOF_QUICK
  220.   DoIO(tio)
  221.  
  222.   -> Check table ID
  223.   IF Int(buffer + $01FE) <> PART_TABLE_FLAG
  224.     PrintF('WARNING: Invalid tabel flag $\z\h[4].\n', Int(buffer + $01FE))
  225.     rc := RETURN_WARN
  226.   ENDIF
  227.  
  228. ENDPROC
  229.  
  230.  
  231.  
  232. /************ Auto-mount dos-partitions ************
  233.  * Generate the mountlist-entries in a file and call the mount
  234.  * command to mount each dos-partition in it.
  235.  */
  236. PROC mount() HANDLE
  237.   DEF cnt, tmp, tmpname
  238.   DEF command[80] :STRING
  239.  
  240.   tmpname := TMPFILENAME    -> Only one instance of string in object-code
  241.   tmp     := stdout         -> Temperary redirected.
  242.   stdout  := Open(tmpname, MODE_NEWFILE)
  243.   IF stdout=NIL
  244.     stdout := tmp
  245.     PrintF('Unable to create a temporary mountlist.\n')
  246.     rc := RETURN_ERROR
  247.     RETURN
  248.   ENDIF
  249.  
  250.   dosparts := ndosparts := 0
  251.   generate(0, TRUE)
  252.   Close(stdout)
  253.   stdout := tmp             -> Restored
  254.  
  255.   FOR cnt := 1 TO dosparts STEP 1
  256.     CtrlC()                       -> User may want to cancel the mount-procedure
  257.     PrintF('Mounting MD\d\d:\n', unit, cnt)
  258.     StringF(command,'Mount MD\d\d: FROM \s', unit, cnt, tmpname)
  259.     tmp := SystemTagList(command, [SYS_OUTPUT, stdout, TAG_DONE])
  260.     IF tmp > rc THEN rc := tmp    -> Copy highest return-code
  261.   ENDFOR
  262.  
  263. EXCEPT DO
  264.  
  265.   DeleteFile(tmpname)
  266.   ReThrow()
  267.  
  268. ENDPROC
  269.  
  270.  
  271.  
  272. /************ Generate mountlist-entries for partition chain ************/
  273. -> 'dosonly' indicates only dos-partitions should be generated.
  274.  
  275. PROC generate(block=0, dosonly=FALSE)
  276.   DEF cnt, bpt, lowcyl, highcyl, isdos
  277.  
  278.   -> Partition table
  279.   DEF buffer[SECTOR_SIZE] : ARRAY OF CHAR
  280.   DEF p:PTR TO partition   -> Pointer to the partition table
  281.  
  282.  
  283.   -> Recursive function, check Ctrl-C and stack (uses auto-exceptions).
  284.   FreeStack()
  285.   CtrlC()
  286.  
  287.   -> Read partition-table block
  288.   readblock(buffer, block)
  289.   p := buffer + $01BE
  290.  
  291.   FOR cnt := 1 TO 4 STEP 1
  292.  
  293.     -> Swap 'Intel'-values:
  294.     p.start_sect := swapL(p.start_sect)
  295.     p.nr_sects   := swapL(p.nr_sects)
  296.  
  297.     -> Can this partition be mounted with CrossDos or not?
  298.     IF (p.sys_ind=1) OR (p.sys_ind=4) OR (p.sys_ind=6)
  299.       INC dosparts
  300.       isdos := TRUE
  301.     ELSE
  302.       INC ndosparts
  303.       isdos := FALSE
  304.     ENDIF
  305.  
  306.     IF  (p.sys_ind <> 0) AND (p.sys_ind <> EXTENDED) AND
  307.     ( (dosonly AND isdos) OR Not(dosonly) ) 
  308.       lowcyl  := p.start_sect + block
  309.       highcyl := lowcyl + p.nr_sects + block
  310.       lowcyl, highcyl, bpt := smaller(lowcyl, highcyl)
  311.       PrintF(
  312.         '\s\d\d:\n'+
  313.         'FileSystem       = \s\n'+
  314.         'Device           = \s\n'+
  315.         'Unit             = \d\n'+
  316.         'Surfaces         = 1\n'+
  317.         'BlocksPerTrack   = \d\n'+
  318.         'Reserved         = 0\n'+
  319.         'LowCyl           = \d\n'+
  320.         'HighCyl          = \d\n'+
  321.         'BufMemType       = 0\n'+
  322.         'Priority         = 10\n'+
  323.         'GlobVec          = -1\n'+
  324.         'DosType          = \s\n'+
  325.         'Activate         = 1\n'+
  326.         '#\n\n',
  327.         IF isdos THEN 'MD'                    ELSE 'ND', unit,
  328.         IF isdos THEN dosparts                ELSE ndosparts,
  329.         IF isdos THEN 'L:CrossDOSFileSystem'  ELSE systype(p.sys_ind),
  330.         device, unit, bpt, lowcyl, highcyl - 1,
  331.         IF isdos THEN '0x4D534400'            ELSE '?',
  332.       )
  333.     ENDIF
  334.  
  335.     IF (p.sys_ind = EXTENDED) AND (p.start_sect <> 0)
  336.       generate(p.start_sect + block, dosonly)
  337.     ENDIF
  338.  
  339.     p++
  340.   ENDFOR
  341.  
  342. ENDPROC
  343.  
  344.  
  345.  
  346. /************ Shows the contents of an partition chain. ************/
  347.  
  348. PROC list_table(block=0)
  349.   DEF cnt
  350.  
  351.   -> Partition table
  352.   DEF buffer[SECTOR_SIZE] : ARRAY OF CHAR
  353.   DEF p:PTR TO partition   -> Pointer to the partition table
  354.  
  355.  
  356.   -> Recursive function, check Ctrl-C and stack (uses auto-exceptions).
  357.   FreeStack()
  358.   CtrlC()
  359.  
  360.   -> Read partition-table block
  361.   readblock(buffer, block)
  362.   p := buffer + $01BE
  363.  
  364.   PrintF('      Start:         End:             Start  Number of\n'+
  365.          ' boot Head Cyl. Sect Head Cyl. Sect   Sector Sectors     MB System\n')
  366.   FOR cnt := 1 TO 4 STEP 1
  367.     -> Swap 'Intel'-values:
  368.     p.start_sect := swapL(p.start_sect)
  369.     p.nr_sects   := swapL(p.nr_sects)
  370.     PrintF('\d[1] \s \d[4]\d[5]\d[5] \d[4]\d[5]\d[5] \d[8] \d[9] \d[4] \s\n',
  371.       cnt,        IF (p.boot_ind) THEN 'yes' ELSE 'no ',
  372.       p.head,     CYLINDER(p.sector, p.cyl),         SECTOR(p.sector),
  373.       p.end_head, CYLINDER(p.end_sector, p.end_cyl), SECTOR(p.end_sector),
  374.       IF p.start_sect = 0 THEN 0 ELSE p.start_sect + block, p.nr_sects,
  375.       p.nr_sects / ($100000/SECTOR_SIZE), systype(p.sys_ind)
  376.       )
  377.     p++
  378.   ENDFOR
  379.  
  380.   -> Check for extended partitions.
  381.   p := buffer + $01BE
  382.   FOR cnt := 1 TO 4 STEP 1
  383.     IF p.sys_ind = EXTENDED
  384.       IF p.start_sect = 0
  385.         PrintF('Bad offset in extended partition number \d.\n', cnt)
  386.       ELSE
  387.         -> Recursive call of this funtion.
  388.         PrintF('\nExtended partition at sector \d:\n', p.start_sect + block)
  389.         list_table(p.start_sect + block)
  390.       ENDIF
  391.     ENDIF
  392.     p++
  393.   ENDFOR
  394.  
  395. ENDPROC
  396.  
  397.  
  398.  
  399. /********** System types of partitions *****************/
  400. PROC systype(t)
  401.   DEF stypes: PTR TO LONG
  402.  
  403.   stypes := [
  404.     0, 'Empty',
  405.     1, 'DOS 12-bit FAT',
  406.     2, 'XENIX root',
  407.     3, 'XENIX usr',
  408.     4, 'DOS 16-bit <32M',
  409.     EXTENDED, 'Extended',
  410.     6, 'DOS 16-bit >=32M',
  411.     7, 'OS/2 HPFS',         -> or QNX?
  412.     8, 'AIX',
  413.     9, 'AIX bootable',
  414.     10, 'OPUS',
  415.     $40, 'Venix 80286',
  416.     $51, 'Novell?',
  417.     $52, 'Microport',       -> or CPM?
  418.     $63, 'GNU HURD',        -> or System V/386?
  419.     $64, 'Novell',
  420.     $75, 'PC/IX',
  421.     $80, 'Old MINIX',       -> Minix 1.4a and earlier
  422.     $81, 'Linux/MINIX',     -> Minix 1.4b and later
  423.     $82, 'Linux swap',
  424.     $83, 'Linux native',
  425.     $93, 'Amoeba',
  426.     $94, 'Amoeba BBT',      -> (bad block table)
  427.     $b7, 'BSDI fs',
  428.     $b8, 'BSDI swap',
  429.     $c7, 'Syrinx',
  430.     $db, 'CP/M',            -> or Concurrent DOS?
  431.     $e1, 'DOS access',
  432.     $e3, 'DOS R/O',
  433.     $f2, 'DOS secondary',
  434.     $ff, 'BBT'              -> (bad track table)
  435.   ]
  436.  
  437.   WHILE (t <= $FF) AND (t > stypes[])
  438.     stypes++
  439.     stypes++
  440.   ENDWHILE
  441.  
  442. ENDPROC IF (t = stypes[]) THEN stypes[1] ELSE 'Unknown'
  443.  
  444.  
  445.  
  446. /*** Some assembler routines for convenience... ***/
  447.  
  448.  
  449.  
  450. /******** Lower the values of lowcyl and highcyl. ********
  451.  * Some file-systems/devices can't handle high values for the cylinders
  452.  * (probably higher than 65536). So we try to keep them low, by increasing
  453.  * the number of cylinders.
  454.  */
  455.  
  456. PROC smaller(lowcyl, highcyl)
  457.   DEF     bpt
  458.  
  459.   MOVE.L  lowcyl,D0
  460.   MOVE.L  highcyl,D1
  461.  
  462.   MOVEQ.L #1,D2           -> Sectors per track.
  463. smaller_itterate:
  464.   BTST    #0,D0
  465.   BNE     smaller_end
  466.   BTST    #0,D1
  467.   BNE     smaller_end
  468.   LSL.W   #1,D2
  469.   LSR.L   #1,D0
  470.   LSR.L   #1,D1
  471.   CMP.W   #$0800,D2       -> Don't overreact (or hang).
  472.   BLT     smaller_itterate
  473. smaller_end:
  474.  
  475.   MOVE.L  D0,lowcyl
  476.   MOVE.L  D1,highcyl
  477.   MOVE.L  D2,bpt
  478.  
  479. ENDPROC lowcyl, highcyl, bpt
  480.  
  481.  
  482. /****** Swap nibbles. Stupid Intel things... *********/
  483. PROC swapL(l)
  484.   MOVE.L  l,D0
  485.   ROR.W   #8,D0
  486.   SWAP.W  D0
  487.   ROR.W   #8,D0
  488. ENDPROC D0
  489.