home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / sysutl / idt.arc / IDT.C < prev    next >
C/C++ Source or Header  |  1988-06-12  |  31KB  |  1,338 lines

  1. #pragma    title("IDT - Find Internal Data Table")
  2. #pragma    subtitle("Introduction")
  3.  
  4. /*
  5. **    program:    idt
  6. **
  7. **    purpose:    This program finds the internal device
  8. **            table used by MS-DOS and reports its
  9. **            contents.  It includes options to dump
  10. **            and/or display each of the various
  11. **            structures pointed to by the idt.
  12. **
  13. **    usage:        idt
  14. **
  15. **    switches:    -i = List the internal data table
  16. **            -p = List the physical device table
  17. **            -l = List the logical device table
  18. **            -d = List the device driver headers
  19. **            -m = List the memory arena
  20. **            -b = List buffer control blocks
  21. **            -f = List internal file control blocks
  22. **            -c = List file control blocks
  23. **            -v = Verbose (dump buffers)
  24. **            -* = Everything (except verbose)
  25. **
  26. **    notes:        Much (most) of the information contained in
  27. **            the idt (including the method used to find
  28. **            it) is undocumented and subject to change
  29. **            and/or errors.  This version will not work
  30. **            for versions of MS-DOS previous to 3.0.
  31. **
  32. **            Considering the wealth of information revealed
  33. **            in these tables, it may me a reasonable risk
  34. **            for an application which takes some care to
  35. **            utilize it - even though it is officially
  36. **            undocumented and will not be supported by
  37. **            the OS vendor (yes, you know who you are!)
  38. **
  39. **    author:        Bill Parrott
  40. **
  41. **            Copyright (c) 1988, Bill Parrott
  42. **             All Rights Reserved
  43. **
  44. **            Use this code in any way and the information
  45. **            contained herein any way you like, without
  46. **            restriction.  If you accomplish something
  47. **            because of what you got here, and if it makes
  48. **            you rich, well I just hope you'll remember
  49. **            who made it all possible :-).  Seriously, a
  50. **            little credit would be nice but apart from
  51. **            that, have at it!
  52. */
  53.  
  54. #define    VERSION        1
  55. #define    REVISION    0
  56.  
  57. #define    PROGRAMNAME    "IDT"
  58.  
  59. /*
  60. **    system includes
  61. */
  62.  
  63. #include    <stdio.h>
  64. #include    <dos.h>
  65. #include    <ctype.h>
  66. #include    <assert.h>
  67. #include    <process.h>
  68.  
  69. /*
  70. **    site includes
  71. */
  72.  
  73. #include    <local/getargs.h>
  74. #include    <local/what.h>
  75.  
  76. #include    "idt.h"
  77.  
  78. #pragma    subtitle("Data and Definitions")
  79. #pragma    page()
  80.  
  81. /*
  82. **    global data
  83. */
  84.  
  85. IDT *idt;                /* address of internal data table    */
  86.  
  87. /*
  88. **    this cell is filled by our function rather that
  89. **    from the idt just so we can say we really did it.
  90. */
  91.  
  92. segment arenastart;            /* start of memory arena        */
  93.  
  94.  
  95. /*
  96. **    switch data
  97. */
  98.  
  99. static    int    doidt = 0;        /* list the internal data table        */
  100. static    int    dopdpt = 0;        /* list the physical device table    */
  101. static    int    doldt = 0;        /* list the logical device table    */
  102. static    int    dodevhdr = 0;        /* list device driver headers        */
  103. static    int    doarena = 0;        /* list memory arena            */
  104. static    int    dobcb = 0;        /* list buffer control blocks        */
  105. static    int    verbose = 0;        /* verbose listing (dumps buffers)    */
  106. static    int    doifcb = 0;        /* list internal file control blocks    */
  107. static    int    dofcbt = 0;        /* list file control blocks        */
  108. static    int    doall = 0;        /* list everything            */
  109.  
  110.  
  111. /*
  112. **    switch table
  113. */
  114.  
  115. ARG    swtab[] =
  116.     {
  117.     { 'i',    BOOLEAN,    &doidt,        "List internal data table"        },
  118.     { 'p',    BOOLEAN,    &dopdpt,    "List physical device table"        },
  119.     { 'l',    BOOLEAN,    &doldt,        "List logical device table"        },
  120.     { 'd',    BOOLEAN,    &dodevhdr,    "List device driver headers"        },
  121.     { 'm',    BOOLEAN,    &doarena,    "List memory arena"            },
  122.     { 'b',    BOOLEAN,    &dobcb,        "List buffer control blocks"        },
  123.     { 'f',    BOOLEAN,    &doifcb,    "List internal file control blocks"    },
  124.     { 'c',    BOOLEAN,    &dofcbt,    "List file control blocks"        },
  125.     { 'v',    BOOLEAN,    &verbose,    "Verbose (dump buffers)"        },
  126.     { '*',    BOOLEAN,    &doall,        "List everything"            }
  127.     };
  128.  
  129. #define    TABSIZE    (sizeof(swtab) / sizeof(ARG))
  130.  
  131.  
  132. /*
  133. **    prototypes
  134. */
  135.  
  136. int main( int, char ** );
  137.  
  138. segment findarena( void );
  139. segment isarena( segment, segment );
  140.  
  141. void showidt( IDT far * );
  142. void showpdpt( PDPT far * );
  143. void showpdpt1( PDPT far * );
  144. void showldt( LDT far * );
  145. void showdevhdr( DEVHDR far * );
  146. void showdevhdr1( DEVHDR far * );
  147. char *trimname( char far *, int );
  148. void showarena( MDB far * );
  149. int isenv( char far * );
  150. int ispsp( char far * );
  151. void showbcb( BCB far * );
  152. void dumpbuffer( byte far * );
  153. void paragraph( byte *, word );
  154. void memkpy( byte *, byte far *, int );
  155. int memkmp( byte *, byte far *, int );
  156. void showifcb( CHAIN far *, int );
  157. void showifcb1( IFCB far * );
  158.  
  159.  
  160.  
  161. /*
  162. **    "what" strings
  163. */
  164.  
  165. static char *WhatStrings[] =
  166.     {
  167.     WHATVER(PROGRAMNAME,VERSION,REVISION),
  168.     WHATWHEN,
  169.     WHATDATE,
  170.     WHAT("Copyright (c) 1988, Bill Parrott"),
  171.     WHAT("  All Rights Reserved")
  172.     };
  173.  
  174. #pragma    subtitle("main()")
  175. #pragma    page()
  176.  
  177. /*
  178. **    main  (need I say more?)
  179. */
  180.  
  181. int main( argc, argv )
  182.  
  183. int argc;
  184. char *argv[];
  185.  
  186.     {
  187.     union REGS r;
  188.     struct SREGS s;
  189.     IDT safeplaceforidt;
  190.     IDT far *p;
  191.     int i;
  192.  
  193.     /*
  194.     **    signon
  195.     */
  196.  
  197.     fprintf( stderr, "\n%s", &WhatStrings[0][4] );
  198.     fprintf( stderr, "\n%s\n", &WhatStrings[3][4] );
  199.  
  200.     /*
  201.     **    check for version
  202.     */
  203.  
  204.     r.h.ah = 0x30;
  205.     intdos( &r, &r );
  206.  
  207.     if ( r.h.al < 0 )
  208.         {
  209.         fprintf( stderr, "\nIncorrect version of MS-DOS.\n" );
  210.         return ( 1 );
  211.         }
  212.  
  213.  
  214.     /*
  215.     **    process the command line
  216.     */
  217.  
  218.     argc = getargs( argc, argv, swtab, TABSIZE );
  219.  
  220.     if ( doall )
  221.         doidt = dopdpt = doldt = dodevhdr = 
  222.         doarena = dobcb = doifcb = dofcbt = 1;
  223.     else
  224.         {
  225.         i  = doidt + dopdpt + doldt + dodevhdr +
  226.              doarena + dobcb + doifcb + dofcbt;
  227.  
  228.         if ( i == 0 )
  229.             {
  230.             fprintf( stderr, "\nusage: idt switch(es)\n" );
  231.             fprintf( stderr, "\n\t-i = list the internal data table" );
  232.             fprintf( stderr, "\n\t-p = list the physical device table" );
  233.             fprintf( stderr, "\n\t-l = list the logical device table" );
  234.             fprintf( stderr, "\n\t-d = list the device driver headers" );
  235.             fprintf( stderr, "\n\t-m = list the memory arena" );
  236.             fprintf( stderr, "\n\t-b = list buffer control blocks" );
  237.             fprintf( stderr, "\n\t-f = list internal file control blocks" );
  238.             fprintf( stderr, "\n\t-c = list file control blocks" );
  239.             fprintf( stderr, "\n\t-v = verbose (dump buffers)" );
  240.             fprintf( stderr, "\n\t-* = list all tables" );
  241.             fprintf( stderr, "\n" );
  242.             return ( 1 );
  243.             }
  244.         }
  245.  
  246.  
  247.     /*
  248.     **    find the memory arena on our own first.
  249.     */
  250.  
  251.     if ( (arenastart = findarena()) == 0 )
  252.         {
  253.         fprintf( stderr, "\n\n\a+++ Can't locate the first memory descriptor!! +++\n" );
  254.         return ( 1 );
  255.         }
  256.  
  257.  
  258.     /*
  259.     **    now look up the internal data table
  260.     */
  261.  
  262.     segread( &s );
  263.  
  264.     r.h.ah = 0x52;        /* magic undocumented function */
  265.     intdosx( &r, &r, &s );
  266.  
  267.  
  268.     /*
  269.     **    get a static copy for playing with
  270.     */
  271.  
  272.     idt = &safeplaceforidt;
  273.  
  274.     FP_SEG(p) = s.es;
  275.     FP_OFF(p) = r.x.bx - 8;
  276.  
  277.     memkpy( (byte *) idt, (byte far *) p, sizeof(IDT) );
  278.  
  279.  
  280.     /*
  281.     **    process selections
  282.     */
  283.  
  284.     if ( doidt )
  285.         showidt( idt );
  286.  
  287.     if ( dopdpt )
  288.         showpdpt( idt->pdpt );
  289.  
  290.     if ( doldt )
  291.         showldt( idt->ldt );
  292.  
  293.     if ( dodevhdr )
  294.         showdevhdr( &idt->nuldev );
  295.  
  296.     if ( doarena )
  297.         showarena( idt->arena );
  298.  
  299.     if ( dobcb )
  300.         showbcb( idt->bcbhead );
  301.  
  302.     if ( doifcb )
  303.         showifcb( idt->ifcb, 1 );
  304.  
  305.     if ( dofcbt )
  306.         showifcb( idt->fcbt, 0 );
  307.  
  308.  
  309.     /*
  310.     **    clean up
  311.     */
  312.  
  313.     printf( "\n" );
  314.  
  315.     return ( 0 );
  316.     }
  317.  
  318. #pragma subtitle("findarena() - find start of memory arena")
  319. #pragma    page()
  320.  
  321. /*
  322. **    function:    findarena
  323. **
  324. **    purpose:    This function demonstrates a well behaved (?)
  325. **            technique for finding the first memory control
  326. **            block.  It uses only information obtained from
  327. **            Microsoft literature and documents in this
  328. **            task... (hopefully freeing it from version
  329. **            dependancies.)  We do, however, make the
  330. **            assumption that MS-DOS memory descriptors
  331. **            are ALWAYS on paragraph boundaries.
  332. **
  333. **    usage:        first = findarena();
  334. **              segment first;
  335. **
  336. **    returns:    segment of first descriptor if found,
  337. **              else 0.
  338. */
  339.  
  340. segment findarena()
  341.  
  342.     {
  343.     word beginsearch;
  344.     word endsearch;
  345.     union REGS r;
  346.  
  347.     /*
  348.     **    find a place to give up the search.  For further
  349.     **    reliability, we make this the end of physical
  350.     **    memory (as DOS knows it).  Besides, the function
  351.     **    isarena() requires it.
  352.     */
  353.  
  354.     beginsearch = 0x40;        /* after interrupt table    */
  355.  
  356.     int86( 0x12, &r, &r );        /* get it from the BIOS        */
  357.     endsearch = r.x.ax << 6;    /* last paragraph + 1        */
  358.  
  359.  
  360.     /*
  361.     **    find the start of the arena
  362.     */
  363.  
  364.     for ( arenastart = beginsearch; arenastart < endsearch; ++arenastart )
  365.         if ( isarena( arenastart, endsearch ) )
  366.             break;
  367.  
  368.     /*
  369.     **    check it, but it can't happen.
  370.     */
  371.  
  372.     if ( arenastart >= endsearch )
  373.         {
  374.         fprintf( stderr, "\nSomething's REALLY screwed up, Martha!!\n" );
  375.         return ( 0 );
  376.         }
  377.  
  378.     return ( arenastart );
  379.     }
  380.  
  381. #pragma    subtitle("isarena() - is segment is the arena?")
  382. #pragma    page()
  383.  
  384. /*
  385. **    function:    isarena
  386. **
  387. **    purpose:    This function determines whether the passed
  388. **            segment address points to the start of DOS'
  389. **            memory allocation arena.
  390. **
  391. **    usage:        result = isarena( seg, endsearch );
  392. **              segment result;
  393. **              segment seg;
  394. **              segment endsearch;
  395. **
  396. **    returns:    0 if not, else segment of high memory + 1
  397. **
  398. **    notes:        To perform this test, we first check to see
  399. **            if the paragraph appears to be a memory
  400. **            descriptor block.  If so, add the block
  401. **            length to get the address of the next block.
  402. **            Then we check that block to see if it's a
  403. **            memory descriptor.  If so, add the block
  404. **            length to get the next block, and so on
  405. **            until we reach the end of the arena.  If
  406. **            any entry is not a descriptor, or if the
  407. **            arena does not end at exactly the end of
  408. **            memory then the test fails.
  409. **
  410. **            The defined value LOOPCHECK (below) is used
  411. **            to keep the algorithm from getting into an
  412. **            endless loop due to a circular link.  The
  413. **            value chosen should be sufficiently large
  414. **            to keep from prematurely terminating a
  415. **            valid (however long) chain of MDBs.
  416. */
  417.  
  418. #define    LOOPCHECK    1024        /* should be high enuf        */
  419.  
  420. segment isarena( seg, endsearch )
  421.  
  422. segment seg;
  423. segment endsearch;
  424.  
  425.     {
  426.     MDB far *p;
  427.     int i;
  428.  
  429.     /*
  430.     **    check to see if it appears to be a memory descriptor.
  431.     */
  432.  
  433.     FP_SEG(p) = seg;
  434.     FP_OFF(p) = 0;        /* address possible descriptor */
  435.  
  436.     if ( p->type != 'M' )
  437.         return ( 0 );    /* most will fail this test    */
  438.  
  439.  
  440.     /*
  441.     **    well, it looks like a duck...
  442.     */
  443.  
  444.     for ( i = 0; i < LOOPCHECK; ++i )
  445.         {
  446.  
  447.         FP_SEG(p) += p->length + 1;    /* find next potential    */
  448.  
  449.         if ( FP_SEG(p) > endsearch )
  450.             return ( 0 );        /* too far        */
  451.  
  452.         if ( p->type == 'Z' )
  453.             break;            /* found last one    */
  454.  
  455.         if ( p->type != 'M' )
  456.             return ( 0 );        /* false alarm        */
  457.  
  458.         }
  459.  
  460.     if ( i == LOOPCHECK )
  461.         return ( 0 );            /* circular loop?    */
  462.  
  463.  
  464.     /*
  465.     **    looks like a duck, and it walks like a duck...
  466.     */
  467.  
  468.     FP_SEG(p) += p->length + 1;        /* last link        */
  469.  
  470.     return ( FP_SEG(p) == endsearch );    /* quack!        */
  471.     }
  472.  
  473. #pragma    subtitle("showidt() - display idt")
  474. #pragma    page()
  475.  
  476. /*
  477. **    function:    showidt
  478. **
  479. **    purpose:    This function displays the contents of the
  480. **            internal data table upon stdout.
  481. **
  482. **    usage:        void showidt( idt );
  483. **              IDT far *idt;
  484. **
  485. **    returns:    nothing
  486. */
  487.  
  488. void showidt( idt )
  489.  
  490. IDT far *idt;
  491.  
  492.     {
  493.     void far *temp;
  494.  
  495.     printf( "\nInternal Data Table at: %p\n", idt );
  496.  
  497.     printf( "\n\t%p = Current Buffer Control Block", idt->curbcb );
  498.     printf( "\n\t%p = Start of MS-DOS Memory Arena", idt->arena );
  499.     temp = idt->arena;
  500.     if ( FP_SEG(temp) != arenastart )
  501.         printf( "\n\t            *** Expected %04x ***", arenastart );
  502.     printf( "\n\t%p = Physical Drive Parameter Table", idt->pdpt );
  503.     printf( "\n\t%p = Internal File Control Blocks", idt->ifcb );
  504.     printf( "\n\t%p = Clock Device Driver", idt->clockdev );
  505.     printf( "\n\t%p = Console Device Driver", idt->condev );
  506.     printf( "\n\t     %04x = Maximum Sector Size", idt->max_ssize );
  507.     printf( "\n\t%p = Buffer Control Block List", idt->bcbhead );
  508.     printf( "\n\t%p = Logical Device Table", idt->ldt );
  509.     printf( "\n\t%p = File Control Block Table", idt->fcbt );
  510.     printf( "\n\t    %5u = Number of protected FCBs", idt->nprotfcbs );
  511.     printf( "\n\t    %5u = Number of Physical Drives (in PDT)", idt->nphysdrives );
  512.     printf( "\n\t    %5u = Number of Logical Drives (in LDT)", idt->nlogdrives );
  513.     printf( "\n" );
  514.     }
  515.  
  516. #pragma    subtitle("showpdpt() - display pdpt")
  517. #pragma    page()
  518.  
  519. /*
  520. **    function:    showpdpt
  521. **
  522. **    purpose:    This function displays the contents of the
  523. **            physical device table upon stdout.
  524. **
  525. **    usage:        void showpdpt( pdpt );
  526. **              PDPT far *pdpt;
  527. **
  528. **    returns:    nothing
  529. */
  530.  
  531. void showpdpt( pdpt )
  532.  
  533. PDPT far *pdpt;
  534.  
  535.     {
  536.     printf( "\nPhysical Device Table at: %p\n", pdpt );
  537.  
  538.     do
  539.         {
  540.         showpdpt1( pdpt );
  541.         pdpt = pdpt->nextentry;
  542.         } while ( FP_OFF(pdpt) != 0xffff );
  543.     }
  544.  
  545.  
  546.  
  547. void showpdpt1( pdpt )
  548.  
  549. PDPT far *pdpt;
  550.  
  551.     {
  552.     printf( "\nAddress of this entry: %p\n", pdpt );
  553.  
  554.     printf( "\n\t       %02x = Drive  (%c:)", pdpt->drive, pdpt->drive + 'A' );
  555.     printf( "\n\t       %02x = Driver unit number", pdpt->dunit );
  556.     printf( "\n\t    %5u = Bytes per sector", pdpt->sectorsize );
  557.     printf( "\n\t      %3u = Sectors per cluster - 1", pdpt->clustersize );
  558.     printf( "\n\t       %02x = Cluster to sector shift", pdpt->shift );
  559.     printf( "\n\t    %5u = Number of reserved (boot) sectors", pdpt->bootsectors );
  560.     printf( "\n\t      %3u = Number of File Allocation Tables (FATs)", pdpt->fats );
  561.     printf( "\n\t    %5u = Number of root directory entries", pdpt->rootsize );
  562.     printf( "\n\t    %5u = Sector number of cluster #2 (first data cluster)", pdpt->dataoffset );
  563.     printf( "\n\t    %5u = Number of clusters + 1", pdpt->lastcluster );
  564.     printf( "\n\t      %3u = Sectors per File Allocation Table (FAT)", pdpt->fatsize );
  565.     printf( "\n\t    %5u = Sector number of root directory", pdpt->diroffset );
  566.     printf( "\n\t%p = Address of device header", pdpt->devheader );
  567.     printf( "\n\t       %02x = Media descriptor byte", pdpt->mediabyte );
  568.     printf( "\n\t       %02x = Access flag", pdpt->accessflag );
  569.     printf( "\n\t%p = Address of next DPT pdpt\n", pdpt->nextentry );
  570.  
  571.     printf( "\n\tAssociated Device Header:\n" );
  572.  
  573.     showdevhdr1( pdpt->devheader );
  574.     }
  575.  
  576. #pragma    subtitle("showldt() - display ldt")
  577. #pragma    page()
  578.  
  579. /*
  580. **    function:    showldt
  581. **
  582. **    purpose:    This function displays the contents of the
  583. **            physical device table upon stdout.
  584. **
  585. **    usage:        void showldt( ldt );
  586. **              LDT far *ldt;
  587. **
  588. **    returns:    nothing
  589. */
  590.  
  591. void showldt( ldt )
  592.  
  593. LDT far *ldt;
  594.  
  595.     {
  596.     int i;
  597.  
  598.     printf( "\nLogical Device Table at: %p\n", ldt );
  599.  
  600.     /*
  601.     **    run through the table
  602.     */
  603.  
  604.     for ( i = 0; i < idt->nlogdrives; ++i, ++ldt )
  605.         {
  606.         printf( "\n\t       %c: = Logical Device", i + 'A' );
  607.         printf( "\n\t%p = Entry address", ldt );
  608.         printf( "\n\tDirectory = %Fs", ldt->currentdir );
  609.         printf( "\n\t       %02x = Code (?)", ldt->code );
  610.         printf( "\n\t%p = Address of associated physical device entry", ldt->pdpt );
  611.         if ( ldt->pdpt )
  612.             printf( " (Drive %c:)", ldt->pdpt->drive + 'A' );
  613.         printf( "\n\t    %5u = Current directory sector", ldt->curdir );
  614.         printf( "\n\t     %04x = Flag (?)\n", ldt->flag );
  615.         }
  616.     }
  617.  
  618. #pragma    subtitle("showdevhdr() - display device headers")
  619. #pragma    page()
  620.  
  621. /*
  622. **    function:    showdevhdr
  623. **
  624. **    purpose:    This function displays the contents of the
  625. **            all device driver headers.
  626. **
  627. **    usage:        void showdevhdr( devhdr );
  628. **              DEVHDR far *devhdr;
  629. **
  630. **    returns:    nothing
  631. */
  632.  
  633. void showdevhdr( devhdr )
  634.  
  635. DEVHDR far *devhdr;
  636.  
  637.     {
  638.     printf( "\nDevice Headers begin at: %p\n", devhdr );
  639.  
  640.     do
  641.         {
  642.         showdevhdr1( devhdr );
  643.         devhdr = devhdr->nextheader;
  644.         } while ( FP_OFF(devhdr) != 0xffff );
  645.     }
  646.  
  647.  
  648.  
  649. void showdevhdr1( devhdr )
  650.  
  651. DEVHDR far *devhdr;
  652.  
  653.     {
  654.     void far *p;
  655.     word attr;
  656.  
  657.     attr = devhdr->attributes;
  658.  
  659.     printf( "\n\t%p = Address of this Device Header", devhdr );
  660.     if ( attr & 0x8000 )
  661.         {
  662.         printf( "\n\t          * Character Device" );
  663.         printf( "\n\t%9s = Device Name", trimname( devhdr->devname, 8 ) );
  664.         }
  665.     else
  666.         {
  667.         printf( "\n\t          * Block Device" );
  668.         printf( "\n\t      %3u = Number of units", (byte) devhdr->devname[0] );
  669.         }
  670.     printf( "\n\t%p = Address of next device header", devhdr->nextheader );
  671.     printf( "\n\t     %04x = Device attributes", attr );
  672.     if ( attr & 0x8000 )
  673.         {
  674.         if ( attr & 0x4000 )
  675.             printf( "\n\t            - Supports IOCTL strings" );
  676.         if ( attr & 0x2000 )
  677.             printf( "\n\t            - Supports output until busy" );
  678.         if ( attr & 0x0800 )
  679.             printf( "\n\t            - Understands open/close" );
  680.         if ( attr & 0x0040 )
  681.             printf( "\n\t            - Supports IOCTL functions" );
  682.         if ( attr & 0x0010 )
  683.             printf( "\n\t            - Is special device" );
  684.         if ( attr & 0x0008 )
  685.             printf( "\n\t            - Is clock device" );
  686.         if ( attr & 0x0004 )
  687.             printf( "\n\t            - Is null device" );
  688.         if ( attr & 0x0002 )
  689.             printf( "\n\t            - Is console output device" );
  690.         if ( attr & 0x0001 )            /* paying attention? */
  691.             printf( "\n\t            - Is console input device" );
  692.         if ( attr & 0x17a0 )
  693.             printf( "\n\t            * Has unidentified bit(s) set" );
  694.         }
  695.     else
  696.         {
  697.         if ( attr & 0x4000 )
  698.             printf( "\n\t            - Supports IOCTL strings" );
  699.         if ( attr & 0x2000 )
  700.             printf( "\n\t            - Uses FAT id byte to find type" );
  701.         if ( attr & 0x0800 )
  702.             printf( "\n\t            - Understands open/close" );
  703.         if ( attr & 0x0040 )
  704.             printf( "\n\t            - Supports IOCTL functions" );
  705.         if ( attr & 0x0010 )
  706.             printf( "\n\t            - Is special device" );
  707.         if ( attr & 0x17af )
  708.             printf( "\n\t            * Has unidentified bit(s) set" );
  709.         }
  710.     FP_SEG(p) = FP_SEG(devhdr);
  711.     FP_OFF(p) = devhdr->strategy;
  712.     printf( "\n\t%p = Strategy entry point", p );
  713.     FP_OFF(p) = devhdr->intrupt;
  714.     printf( "\n\t%p = Driver interrupt entry point\n", p );
  715.     }
  716.  
  717.  
  718.  
  719. char *trimname( name, len )
  720.  
  721. char far *name;
  722. int len;
  723.  
  724.     {
  725.     static char buff[9];
  726.     int i;
  727.  
  728.     assert( len <= 8 );
  729.  
  730.     for ( i = 0; i < len; ++i )
  731.         if ( isprint( *name ) && (*name != ' ') )
  732.             buff[i] = *name++;
  733.         else
  734.             break;
  735.  
  736.     buff[i] = '\0';
  737.  
  738.     return ( buff );
  739.     }
  740.  
  741. #pragma    subtitle("showarena() - display memory arena")
  742. #pragma    page()
  743.  
  744. /*
  745. **    function:    showarena
  746. **
  747. **    purpose:    This function displays the contents of the
  748. **            memory arena.
  749. **
  750. **    usage:        void showarena( arena );
  751. **              MDB far *arena;
  752. **
  753. **    returns:    nothing
  754. */
  755.  
  756. void showarena( arena )
  757.  
  758. MDB far *arena;
  759.  
  760.     {
  761.     double kbytes;
  762.     void far *mem;
  763.     int done;
  764.  
  765.     printf( "\nMemory Arena begins at: %p\n", arena );
  766.  
  767.     if ( arena->type != 'M' )
  768.         {
  769.         printf( "\n\t+++ Memory arena not found +++\n" );
  770.         return;
  771.         }
  772.  
  773.     done = 0;
  774.  
  775.     while ( !done )
  776.         {
  777.         mem = arena;
  778.         ++FP_SEG(mem);
  779.  
  780.         printf( "\n\t%04x paragraphs ", arena->length );
  781.         kbytes = (double) arena->length / 64.0;
  782.         printf( "(%6.2f KB)", kbytes );
  783.         printf( " at %p,", arena );
  784.         printf( " Owner=%04x,", arena->owner );
  785.  
  786.         if ( arena->owner == NULL )
  787.             printf( " Free" );
  788.  
  789.         if ( arena->type == 'M' )
  790.             if ( ispsp( mem ) )
  791.                 printf( " PSP" );
  792.             else
  793.                 if ( isenv( mem ) )
  794.                     printf( " Environment" );
  795.                 else
  796.                     printf( " Data" );
  797.  
  798.         if ( done = (arena->type == 'Z') )
  799.             printf( " [Last Block]" );
  800.  
  801.         FP_SEG(arena) += arena->length + 1;
  802.         }
  803.  
  804.     printf( "\n" );
  805.     }
  806.  
  807. #pragma    subtitle("ispsp() - see if block is a PSP")
  808. #pragma    page()
  809.  
  810. /*
  811. **    function:    ispsp
  812. **
  813. **    purpose:    This functions checks a block of memory to
  814. **            see if it looks like a program segment prefix.
  815. **
  816. **    usage:        result = ispsp( p );
  817. **              int result;
  818. **              char far *;
  819. **
  820. **    returns:    0 if not PSP.
  821. **
  822. **    notes:        The following tests are performed before a
  823. **            segment qualifies as a PSP:
  824. **
  825. **            1) The word at offset 00h must contain an
  826. **               INT 20h instruction.
  827. **            2) The word at offset 50h must contain an
  828. **               INT 21h instruction.
  829. **            3) The byte at offset 52h must contain a
  830. **               RETF (far return) instruction.
  831. **            4) The owner of the DOS memory block
  832. **               containing the PSP-elect must be the
  833. **               PSP itself.
  834. */
  835.  
  836. int ispsp( p )
  837.  
  838. char far *p;
  839.  
  840.     {
  841.     PSP far *psp;
  842.  
  843.     /*
  844.     **    check PSP contents
  845.     */
  846.  
  847.     psp = (PSP far *) p;
  848.  
  849.     if ( psp->wmboot != 0x20cd )        /* test 1 */
  850.         return ( 0 );
  851.  
  852.     if ( psp->int21 != 0x21cd )        /* test 2 */
  853.         return ( 0 );
  854.  
  855.     if ( psp->farret != 0xcb )        /* test 3 */
  856.         return ( 0 );
  857.  
  858.     /*
  859.     **    external test
  860.     */
  861.  
  862.     --FP_SEG(p);
  863.     FP_OFF(p) = 0;                /* test 4 */
  864.  
  865.     return ( FP_SEG(psp) == ((MDB far *) p)->owner );
  866.  
  867.     }
  868.  
  869. #pragma    subtitle("isenv() - see if block is environment")
  870. #pragma    page()
  871.  
  872. /*
  873. **    function:    isenv
  874. **
  875. **    purpose:    This functions checks a block of memory to
  876. **            see if it looks like an environment segment.
  877. **
  878. **    usage:        result = isenv( p );
  879. **              int result;
  880. **              char far *;
  881. **
  882. **    returns:    0 if not environment.
  883. **
  884. **    notes:        If the block begins with a series of 1
  885. **            or more alphanumeric characters followed
  886. **            immediately by an equal '=' followed
  887. **            immediately by a string of displayable
  888. **            ASCII characters followed immediately by
  889. **            a null (0) byte, then it is assumed to be
  890. **            an environment block.  Ditto.
  891. */
  892.  
  893. int isenv( p )
  894.  
  895. char far *p;
  896.  
  897.     {
  898.     char far *q;
  899.  
  900.     /*
  901.     **    check for a string of the form:
  902.     **
  903.     **        <alphanumeric> <equal> <text> <NULL>
  904.     **
  905.     **    where:
  906.     **        <alphanumeric>    : <alpha> | <numeric>
  907.     **        <alpha>        : <uppercase> | <lowercase>
  908.     **        <uppercase>    : A,B,C,...,Z
  909.     **        <lowercase>    : a,b,c,...,z
  910.     **        <numeric>    : 0,1,2,...,9
  911.     **        <equal>        : =
  912.     **        <text>        : [0x20..0x7e]
  913.     **        <NULL>        : '\0'
  914.     */
  915.  
  916.     q = p;
  917.     while ( isalnum( *p ) )
  918.         ++p;
  919.  
  920.     if ( p == q )
  921.         return ( 0 );        /* require at least one char    */
  922.  
  923.     if ( *p++ != '=' )
  924.         return ( 0 );        /* no =                */
  925.  
  926.     q = p;
  927.     while ( isprint( *p ) )
  928.         ++p;
  929.  
  930.     if ( *p != '\0')
  931.         return ( 0 );        /* '\0' missing at the end    */
  932.  
  933.     return ( !(p == q) );
  934.     }
  935.  
  936. #pragma    subtitle("showbcb() - display memory bcb")
  937. #pragma    page()
  938.  
  939. /*
  940. **    function:    showbcb
  941. **
  942. **    purpose:    This function displays the contents of the
  943. **            buffer control blocks.
  944. **
  945. **    usage:        void showbcb( bcb );
  946. **              BCB far *bcb;
  947. **
  948. **    returns:    nothing
  949. */
  950.  
  951. void showbcb( bcb )
  952.  
  953. BCB far *bcb;
  954.  
  955.     {
  956.     int done;
  957.     BCB far *p;
  958.  
  959.     printf( "\nBuffer control blocks begin at: %p\n", bcb );
  960.  
  961.     done = 0;
  962.  
  963.     while ( !done )
  964.         {
  965.         p = bcb->nextbcb;
  966.  
  967.         printf( "\n\t%p = Address of this control block", bcb );
  968.         if ( bcb == idt->curbcb )
  969.             printf( "  (Current Buffer)" );
  970.         printf( "\n\t%p = Next control block", p );
  971.         printf( "\n\t       %02x = Action code", bcb->action );
  972.         printf( "\n\t    %5u = Logical sector number", bcb->logsec );
  973.         printf( "\n\t      %3u = Number of FATs", bcb->nfats );
  974.         printf( "\n\t      %3u = Sectors per FAT", bcb->sectorsperfat );
  975.         printf( "\n\t%p = Associated physical device parameters (%c:)", bcb->pdpt, bcb->pdpt->drive + 'A' );
  976.         printf( "\n\t%p = Buffer address\n", bcb->buffer );
  977.  
  978.         if ( verbose )
  979.             dumpbuffer( bcb->buffer );
  980.  
  981.         if ( !(done = (FP_OFF(p) == 0xffff)) )
  982.             bcb = p;
  983.         }
  984.  
  985.     printf( "\n" );
  986.     }
  987.  
  988. #pragma    subtitle("dumpbuffer() - hex dump a buffer")
  989. #pragma    page()
  990.  
  991. /*
  992. **    function:    dumpbuffer
  993. **
  994. **    purpose:    This function is called to produce a hex
  995. **            dump of the addressed buffer.  It will
  996. **            always dump 512 bytes, however it will
  997. **            abbreviate the dump if possible by not
  998. **            displaying consecutive duplicate paragraphs.
  999. **
  1000. **    usage:        void dumpbuffer( p );
  1001. **              byte far *p;
  1002. **
  1003. **    returns:    nothing
  1004. */
  1005.  
  1006. void dumpbuffer( p )
  1007.  
  1008. byte far *p;
  1009.  
  1010.     {
  1011.     byte lastpara[16];
  1012.     int sameaslast;
  1013.     int para;
  1014.  
  1015.     printf( "\n\tBuffer Contents:\n" );
  1016.  
  1017.     for ( sameaslast = para = 0; para < 32; ++para, p += 16 )
  1018.         {
  1019.         if ( para && (para < 31) )
  1020.             {
  1021.             if ( memkmp( lastpara, p, 16 ) )
  1022.                 {
  1023.                 memkpy( lastpara, p, 16 );
  1024.                 paragraph( lastpara, para << 4 );
  1025.                 sameaslast = 0;
  1026.                 }
  1027.             else
  1028.                 if ( !sameaslast++ )
  1029.                     printf( "\n\t  =======" );
  1030.             }
  1031.         else
  1032.             {
  1033.             memkpy( lastpara, p, 16 );
  1034.             paragraph( lastpara, para << 4 );
  1035.             }
  1036.         }
  1037.  
  1038.     printf( "\n" );
  1039.     }
  1040.  
  1041.  
  1042.  
  1043. void paragraph( p, o )
  1044.  
  1045. byte *p;
  1046. word o;
  1047.  
  1048.     {
  1049.     int x;
  1050.  
  1051.     printf( "\n\t%04x:", o );
  1052.  
  1053.     /*
  1054.     **    hex part of dump
  1055.     */
  1056.  
  1057.     for ( x = 0; x < 16; ++x )
  1058.         printf( " %02x", p[x] );
  1059.  
  1060.     /*
  1061.     **    show ASCII for fun
  1062.     */
  1063.  
  1064.     printf( " " );
  1065.  
  1066.     for ( x = 0; x < 16; ++x )
  1067.         printf( "%c", isprint( p[x] ) ? p[x] : '.' );
  1068.     }
  1069.  
  1070. #pragma    subtitle("memk..() - near/far memory functions")
  1071. #pragma    page()
  1072.  
  1073. /*
  1074. **    function:    memkpy
  1075. **
  1076. **    purpose:    This function if used to copy data from
  1077. **            far memory to near memory.  Is is similar
  1078. **            to memcpy().
  1079. **
  1080. **    usage:        void memkpy( dest, src, len );
  1081. **              byte *dest;
  1082. **              byte far *src;
  1083. **              int len;
  1084. **
  1085. **    returns:    nothing
  1086. */
  1087.  
  1088. void memkpy( d, s, l )
  1089.  
  1090. byte *d;
  1091. byte far *s;
  1092. int l;
  1093.  
  1094.     {
  1095.     while ( l-- )
  1096.         *d++ = *s++;
  1097.     }
  1098.  
  1099.  
  1100.  
  1101. /*
  1102. **    function:    memkmp
  1103. **
  1104. **    purpose:    This function if used to compare data in
  1105. **            far memory to data in near memory.  It is
  1106. **            similar to memkmp().
  1107. **
  1108. **    usage:        void memkmp( p1, p2, len );
  1109. **              byte *p1;
  1110. **              byte far *p2;
  1111. **              int len;
  1112. **
  1113. **    returns:    nothing
  1114. */
  1115.  
  1116. int memkmp( d, s, l )
  1117.  
  1118. byte *d;
  1119. byte far *s;
  1120. int l;
  1121.  
  1122.     {
  1123.     if ( !l )
  1124.         return ( 0 );
  1125.  
  1126.     while ( --l && ( *d == *s ) )
  1127.         ++d, ++s;
  1128.  
  1129.     return ( *d - *s );
  1130.     }
  1131.  
  1132. #pragma    subtitle("showifcb() - display internal fcbs")
  1133. #pragma    page()
  1134.  
  1135. /*
  1136. **    function:    showifcb
  1137. **
  1138. **    purpose:    This function displays the contents of the
  1139. **            internal file control block chain.
  1140. **
  1141. **    usage:        void showifcb( chain, flag );
  1142. **              CHAIN far *chain;
  1143. **              int flag;  (* 1 if ifcb, 0 if fcbt *)
  1144. **
  1145. **    returns:    nothing
  1146. */
  1147.  
  1148. void showifcb( chain, flag )
  1149.  
  1150. CHAIN far *chain;
  1151. int flag;
  1152.  
  1153.     {
  1154.     CHAIN far *c;
  1155.     IFCB far *ifcb;
  1156.     int nifcbs;
  1157.     int nlinks;
  1158.     int done;
  1159.     int i;
  1160.  
  1161.     /*
  1162.     **    get some basic information
  1163.     */
  1164.  
  1165.     c = chain;
  1166.  
  1167.     nlinks = nifcbs = done = 0;
  1168.  
  1169.     do
  1170.         {
  1171.         nifcbs += c->nentries;
  1172.         ++nlinks;
  1173.         c = c->nextchain;
  1174.         } while ( FP_OFF(c) != 0xffff );
  1175.  
  1176.     if ( flag )
  1177.         printf( "\nInternal File Control Block Chain at %p contains", chain );
  1178.     else
  1179.         printf( "\nFile Control Block Chain at %p contains", chain );
  1180.  
  1181.     if ( nlinks > 1 )
  1182.         printf( "\n%d links with a total of %d internal file control blocks.\n", nlinks, nifcbs );
  1183.     else
  1184.         printf( "\n1 link with %d internal file control blocks.\n", nifcbs );
  1185.  
  1186.  
  1187.     /*
  1188.     **    now give the details
  1189.     */
  1190.  
  1191.     c = chain;
  1192.  
  1193.     do
  1194.         {
  1195.         if ( nlinks > 1 )
  1196.             printf( "\nLink at %p contains %d blocks\n", c, c->nentries );
  1197.  
  1198.         ifcb = (IFCB far *) c;
  1199.         FP_OFF(ifcb) += sizeof(CHAIN);
  1200.  
  1201.         for ( i = 0; i < c->nentries; ++i )
  1202.             showifcb1( &ifcb[i] );
  1203.  
  1204.         c = c->nextchain;
  1205.         } while ( FP_OFF(c) != 0xffff );
  1206.  
  1207.     printf( "\n" );
  1208.     }
  1209.  
  1210.  
  1211.  
  1212.  
  1213. #define    MO    (ifcb->filedate.month)
  1214. #define    DA    (ifcb->filedate.day)
  1215. #define    YR    (ifcb->filedate.year + 1980)
  1216.  
  1217. #define    HR    (ifcb->filetime.hour)
  1218. #define    MIN    (ifcb->filetime.minute)
  1219. #define    SEC    (ifcb->filetime.second * 2)
  1220.  
  1221. void showifcb1( ifcb )
  1222.  
  1223. IFCB far *ifcb;
  1224.  
  1225.     {
  1226.     word attr;
  1227.     int i;
  1228.     static char *openmode[4] =
  1229.             { "Read", "Write", "Read/Write", "Unknown Mode" };
  1230.     static char flag[] = "??ADVSHR";
  1231.  
  1232.     printf( "\n\t     %p = Address of this control block", ifcb );
  1233.  
  1234.     if ( ifcb->filename[0] == 0 )
  1235.         {
  1236.         printf( "  (NEVER USED)\n" );
  1237.         return;
  1238.         }
  1239.  
  1240.     printf( "\n\t         %5u = Number of opens", ifcb->nopens );
  1241.     if ( ifcb->nopens == 0 )
  1242.         {
  1243.         printf( "  (NOT OPEN)" );
  1244.  
  1245.         if ( !verbose )
  1246.             {
  1247.             printf( "\n" );
  1248.             return;
  1249.             }
  1250.         }
  1251.  
  1252.     printf( "\n\t          %04x = Open mode  (%s)", ifcb->mode, openmode[ifcb->mode & 3] );
  1253.     printf( "\n\t          %04x = PSP of owner", ifcb->owner );
  1254.  
  1255.     printf( "\n\t          %04x = Device attributes", attr = ifcb->devattr );
  1256.     if ( attr & 0x0080 )
  1257.         {
  1258.         printf( "\n\t                 - Opened as device" );
  1259.         if ( attr & 0x4000 )
  1260.             printf( "\n\t                 - Processes control strings" );
  1261.         else
  1262.             printf( "\n\t                 - Cannot process control strings" );
  1263.         if ( attr & 0x2000 )
  1264.             printf( "\n\t                 - Supports output until busy" );
  1265.         else                    /* if u cn rd ths u cn gt a gd jb! */
  1266.             printf( "\n\t                 - Doesn't support output until busy" );
  1267.         if ( attr & 0x0800 )
  1268.             printf( "\n\t                 - Understands open/close" );
  1269.         else
  1270.             printf( "\n\t                 - Doesn't understand open/close" );
  1271.         if ( attr & 0x0040 )
  1272.             printf( "\n\t                 - Ready" );
  1273.         else
  1274.             printf( "\n\t                 - Not ready" );
  1275.         if ( attr & 0x0020 )
  1276.             printf( "\n\t                 - Raw" );
  1277.         else
  1278.             printf( "\n\t                 - Cooked" );
  1279.         if ( attr & 0x0010 )
  1280.             printf( "\n\t                 - Special device" );
  1281.         if ( attr & 0x0008 )
  1282.             printf( "\n\t                 - Clock device" );
  1283.         if ( attr & 0x0004 )
  1284.             printf( "\n\t                 - Null device" );
  1285.         if ( attr & 0x0002 )
  1286.             printf( "\n\t                 - Console output device" );
  1287.         if ( attr & 0x0001 )
  1288.             printf( "\n\t                 - Console input device" );
  1289.         if ( attr & 0x9700 )
  1290.             printf( "\n\t                 - ?? (%04x)", attr & 0x9700 );
  1291.         }
  1292.     else
  1293.         {
  1294.         printf( "\n\t                 - Opened as file" );
  1295.         if ( attr & 0x0040 )
  1296.             printf( "\n\t                 - Not written to" );
  1297.         else
  1298.             printf( "\n\t                 - Written to" );
  1299.         printf( "\n\t                 - On drive %c:", (attr & 0x002f) + 'A' );
  1300.         if ( attr & 0xff00 )
  1301.             printf( "\n\t                 - ?? (%04x)", attr & 0xff00 );
  1302.         }
  1303.  
  1304.     if ( attr & 0x0080 )
  1305.         {
  1306.         printf( "\n\t    '%8.8Fs' = Device name", ifcb->filename );
  1307.         printf( "\n\t     %p = Driver header address", ifcb->pdpt );
  1308.         }
  1309.     else
  1310.         {
  1311.         printf( "\n\t'%8.8Fs.%3.3Fs' = File name", ifcb->filename, ifcb->fileext );
  1312.         printf( "\n\t    %2d/%02d/%04d = File date", MO, DA, YR );
  1313.         printf( "\n\t      %2d:%02d:%02d = File time", HR, MIN, SEC );
  1314.         printf( "\n\t            %02x = Attribute (flags) byte", ifcb->fileattr );
  1315.         if ( ifcb->fileattr )
  1316.             {
  1317.             printf( "  [" );
  1318.             for ( i = 0; i < 8; ++i )
  1319.                 if ( ifcb->fileattr & (0x80 >> i) )
  1320.                     printf( "%c", flag[i] );
  1321.                 else
  1322.                     printf( "%c", '-' );
  1323.             printf( "]" );
  1324.             }
  1325.         printf( "\n\t         %5u = First cluster in file", ifcb->firstcluster );
  1326.         printf( "\n\t         %5u = Number of clusters in file", ifcb->nclusters );
  1327.         printf( "\n\t         %5u = Current cluster", ifcb->curcluster );
  1328.         printf( "\n\t    %10lu = File size (bytes)", ifcb->filesize );
  1329.         printf( "\n\t    %10lu = Current file position", ifcb->filepos );
  1330.         printf( "\n\t         %5u = Sector in directory containing file's entry", ifcb->dirsector );
  1331.         printf( "\n\t            %2u = Index of directory entry in sector", ifcb->dirindex );
  1332.         printf( "\n\t     %p = Associated physical device parameters (%c:)", ifcb->pdpt, ifcb->pdpt->drive + 'A' );
  1333.         }
  1334.  
  1335.     printf( "\n" );
  1336.     }
  1337.  
  1338.