home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d172 / popinfo.lha / PopInfo / PopInfo.c < prev    next >
C/C++ Source or Header  |  1988-11-22  |  19KB  |  515 lines

  1.  
  2. /* PopInfo v2.0
  3.  
  4.    A Workbench utility to show you the info that Workbench doesn't.
  5.  
  6.    © Copyright 1988 Jonathan Potter
  7.    Placed in the Public Domain (NOT Shareware) and is NOT to be sold for
  8.       profit.. a MAXIMUM of $10 may be charged for a copying fee, etc..
  9.  
  10.    HISTORY:
  11.  
  12.       around mid-September : v1.0 written -
  13.                                   this was so simple & buggy that it was
  14.                                   never released..
  15.       1-October-1988       : v2.0 written -
  16.                                   a total rewrite took 2 days
  17.                                   or around 11 hours
  18.  
  19.    COMPILE:
  20.  
  21.       Compiles with Manx Aztec C v3.6a using 32 bit ints with
  22.  
  23.       cc +l -s PopInfo
  24.       as ReadBlock
  25.       ln -o PopInfo +cdb PopInfo.o ReadBlock.o -lc32
  26.  
  27.    BUGS:
  28.  
  29.       none known of.. no doubt there are some....
  30.  
  31.    AUTHOR:
  32.             Jonathan Potter
  33.             3 William Street
  34.             Clarence Park
  35.             South Australia (a boring place to live)
  36.             Australia 5034 (can't wait to get back to London!!!)
  37.  
  38.    Enjoy the program! And,
  39.  
  40.                           I'll see you on the Dark Side of the Moon!!! */
  41.  
  42.  
  43. /* includes */
  44. #include <exec/tasks.h>
  45. #include <exec/memory.h>
  46. #include <intuition/intuition.h>
  47. #include <devices/trackdisk.h>
  48. #include <devices/timer.h>
  49. #include <libraries/dosextens.h>
  50.  
  51. /* windows */
  52. struct NewWindow Credits={
  53.    235,65,170,73,
  54.    -1,-1,
  55.    NULL,
  56.    SMART_REFRESH|NOCAREREFRESH,
  57.    NULL, NULL,
  58.    NULL,
  59.    NULL, NULL,
  60.    0,0,0,0,
  61.    WBENCHSCREEN
  62. };
  63. struct NewWindow SWindow={
  64.    0,0,12,10,
  65.    -1,-1,
  66.    ACTIVEWINDOW,
  67.    ACTIVEWINDOW,
  68.    NULL,NULL,
  69.    "P",
  70.    NULL,NULL,
  71.    0,0,0,0,
  72.    WBENCHSCREEN
  73. };
  74. struct NewWindow MWindow={
  75.    0,0,444,0,
  76.    -1,-1,
  77.    CLOSEWINDOW|INACTIVEWINDOW|MOUSEBUTTONS,
  78.    WINDOWCLOSE|INACTIVEWINDOW|ACTIVATE|NOCAREREFRESH|SMART_REFRESH|RMBTRAP,
  79.    NULL,NULL,
  80.    "PopInfo v2.0",
  81.    NULL,NULL,
  82.    0,0,0,0,
  83.    WBENCHSCREEN
  84. };
  85. struct NewWindow LWindow={
  86.    0,0,586,170,
  87.    -1,-1,
  88.    NULL,
  89.    ACTIVATE|WINDOWDEPTH|RMBTRAP|NOCAREREFRESH|SMART_REFRESH,
  90.    NULL,NULL,
  91.    "",
  92.    NULL,NULL,
  93.    0,0,0,0,
  94.    WBENCHSCREEN
  95. };
  96.  
  97. /* a few structs */
  98. struct IntuitionBase *IntuitionBase;
  99. struct Window *Window, *CWindow;
  100. struct timerequest Time_Req;
  101. struct MsgPort *Timer_Port;
  102. struct Port *diskport;
  103. struct IOStdReq *diskreq;
  104. struct IntuiMessage *Msg, *GetMsg();
  105. struct FileLock *lock, *Lock();
  106. struct InfoData *data;
  107. struct DateStamp now;
  108. struct DosLibrary *DosBase;
  109. struct DeviceList *devlist;
  110. struct RootNode *rootnode;
  111. struct DosInfo *dosinfo;
  112. struct RastPort *RP;
  113. struct GfxBase *GfxBase;
  114.  
  115. /* some strings, etc.. */
  116. char txt[80], bwn[]="Bootblock of disk in DFx:";
  117. unsigned char diskbuffer[3*512];
  118. /* a working bootblock */
  119. unsigned char bootblock[]={'D','O','S',0,0xc0,0x20,0x0f,0x19,0x00,0x00,0x03,
  120.    0x70,0x43,0xfa,0x00,0x18,0x4e,0xae,0xff,0xa0,0x4a,0x80,0x67,0x0a,0x20,
  121.    0x40,0x20,0x68,0x00,0x16,0x70,0x00,0x4e,0x75,0x70,0xff,0x60,0xfa,0x64,
  122.    0x6f,0x73,0x2e,0x6c,0x69,0x62,0x72,0x61,0x72,0x79,0x00,0x00,0x00,0x00,
  123.    0x00};
  124.  
  125. /* intuitext structures... i HATE intuitext */
  126. struct IntuiText mesg={
  127.    1,0,JAM1,10,12,(struct TextAttr *) NULL,txt,(struct IntuiText *) NULL };
  128.  
  129. struct IntuiText vbb2={
  130.    0,1,JAM2,10,18,(struct TextAttr *) NULL,(UBYTE *)"with non-standard bootblocks?",
  131.    NULL};
  132. struct IntuiText vbb1={
  133.    0,1,JAM2,10,8,(struct TextAttr *) NULL,(UBYTE *)"View first two sectors of disk(s)",
  134.    &vbb2};
  135. struct IntuiText vbbp={
  136.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Yup",NULL};
  137. struct IntuiText vbbn={
  138.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Nup",NULL};
  139.  
  140. struct IntuiText il1={
  141.    0,1,JAM2,10,8,(struct TextAttr *) NULL,(UBYTE *)"Install this disk?",
  142.    NULL};
  143. struct IntuiText ilp={
  144.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Yup",NULL};
  145. struct IntuiText iln={
  146.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Nup",NULL};
  147.  
  148. struct IntuiText rus2={
  149.    0,1,JAM2,10,18,(struct TextAttr *) NULL,(UBYTE *)"to install this disk?",
  150.    NULL};
  151. struct IntuiText rus1={
  152.    0,1,JAM2,10,8,(struct TextAttr *) NULL,(UBYTE *)"Are you sure that you want",
  153.    &rus2};
  154. struct IntuiText rusp={
  155.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Yup",NULL};
  156. struct IntuiText rusn={
  157.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Nup",NULL};
  158.  
  159. struct IntuiText cvb1={
  160.    0,1,JAM2,10,8,(struct TextAttr *) NULL,(UBYTE *)"Continue viewing bootblocks?",
  161.    NULL};
  162. struct IntuiText cvbp={
  163.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Yup",NULL};
  164. struct IntuiText cvbn={
  165.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Nup",NULL};
  166.  
  167. struct IntuiText wp2={
  168.    0,1,JAM2,10,18,(struct TextAttr *) NULL,(UBYTE *)"Try it again?",NULL};
  169. struct IntuiText wp1={
  170.    0,1,JAM2,10,8,(struct TextAttr *) NULL,(UBYTE *)"ERROR! Disk is write protected!",
  171.    &wp2};
  172. struct IntuiText wpp={
  173.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Yup",NULL};
  174. struct IntuiText wpn={
  175.    0,1,JAM2,7,3,(struct TextAttr *) NULL,"Nup",NULL};
  176.  
  177. /* start */
  178. main()
  179. {
  180.    int oldpri,numdevs,nondos,nodisk,flag,sbbflag,a,b,c,x,y,dnum,sum,lastsum,error;
  181.    int nsbb[4];
  182.    UBYTE devname[4];
  183.    char *bbmess, *status;
  184.    register unsigned int *iptr;
  185.    unsigned int *ptr;
  186.  
  187.    oldpri=SetTaskPri(FindTask(0),18);
  188.  
  189.    OpenAll(); /* open all the libraries, etc.. */
  190.  
  191.    for(;;) { /* infinite */
  192.       waitaround:  /* yup.. */
  193.       Wait(1L<<Window->UserPort->mp_SigBit); /* wait for something to happen */
  194.       Msg=GetMsg(Window->UserPort); /* something's happened.. */
  195.          if (Msg->Class==CLOSEWINDOW) {  /* say goodbye */
  196.             ReplyMsg(Msg);
  197.             CloseWindow(Window);
  198.             CloseLibrary(IntuitionBase);
  199.             CloseLibrary(DosBase);
  200.             CloseDevice(&Time_Req);
  201.             DeletePort(Timer_Port);
  202.             DeletePort(diskport);
  203.             DeleteStdIO(diskreq);
  204.             SetTaskPri(FindTask(0),oldpri);
  205.             exit(0);  /* bye! */
  206.          }
  207.          if (Msg->Class==ACTIVEWINDOW) {  /* clicked on small window */
  208.             ReplyMsg(Msg);
  209.             if (Msg->MouseX > 12 || Msg->MouseY > 10) goto waitaround;
  210.             if (flag==1) break;
  211.             flag=1;
  212.             CloseWindow(Window); /* close little window */
  213.             numdevs=countdevices(); /* count number of devices present in */
  214.             if (numdevs>16) numdevs=16; /* system and set medium window */
  215.             MWindow.Height=50+(9*numdevs); /* size accordingly */
  216.             Window=(struct Window *) OpenWindow(&MWindow); /* open medium */
  217.             wprint("Unit   Bytes      Used       Free       Ers  WPS  SBB",0,1);
  218.             wprint("____   _____      ____       ____       ___  ___  ___",0,2);
  219.             y=12;
  220.             Forbid(); /* better to be safe.. */
  221.             rootnode=(struct RootNode *) DosBase->dl_Root;
  222.             dosinfo=(struct DosInfo *) BADDR(rootnode->rn_Info);
  223.             devlist=(struct DeviceList *) BADDR(dosinfo->di_DevInfo);
  224.             while (devlist) { /* scan devicelist */
  225.                if (devlist->dl_Type!=NULL) { /* is right type? */
  226.                   devlist=(struct DeviceList *) BADDR(devlist->dl_Next);
  227.                   continue;
  228.                }
  229.                conbstr((BPTR) devlist->dl_Name,devname);
  230.                strcat(devname,":");
  231.                if (DLT_DEVICE!=NULL || devlist->dl_Task) {
  232.                   iptr[0]=0;
  233.                   dnum=-1;
  234.                   nodisk=0;
  235.                   nondos=0;
  236.                   bbmess="N/A";
  237.                   status="R/W";
  238.                   if (devname[0]==68 && devname[1]==70) dnum=devname[2]-48;
  239.                   if (dnum!=-1) { /* device is a DFx: */
  240.                      bbmess="Yes";
  241.                      error=OpenDevice("trackdisk.device",dnum,diskreq,0);
  242.                         diskreq->io_Command=TD_CHANGESTATE; /* disk there? */
  243.                         DoIO(diskreq);
  244.                         if (diskreq->io_Actual!=0) { /* nup */
  245.                            nodisk=1;
  246.                            CloseDevice(diskreq);
  247.                            goto display; /* aaargh! a goto */
  248.                         }
  249.                         diskreq->io_Command=TD_PROTSTATUS; /* write */
  250.                         DoIO(diskreq);                     /* protected ? */
  251.                         if (diskreq->io_Actual!=0) status="R O"; /* yup */
  252.                         error=ReadBlock(); /* read boot block */
  253.                         diskreq->io_Command=TD_MOTOR; /* shut motor up */
  254.                         diskreq->io_Length=0;
  255.                         DoIO(diskreq);
  256.                         CloseDevice(diskreq);
  257.                         ptr=diskbuffer;
  258.                         iptr=diskbuffer;
  259.                         if (iptr[0]!=ID_DOS_DISK) { /* a dos disk? */
  260.                            nondos=1; /* this includes unformatted disks */
  261.                            goto display;
  262.                         }
  263.                         sum=0;
  264.                         for (a=0;a<256;a++) { /* calculate checksum */
  265.                            lastsum=sum;
  266.                            sum=sum+ptr[a];
  267.                            if (lastsum>sum) sum++;
  268.                         }
  269.                         if (sum!=0) { /* if sum isn't 0, disk isn't */
  270.                            nsbb[dnum]=0; /* bootable */
  271.                            bbmess="NBB";
  272.                            goto display;
  273.                         }
  274.                         ptr=&diskbuffer[4];
  275.                         for (x=0;x<39;x++) {
  276.                            if (diskbuffer[8+x]!=bootblock[8+x]) {
  277.                               nsbb[dnum]=5; /* disk has a non standard */
  278.                               sbbflag=1; /* bootblock.. virus? or just a */
  279.                               bbmess="No"; /* special bootblock.. */
  280.                            }
  281.                         }
  282.                   }
  283. display:
  284.                   dnum=0;
  285.                   if (nodisk!=1 && nondos!=1) { /* dos disk present */
  286.                      lock=Lock(devname,ACCESS_READ);
  287.                      Info(lock,data);
  288.                      sprintf(txt,"%-4s   %-9ld  %-9ld  %-9ld  %-3ld  %-3s  %-3s",
  289.                         devname,
  290.                         data->id_BytesPerBlock*data->id_NumBlocks,
  291.                         data->id_BytesPerBlock*data->id_NumBlocksUsed,
  292.                         (data->id_BytesPerBlock*data->id_NumBlocks)-
  293.                            (data->id_BytesPerBlock*data->id_NumBlocksUsed),
  294.                         data->id_NumSoftErrors,
  295.                         status,
  296.                         bbmess);
  297.                      PrintIText(Window->RPort,&mesg,0,y);
  298.                      y+=9;
  299.                      UnLock(lock);
  300.                   }
  301.                   else if (nodisk==1) { /* no disk there */
  302.                      sprintf(txt,"%-4s   No disk present in drive.", devname);
  303.                      PrintIText(Window->RPort,&mesg,0,y);
  304.                      y+=9;
  305.                      nodisk=0;
  306.                   }
  307.                   else if (nondos==1) { /* not a dos disk */
  308.                      sprintf(txt,"%-4s   Not a DOS disk.", devname);
  309.                      PrintIText(Window->RPort,&mesg,0,y);
  310.                      y+=9;
  311.                      nondos=0;
  312.                   }
  313.                }
  314.                devlist=(struct DeviceList *) BADDR(devlist->dl_Next);
  315.             }
  316.             Permit(); /* phew */
  317.             y+=5;
  318.             sprintf(txt,"FREE MEMORY  FAST:%-7ld  CHIP:%-6ld  TOTAL:%-7ld",
  319.                (AvailMem(MEMF_FAST) >> 10) * 1024,
  320.                (AvailMem(MEMF_CHIP) >> 10) * 1024,
  321.                ((AvailMem(MEMF_FAST) >> 10) * 1024) +
  322.                ((AvailMem(MEMF_CHIP) >> 10) *1024));
  323.             PrintIText(Window->RPort,&mesg,0,y);
  324.             DateStamp(&now);
  325.             sprintf(txt,"                    TIME %02d:%02d:%02d",
  326.                now.ds_Minute/60, now.ds_Minute%60,
  327.                now.ds_Tick/TICKS_PER_SECOND);
  328.             PrintIText(Window->RPort,&mesg,0,y+9);
  329.             Time_Req.tr_time.tv_secs=0;
  330.             Time_Req.tr_time.tv_micro=250000;
  331.             SendIO((char *) &Time_Req.tr_node);
  332.             if (sbbflag==1) {  /* non standard bootblock */
  333.                sbbflag=0; /* wanna view it (them) ? */
  334.                error=AutoRequest(Window, &vbb1, &vbbp, &vbbn, 0,0,320,70);
  335.                if (error!=TRUE) goto lbandf; /* nup */
  336.                CloseWindow(Window); /* yup */
  337.                for (c=0;c<4;c++) { /* go through df's 0 to 3 */
  338.                   if (nsbb[c]==5) {  /* if 5, has non standard bootblock */
  339.                      nsbb[c]=0;
  340.                      Window=(struct Window *) OpenWindow(&LWindow);
  341.                      bwn[23]=c+48; /* set the window title */
  342.                      SetWindowTitles(Window, bwn, -1);
  343.                      RP=Window->RPort;
  344.                      error=OpenDevice("trackdisk.device",c,diskreq,0);
  345.                      error=ReadBlock(); /* read the bootblock again */
  346.                      diskreq->io_Command=TD_MOTOR;
  347.                      diskreq->io_Length=0;
  348.                      DoIO(diskreq); /* shut motor up */
  349.                      CloseDevice(diskreq);
  350.                      SetAPen(RP,3);
  351.                      Move(RP, 14+(12*8), 165);
  352.                      Text(RP, "Block 0", 7);
  353.                      Move(RP, 324+(12*8), 165);
  354.                      Text(RP, "Block 1", 7);
  355.                      SetAPen(RP, 1);
  356.                      x=0; y=0;
  357.                      SetAPen(RP,1);
  358.                      SetDrMd(RP,JAM2);
  359.                      for (a=0;a<512;a=a+32) { /* display the bootblock */
  360.                         Move(RP,10+(x*8),20+(y*9));
  361.                         Text(RP,&diskbuffer[a],32);
  362.                         Move(RP,320+(x*8),20+(y*9));
  363.                         Text(RP,&diskbuffer[a+512],32);
  364.                         y++;
  365.                      }
  366.                      error=AutoRequest(Window,&il1,&ilp,&iln,0,0,320,70);
  367.                      if (error==TRUE) { /* yep! install it */
  368.                         error=AutoRequest(Window,&rus1,&rusp,&rusn,0,0,320,70);
  369.                            if (error!=TRUE) goto forgetit; /* no thanks */
  370.                         error=OpenDevice("trackdisk.device",c,diskreq,0);
  371.                         tryagain:
  372.                         diskreq->io_Command=TD_PROTSTATUS;
  373.                         DoIO(diskreq);
  374.                         if (diskreq->io_Actual != 0) { /* write protected */
  375.                            error=AutoRequest(Window,&wp1,&wpp,&wpn,0,0,320,70);
  376.                            if (error==TRUE) goto tryagain; /* try again */
  377.                            CloseDevice(diskreq);
  378.                            goto forgetit; /* forget it! */
  379.                         }
  380.                         for (x=0;x<1024;x++) /* write bootblock to disk */
  381.                         diskbuffer[x]=0;
  382.                         CopyMem(bootblock,diskbuffer,50);
  383.                         diskreq->io_Length=1024;
  384.                         diskreq->io_Data=&diskbuffer[0];
  385.                         diskreq->io_Command=CMD_WRITE;
  386.                         diskreq->io_Offset=0L;
  387.                         DoIO(diskreq);
  388.                         diskreq->io_Command=CMD_UPDATE;
  389.                         DoIO(diskreq);
  390.                         diskreq->io_Length=0; /* once again.. shut the */
  391.                         diskreq->io_Command=TD_MOTOR; /* bloody motor up */
  392.                         DoIO(diskreq);
  393.                      }
  394.                      forgetit: /* view rest of bootblocks? (if any) */
  395.                      error=AutoRequest(Window,&cvb1,&cvbp,&cvbn,0,0,320,70);
  396.                      CloseWindow(Window);
  397.                      if (error!=TRUE) { /* no thanks */
  398.                         Window=(struct Window *) OpenWindow(&SWindow);
  399.                         flag=0;
  400.                         goto waitaround;
  401.                      }
  402.                   }
  403.                }
  404.                Window=(struct Window *) OpenWindow(&SWindow);
  405.                flag=0;
  406.                goto waitaround;
  407.                lbandf: /* this stops IDCMP sending an inactivewindow */
  408.                Msg=GetMsg(Window->UserPort); /* just because we clicked */
  409.                if (Msg->Class!=INACTIVEWINDOW) goto lbandf; /* on the */
  410.                lbandf2: /* requester box... */
  411.                Msg=GetMsg(Window->UserPort);
  412.                if (Msg->Class==INACTIVEWINDOW) {
  413.                   ReplyMsg(Msg);
  414.                   goto waitaround;
  415.                }
  416.                goto lbandf2;
  417.             }
  418.          }
  419.          if (Msg->Class==INACTIVEWINDOW) { /* clicked outside window */
  420.             ReplyMsg(Msg);
  421.             if (flag=0) break;
  422.  
  423.             flag=0;
  424.             CloseWindow(Window); /* bye bye medium */
  425.             Window=(struct Window *) OpenWindow(&SWindow); /* hello small */
  426.          }
  427.          if (Msg->Class==MOUSEBUTTONS && Msg->Code==MENUDOWN) {
  428.             /* right mouse button */
  429.             ReplyMsg(Msg);
  430.             CWindow=(struct Window *) OpenWindow(&Credits); /* open credits */
  431.             sprintf(txt,"PopInfo v2.0");
  432.             PrintIText(CWindow->RPort,&mesg,27,1);
  433.             sprintf(txt,"© Copyright 1988");
  434.             PrintIText(CWindow->RPort,&mesg,11,10);
  435.             sprintf(txt,"Jonathan Potter");
  436.             PrintIText(CWindow->RPort,&mesg,15,20);
  437.             sprintf(txt,"PUBLIC DOMAIN 1988");
  438.             PrintIText(CWindow->RPort,&mesg,3,40);
  439.             for (;;) { /* wait until menu button released */
  440.                Msg=GetMsg(Window->UserPort);
  441.                if (Msg->Code==MENUUP)
  442.                   break;
  443.             }
  444.             CloseWindow(CWindow); /* close credits window */
  445.          }
  446.       goto waitaround;
  447.    }
  448. }
  449.  
  450. OpenAll() /* open all the libraries */
  451. {
  452.    IntuitionBase=(struct IntuitionBase *) OpenLibrary("intuition.library",0);
  453.    Window=(struct Window *) OpenWindow(&SWindow); /* open window */
  454.    if (Window==NULL) { /* not enough memory for window */
  455.       DeletePort(diskport);
  456.       DeleteStdIO(diskreq);
  457.       CloseLibrary(IntuitionBase);
  458.       exit(0);
  459.    }
  460.    DosBase=(struct DosLibrary *) OpenLibrary(DOSNAME,0L);
  461.    diskport=CreatePort(0,0);
  462.    diskreq=CreateStdIO(diskport);
  463.    GfxBase=(struct GfxBase *) OpenLibrary("graphics.library",0);
  464.    Timer_Port=CreatePort("Timer Port",0);
  465.    OpenDevice(TIMERNAME,UNIT_VBLANK, (char *) &Time_Req,0);
  466.    lock=(struct FileLock *) AllocMem(sizeof(struct FileLock),MEMF_CHIP|MEMF_CLEAR);
  467.    data=(struct InfoData *) AllocMem(sizeof(struct InfoData),MEMF_CHIP|MEMF_CLEAR);
  468.    Time_Req.tr_node.io_Message.mn_ReplyPort=Timer_Port;
  469.    Time_Req.tr_node.io_Command=TR_ADDREQUEST;
  470.    Time_Req.tr_node.io_Flags=0;
  471.    Time_Req.tr_node.io_Error=0;
  472. }
  473.  
  474. wprint(string,x,y) /* a simple intuitext print routine */
  475. char *string;
  476. int x,y;
  477. {
  478.    sprintf(txt,string);
  479.    PrintIText(Window->RPort,&mesg,x,y);
  480. }
  481.  
  482. conbstr(bp,buf) /* convert a bstr to char */
  483. BSTR bp;
  484. char *buf;
  485. {
  486.    register UBYTE *cp;
  487.    register int len,i;
  488.    cp=(UBYTE *) BADDR(bp);
  489.    len=(int) *(cp++);
  490.    len=(len>20)?20:len;
  491.    for (i=0;i<len;i++) buf[i]=*(cp++);
  492.    buf[i]='\0';
  493. }
  494.  
  495. countdevices() /* count devices in system */
  496. {
  497.    int devices;
  498.    devices=0;
  499.    Forbid();  /* afraid so */
  500.    rootnode=(struct RootNode *) DosBase->dl_Root;
  501.    dosinfo=(struct DosInfo *) BADDR(rootnode->rn_Info);
  502.    devlist=(struct DeviceList *) BADDR(dosinfo->di_DevInfo);
  503.    while (devlist) {
  504.       if (devlist->dl_Type!=NULL) {
  505.          devlist=(struct DeviceList *) BADDR(devlist->dl_Next);
  506.          continue;
  507.       }
  508.       if (DLT_DEVICE!=NULL || devlist->dl_Task) ++devices;
  509.       devlist=(struct DeviceList *) BADDR(devlist->dl_Next);
  510.    }
  511.    Permit();  /* wop */
  512.    return(devices);
  513. }
  514.  
  515.