home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / disk utilities / backup / backup_restore / backup_src_v3.20.lha / DiskChanger.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-28  |  21.6 KB  |  929 lines

  1. // DiskChanger.c
  2. // 28 Jul 1996 10:34:27
  3.  
  4. #ifndef    BACKUP_INCLUDE
  5. #include "IncludeAll.c"
  6. #endif
  7. #include "Backup.h"
  8. #include "Backup_proto.h"
  9. #include "BackupStrings.h"
  10. #include "DiskChanger.h"
  11.  
  12. #define    d(x)        ;
  13.  
  14. #define    POLL_TAPE
  15.  
  16.  
  17. static struct IORequest *DCOpenDevice(char *name, int unit, ULONG IORSize, ULONG Flags);
  18. static void DCCloseDevice(struct IORequest *req);
  19. static void SendDC(struct DiskChangeInfo *dci, unsigned short Class);
  20. static void __asm __saveds DiskChangerInt(register __a1 struct DiskChangeInfo *dci);
  21. static ULONG DCTestDiskChange(struct DiskChangeInfo *dci, BOOL First);
  22. static ULONG DCTestNewDisk(struct DiskChangeInfo *dci);
  23. static enum TestDiskResult DCCheckLabel(struct DiskChangeInfo *dci);
  24. static void AbortTimerIO(struct DiskChangeInfo *dci);
  25. static void SetDiskStatus(struct DiskChangeInfo *dci, enum DskStat NewState);
  26. static void SendDCRx(struct DiskChangeInfo *dci, unsigned short Class);
  27. static BOOL CheckDCTxPort(struct DiskChangeInfo *dci);
  28.  
  29.  
  30. // aus ProcStart.asm
  31. extern APTR __far DiskChangerSeg;        // SegList für CreateProc
  32.  
  33. // aus Backup.c
  34. extern struct Window *aktWindow;
  35. extern char StartZeit[8];
  36. extern struct BackupDevInfo globDrvDat;        // globale Disk-Parameter
  37. extern struct DiskFlags __far *Disks;
  38. extern struct BackupOptions myOptions;        // Einstellungen für die aktuelle Sicherung
  39.  
  40. // aus Backup_Window.c
  41. extern unsigned long DiskChangeMaske;
  42.  
  43.  
  44. // Lokale Konstanten
  45. #ifdef POLL_TAPE
  46. static const DC_Poll = 2500;            // Zeit zwischen 2 Polls für Band in ms
  47. #endif
  48.  
  49. static const DC_Timeout = 1300;            // Wartezeit für neue Disk in ms
  50.                         // vergrößert wegen Komplikationen mit dem mfm.device
  51. static const DC_StackSize = 8192;        // Stackgröße für DiskChanger-Task
  52.  
  53.  
  54. // Lokale Variablen
  55. static struct SignalSemaphore StartDCSema;    // Semaphore zur Verriegelung bei Prozeß-Start
  56. static short StartDCSemaInit = FALSE;
  57.  
  58. static InfoLineHandle PilHandle = NULL;
  59.  
  60.  
  61. struct DiskChangeInfo *StartDiskChanger(short UnitNr, 
  62.         BOOL FirstDisk, short NextDiskNo)
  63. {
  64.     struct DiskChangeInfo *dci;
  65.     struct Process *myproc;
  66.     struct MsgPort *myport;
  67.     struct DiskFlags *Dsk = &Disks[UnitNr];
  68.  
  69.     ASSERT_VALID(Dsk);
  70.  
  71.     if (globDrvDat.BlockSize == 0)
  72.         {
  73.         alarm(GetString(MSG_ZEROBLOCKSIZE), __FUNC__);
  74.         return FALSE;
  75.         }
  76.  
  77.     dci = calloc(sizeof(struct DiskChangeInfo), 1);
  78.     if (dci == NULL)
  79.         {
  80.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "dci", sizeof(struct DiskChangeInfo));
  81.         return NULL;
  82.         }
  83.  
  84.     if (!StartDCSemaInit)
  85.         {
  86.         InitSemaphore(&StartDCSema);
  87.         StartDCSemaInit = TRUE;
  88.         }
  89.  
  90.     InitSemaphore(&dci->Sema);
  91.  
  92.     dci->DCRxPort = CreateMsgPort();
  93.     if (NULL == dci->DCRxPort)
  94.         {
  95.         alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "DCRxPort");
  96.         return FALSE;
  97.         }
  98.  
  99.     memcpy(dci->StartZeit, StartZeit, sizeof(dci->StartZeit));
  100.     dci->NextDiskNr = NextDiskNo;
  101.  
  102.     dci->DiskBlockSize = globDrvDat.BlockSize;
  103.     dci->DiskBufMemType = globDrvDat.BufMemType;
  104.  
  105.     dci->UnitNr = UnitNr;
  106.  
  107.     dci->TDName = Dsk->DeviceName;
  108.     dci->TDUnit = Dsk->Unit;
  109.     dci->TDFlags = Dsk->DrvDat.Flags;
  110.     dci->DOSName = Dsk->DOSName;
  111.  
  112.     dci->DrvDat = &Dsk->DrvDat;
  113.     dci->Env = Dsk->Env;
  114.     dci->DiskStatus = CheckingDisk;
  115.  
  116.     if (Dsk->TapeReq)
  117.         {
  118.         dci->isTape = TRUE;
  119.         dci->TapeReq = AllocVec(sizeof(struct TapeIO), Dsk->DrvDat.BufMemType);
  120.         if (dci->TapeReq == NULL)
  121.             {
  122.             alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "dci->TapeReq", sizeof(struct TapeIO));
  123.             return NULL;
  124.             }
  125.         *dci->TapeReq = *Dsk->TapeReq;
  126.         }
  127.  
  128.     dci->Pos = FirstDisk ? 1 : 2;
  129.  
  130.     sprintf(dci->ProcessName, "Backup_DiskChange_%s", Dsk->DOSName);
  131.  
  132.     ObtainSemaphore(&StartDCSema);        // Prozeß blockieren bis <dci> eingetragen
  133.     myport = CreateProc(dci->ProcessName, 0L, MKBADDR(&DiskChangerSeg), DC_StackSize);
  134.  
  135.     if (myport)
  136.         {
  137.         struct DCMessage *Msg;
  138.         ULONG off;
  139.  
  140.         off = offsetof(struct Process, pr_MsgPort);
  141.         myproc = (struct Process *) ((char *) myport - off);
  142.         myproc->pr_Task.tc_UserData = (APTR) dci;
  143.         ReleaseSemaphore(&StartDCSema);
  144.  
  145.         // auf Init.-Quittung warten
  146.         WaitPort(dci->DCRxPort);
  147.         Msg = (struct DCMessage *) GetMsg(dci->DCRxPort);    // Quittung holen
  148.         if (Msg)
  149.             {
  150.             dci->Result = DC_INITOK == Msg->dc_Class ? DCOK : BAD;
  151.             d(kprintf(__FUNC__ "/%ld: Msg=%08lx  Class=%lx\n", __LINE__, Msg, Msg->dc_Class);)
  152.             free(Msg);
  153.             }
  154.         else
  155.             dci->Result = BAD;
  156.         }
  157.     else
  158.         {
  159.         ReleaseSemaphore(&StartDCSema);
  160.         alarm(GetString(MSG_CREATEPROC_FAILED), __FUNC__, dci->ProcessName);
  161.         dci->Result = BAD;    // CreateProc versagt !
  162.         }
  163.  
  164.     if (DCOK == dci->Result)
  165.         {
  166.         DiskChangeMaske |= 1 << dci->DCTxPort->mp_SigBit;
  167.         }
  168.     else
  169.         {
  170.         free(dci);
  171.         dci = NULL;
  172.         }
  173.  
  174.     return dci;
  175. }
  176.  
  177.  
  178. void EndDiskChanger(struct DiskChangeInfo *dci)
  179. {
  180.     ASSERT_VALID(dci);
  181.  
  182.     if (dci && dci->DiskChangerTask)
  183.         {
  184.         if (dci->DCRxPort && dci->DCTxPort)
  185.             {
  186.             struct DCMessage *Msg;
  187.             unsigned short Class;
  188.  
  189.             SendDC(dci, DC_SHUTDOWN);
  190.  
  191.             do    {
  192.                 // warten auf Ende-Quittung
  193.                 WaitPort(dci->DCRxPort);
  194.                 Msg = (struct DCMessage *) GetMsg(dci->DCRxPort);
  195.                 if (Msg)
  196.                     {
  197.                     d(kprintf(__FUNC__ "/%ld: Msg=%08lx  Class=%lx\n", __LINE__, Msg, Msg->dc_Class);)
  198.                     Class = Msg->dc_Class;
  199.                     free(Msg);
  200.                     }
  201.                 else
  202.                     Class = 0;
  203.                 } while (Class != DC_DOWN);
  204.             }
  205.  
  206.         dci->DiskChangerTask = NULL;
  207.         if (dci->TapeReq)
  208.             {
  209.             FreeVec(dci->TapeReq);
  210.             dci->TapeReq = NULL;
  211.             }
  212.  
  213.         if (dci->DCRxPort)
  214.             {
  215.             DeleteMsgPort(dci->DCRxPort);
  216.             dci->DCRxPort = NULL;
  217.             }
  218.  
  219.         free(dci);
  220.         }
  221. }
  222.  
  223.  
  224. // Message an DiskChanger-Prozeß senden
  225. static void SendDC(struct DiskChangeInfo *dci, unsigned short Class)
  226. {
  227.     struct DCMessage *Msg;
  228.  
  229.     Msg = malloc(sizeof(struct DCMessage));
  230.     if (Msg)
  231.         {
  232.         Msg->dc_Msg.mn_ReplyPort = dci->DCRxPort;
  233.         Msg->dc_Msg.mn_Length = sizeof(struct DCMessage);
  234.         Msg->dc_Class = Class;
  235.  
  236.         d(kprintf(__FUNC__ "/%ld: send %lx\n", __LINE__, (long) Class);)
  237.         PutMsg(dci->DCTxPort, (struct Message *) Msg);
  238.  
  239.         WaitPort(dci->DCRxPort);        // Warten auf Reply
  240.         Msg = (struct DCMessage *) GetMsg(dci->DCRxPort);    // Reply-Port leeren
  241.         free(Msg);
  242.         }
  243. }
  244.  
  245.  
  246. // ======================================================
  247. // ab hier läuft der Code als eigener Prozeß !
  248.  
  249. // main() des DiskChangers
  250. void __saveds BackupDiskChanger(void)
  251. {
  252.     struct DiskChangeInfo *dci;
  253.     struct Task *myTask;
  254.     struct Device *dev;
  255.     ULONG Signals, Signals2;
  256.     BYTE DiskChangeSignal;
  257.     BOOL DCRunning;
  258.  
  259.     ObtainSemaphore(&StartDCSema);    // Warten bis dci eingetragen ist
  260.     myTask = FindTask(NULL);
  261.     dci = (struct DiskChangeInfo *) myTask->tc_UserData;
  262.     ReleaseSemaphore(&StartDCSema);
  263.  
  264.     ObtainSemaphore(&dci->Sema);
  265.  
  266.     dci->DiskChangerTask = myTask;
  267.     DiskChangeSignal = AllocSignal(-1);
  268.     dci->DiskChangeMask = 1 << DiskChangeSignal;
  269.  
  270.     do    {
  271.         dci->DCTxPort = CreateMsgPort();
  272.         if (dci->DCTxPort == NULL)
  273.             {
  274.             ReleaseSemaphore(&dci->Sema);
  275.             SendDCRx(dci, DC_INITBAD);
  276.             alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "DCTxPort");
  277.             break;
  278.             }
  279.  
  280.         dci->DCTxPortMask = 1 << dci->DCTxPort->mp_SigBit;
  281.  
  282.         dci->DiskChangeInt.is_Node.ln_Succ = NULL;
  283.         dci->DiskChangeInt.is_Node.ln_Pred = NULL;
  284.         dci->DiskChangeInt.is_Node.ln_Type = NT_INTERRUPT;
  285.         dci->DiskChangeInt.is_Node.ln_Pri = 0;
  286.         dci->DiskChangeInt.is_Node.ln_Name = NULL;
  287.         dci->DiskChangeInt.is_Data = dci;
  288.         dci->DiskChangeInt.is_Code = (void (*)()) DiskChangerInt;
  289.  
  290.         dci->DiskIOReq = (struct IOExtTD *) DCOpenDevice(dci->TDName,
  291.                 dci->TDUnit, sizeof(struct IOExtTD), dci->TDFlags);
  292.  
  293.         if (NULL == dci->DiskIOReq)
  294.             {
  295.             // Init. Mißerfolg melden
  296.             ReleaseSemaphore(&dci->Sema);
  297.             SendDCRx(dci, DC_INITBAD);
  298.  
  299.             break;
  300.             }
  301.         dci->ChangeIOReq = *(dci->DiskIOReq);
  302.  
  303.         dci->TimerIOReq = (struct timerequest *) DCOpenDevice((STRPTR) TIMERNAME,
  304.                 UNIT_VBLANK, sizeof(struct timerequest), 0);
  305.         if (dci->TimerIOReq == NULL)
  306.             {
  307.             // Init. Mißerfolg melden
  308.             DCCloseDevice((struct IORequest *) dci->DiskIOReq);
  309.             SendDCRx(dci, DC_INITBAD);
  310.             ReleaseSemaphore(&dci->Sema);
  311.  
  312.             break;
  313.             }
  314.         dci->TimerMask = 1 << dci->TimerIOReq->tr_node.io_Message.mn_ReplyPort->mp_SigBit;
  315.         dci->TimerInUse = 0;
  316.  
  317. #ifdef POLL_TAPE
  318.         if (!dci->isTape)
  319. #endif
  320.             {
  321.             // DiskChange-Interrupt einhängen
  322.             dci->ChangeIOReq.iotd_Req.io_Command = TD_ADDCHANGEINT;
  323.             dci->ChangeIOReq.iotd_Req.io_Flags = 0;
  324.             dci->ChangeIOReq.iotd_Req.io_Length = sizeof(struct Interrupt);
  325.             dci->ChangeIOReq.iotd_Req.io_Data = (APTR) &dci->DiskChangeInt;
  326.             SendIO((struct IORequest *) &dci->ChangeIOReq);
  327.             }
  328.  
  329.         // Init. Ok melden
  330.         SendDCRx(dci, DC_INITOK);
  331.  
  332.         if (dci->isTape)
  333.             {
  334.             dci->TapeReq->Req = dci->DiskIOReq;
  335.             TapeInitProperties(dci->TapeReq);
  336.             }
  337.  
  338.         Signals2 = DCTestDiskChange(dci, TRUE);        // zu Beginn Disk-Zustand festhalten
  339.  
  340.         ReleaseSemaphore(&dci->Sema);
  341.         // Init. fertig
  342.  
  343. #ifdef POLL_TAPE
  344.         if (dci->isTape)
  345.             {
  346.             dci->TimerIOReq->tr_time.tv_secs = 0;
  347.             dci->TimerIOReq->tr_time.tv_micro = 1000 * DC_Poll;
  348.             dci->TimerIOReq->tr_node.io_Command = TR_ADDREQUEST;
  349.             SendIO((struct IORequest *) dci->TimerIOReq);
  350.             dci->TimerInUse = 1;
  351.             d(kprintf(__FUNC__ "/%ld: %s: Band-Timer erstmals gestartet\n", __LINE__, dci->DOSName);)
  352.             }
  353. #endif
  354.         DCRunning = TRUE;
  355.  
  356.         do    {
  357.             if (Signals2)
  358.                 {
  359.                 Signals = Signals2;
  360.                 Signals2 = 0L;
  361.                 }
  362.             else
  363.                 Signals = Wait(dci->DiskChangeMask | dci->DCTxPortMask | dci->TimerMask);
  364.  
  365.  
  366.             if (Signals & dci->DCTxPortMask)
  367.                 {
  368.                 DCRunning &= CheckDCTxPort(dci);
  369.                 }
  370. #ifdef POLL_TAPE
  371.             if (dci->isTape)
  372.                 {
  373.                 if (Signals & dci->TimerMask)
  374.                     {
  375.                     short NoDisk, Empty;
  376.  
  377.                     WaitIO((struct IORequest *) dci->TimerIOReq);
  378.  
  379.                     NoDisk = TapeChangeState(dci->TapeReq);
  380.                     Empty = dci->DiskStatus == EmptyDrive ||
  381.                         dci->DiskStatus == WaitingForDisk ||
  382.                         dci->DiskStatus == CheckingDisk;
  383.  
  384.                     if ((!NoDisk && Empty)
  385.                         || (NoDisk && !Empty))
  386.                         {
  387.                         Signals2 |= DCTestDiskChange(dci, FALSE);
  388.                         }
  389.  
  390.                     dci->TimerIOReq->tr_time.tv_secs = 0;
  391.                     dci->TimerIOReq->tr_time.tv_micro = 1000 * DC_Poll;
  392.                     dci->TimerIOReq->tr_node.io_Command = TR_ADDREQUEST;
  393.                     SendIO((struct IORequest *) dci->TimerIOReq);
  394.                     dci->TimerInUse = 1;
  395.                     d(kprintf(__FUNC__ "/%ld: %s: Band-Timer neu gestartet\n", __LINE__, dci->DOSName);)
  396.                     }
  397.                 }
  398.             else
  399. #endif
  400.                 {
  401.                 if (Signals & dci->TimerMask)
  402.                     {
  403.                     d(kprintf(__FUNC__ "/%ld: %s: Timer abgelaufen\n", __LINE__, dci->DOSName);)
  404.                     dci->TimerInUse = 0;
  405.                     Signals2 |= DCTestNewDisk(dci);
  406.                     }
  407.  
  408.                 if (Signals & dci->DiskChangeMask)
  409.                     {
  410.                     // Diskwechsel wurde erkannt
  411.                     Signals2 |= DCTestDiskChange(dci, FALSE);
  412.                     }
  413.                 }
  414.             } while (DCRunning);
  415.  
  416.         // Prozeß wird beendet
  417.  
  418. #ifdef POLL_TAPE
  419.         if (!dci->isTape)
  420. #endif
  421.             {
  422.             // DiskChange-Interrupt wieder entfernen !
  423.             dev = dci->ChangeIOReq.iotd_Req.io_Device;
  424.             if (dev->dd_Library.lib_Version >= 38)
  425.                 {
  426.                 dci->ChangeIOReq.iotd_Req.io_Command = TD_REMCHANGEINT;
  427.                 dci->ChangeIOReq.iotd_Req.io_Flags = IOF_QUICK;
  428.                 dci->ChangeIOReq.iotd_Req.io_Length = sizeof(struct Interrupt);
  429.                 dci->ChangeIOReq.iotd_Req.io_Data = (APTR) &dci->DiskChangeInt;
  430.  
  431.                 DoIO((struct IORequest *) &dci->ChangeIOReq);
  432.                 }
  433.             else
  434.                 {
  435.                 Forbid();
  436.                 Remove((struct Node *) &dci->ChangeIOReq);
  437.                 Permit();
  438.                 }
  439.             }
  440.         } while (0);
  441.  
  442.     AbortTimerIO(dci);
  443.     DCCloseDevice((struct IORequest *) dci->TimerIOReq);
  444.     DCCloseDevice((struct IORequest *) dci->DiskIOReq);
  445.  
  446.     ObtainSemaphore(&dci->Sema);
  447.  
  448.     Forbid();
  449.     SendDCRx(dci, DC_DOWN);
  450.     ReleaseSemaphore(&dci->Sema);
  451.  
  452.     FreeSignal(DiskChangeSignal);
  453.  
  454.     if (dci->DCTxPort)
  455.         {
  456.         DeleteMsgPort(dci->DCTxPort);
  457.         dci->DCTxPort = NULL;
  458.         }
  459. }
  460.  
  461.  
  462. static struct IORequest *DCOpenDevice(char *name, int unit, ULONG IORSize,
  463.         ULONG Flags)
  464. {
  465.     int error;
  466.     struct MsgPort *port;
  467.     struct IORequest *req;
  468.  
  469.     ASSERT_VALID(name);
  470.  
  471.     if ((port = CreateMsgPort()) == NULL)
  472.         {
  473.         alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "port");
  474.         return NULL;
  475.         }
  476.  
  477.     req = CreateIORequest(port, IORSize);
  478.     if (req == NULL)
  479.         {
  480.         alarm(GetString(MSG_CREATEEXTIO_FAILED), __FUNC__, "req");
  481.         DeleteMsgPort(port);
  482.         return NULL;
  483.         }
  484.     error = OpenDevice(name, unit, req, Flags);
  485.     if (error)
  486.         {
  487.         alarm(GetString(MSG_ERROR_OPENDEVICE), __FUNC__,
  488.             name, unit, ErrorText(error), error);
  489.         DeleteIORequest(req);
  490.         DeleteMsgPort(port);
  491.  
  492.         return NULL;
  493.         }
  494.  
  495.     return req;
  496. }
  497.  
  498.  
  499. static void DCCloseDevice(struct IORequest *req)
  500. {
  501.     if (req)
  502.         {
  503.         struct MsgPort *Port;
  504.  
  505.         CloseDevice(req);
  506.  
  507.         Port = req->io_Message.mn_ReplyPort;
  508.  
  509.         DeleteIORequest(req);
  510.         DeleteMsgPort(Port);
  511.         }
  512. }
  513.  
  514.  
  515. // DiskChange-Interrupt-Routine. Signalisiert dem DiskChanger-Prozeß einen
  516. // Diskwechsel im Laufwerk.
  517. static void __asm __saveds DiskChangerInt(register __a1 struct DiskChangeInfo *dci)
  518. {
  519.     Signal(dci->DiskChangerTask, dci->DiskChangeMask);
  520. }
  521.  
  522.  
  523. static ULONG DCTestDiskChange(struct DiskChangeInfo *dci, BOOL First)
  524. {
  525.     char Message[80];
  526.     ULONG Result = 0L;
  527.  
  528.     ASSERT_VALID(dci);
  529.  
  530.     SetDiskStatus(dci, CheckingDisk);
  531.     dci->ChangeCount = ChangeNum(dci->DiskIOReq);
  532.     AbortTimerIO(dci);
  533.  
  534.     PopInfoLine(&PilHandle);
  535.  
  536.     if (First && dci->isTape)
  537.         TapeTryLoadUnLoad(dci->TapeReq, TRUE);
  538.  
  539. #ifdef POLL_TAPE
  540.     if (((dci->isTape && TapeChangeState(dci->TapeReq))
  541.             || (!dci->isTape && ChangeState(dci->DiskIOReq))) == 0)
  542. #else
  543.     if (ChangeState(dci->DiskIOReq) == 0)
  544. #endif
  545.         {
  546.         // Medium ist vorhanden
  547.  
  548. #ifdef POLL_TAPE
  549.         if (dci->isTape)
  550.             {
  551.             Result = DCTestNewDisk(dci);
  552.             }
  553.         else
  554. #endif
  555.             {
  556.             // Diskette ist eingelegt, jetzt Timer starten
  557.             dci->TimerIOReq->tr_time.tv_secs = 0;
  558.             dci->TimerIOReq->tr_time.tv_micro = 1000 * DC_Timeout;
  559.             dci->TimerIOReq->tr_node.io_Command = TR_ADDREQUEST;
  560.             SendIO((struct IORequest *) dci->TimerIOReq);
  561.             dci->TimerInUse = 1;
  562.             }
  563.         }
  564.     else
  565.         {
  566.         // keine Diskette im Laufwerk
  567.         d(kprintf(__FUNC__ "/%ld: %s: Laufwerk leer\n", __LINE__, dci->DOSName);)
  568.  
  569.         stccpy(Message, dci->DOSName, sizeof(Message)-2);
  570.         strcat(Message, ": ");
  571.  
  572.         ObtainSemaphore(&dci->Sema);
  573.         if (dci->DiskStatus != WaitingForDisk)
  574.             {
  575.             DiskText(Message, ~0, ~0, dci->Pos);
  576.  
  577.             if (dci->DiskStatus != DiskInUse)
  578.                 SetDiskStatus(dci, EmptyDrive);
  579.             }
  580.         ReleaseSemaphore(&dci->Sema);
  581.         }
  582.  
  583.     return Result;
  584. }
  585.  
  586.  
  587. static ULONG DCTestNewDisk(struct DiskChangeInfo *dci)
  588. {
  589.     char Message[80];
  590.     ULONG Result = 0L;
  591.  
  592.     ASSERT_VALID(dci);
  593.  
  594.     strcpy(Message, dci->DOSName);
  595.     strcat(Message, ": ");
  596.  
  597.     if (!dci->isTape)
  598.         {
  599.         ObtainSemaphore(&dci->Sema);
  600.         Forbid();
  601.         GetDriveParms(dci->DrvDat, dci->Env, dci->DiskIOReq, dci->isTape);    // aktuelle Parameter holen
  602.         if (globDrvDat.isPreliminary)
  603.             {
  604.             // globale Diskparameter endgültig eintragen
  605.             globDrvDat = *dci->DrvDat;
  606.             globDrvDat.isPreliminary = FALSE;
  607.             }
  608.         else if (CheckDriveParms(dci->DrvDat, &globDrvDat))
  609.             {
  610.             // Disk-Parameter haben sich verändert !!
  611.             if (dci->DiskStatus != WaitingForDisk)
  612.                 SetDiskStatus(dci, DiskObsolete);
  613.             strcat(Message, GetString(MSG_WRONG_DISK_TYPE));
  614.  
  615.             PopInfoLine(&PilHandle);
  616.             PilHandle = PushInfoLine(Message);
  617.  
  618.             Permit();
  619.             ReleaseSemaphore(&dci->Sema);
  620.  
  621.             return 0l;
  622.             }
  623.  
  624.         Permit();
  625.         ReleaseSemaphore(&dci->Sema);
  626.         }
  627.  
  628.     if (dci->isTape && TapeChangeState(dci->TapeReq))
  629.         return 0;
  630.  
  631.     if ((dci->isTape && TapeProtStatus(dci->TapeReq))
  632.             || (!dci->isTape && ProtStatus(dci->DiskIOReq)))
  633.         {
  634.         // Disk ist schreibgeschützt
  635.         strcat(Message, dci->isTape ? GetString(MSG_TAPE1) : GetString(MSG_DISK1));
  636.         strcat(Message, GetString(MSG_IS_WRITEPROTECTED));
  637.  
  638.         SignalUnIconifyMainWindow();
  639.  
  640.         PopInfoLine(&PilHandle);
  641.         PilHandle = PushInfoLine(Message);
  642.  
  643.         if (dci->isTape)
  644.             {
  645.             // schreibgeschütztes Band auswerfen
  646.             TapeTryLoadUnLoad(dci->TapeReq, FALSE);
  647.             }
  648.         }
  649.     else
  650.         {
  651.         switch (DCCheckLabel(dci))
  652.             {
  653.         case DOSDISK:
  654.             d(kprintf(__FUNC__ "/%ld: %s: DOS-Disk erkannt\n", __LINE__, dci->DOSName);)
  655.             if (myOptions.bo_WarnDosDisk)
  656.                 {
  657.                 SignalUnIconifyMainWindow();
  658.                 if ( yesnoWindow(aktWindow, dci->DiskChangeMask | dci->DCTxPortMask,
  659.                     &Result, GetString(MSG_USE_DOSDISK_Q),
  660.                         dci->DOSName) != *GetString(MSG_YES_SHORT) )
  661.                     {
  662.                     // DOS-Disk NICHT verwenden
  663.                     break;
  664.                     }
  665.                 }
  666.             // hier weiter mit OK !!!
  667.         case UNREADABLE:
  668.         case OK:
  669.             d(kprintf(__FUNC__ "/%ld: %s: Disk Ok\n", __LINE__, dci->DOSName);)
  670.             if (dci->isTape)
  671.                 {
  672.                 char Msg2[80];
  673.  
  674.                 sprintf(Msg2, "%s: %s #%-3d",
  675.                     dci->DOSName,
  676.                     GetString(MSG_TAPE_LABEL),
  677.                     dci->NextDiskNr);
  678.  
  679.                 // "TAPE: Tape #999   abcdefgh"
  680.                 sprintf(Message, "%s %*s", Msg2, 63-37 - strlen(Msg2),
  681.                     TapeFormat(dci->TapeReq));
  682.  
  683.             //    sprintf(Message, "%s: %s #%-3d    %-8.8s",
  684.             //        dci->DOSName,
  685.             //        GetString(MSG_TAPE_LABEL),
  686.             //        dci->NextDiskNr,
  687.             //        TapeFormat(dci->TapeReq));
  688.                 }
  689.             else
  690.                 {
  691.                 sprintf(Message, "%s: %s #%-3d",
  692.                     dci->DOSName,
  693.                     GetString(MSG_DISK_LABEL),
  694.                     dci->NextDiskNr);
  695.                 }
  696.             DiskText(Message, ~0, ~0, dci->Pos);
  697.  
  698.             PopInfoLine(&PilHandle);
  699.  
  700.             d(kprintf(__FUNC__ "/%ld: %s: DiskStatus=%ld\n", __LINE__, dci->DOSName, dci->DiskStatus);)
  701.             if (dci->DiskStatus != DiskInUse)
  702.                 {
  703.                 ObtainSemaphore(&dci->Sema);
  704.                 dci->withQFA = dci->TapeReq && dci->TapeReq->withQFA;
  705.                 d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  706.                 SetDiskStatus(dci, DiskOk);
  707.                 d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  708.                 ReleaseSemaphore(&dci->Sema);
  709.                 }
  710.             break;
  711.  
  712.         case DISKCHANGED:
  713.             d(kprintf(__FUNC__ "/%ld: %s: Disk gewechselt\n", __LINE__, dci->DOSName);)
  714.             ObtainSemaphore(&dci->Sema);
  715.             if (dci->DiskStatus != WaitingForDisk)
  716.                 SetDiskStatus(dci, EmptyDrive);
  717.             ReleaseSemaphore(&dci->Sema);
  718.             DiskText(Message, ~0, ~0, dci->Pos);
  719.             break;
  720.  
  721.         case FROMTHISSET:
  722.             d(kprintf(__FUNC__ "/%ld: %s: Disk vom aktuellen Satz\n", __LINE__, dci->DOSName);)
  723.             if (dci->DiskStatus != DiskInUse)
  724.                 {
  725.                 ObtainSemaphore(&dci->Sema);
  726.                 if (dci->DiskStatus != WaitingForDisk)
  727.                     SetDiskStatus(dci, DiskObsolete);
  728.                 ReleaseSemaphore(&dci->Sema);
  729.                 DiskText(Message, ~0, ~0, dci->Pos);
  730.  
  731.                 strcat(Message, GetString(dci->isTape ? MSG_TAPE_FROM_THISSET
  732.                     : MSG_DISK_FROM_THISSET) );
  733.  
  734.                 SignalUnIconifyMainWindow();
  735.  
  736.                 PopInfoLine(&PilHandle);
  737.                 PilHandle = PushInfoLine(Message);
  738.                 }
  739.             break;
  740.  
  741.         case PANIC:
  742.             DiskText(Message, ~0, ~0, dci->Pos);
  743.             d(kprintf(__FUNC__ "/%ld: %s: Panik!!!\n", __LINE__, dci->DOSName);)
  744.             break;
  745.             }
  746.         }
  747.  
  748.     return Result;
  749. }
  750.  
  751.  
  752. // Prüft Diskette. Wenn es eine Backup-Disk ist,
  753. // dürfen Datum und Uhrzeit nicht mit den aktuellen Werten
  754. // übereinstimmen, sonst wurde eine Diskette vom aktuellen
  755. // Backup-Satz nochmals verwendet.
  756. // return OK,  wenn Disk Ok
  757. // return FROMTHISSET, wenn Disk vom aktuellen Satz.
  758. // return DISKCHANGED, wenn Diskwechsel nicht vollständig
  759. // return DOSDISK, wenn DOS-Diskette
  760. static enum TestDiskResult DCCheckLabel(struct DiskChangeInfo *dci)
  761. {
  762.     struct IOExtTD req;
  763.     short error;
  764.     enum TestDiskResult erg;
  765.     struct DiskLabel *secbuff;
  766.  
  767.     ASSERT_VALID(dci);
  768.  
  769.     if (dci->DiskStatus == DiskInUse)
  770.         return OK;
  771.  
  772.     if (dci->isTape && TapeChangeState(dci->TapeReq))
  773.         return DISKCHANGED;
  774.  
  775.     secbuff = (struct DiskLabel *) AllocVec(dci->DiskBlockSize, dci->DiskBufMemType|MEMF_CLEAR);
  776.     if (secbuff == NULL)
  777.         {
  778.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "secbuff", dci->DiskBlockSize);
  779.         return PANIC;
  780.         }
  781.     req = *dci->DiskIOReq;
  782.  
  783.     // Disk-Label lesen
  784.  
  785.     if (dci->isTape)
  786.         {
  787.         TapeInitDrive(dci->TapeReq, &Disks[dci->UnitNr]);
  788.  
  789.         if (dci->TapeReq->withQFA)
  790.             {
  791.             error = TapeRewind(dci->TapeReq) ||
  792.                 TapeSetDirectoryPartition(dci->TapeReq) ||
  793.                 TapeRead(dci->TapeReq, (char *) secbuff, dci->DiskBlockSize) ||
  794.                 TapeRewind(dci->TapeReq);
  795.             }
  796.  
  797.         if (!dci->TapeReq->withQFA)
  798.             {
  799.             error = TapeRewind(dci->TapeReq) ||
  800.                 TapeRead(dci->TapeReq, (char *) secbuff, dci->DiskBlockSize) ||
  801.                 TapeRewind(dci->TapeReq);
  802.             }
  803.         }
  804.     else
  805.         {
  806.         Clear(&req);        // zuerst interne Buffer löschen
  807.         error = TRead(&req, 0, (char *) secbuff, dci->DiskBlockSize);
  808.         }
  809.  
  810.     switch (error)
  811.         {
  812.     case 0:
  813.         // Sektor konnte gelesen werden
  814.  
  815.         ObtainSemaphore(&dci->Sema);
  816.         memcpy(&dci->Label, secbuff, sizeof(struct DiskLabel));
  817.         ReleaseSemaphore(&dci->Sema);
  818.  
  819.         if (strcmp(secbuff->Id, DISKID) == 0
  820.             && memcmp(dci->StartZeit, secbuff->BackupZeit, sizeof(dci->StartZeit)) == 0 )
  821.                 {
  822.             erg = FROMTHISSET;    // Disk ist vom aktuellen Satz
  823.             break;
  824.             }
  825.         else if (strncmp(secbuff->Id, "DOS", 3) == 0)
  826.             {
  827.             erg = DOSDISK;    // DOS-Diskette, vor Gebrauch nachfragen
  828.             break;
  829.             }
  830.         else
  831.             erg = OK;
  832.         break;
  833.  
  834.     case TDERR_DiskChanged:
  835.         // keine Disk im Laufwerk
  836.         erg = DISKCHANGED;
  837.         AbortTimerIO(dci);
  838.         break;
  839.  
  840.     default:
  841.         // Sektor 0 nicht lesbar
  842.         erg = UNREADABLE;    // Keine Backup-Disk
  843.         break;
  844.         }
  845.  
  846.     FreeVec(secbuff);
  847.     if (!dci->isTape)
  848.         MotorOff(&req);
  849.  
  850.     return erg;
  851. }
  852.  
  853.  
  854. static void AbortTimerIO(struct DiskChangeInfo *dci)
  855. {
  856.     ASSERT_VALID(dci);
  857.  
  858.     if (dci->TimerInUse && dci->TimerIOReq->tr_node.io_Message.mn_Node.ln_Type == NT_MESSAGE)
  859.         {
  860.         AbortIO((struct IORequest *) dci->TimerIOReq);
  861.         WaitIO((struct IORequest *) dci->TimerIOReq);
  862.         dci->TimerInUse = 0;
  863.         }
  864. }
  865.  
  866.  
  867. static void SetDiskStatus(struct DiskChangeInfo *dci, enum DskStat NewState)
  868. {
  869.     d(kprintf(__FUNC__ "/%ld  NewState=%ld\n", __LINE__, NewState);)
  870.     if (NewState != dci->DiskStatus)
  871.         {
  872.         ObtainSemaphore(&dci->Sema);
  873.         dci->DiskStatus = NewState;
  874.         ReleaseSemaphore(&dci->Sema);
  875.         d(kprintf(__FUNC__ "/%ld vor SignalNewDisk()\n", __LINE__);)
  876.         SignalNewDiskOk();
  877.         }
  878. }
  879.  
  880.  
  881.  
  882.  
  883. // Message vom DiskChanger-Prozeß an Hauptprozeß senden
  884. static void SendDCRx(struct DiskChangeInfo *dci, unsigned short Class)
  885. {
  886.     struct DCMessage *Msg;
  887.  
  888.     Msg = malloc(sizeof(struct DCMessage));
  889.     if (Msg)
  890.         {
  891.         Msg->dc_Msg.mn_ReplyPort = NULL;
  892.         Msg->dc_Msg.mn_Length = sizeof(struct DCMessage);
  893.         Msg->dc_Class = Class;
  894.         d(kprintf(__FUNC__ "/%ld: send %lx\n", __LINE__, (long) Class);)
  895.         PutMsg(dci->DCRxPort, (struct Message *) Msg);
  896.         }
  897. }
  898.  
  899.  
  900. // Ergebnis: FALSE wenn abgebrochen werden muß
  901. static BOOL CheckDCTxPort(struct DiskChangeInfo *dci)
  902. {
  903.     BOOL DCRunning = TRUE;
  904.     struct DCMessage *Msg;
  905.  
  906.     while (Msg = (struct DCMessage *) GetMsg(dci->DCTxPort))
  907.         {
  908.         unsigned short Class;
  909.  
  910.         Class = Msg->dc_Class;
  911.         ReplyMsg((struct Message *) Msg);
  912.  
  913.         switch (Class)
  914.             {
  915.         case DC_SHUTDOWN:
  916.             d(kprintf(__FUNC__ "/%ld: >>received DC_ABORT oder DC_SHUTDOWN\n", __LINE__);)
  917.             DCRunning = FALSE;
  918.             break;
  919.         default:
  920.             d(kprintf(__FUNC__ "/%ld: >>received unknown %ld\n", __LINE__, (long) Class);)
  921.             break;
  922.             }
  923.         }
  924.  
  925.     return (BOOL) DCRunning;
  926. }
  927.  
  928.  
  929.