PlugIns fr GEMAR ¾ Steffen Engel 1992-94 25.05.94 ALLGEMEINES In dieser Datei werden alle n”tigen Informationen zu PlugIns gegeben, der aktuelle Stand der von GEMAR installierten PlugIn-Calls, die Liste der aktuell existierenden PlugIns und der aktuelle Stand der PlugIns und ihrer Programmierung. Die mit GEMAR gelieferten PlugIns sind grunds„tzlich alle deaktiviert, indem die Namen mit PLX enden. Bitte beurteilen Sie selbst, welche PlugIns fr Sie sinnvoll sind. WAS SIND PLUGINS? Um GEMAR mit weiteren F„higkeiten auszustatten, wurde ein Konzept entworfen, mit dem externe Programme als Erweiterung hinzugeladen werden k”nnen. Dabei wird von GEMAR an bestimmten Stellen einfach kontrolliert, ob ein zu diesem Zweck geh”rendes PlugIn existiert, und ruft es gegebenenfalls auf. Grunds„tzlich wurde das Konzept relativ einfach gehalten, da es dadurch einerseits einfach zu verstehen und programmieren ist und andererseits kein vollst„ndig modulares Programmierungssystem entworfen werden sollte. Mit diesem Konzept sind nur kleine Erweiterungen oder Ersetzungen von Teilen von GEMAR m”glich. PlugIns sind vor allem dann sinnvoll, wenn kleine Erweiterungen an GEMAR gemacht werden sollen, die fr bestimmte Probleme sinnvoll sind, aber zu speziell sind, um allgemein in GEMAR eingebaut zu werden. PlugIns werden von GEMAR grunds„tzlich im Ordner PLUGIN im GEMAR-Pfad gesucht. AUFBAU UND PROGRAMMIERUNG VON PLUGINS PlugIns werden grunds„tzlich als Pozeduren aufgerufen. Als Methode wurde ein „hnlicher Weg gew„hlt wie bei CPX-Modulen. Zur Identifikation tragen PlugIns zur Zeit einen 512-Byte langen Kopf: TYPE tPlugHead = RECORD Magic : lCARDINAL; (* 'Plug' *) Identify : ARRAY[0..19] OF CHAR; (* Kontrolle fr Programm *) SlotIdent : ARRAY[0..19] OF CHAR; (* Identifikation fr Verwendung *) Info : ARRAY[0..467] OF CHAR; (* Beschreibung *) END; Identify dient dabei dazu, zu erkennen, ob dieses Plugin berhaupt fr das laufende Programm ist. Bei Gemar muž Identify immer 'Gemar' sein. SlotIdent dient zur Erkennung, ob das PlugIn fr den Slot geeignet ist. Dies dient als Schutz, daž zB ein Plugin fr die Index-Bearbeitung nicht fr SCSI-Routinen eingeklinkt wird. PlugIns werden geladen und danach wird der Rumpf des PlugIns mit einem Zeiger auf folgende Struktur aufgerufen: tPlugEnvironment = RECORD (* aktuelle Parameterversion = 1.00 = 0100H *) Version : sINTEGER; (* Version zeigt Umfang der Parameter an *) Private : ADDRESS; (* spezielle Parameter fr den Rumpf *) ApplId : sINTEGER; (* Applikationsid des rufenden Programmes *) VDIHandle: sINTEGER; (* Workstation des Hauptprogrammes *) PlugPath : POINTER TO ARRAY[0..512] OF CHAR; (* Name und Pfad des PlugIn, kann auch relativ sein *) Alert : PROCEDURE((* def *) sINTEGER, VAR (* msg *) STRING) : sINTEGER; END; In C sieht das entsprechend so aus: typedef struct { int Version; void *private; int ApplId; int VDIHandle; char *PlugPath; int (*Alert) (int defbutt, char *msg); } PLUGPARMS; Die Struktur wird grunds„tzlich abw„rtskompatibel sein, d.h. bei erweiterten Versionen kommen zus„tzliche Parameter hinzu und die Versionsnummer wird erh”ht. Nach einer evtl. n”tigen Initialisierung (zB Abfragen, ob das Modul berhaupt aktiviert werden soll) muž das PlugIn mit einem Zeiger auf eine Tabelle von Funktionen antworten: TYPE tpPlugProcs = POINTER TO tPlugProcs; tPlugProc = PROCEDURE((* par : *) ADDRESS) : lINTEGER; tPlugProcs = RECORD num : SHORTINT; (* Anzahl der Funktionen *) Procs : ARRAY[0..07FFFH] OF tPlugProc; END; Ein Null-Zeiger zeigt an, daž das PlugIn nicht aktiviert werden soll (oder bereits fertig ist). Diese Funktionen werden dann zur eigentlichen Verwendung ein- oder mehrmals aufgerufen. Als Parameter wird ein Zeiger bergeben, der auf die zu bearbeitenden Daten zeigt. Bitte beachten Sie, daž UNBEDINGT aller Speicher bei der Deinitialisierung des PlugIns freigegeben wird, da der Speicher nicht durch das Freigeben des PlugIn freigeben wird! Die Aufforderung zur Deinitialisierung erfolgt durch Aufruf der Funktion 0 mit -1 (0FFFFFFFFH) als Parameter. Als Beispiel sollten Sie sich die beiliegenden PlugIns ansehen, insbesondere PLUGPARM.D PARAMETER IN GEMAR Als Standardstruktur wird von GEMAR in private ein Zeiger auf die folgende Struktur bergeben: TYPE tPlugPrivate = RECORD Version : SHORTCARD; (* = 0200H = 2.00 *) special : ADDRESS; (* Spezielles fr Art des PlugIn *) StrHandle : SHORTCARD; StrMaxLen : LONGCARD; BlockLen: SHORTCARD; (* Blockl„nge des Streamers *) ScsiIn : PROCEDURE ((* ScsiCmd *) tpScsiCmd) : SHORTINT; ScsiOut : PROCEDURE ((* ScsiCmd *) tpScsiCmd) : SHORTINT; SuperOn : PROC; SuperOff : PROC; END; In C sieht das so aus: typedef struct { unsigned word version; void *special; word strhandle; long strmaxlen; word blocklen; word (*ScsiIn) (SCSIPARMS *Parms); word (*ScsiOut) (SCSIPARMS *Parms); void (*SuperOn) (); void (*SuperOff) (); } tScsiCall; tScsiCmd = RECORD handle : SHORTCARD; (* das handle des Ger„tes *) Cmd : ADDRESS; (* Zeiger auf CmdBlock *) CmdLen : SHORTCARD; (* L„nge des Cmd-Block *) Buffer : ADDRESS; (* Datenpuffer *) TransferLen : LONGCARD; (* šbertragungsl„nge *) SenseBuffer : ADDRESS; (* Puffer fr ReqSense (18 Bytes) *) Timeout : LONGCARD; (* Timeout in 1/200 sec *) Flags : BITSET; (* Bitvektor fr Ablaufwnsche *) END; tpScsiCmd = POINTER TO tScsiCmd; Return-Werte fr ScsiIn und ScsiOut sind: NOSCSIERROR = 0; (* Kein Fehler *) SELECTERROR = -1; (* Fehler beim Selektieren *) STATUSERROR = -2; (* Default-Fehler *) PHASEERROR = -3; (* ungltige Phase *) BSYERROR = -4; (* BSY verloren *) BUSERROR = -5; (* Busfehler bei DMA-šbertragung *) TRANSERROR = -6; (* Fehler beim DMA-Transfer (nichts bertragen) *) FREEERROR = -7; (* Bus wird nicht mehr freigegeben *) TIMEOUTERROR = -8; (* Timeout *) DATATOOLONG = -9; (* Daten fr ACSI-Softtransfer zu lang *) LINKERROR = -10; (* Fehler beim Senden des Linked-Command (ACSI) *) TIMEOUTARBIT = -11; (* Timeout bei der Arbitrierung *) PENDINGERR = -12; Werte > 0 sind das Statusbyte des SCSI-Ger„tes (siehe SCSI-Norm) ACHTUNG!!! BlockLen kann sich w„hrend des Betriebes von GEMAR „ndern und ist nur gltig, wenn ein Band geladen ist!! special ist dabei ein Spezial-Parameter fr das PlugIn, der von der Art des PlugIn abh„ngt. Dieser Parameter ist _NUR_ w„hrend der Initialisierung des PlugIn gltig und muž daher getrennt von der private-Struktur gesichert werden!! Es reicht, den Zeiger zu sichern, da die Struktur auf die special zeigt, nicht flchtig ist. EXISTIERENDE PLUGINS Zur Zeit existieren fnf PlugIn-Slots: -REQSENSE pr„zisiert die Fehlermeldungen des Streamers, die in den Request Sense Daten bergeben werden. -INDEX wird nach jedem Backup aufgerufen und kann entweder den Inhalt eines Bandes ausdrucken, oder in eine Datei schreiben. Darin k”nnen INDEX.PLG und SCANINDEX.PLG eingesetzt werden. -SCANINDE wird beim Indexscanning aufgerufen. Damit kann eine Datei auf einem Band gesucht werden. Darin k”nnen INDEX.PLG und SCANINDEX.PLG eingesetzt werden. -SCSI Wird bei allen SCSI-Befehlen gerufen und kann damit Anpassungen an exotische Streamer durchfhren. Darin k”nnen die folgenden Plugins eingesetzt werden: -SPACE.PLG wird bei Space-Operationen des Streamers gerufen, um ein modifziertes Spacing durchzufhren -QFA.PLG wird bei eingeschaltetem Quick File Access fr die Funktionen benutzt. Dabei ist egal, welche Art eingeschaltet ist (Seek oder Locate) -Index-Import Wird bei unbekanntem Band-Header gerufen. Damit sind Restores von GEMAR-fremden B„ndern m”glich. SCANINDE und INDEX besitzen gleiche Aufrufe, daž heižt, Sie k”nnen INDEX.PLG in SCANINDE.PLG umbenennen und damit per 'Scannen' nachtr„glich den Inhalt des Bandes in eine Datei schreiben lassen. EXISTIERENDE PLUGIN-AUFRUFE 1. Namentliche installierte PlugIns: -INDEX.PLG: Aufruf : Nach einem Backup Name : INDEX.PLG Anzahl : 1 (Laden nach Name) SlotIdent : 'Index' Prozeduren: 2 Prozeduren fr Aufruf 1. Prozedur : Der Call bekommt Zeiger auf Index-Eintr„ge, jeweils einen Ordner alphabetisch durchlaufen, danach den n„chsttieferen Ordner. Auf dieser Basis w„re zB ein Exporter in eine Datenbank m”glich. bergebene Struktur: s. INDEX.M 2. Prozedur Zeiger auf den Index-Header. Ein Aufruf zeigt an, daž ein neuer Index gelesen wurde und der Header mit den Daten gefllt ist. -SCANINDEX.PLG: Aufruf : bei Index-Scanning Name : SCANINDE.PLG Anzahl : 1 (Laden nach Name) SlotIdent : 'Index' Prozeduren: 2 Prozeduren fr Aufruf, wie INDEX retour = 1 bricht Scanning ab und w„hlt den aktuellen Index 2. Typbasiert installierte PlugIns: -REQSENSE: Aufruf : Nach einem Scsi-Fehler (Check Condition auf Streamerzugriff). Anzahl : 1 SlotIdent : 'REQSENSE' Prozeduren: 1 Prozedur fr Aufruf Parameter : Zeiger auf Request-Sense-Daten, die vorher vom SCSI-Ger„t geholt wurden. Antwort : Zeiger auf einen (nullterminierten) String, der in die Alertbox eingesetzt wird ('Check Condition(%s)') -SCSI: Aufruf : Wird bei allen SCSI-Kommandos gerufen Anzahl : 1 SlotIdent : 'SCSI' Prozeduren: 2 Prozeduren fr Aufruf 1. Prozedur ist SCSIIn 2. Prozedur ist SCSIOut Parameter : Zeiger auf die ScsiStruktur Bemerkung : Aufruf im Supervisor-Modus! -Index-Import: Aufruf : Wird bei unbekanntem Band-Header gerufen Anzahl : frei SlotIdent : 'Index-Import' Bemerkung : Dokumentation nur fr Programmierer von Importern. Weitere Aufrufe richte ich gerne ein, Ideen sind immer willkommen. HISTORY 17.07.94 -Umstellung auf den Header vor dem PlugIn -Umstellung der private-Parameter. 20.12.94 -Umstellung auf Slotbasierte PlugIns Steffen Engel