SYSDUMPs AND HP's "TurboSTORE" FACILITY by Eugene Volokh, VESOFT Published by INTERACT Magazine, Sep 1988. At a recent meeting of the GLUG (Greater Los Angeles Users' Group), one of our users approached me with a technical problem. He had just bought HP's new TurboSTORE product, which (among other things) lets you mount several tapes on several tape drives and then specify all those tape drives on one :STORE command. This way, if your nightly backup takes 3 reels and you happen to have 3 tape drives, you could mount tapes on each of the tape drives and say: :FILE T7;DEV=7 :FILE T8;DEV=8 :FILE T9;DEV=9 :STORE @.@.@;DATE>=xxx;STORESET=(*T7),(*T8),(*T9) Instead of just specifying the tape file to store to (after the fileset), you can specify the ;STORESET= keyword; :STORE will write to the tape on ldev 7, then to the one on ldev 8, and then to the one on ldev 9. You mount the tapes, do the :STORE, and then go home -- no need to stay around to mount additional tapes. (This works especially well if you have HP's new 7980XC compressing tape drives, which could let you cut your system backup to 2 or 3 tapes rather than 7 or 8 -- the user who prompted this whole paper is getting a 4 to 1 compression ratio.) It's much more convenient, and can save you $$$ on your nightly operator costs. The problem with TurboSTORE is that, although it works perfectly on the :STORE command, it can't be used with :SYSDUMP -- the one place you most want to have it (for backup purposes). If you try saying :FILE T7;DEV=7 :FILE T8;DEV=8 :FILE T9;DEV=9 :SYSDUMP (*T7),(*T8),(*T9) instead of :SYSDUMP *T you'll get a syntax error; if you say :SYSDUMP *T ... ENTER DUMP FILE SUBSET (S) @.@.@;STORESET=(*T7),(*T8),(*T9) then you'll get an error "'STORESET' NOT ALLOWED WHEN POSITIONAL TAPE NAME IS SPECIFIED (S/R 6293)". Thus, you either have to abandon TurboSTORE for system backups (if you do, why use TurboSTORE at all? -- how many other multi-reel :STOREs do you do?) or do all your system backups with :STORE. The latter alternative -- using :STORE for backups -- seems palatable, but has two substantial problems: 1. Backups made with :STORE do not contain the SYSTEM DIRECTORY. If you need to restore from a :STORE backup, the best you can do is put on a ;CREATE, but that still might not create all the users and groups, and certainly won't preserve capabilities, security masks, etc. Your normal coldload tape (which you had to make with :SYSDUMP) would have this information, but unless you cut a new coldload tape every night, the directory information on it will be substantially out of date. 2. While you can :RESTORE equally well from a :STORE backup as from a :SYSDUMP backup, you can't do a RELOAD COMPACT from a :STORE tape. If you like to use this option for better disc space utilization, switching to :STORE backups may be unpleasant. Well, you say, these might be non-trivial problems, but what can you do? If that's the way TurboSTORE works, we have to live with it and wait for a new version that might fix the problem (which may be some time down the road). Fortunately, our user was an imaginative type -- he though that something could be done directly, without having to wait. Even when I assured him that the problem was probably quite deep and intractable, he still goaded me to go on; and, as it ultimately turned out, we managed to come up with a very simple solution. The :SYSDUMP command does not write the files-to-be-stored to tape itself; it uses :STORE to do this. After writing all the system information to the backup tape, it creates STORE.PUB.SYS (the :STORE program) as a son process and tells it (via the ;INFO= string) which files are to be stored. Actually, it passes to STORE.PUB.SYS all the text that you typed in response to "ENTER DUMP FILE SUBSET (S)", so any :STORE keywords specified there (e.g. "@.@.@;STORESET=(*T7),(*T8),(*T9)") are seen by STORE.PUB.SYS. In fact, if you say :SYSDUMP *T ... ENTER DUMP FILE SUBSET (S) @.@.@;STORESET=(*T7),(*T8),(*T9) then SYSDUMP will essentially do (using the CREATEPROCESS intrinsic) the equivalent of :RUN STORE.PUB.SYS;& INFO="STORE @.@.@;*DUMPTAPE;STORESET=(*T7),(*T8),(*T9)" The only reason why this fails seems to be that STORE.PUB.SYS doesn't let you specify both the "storefile" (*DUMPTAPE) parameter and ;STORESET=. It's purely a syntax check on STORE's part; if only SYSDUMP had done a :RUN STORE.PUB.SYS; INFO="STORE @.@.@;STORESET=(*T7),(*T8),(*T9)" -- without specifying *DUMPTAPE -- then everything would work! SYSDUMP would write all the system stuff to the store file you specified (in our example, *T, which SYSDUMP later refers to as *DUMPTAPE), and then use STORE.PUB.SYS to write all the files to the given ;STORESET=. Of course, *T (the SYSDUMP tape) would have to be on the same device as *T7 (the first tape in the ;STORESET= parameter). (Note that SYSDUMP always refers to the tape parameter as *DUMPTAPE, even though you specified it as *T -- the :SYSDUMP command automatically sets up a ":FILE DUMPTAPE=*T" file equation.) So now we know what we wish SYSDUMP would do -- not pass the *DUMPTAPE parameter to STORE.PUB.SYS when the user specifies a ;STORESET= parameter. Now, the question is: how do we make SYSDUMP do it? How do we force an HP program (the source of which we don't, of course, have) to do something it wasn't designed to do? The solution is surprisingly simple. In fact, it does NOT involve patching any SYSDUMP code (which would be highly uncertain, which would constrain the nature of our patch, and which would require us to re-deduce the patch for every new version of SYSDUMP). What it does involve is doing the following: * :HELLO MANAGER.SYS * :NEWGROUP VESTORE.SYS;CAP=IA,BA,PH,PM,MR,DS * :FCOPY FROM=SYSDUMP.PUB.SYS;TO=SYSDUMP.VESTORE.SYS;NEW * Compile the following SPL program: $CONTROL NOSOURCE, USLINIT, SEGMENT=VESTORE, SUBPROGRAM BEGIN PROCEDURE CREATEPROCESS (ERR, PIN, PROGRAM, NUMBERS, ITEMS); INTEGER ERR; INTEGER PIN; BYTE ARRAY PROGRAM; INTEGER ARRAY NUMBERS; INTEGER ARRAY ITEMS; OPTION VARIABLE; BEGIN INTRINSIC LOADPROC, UNLOADPROC; INTEGER VAR'MASK = Q-4; INTEGER STATUS = Q-1; BYTE POINTER INFO; INTEGER INFO'LEN, I, J, PLABEL, IDENT; BYTE ARRAY PROC'NAME(0:15); IF VAR'MASK.(14:1)=1 AND VAR'MASK.(15:1)=1 THEN BEGIN << NUMBERS and ITEMS specified, look at them >> INFO'LEN:=0; I:=0; WHILE NUMBERS(I)<>0 DO BEGIN << find INFO and INFO LENGTH values >> IF NUMBERS(I)=11 <<info>> THEN @INFO:=ITEMS(I) ELSE IF NUMBERS(I)=12 <<infolen>> THEN INFO'LEN:=ITEMS(I); I:=I+1; END; IF INFO'LEN<>0 THEN FOR I:=0 UNTIL INFO'LEN-11 DO IF INFO(I)=";STORESET=" THEN << store-set specified? >> FOR J:=0 UNTIL INFO'LEN-12 DO IF INFO(J)=";*DUMPTAPE;" THEN MOVE INFO(J):=" ;"; << delete *DUMPTAPE >> END; << Can't call CREATEPROCESS directly (this would just call >> << this procedure recursively) -- LOADPROC it and then call. >> MOVE PROC'NAME:="CREATEPROCESS "; IDENT:=LOADPROC (PROC'NAME, 0, PLABEL); TOS:=@ERR; TOS:=@PIN; TOS:=@PROGRAM; TOS:=@NUMBERS; TOS:=@ITEMS; TOS:=VAR'MASK; TOS:=PLABEL; ASSEMBLE (PCAL 0); IF > THEN STATUS.(6:2):=0 << set condition code >> ELSE IF < THEN STATUS.(6:2):=1 ELSE STATUS.(6:2):=2; UNLOADPROC (IDENT); END; END. * Add it to a group SL by saying :SEGMENTER -BUILDSL SL.VESTORE.SYS,20,1 -USL $OLDPASS (or whatever USL you compiled the above SPL procedure into) -ADDSL VESTORE -EXIT * Now, whenever you want to do a system backup, instead of saying ":SYSDUMP *T,*LISTFILE", say :FILE DUMPTAPE=*T :FILE SYSDLIST=*LISTFILE (or $STDLIST, if you like) :RUN SYSDUMP.VESTORE.SYS;LIB=G * When SYSDUMP.VESTORE.SYS prompts you with "ENTER DUMP FILE SUBSET (S)", say fileset,fileset,...,fileset;STORESET=(*tape,*tape,...) In other words, specify everything that you'd normally specify when asked for the dump file subsets, PLUS the ;STORESET= parameter that you'd specify on an ordinary :STORE command. Now, SYSDUMP.VESTORE.SYS -- an exact copy of SYSDUMP.PUB.SYS -- will do your system backup USING TurboSTORE'S ;STORESET= KEYWORD. How does this work? Well, when SYSDUMP.VESTORE.SYS (which was run with ;LIB=G) calls the CREATEPROCESS intrinsic to create STORE.PUB.SYS, it will actually call our own CREATEPROCESS procedure that we've put into SL.VESTORE.SYS. This CREATEPROCESS procedure looks exactly like the CREATEPROCESS intrinsic; however, it also examines the ;INFO= parameter that's being passed to the program-to-be-created. (We find the ;INFO= string and its length in the NUMBERS and ITEMS arrays passed to CREATEPROCESS.) If this ;INFO= string contains the string ";STORESET=", then our CREATEPROCESS procedure REMOVES the string ";*DUMPTAPE" from the ;INFO= parameter. After this is done, our own CREATEPROCESS calls the REAL CREATEPROCESS. Unfortunately, it can't just simply call CREATEPROCESS, since that would call our own CREATEPROCESS recursively (instead of calling the real CREATEPROCESS in the system SL). Instead, we use LOADPROC to load the real CREATEPROCESS explicitly from the system SL and then call it using PCAL 0. :SYSDUMP and TurboSTORE can now work together. The customer for whom we originally did this is using this quite successfully for his nightly backups. There may be some problems with our approach that we haven't encountered (use it at your own risk!), but it seems to be working quite well. If you're a TurboSTORE customer, try it -- it might help you out of an unpleasant spot!