home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / CDTools / Eject / Source / Eject.c
C/C++ Source or Header  |  1994-12-25  |  18KB  |  803 lines

  1. /*
  2. **    Eject - AmigaDOS 2.04 utility
  3. **
  4. **    Copyright © 1994-1994 by Olaf `Olsen' Barthel
  5. **        Public Domain
  6. **
  7. **    :ts=4
  8. */
  9.  
  10.     /* Just a few includes... */
  11.  
  12. #include <intuition/intuitionbase.h>
  13.  
  14. #include <exec/execbase.h>
  15. #include <exec/memory.h>
  16. #include <exec/io.h>
  17.  
  18. #include <devices/scsidisk.h>
  19.  
  20. #include <workbench/workbench.h>
  21. #include <workbench/startup.h>
  22.  
  23. #include <dos/filehandler.h>
  24. #include <dos/dosextens.h>
  25. #include <dos/rdargs.h>
  26.  
  27. #include <clib/intuition_protos.h>
  28. #include <clib/exec_protos.h>
  29. #include <clib/icon_protos.h>
  30. #include <clib/dos_protos.h>
  31. #include <clib/wb_protos.h>
  32.  
  33. #include <string.h>
  34.  
  35.     /* SCSI start/stop unit command. */
  36.  
  37. struct StartStopUnit
  38. {
  39.     UBYTE    OperationCode,        /* 0x1B */
  40.             LUN_Reserved_Immed,    /* %AAABBBBC, A = LUN, C = Immediate (0 = wait for completion) */
  41.             Reserved[2],
  42.             LoEj_Start,            /* %000000AB, A = Load/Eject (1 = eject after stop), */
  43.             Control;            /* B = Start/Stop (1 = Start, 0 = Stop) */
  44. };
  45.  
  46.     /* SCSI test unit ready command. */
  47.  
  48. struct TestUnitReady
  49. {
  50.     UBYTE    Command,            /* 0x00 */
  51.             LUN,
  52.             Reserved[3],
  53.             Control;
  54. };
  55.  
  56.     /* SCSI inquiry command. */
  57.  
  58. struct Inquiry
  59. {
  60.     UBYTE    Command,        /* 0x12 */
  61.             LUN,
  62.             PageCode,
  63.             Reserved,
  64.             AllocationLength,
  65.             Control;
  66. };
  67.  
  68.     /* Data format returned by inquiry command. */
  69.  
  70. struct InquiryData
  71. {
  72.     UBYTE    PeripheralType,
  73.             DeviceTypeModifier,
  74.             Version,
  75.             Reserved[5],
  76.             Vendor[8],
  77.             Product[16],
  78.             Revision[4];
  79. };
  80.  
  81.     /* Version identification. */
  82.  
  83. STRPTR                     Version = "$VER: Eject 1.0 (25.12.94)\r\n";
  84.  
  85.     /* Global library bases. */
  86.  
  87. struct ExecBase            *SysBase;
  88. struct DosLibrary        *DOSBase;
  89. struct IntuitionBase    *IntuitionBase;
  90. struct Library            *IconBase,
  91.                         *WorkbenchBase;
  92.  
  93.     /* Shell command template data. */
  94.  
  95. STRPTR Template = "DEVICE/A/M";
  96.  
  97. enum { ARG_DEVICE=0, ARGCOUNT };
  98.  
  99.     /* Prototypes for this module. */
  100.  
  101. BYTE    DoSCSICmd(struct IOStdReq *DeviceRequest,ULONG Unit,APTR Command,LONG CommandLen,APTR Data,LONG DataLen);
  102. BYTE    TestUnitReady(struct IOStdReq *DeviceRequest,ULONG Unit);
  103. BOOL    CheckMediaType(struct IOStdReq *DeviceRequest,ULONG Unit);
  104. BYTE    EjectMedia(struct IOStdReq *DeviceRequest,ULONG Unit);
  105. BOOL    Eject(const STRPTR DeviceName,ULONG Unit,ULONG Flags,BOOL Echo);
  106. BOOL    FindDevice(const BPTR FileLock,const STRPTR FileName,STRPTR Device,ULONG *Unit,ULONG *Flags);
  107.  
  108.     /* Main(VOID):
  109.      *
  110.      *    Program entry point.
  111.      */
  112.  
  113. LONG __saveds
  114. Main(VOID)
  115. {
  116.     struct Process        *ThisProcess;
  117.     LONG                 Result = RETURN_FAIL;
  118.     struct WBStartup    *WBenchMsg;
  119.  
  120.         /* Set up SysBase. */
  121.  
  122.     SysBase = *(struct ExecBase **)4;
  123.  
  124.         /* That's me. */
  125.  
  126.     ThisProcess = (struct Process *)FindTask(NULL);
  127.  
  128.         /* Are we a child of Workbench? */
  129.  
  130.     if(ThisProcess -> pr_CLI)
  131.         WBenchMsg = NULL;
  132.     else
  133.     {
  134.             /* Wait for the startup message. */
  135.  
  136.         WaitPort(&ThisProcess -> pr_MsgPort);
  137.  
  138.         WBenchMsg = (struct WBStartup *)GetMsg(&ThisProcess -> pr_MsgPort);
  139.     }
  140.  
  141.         /* Open dos.library. */
  142.  
  143.     if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37))
  144.     {
  145.             /* Workbench invocation? */
  146.  
  147.         if(WBenchMsg)
  148.         {
  149.             struct MsgPort *IconPort;
  150.  
  151.                 /* Hold it... */
  152.  
  153.             Forbid();
  154.  
  155.                 /* See if Eject is already running, if so tell
  156.                  * it to quit.
  157.                  */
  158.  
  159.             if(IconPort = FindPort("« Eject »"))
  160.                 Signal(IconPort -> mp_SigTask,SIGBREAKF_CTRL_C);
  161.  
  162.             Permit();
  163.  
  164.                 /* Are we the one and only ?*/
  165.  
  166.             if(!IconPort)
  167.             {
  168.                     /* Create the global port. */
  169.  
  170.                 if(IconPort = CreateMsgPort())
  171.                 {
  172.                         /* Give it a name and a special priority. */
  173.  
  174.                     IconPort -> mp_Node . ln_Name    = "« Eject »";
  175.                     IconPort -> mp_Node . ln_Pri    = 1;
  176.  
  177.                         /* Open Intuition if possible. */
  178.  
  179.                     IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37);
  180.  
  181.                         /* Take care of the remaining libraries. */
  182.  
  183.                     if(IconBase = OpenLibrary("icon.library",37))
  184.                     {
  185.                         if(WorkbenchBase = OpenLibrary("workbench.library",37))
  186.                         {
  187.                             BPTR                 OldDir = CurrentDir(WBenchMsg -> sm_ArgList -> wa_Lock);
  188.                             struct DiskObject    *Icon = GetDiskObjectNew(WBenchMsg -> sm_ArgList -> wa_Name);
  189.  
  190.                                 /* We need the icon. */
  191.  
  192.                             if(Icon)
  193.                             {
  194.                                 struct AppIcon *AppIcon;
  195.  
  196.                                     /* Add the AppIcon. */
  197.  
  198.                                 if(AppIcon = AddAppIconA(0,0,FilePart(WBenchMsg -> sm_ArgList -> wa_Name),IconPort,NULL,Icon,NULL))
  199.                                 {
  200.                                     struct AppMessage    *Message;
  201.                                     ULONG                 Signals;
  202.                                     BOOL                 Done = FALSE;
  203.                                     struct Window        *ReqWindow = NULL;
  204.                                     struct AppWindow    *AppWindow = NULL;
  205.  
  206.                                         /* Make the global port visible. */
  207.  
  208.                                     AddPort(IconPort);
  209.  
  210.                                         /* Keep going... */
  211.  
  212.                                     do
  213.                                     {
  214.                                             /* Tie in the window signal if necessary. */
  215.  
  216.                                         if(ReqWindow)
  217.                                             Signals = 1L << ReqWindow -> UserPort -> mp_SigBit;
  218.                                         else
  219.                                             Signals = NULL;
  220.  
  221.                                             /* Wait for something to happen. */
  222.  
  223.                                         Signals = Wait(Signals | (1L << IconPort -> mp_SigBit) | SIGBREAKF_CTRL_C);
  224.  
  225.                                             /* Do we have the notification window open? */
  226.  
  227.                                         if(ReqWindow)
  228.                                         {
  229.                                                 /* Did the signal originate here? */
  230.  
  231.                                             if(Signals & (1L << ReqWindow -> UserPort -> mp_SigBit))
  232.                                             {
  233.                                                 ULONG    IDCMP = NULL;
  234.                                                 LONG    Result;
  235.  
  236.                                                     /* Process the events. */
  237.  
  238.                                                 Result = SysReqHandler(ReqWindow,&IDCMP,FALSE);
  239.  
  240.                                                     /* Shut the window? */
  241.  
  242.                                                 if(Result == 0 || (Result == -2 && !(IDCMP & IDCMP_RAWKEY)))
  243.                                                 {
  244.                                                     if(AppWindow)
  245.                                                     {
  246.                                                         RemoveAppWindow(AppWindow);
  247.  
  248.                                                         AppWindow = NULL;
  249.                                                     }
  250.  
  251.                                                     FreeSysRequest(ReqWindow);
  252.  
  253.                                                     ReqWindow = NULL;
  254.                                                 }
  255.                                             }
  256.                                         }
  257.  
  258.                                             /* A signal from Workbench? */
  259.  
  260.                                         if(Signals & (1L << IconPort -> mp_SigBit))
  261.                                         {
  262.                                                 /* Pick up all incoming data. */
  263.  
  264.                                             while(Message = (struct AppMessage *)GetMsg(IconPort))
  265.                                             {
  266.                                                     /* User dropped icons on the AppWindow/AppIcon. */
  267.  
  268.                                                 if(Message -> am_NumArgs)
  269.                                                 {
  270.                                                     UBYTE    DeviceName[256];
  271.                                                     ULONG    Unit,Flags;
  272.                                                     LONG    i;
  273.  
  274.                                                         /* Take care of all entries. */
  275.  
  276.                                                     for(i = 0 ; i < Message -> am_NumArgs ; i++)
  277.                                                     {
  278.                                                         if(FindDevice(Message -> am_ArgList[i] . wa_Lock,Message -> am_ArgList[i] . wa_Name,DeviceName,&Unit,&Flags))
  279.                                                             Eject(DeviceName,Unit,Flags,FALSE);
  280.                                                     }
  281.                                                 }
  282.                                                 else
  283.                                                 {
  284.                                                         /* It's just a double-click on the icon.
  285.                                                          * See if the notification window is
  286.                                                          * already open.
  287.                                                          */
  288.  
  289.                                                     if(ReqWindow)
  290.                                                     {
  291.                                                             /* Make the window visible. */
  292.  
  293.                                                         if(IntuitionBase -> LibNode . lib_Version >= 39)
  294.                                                             ScreenPosition(ReqWindow -> WScreen,SPOS_MAKEVISIBLE,ReqWindow -> LeftEdge,ReqWindow -> TopEdge,ReqWindow -> LeftEdge + ReqWindow -> Width - 1,ReqWindow -> TopEdge + ReqWindow -> Height - 1);
  295.  
  296.                                                         WindowToFront(ReqWindow);
  297.  
  298.                                                         ScreenToFront(ReqWindow -> WScreen);
  299.  
  300.                                                         ActivateWindow(ReqWindow);
  301.                                                     }
  302.                                                     else
  303.                                                     {
  304.                                                             /* Did we succeed in opening Intuition? */
  305.  
  306.                                                         if(IntuitionBase)
  307.                                                         {
  308.                                                             struct EasyStruct Easy;
  309.  
  310.                                                                 /* Fill in the data. */
  311.  
  312.                                                             Easy . es_StructSize    = sizeof(struct EasyStruct);
  313.                                                             Easy . es_Flags            = NULL;
  314.                                                             Easy . es_Title            = (STRPTR)"Eject";
  315.                                                             Easy . es_GadgetFormat    = (STRPTR)"Continue";
  316.                                                             Easy . es_TextFormat    = (STRPTR)"\"Eject\" Copyright © 1994-1995 by\nOlaf `Olsen' Barthel <olsen@sourcery.han.de>\nPublic Domain";
  317.  
  318.                                                                 /* Open the notification window and just
  319.                                                                  * for the fun of it make it an AppWindow.
  320.                                                                  */
  321.  
  322.                                                             if(ReqWindow = BuildEasyRequest(NULL,&Easy,IDCMP_RAWKEY,NULL))
  323.                                                                 AppWindow = AddAppWindowA(0,0,ReqWindow,IconPort,NULL);
  324.                                                         }
  325.                                                     }
  326.                                                 }
  327.  
  328.                                                 ReplyMsg((struct Message *)Message);
  329.                                             }
  330.                                         }
  331.  
  332.                                             /* Terminate? */
  333.  
  334.                                         if(Signals & SIGBREAKF_CTRL_C)
  335.                                             Done = TRUE;
  336.                                     }
  337.                                     while(!Done);
  338.  
  339.                                         /* Remove the AppWindow link. */
  340.  
  341.                                     if(AppWindow)
  342.                                         RemoveAppWindow(AppWindow);
  343.  
  344.                                         /* Remove the AppIcon. */
  345.  
  346.                                     RemoveAppIcon(AppIcon);
  347.  
  348.                                         /* Hide the global port. */
  349.  
  350.                                     RemPort(IconPort);
  351.  
  352.                                         /* Dispatch all remaining messages. */
  353.  
  354.                                     while(Message = (struct AppMessage *)GetMsg(IconPort))
  355.                                         ReplyMsg((struct Message *)Message);
  356.  
  357.                                         /* Close the notification window if necessary. */
  358.  
  359.                                     if(ReqWindow)
  360.                                         FreeSysRequest(ReqWindow);
  361.                                 }
  362.  
  363.                                     /* Get rid of the icon. */
  364.  
  365.                                 FreeDiskObject(Icon);
  366.                             }
  367.  
  368.                                 /* Get back... */
  369.  
  370.                             CurrentDir(OldDir);
  371.  
  372.                                 /* And clean up the libraries. */
  373.  
  374.                             CloseLibrary(WorkbenchBase);
  375.                         }
  376.  
  377.                         CloseLibrary(IconBase);
  378.                     }
  379.  
  380.                     if(IntuitionBase)
  381.                         CloseLibrary((struct Library *)IntuitionBase);
  382.  
  383.                         /* Don't forget the global port. */
  384.  
  385.                     DeleteMsgPort(IconPort);
  386.                 }
  387.             }
  388.         }
  389.         else
  390.         {
  391.             struct RDArgs    *ArgsPtr;
  392.             STRPTR             Args[ARGCOUNT];
  393.  
  394.                 /* Clear the args. */
  395.  
  396.             memset(Args,0,sizeof(Args));
  397.  
  398.                 /* Read the command arguments if any. */
  399.  
  400.             if(ArgsPtr = ReadArgs(Template,(LONG *)Args,NULL))
  401.             {
  402.                 STRPTR *Names = (STRPTR *)Args[ARG_DEVICE];
  403.  
  404.                     /* Process all names. */
  405.  
  406.                 while(*Names)
  407.                 {
  408.                     UBYTE    DeviceName[256];
  409.                     ULONG    Unit,Flags;
  410.                     BPTR    FileLock;
  411.  
  412.                         /* Try to get a lock on the object in question. */
  413.  
  414.                     FileLock = Lock(*Names,ACCESS_READ);
  415.  
  416.                         /* Try to find the corresponding device. */
  417.  
  418.                     if(FindDevice(FileLock,*Names,DeviceName,&Unit,&Flags))
  419.                     {
  420.                             /* Don't keep the icon longer on the
  421.                              * desktop than necessary.
  422.                              */
  423.  
  424.                         UnLock(FileLock);
  425.  
  426.                             /* Try to eject the media. */
  427.  
  428.                         if(Eject(DeviceName,Unit,Flags,TRUE))
  429.                             Result = RETURN_OK;
  430.                         else
  431.                         {
  432.                             if(Result == RETURN_FAIL)
  433.                                 Result = RETURN_ERROR;
  434.                             else
  435.                                 Result = RETURN_WARN;
  436.                         }
  437.                     }
  438.                     else
  439.                     {
  440.                             /* Release the file lock. */
  441.  
  442.                         UnLock(FileLock);
  443.  
  444.                         Printf("Eject: Unable to find device \"%s\".\n",*Names);
  445.  
  446.                         if(Result == RETURN_FAIL)
  447.                             Result = RETURN_ERROR;
  448.                         else
  449.                             Result = RETURN_WARN;
  450.                     }
  451.  
  452.                         /* Proceed to the next name... */
  453.  
  454.                     Names++;
  455.                 }
  456.             }
  457.             else
  458.             {
  459.                 PrintFault(IoErr(),"Eject");
  460.  
  461.                 Result = RETURN_ERROR;
  462.             }
  463.         }
  464.  
  465.             /* Clean up. */
  466.  
  467.         CloseLibrary((struct Library *)DOSBase);
  468.     }
  469.     else
  470.         ThisProcess -> pr_Result2 = ERROR_INVALID_RESIDENT_LIBRARY;
  471.  
  472.         /* Reply the startup message if necessary. */
  473.  
  474.     if(WBenchMsg)
  475.     {
  476.         Forbid();
  477.  
  478.         ReplyMsg((struct Message *)WBenchMsg);
  479.     }
  480.  
  481.     return(Result);
  482. }
  483.  
  484.     /* DoSCSICmd(...):
  485.      *
  486.      *    Send a SCSI command to the driver in question.
  487.      */
  488.  
  489. BYTE
  490. DoSCSICmd(struct IOStdReq *DeviceRequest,ULONG Unit,APTR Command,LONG CommandLen,APTR Data,LONG DataLen)
  491. {
  492.     struct SCSICmd     SCSICmd;
  493.     UBYTE            *CommandArray = Command,
  494.                      SenseBuffer[20];
  495.  
  496.         /* Patch in the LUN. */
  497.  
  498.     CommandArray[1] |= ((Unit / 10) & 7) << 5;
  499.  
  500.         /* Set up the basic data. */
  501.  
  502.     DeviceRequest -> io_Command        = HD_SCSICMD;
  503.     DeviceRequest -> io_Data        = &SCSICmd;
  504.     DeviceRequest -> io_Length        = sizeof(struct SCSICmd);
  505.  
  506.         /* Now fill in the command. */
  507.  
  508.     memset(&SCSICmd,0,sizeof(struct SCSICmd));
  509.  
  510.     SCSICmd . scsi_Command        = Command;
  511.     SCSICmd . scsi_CmdLength    = CommandLen;
  512.     SCSICmd . scsi_Flags        = SCSIF_AUTOSENSE;
  513.     SCSICmd . scsi_SenseData    = SenseBuffer;
  514.     SCSICmd . scsi_SenseLength    = 18;
  515.  
  516.     if(Data)
  517.     {
  518.         SCSICmd . scsi_Data        = Data;
  519.         SCSICmd . scsi_Length    = DataLen;
  520.  
  521.         SCSICmd . scsi_Flags |= SCSIF_READ;
  522.     }
  523.     else
  524.         SCSICmd . scsi_Flags |= SCSIF_WRITE;
  525.  
  526.         /* Cast the dice. */
  527.  
  528.     return(DoIO((struct IORequest *)DeviceRequest));
  529. }
  530.  
  531.     /* TestUnitReady(struct IOStdReq *DeviceRequest,ULONG Unit):
  532.      *
  533.      *    Check if this particular device is ready for action,
  534.      *    i.e. there is a medium loaded.
  535.      */
  536.  
  537. BYTE
  538. TestUnitReady(struct IOStdReq *DeviceRequest,ULONG Unit)
  539. {
  540.     struct TestUnitReady TestUnitReady;
  541.  
  542.     memset(&TestUnitReady,0,sizeof(TestUnitReady));
  543.  
  544.     return(DoSCSICmd(DeviceRequest,Unit,&TestUnitReady,sizeof(TestUnitReady),NULL,0));
  545. }
  546.  
  547.     /* CheckMediaType(struct IOStdReq *DeviceRequest,ULONG Unit):
  548.      *
  549.      *    Check if the device in question supports removable
  550.      *    media. However, this does not mean that the device is
  551.      *    capable of ejecting it on its own.
  552.      */
  553.  
  554. BOOL
  555. CheckMediaType(struct IOStdReq *DeviceRequest,ULONG Unit)
  556. {
  557.     struct Inquiry        Inquiry;
  558.     struct InquiryData    InquiryData;
  559.  
  560.     memset(&Inquiry,0,sizeof(Inquiry));
  561.  
  562.     Inquiry . Command            = 0x12;
  563.     Inquiry . AllocationLength    = sizeof(struct InquiryData);
  564.  
  565.     if(!DoSCSICmd(DeviceRequest,Unit,&Inquiry,sizeof(struct Inquiry),&InquiryData,sizeof(struct InquiryData)))
  566.     {
  567.             /* A removable medium bit of zero indicates that the
  568.              * medium is not removable. A RMB bit of one indicates
  569.              * that the medium is removable.
  570.              */
  571.  
  572.         if(InquiryData . DeviceTypeModifier & 0x80)
  573.             return(TRUE);
  574.     }
  575.  
  576.     return(FALSE);
  577. }
  578.  
  579.     /* EjectMedia(struct IOStdReq *DeviceRequest,ULONG Unit):
  580.      *
  581.      *    Eject the removable medium; this is accomplished via
  582.      *    the start/stop command. We request that the medium
  583.      *    should be unloaded after the unit is stopped. This
  584.      *    command is sometimes referred to as "load unload".
  585.      */
  586.  
  587. BYTE
  588. EjectMedia(struct IOStdReq *DeviceRequest,ULONG Unit)
  589. {
  590.     struct StartStopUnit StartStopUnit;
  591.  
  592.     memset(&StartStopUnit,0,sizeof(StartStopUnit));
  593.  
  594.     StartStopUnit . OperationCode    = 0x1B;
  595.     StartStopUnit . LoEj_Start        = 0x02;
  596.  
  597.     return(DoSCSICmd(DeviceRequest,Unit,&StartStopUnit,sizeof(StartStopUnit),NULL,0));
  598. }
  599.  
  600.     /* Eject(const STRPTR DeviceName,ULONG Unit,ULONG Flags,BOOL Echo):
  601.      *
  602.      *    This routine does the dirty work. Open the device driver,
  603.      *    check for the device type, see if any media is loaded,
  604.      *    eject it if necessary.
  605.      */
  606.  
  607. BOOL
  608. Eject(const STRPTR DeviceName,ULONG Unit,ULONG Flags,BOOL Echo)
  609. {
  610.     struct MsgPort    *DevicePort;
  611.     BOOL             Result = FALSE;
  612.  
  613.         /* Set up the interface data... */
  614.  
  615.     if(DevicePort = CreateMsgPort())
  616.     {
  617.         struct IOStdReq *DeviceRequest;
  618.  
  619.         if(DeviceRequest = (struct IOStdReq *)CreateIORequest(DevicePort,sizeof(struct IOStdReq)))
  620.         {
  621.             if(!OpenDevice(DeviceName,Unit,(struct IORequest *)DeviceRequest,Flags))
  622.             {
  623.                 Result = TRUE;
  624.  
  625.                     /* So far, so good. Now take a look if the device
  626.                      * supports removable media.
  627.                      */
  628.  
  629.                 if(CheckMediaType(DeviceRequest,Unit))
  630.                 {
  631.                         /* Now check if there is any media loaded.
  632.                          * We do the check twice in case the medium
  633.                          * has just been loaded. To indicate this
  634.                          * case, the SCSI standard requests that the
  635.                          * device rejects the first command following
  636.                          * the medium change.
  637.                          */
  638.  
  639.                     if(!TestUnitReady(DeviceRequest,Unit) && !TestUnitReady(DeviceRequest,Unit))
  640.                     {
  641.                             /* Go! */
  642.  
  643.                         if(EjectMedia(DeviceRequest,Unit))
  644.                         {
  645.                             if(Echo)
  646.                                 Printf("Eject: Error #%ld ejecting media.\n",DeviceRequest -> io_Error);
  647.  
  648.                             Result = FALSE;
  649.                         }
  650.                     }
  651.                 }
  652.  
  653.                     /* Clean up... */
  654.  
  655.                 CloseDevice((struct IORequest *)DeviceRequest);
  656.             }
  657.             else
  658.             {
  659.                 if(Echo)
  660.                     Printf("Eject: Error #%ld opening device \"%s\" unit #%ld.\n",DeviceRequest -> io_Error,DeviceName,Unit);
  661.             }
  662.  
  663.             DeleteIORequest(DeviceRequest);
  664.         }
  665.         else
  666.         {
  667.             if(Echo)
  668.                 Printf("Eject: Cannot create IOStdReq.\n");
  669.         }
  670.  
  671.         DeleteMsgPort(DevicePort);
  672.     }
  673.     else
  674.     {
  675.         if(Echo)
  676.             Printf("Eject: Cannot create MsgPort.\n");
  677.     }
  678.  
  679.     return(Result);
  680. }
  681.  
  682.     /* FindDevice(...):
  683.      *
  684.      *    Find a device by name/filelock.
  685.      */
  686.  
  687. BOOL
  688. FindDevice(const BPTR FileLock,const STRPTR FileName,STRPTR Device,ULONG *Unit,ULONG *Flags)
  689. {
  690.     struct DosList *Entry;
  691.  
  692.         /* For a start, lock the doslist entries we are interested in. */
  693.  
  694.     if(Entry = LockDosList(LDF_DEVICES | LDF_READ))
  695.     {
  696.             /* Do we have a filelock? */
  697.  
  698.         if(FileLock)
  699.         {
  700.             struct FileLock *LockPtr = (struct FileLock *)BADDR(FileLock);
  701.  
  702.                 /* Walk down the list. */
  703.  
  704.             while(Entry = NextDosEntry(Entry,LDF_DEVICES | LDF_READ))
  705.             {
  706.                     /* If the filing system task that manages this
  707.                      * device equals the one the filelock originated
  708.                      * from chances are very high that this is the
  709.                      * one we were looking for. Please note that this
  710.                      * technique is not absolutely bullet-proof as in
  711.                      * theory it is possible to write a filing system
  712.                      * which manages multiple devices. The task address
  713.                      * might thus not necessarily point to the right
  714.                      * doslist entry.
  715.                      */
  716.  
  717.                 if(Entry -> dol_Task == LockPtr -> fl_Task)
  718.                 {
  719.                     struct FileSysStartupMsg *Startup = (struct FileSysStartupMsg *)BADDR(Entry -> dol_misc . dol_handler . dol_Startup);
  720.  
  721.                         /* Is this a valid entry? There might not be
  722.                          * a pointer to the FSSM stored here; the
  723.                          * Port-Handler for example uses this field
  724.                          * to tell references to SER:, PAR: and PRT:
  725.                          * apart.
  726.                          */
  727.  
  728.                     if(TypeOfMem(Startup))
  729.                     {
  730.                             /* Is this a valid device name? */
  731.  
  732.                         if(TypeOfMem(BADDR(Startup -> fssm_Device)))
  733.                         {
  734.                             STRPTR Name = BADDR(Startup -> fssm_Device);
  735.  
  736.                                 /* Fill in the necessary data. */
  737.  
  738.                             strcpy(Device,Name + 1);
  739.  
  740.                             *Unit    = Startup -> fssm_Unit;
  741.                             *Flags    = Startup -> fssm_Flags;
  742.  
  743.                                 /* Release the list. */
  744.  
  745.                             UnLockDosList(LDF_DEVICES | LDF_READ);
  746.  
  747.                                 /* Success. */
  748.  
  749.                             return(TRUE);
  750.                         }
  751.                     }
  752.                 }
  753.             }
  754.         }
  755.         else
  756.         {
  757.             UBYTE    LocalName[256];
  758.             LONG    Len;
  759.  
  760.                 /* Make a copy of the file name. */
  761.  
  762.             strcpy(LocalName,FileName);
  763.  
  764.             Len = strlen(LocalName);
  765.  
  766.                 /* Remove the colon; we expect plain device
  767.                  * names such as DF0, CD0 or HD0 here.
  768.                  */
  769.  
  770.             if(LocalName[Len - 1] == ':')
  771.                 LocalName[Len - 1] = 0;
  772.  
  773.                 /* Try to find the device entry in question. */
  774.  
  775.             if(Entry = FindDosEntry(Entry,LocalName,LDF_DEVICES | LDF_READ))
  776.             {
  777.                 struct FileSysStartupMsg *Startup = (struct FileSysStartupMsg *)BADDR(Entry -> dol_misc . dol_handler . dol_Startup);
  778.  
  779.                 if(TypeOfMem(Startup))
  780.                 {
  781.                     if(TypeOfMem(BADDR(Startup -> fssm_Device)))
  782.                     {
  783.                         STRPTR Name = BADDR(Startup -> fssm_Device);
  784.  
  785.                         strcpy(Device,Name + 1);
  786.  
  787.                         *Unit    = Startup -> fssm_Unit;
  788.                         *Flags    = Startup -> fssm_Flags;
  789.  
  790.                         UnLockDosList(LDF_DEVICES | LDF_READ);
  791.  
  792.                         return(TRUE);
  793.                     }
  794.                 }
  795.             }
  796.         }
  797.  
  798.         UnLockDosList(LDF_DEVICES | LDF_READ);
  799.     }
  800.  
  801.     return(FALSE);
  802. }
  803.