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