/* REXX */ /* */ /* AUTHOR: MARK ZELDEN */ /* */ /**************************************************************/ /* LINK LIST LIBRARIES Checker REXX Exec */ /**************************************************************/ /* This REXX exec checks for invalid syntax (missing / extra */ /* commas), for data sets not cataloged in the master */ /* catalog, invalid link list datasets (not a PDS or RECFM=U) */ /* and the concatenation algorithm: */ /* (32) + (16n) + (k-1) */ /* n = the number of DASD extents (PDS/E counts as 1) */ /* k = the number of data set in the link list */ /* The result of the algorithm cannot exceed 2040 */ /* */ /* If running DFSMS/MVS 1.3 or later, then the only */ /* restriction is that the total number of extents must not */ /* not exceed 255. */ /**************************************************************/ /* EXECUTION SYNTAX: */ /* */ /* TSO %LNKVER < IEASYSxx | LNKLSTxx > (option) */ /* */ /* - The first parm is the IEASYSxx name that */ /* will be used to build the link list in SYS1.PARMLIB, */ /* or a LNKLSTxx member name in SYS1.PARMLIB. */ /* The default is IEASYS00 */ /* */ /* Valid options are: NODETAIL and DETAIL */ /* The default is NODETAIL */ /* */ /* EXAMPLES: */ /* TSO %LNKVER */ /* TSO %LNKVER LNKLST00 */ /* TSO %LNKVER IEASYS01 DETAIL */ /* */ /* Any errors encountered are displayed on the terminal */ /* along with a short summary at the end. If the "DETAIL" */ /* option is used, an extent summary by data set is also */ /* displayed. */ /* */ /**************************************************************/ /* Trace ?R */ /* Trace ?I */ /* Trace err */ Arg MEMNAME OPTION /* */ /* Verify input parameters */ /* */ If MEMNAME = '' then MEMNAME = 'IEASYS00' If Index(MEMNAME,'LNKLST') = 0 & Index(MEMNAME,'IEASYS') = 0 then do Say 'INVALID SYS1.PARMLIB MEMBER SPECIFIED' Say 'IF SPECIFIED, THE MEMBER NAME MUST BE EITHER IEASYSxx' , 'OR LNKLSTxx' Say 'EXAMPLE: TSO %LNKVER' Say 'EXAMPLE: TSO %LNKVER LNKLST00' Say 'EXAMPLE: TSO %LNKVER IEASYS00 DETAIL' Exit 12 End If OPTION <> 'DETAIL' & OPTION <>'NODETAIL' & OPTION <> '' then do Say 'INVALID OPTION SPECIFIED' Say 'OPTION MUST BE "NODETAIL" (DEFAULT) OR "DETAIL"' Say 'EXAMPLE: TSO %LNKVER' Say 'EXAMPLE: TSO %LNKVER LNKLST00' Say 'EXAMPLE: TSO %LNKVER IEASYS00 DETAIL' Exit 12 End If OPTION = '' then OPTION = 'NODETAIL' /* */ /* Build Library List to verify */ /* */ Call MEMBER_CHECK MEMNAME Call READ_FILE MEMNAME If Index(MEMNAME,'LNKLST') <> 0 then do /* LNKLSTxx specified */ Call FIND_COMMENTS Call CHECK_COMMAS LIBREC.0 = INREC.0 Do I = 1 to LIBREC.0 LIBREC.I = INREC.I End Say 'LINK LIST VERIFICATION WILL USE THE FOLLOWING MEMBER:' MEMNAME Call VERIFY_LIST End /* */ /* IEASYSxx is specified, check members and */ /* build library list */ /* */ Else do Do I = 1 to INREC.0 /* look for LNK= in IEASYSxx */ If Index(INREC.I,'LNK=') = 0 then iterate Else do SRCH = INREC.I Leave End End STRTLIST = Index(SRCH,'LNK=') If Substr(SRCH,STRTLIST+4,1) = '(' then do /* */ /* Multi LNK=(xx,xx,xx) specified in IEASYSxx */ /* */ ENDLIST = Index(SRCH,')',STRTLIST+4) If ENDLIST = 0 then do /* LNK = spans more than one line */ ENDLIST = Index(SRCH,', ',STRTLIST+4) LIST = Substr(SRCH,STRTLIST+5,ENDLIST-STRTLIST-5) Do Forever /* loop to find end of LNK= specifications */ I = I+1 /* increment record count */ SRCH2 = INREC.I STRTLST2 = Wordindex(SRCH2,1) ENDLIST2 = Index(SRCH2,')',STRTLST2) If ENDLIST2 = 0 then do /* end of list not found */ ENDLIST2 = Index(SRCH2,', ',STRTLST2) LIST2 = Substr(SRCH2,STRTLST2,ENDLIST2-STRTLST2) LIST = LIST LIST2 Iterate /* get another record */ End Else do /* end of list found */ LIST2 = Substr(SRCH2,STRTLST2,ENDLIST2-STRTLST2) LIST = LIST LIST2 Leave /* exit do forever loop */ End End /* do forever */ End /* if ENDLIST = 0 */ Else /* LNK = is on one line only */ LIST = Substr(SRCH,STRTLIST+5,ENDLIST-STRTLIST-5) LIST = Translate(LIST,' ',',') /* remove commas */ NUMONLST = Words(LIST) /* number of LNKLSTxx members */ If word(list,numonlst) = 'L' then do numonlst = numonlst-1 LIST = Translate(LIST,' ','L ') /* remove last "L " */ End LIBREC.0 = 0 /* initialize variable */ Do J = 1 to NUMONLST MEM.J = 'LNKLST' || WORD(LIST,J) /* LNKLSTxx mbr name */ Call MEMBER_CHECK MEM.J Call READ_FILE MEM.J Call FIND_COMMENTS Call CHECK_COMMAS Do I = 1 to INREC.0 LIBNUM = LIBREC.0 + I LIBREC.LIBNUM = INREC.I End LIBREC.0 = LIBREC.0 + INREC.0 End Say 'LINK LIST VERIFICATION WILL USE THE FOLLOWING', MEMNAME 'SUFFIXES:' Say LIST Call VERIFY_LIST End /* */ /* Single LNK=xx specified in IEASYSxx */ /* */ Else do SUF = Substr(SRCH,STRTLIST+4,2) CURMBR = 'LNKLST' || SUF Call MEMBER_CHECK CURMBR Call READ_FILE CURMBR Call FIND_COMMENTS Call CHECK_COMMAS LIBREC.0 = INREC.0 Do I = 1 to LIBREC.0 LIBREC.I = INREC.I End Say 'LINK LIST VERIFICATION WILL USE THE FOLLOWING', MEMNAME 'SUFFIX:' SUF Call VERIFY_LIST End End /* */ /* Done processing libraries - check */ /* concatentation algorithm, write totals, */ /* and exit. */ /* */ If Substr(FMIDNUM,4,4) < 6602 & ALG > 2040 then do Say 'ERROR - THE LNKLST CONCATENATION ALGORITHM EXCEEDED 2040' Say ' ' ALGERR = 'TRUE' End Else if EXTENTS > 255 then do Say 'ERROR - THE NUMBER OF EXTENTS EXCEEDED 255' Say ' ' ALGERR = 'TRUE' End Say ' S U M M A R Y ' Say '----------------------------------------------------' If ALGERR = 'TRUE' then Say ' TOTAL ERRORS =' ERRCNT + 1 Else Say ' TOTAL ERRORS =' ERRCNT Say ' TOTAL LIBRARIES =' TOTLIBS - ERRCNT If Substr(FMIDNUM,4,4) < 6602 then do Say ' TOTAL EXTENTS =' EXTENTS Say ' ALGORITHM RESULT =' ALG ' (CAN''T BE > 2040) ' End Else do Say ' TOTAL EXTENTS =' EXTENTS ' (CAN''T BE > 255)' Say ' ALGORITHM RESULT =' ALG End Say ' ' If OPTION = 'DETAIL' then do Say ' NUM EXT ALG VOLUME LNKLST LIBRARY' Say ' EXT TOTL TOTL SERIAL DATA SET NAME' Say ' --- ---- ---- ------ ----------------------' || , '--------------------' Do I = 1 to TOTLIBS Say '' Right(EXT.I,3) '' Right(EXTT.I,4) '' Right(TOT.I,4) , '' Right(VOL.I,6) '' LIB.I End End If ERRCNT = 0 then Exit 0 else Exit 12 /********************************************************************/ /* S U B R O U T I N E S */ /********************************************************************/ /* */ /* Subroutine to verify LINK LIST libraries */ /* */ VERIFY_LIST: Say 'BEGINNING VERIFICATION OF LINK LIST - PLEASE WAIT...' Say ' ' /* */ /* Initilize variables */ /* */ NUMRECS = LIBREC.0 /* total recs in LINKLST */ TEMPTOT = 0 /* specified libs to check */ TOTLIBS = 0 /* total libs to check */ ERRCNT = 0 /* total libs with errors */ EXTENTS = 0 /* total number of extents */ ALG = 32 - 1 /* part of concat algorithm*/ /* */ /* Determine Master Catalog data set name */ /* and operating system FMID */ /* */ CVT = C2d(Storage(10,4)) AMCBS = C2d(Storage(D2x(CVT + 256),4)) ACB = C2d(Storage(D2x(AMCBS + 8),4)) CAXWA = C2d(Storage(D2x(ACB + 64),4)) MCATDSN = Storage(D2x(CAXWA + 52),44) MCATDSN = Strip(MCATDSN,T) FMIDNUM = Storage(D2x(CVT - 32),7) If Substr(FMIDNUM,4,1) < 6 then VOLSOK = 'N' Else VOLSOK = 'Y' /* OK to use VOLSERs if OS/390 */ /* */ /* Put a list of all library names to check in */ /* the "LIB." stem variable. */ /* */ Do I = 1 to NUMRECS REC = Substr(LIBREC.I,1,71) REC = Translate(REC,' ',',') Call CHECK_COMMENTS NUMONREC = Words(REC) Do J = 1 to NUMONREC TEMPTOT = TEMPTOT + 1 TEMPLIB.TEMPTOT = Word(REC,J) End End /* */ /* Automatically include default libraries */ /* */ LIB.1 = 'SYS1.LINKLIB' LIB.2 = 'SYS1.MIGLIB' LIB.3 = 'SYS1.CSSLIB' TOTLIBS = 3 /* */ /* Remove default libraries if they were */ /* already specified in input parm member. */ /* */ Do I = 1 to TEMPTOT If TEMPLIB.I == 'SYS1.LINKLIB' | , TEMPLIB.I == 'SYS1.MIGLIB' | , TEMPLIB.I == 'SYS1.CSSLIB' , then iterate Else Do TOTLIBS = TOTLIBS + 1 LIB.TOTLIBS = TEMPLIB.I End End Do I = 1 to TOTLIBS /* */ /* If OS/390, then VOLSERs ARE allowed in LNKLST */ /* */ FIND1 = Index(LIB.I,'(') Select When FIND1 <> 0 & VOLSOK = 'Y' then do VOL.I = Substr(LIB.I,FIND1+1,6) LIB.I = Substr(LIB.I,1,FIND1-1) RETCODE = Listdsi(''''LIB.I'''' 'volume('VOL.I')' NORECALL) If RETCODE <> 0 then do Say 'ERROR ENCOUNTERED WHILE VERIFYING THE FOLLOWING DATASET:' Say LIB.I If SYSREASON = 24 then do Say LIB.I 'DOES NOT EXIST ON VOLUME 'VOL.I LIB.I = LIB.I || ' ** IGNORED - NOT ON SPECIFIED VOL **' End Else do Say SYSMSGLVL2 LIB.I = LIB.I || ' ** IGNORED' SYSMSGLVL2 '**' End Say ' ' ERRCNT = ERRCNT + 1 EXT.I = 'ERR' EXTT.I = 'ERR' TOT.I = 'ERR' VOL.I = '*ERR*' Iterate End /* if RETCODE <>0 */ End /* when FIND1 <>0 & VOLSOK ='Y' */ /* */ /* Not OS/390, VOLSERs ARE not allowed in LNKLST */ /* */ When FIND1 <> 0 & VOLSOK = 'N' then do VOL.I = Substr(LIB.I,FIND1+1,6) LIB.I = Substr(LIB.I,1,FIND1-1) Say 'ERROR ENCOUNTERED WHILE VERIFYING THE FOLLOWING DATASET:' Say LIB.I Say 'VOLSERS ARE NOT ALLOWED IN THIS VERSION OF MVS' Say ' ' ERRCNT = ERRCNT + 1 EXT.I = 'ERR' EXTT.I = 'ERR' TOT.I = 'ERR' LIB.I = LIB.I || ' ** IGNORED - VOLSER NOT ALLOWED **' Iterate End /* when FIND1 <>0 & VOLSOK ='N' */ /* */ /* VOLSERs are not coded */ /* */ When FIND1 = 0 then do /* */ /* See if Library is Cataloged */ /* */ RETCODE = Listdsi(''''LIB.I'''' NORECALL) If RETCODE <> 0 then do Say 'ERROR ENCOUNTERED WHILE VERIFYING THE FOLLOWING DATASET:' Say LIB.I If SYSREASON = 5 then do Say 'DATA SET IS NOT CATALOGED' LIB.I = LIB.I || ' ** IGNORED - NOT CATALOGED **' End Else do Say SYSMSGLVL2 LIB.I = LIB.I || ' ** IGNORED' SYSMSGLVL2 '**' End Say ' ' ERRCNT = ERRCNT + 1 EXT.I = 'ERR' EXTT.I = 'ERR' TOT.I = 'ERR' VOL.I = '*ERR*' Iterate End /* if RETCODE <>0 */ VOL.I = SYSVOLUME /* */ /* Check to see if library is in the Master Catalog */ /* */ junk=outtrap(LINE.) /* trap output */ Address TSO "LISTCAT ENT('"LIB.I"') CAT('"MCATDSN"')" junk=outtrap('off') /* trap off */ If RC <> 0 then do Say 'ERROR ENCOUNTERED WHILE VERIFYING THE FOLLOWING DATASET:' Say LIB.I Say 'DATA SET IS NOT CATALOGED IN THE MASTER CATALOG' Say ' ' ERRCNT = ERRCNT + 1 EXT.I = 'ERR' EXTT.I = 'ERR' TOT.I = 'ERR' LIB.I = LIB.I || ' ** IGNORED - NOT IN MCAT **' Iterate End If SYSDSORG <> 'PO' | SYSRECFM <> 'U' then do Say 'ERROR ENCOUNTERED WHILE VERIFYING THE FOLLOWING DATASET:' Say LIB.I Say 'DATA SET IS NOT A PDS OR IS NOT A LOADLIB' Say ' ' ERRCNT = ERRCNT + 1 EXT.I = 'ERR' EXTT.I = 'ERR' TOT.I = 'ERR' LIB.I = LIB.I || ' ** IGNORED - NOT A PDS/LOADLIB **' Iterate End End /* when FIND1 = 0 */ End /* select */ If SYSUSED = 'N/A' then SYSEXTENTS = 1 /* PDS/E */ EXTENTS = EXTENTS + SYSEXTENTS EXT.I = SYSEXTENTS /* VOL.I = SYSVOLUME */ ALG = ALG + (16 * EXT.I) + 1 TOT.I = ALG EXTT.I = EXTENTS If Substr(FMIDNUM,4,4) < 6602 & , ALG > 2040 then LIB.I = LIB.I || ' ** IGNORED - ALG > 2040 **' Else if, EXTENTS > 255 then LIB.I = LIB.I || ' ** IGNORED - # EXT > 255 **' End /* do I = 1 to totlibs */ Return /* */ /* Subroutine to verify parmlib members */ /* */ MEMBER_CHECK: Arg CURMBR CHKMBR = Sysdsn('''SYS1.PARMLIB(' || CURMBR || ')''') If CHKMBR <> 'OK' then do Say 'UNABLE TO LOCATE SYS1.PARMLIB(' || CURMBR || ')' Exit 12 End Return /* */ /* Subroutine to read library members */ /* */ READ_FILE: Arg CURMBR "ALLOC DA('SYS1.PARMLIB("CURMBR")') F(LNKMEM) SHR REUSE" If RC <> 0 then exit 12 "EXECIO * DISKR LNKMEM (STEM INREC. FINIS" /* check for open error */ If RC <> 0 then do Say 'ERROR OPENING DATASET SYS1.PARMLIB('CURMBR').' Exit 12 End Return /* */ /* Subroutine to find comments at end of members */ /* */ FIND_COMMENTS: Do I = INREC.0 to 1 by -1 TEST = Word(INREC.I,1) If Index(TEST,'/*') = 0 then leave Else INREC.0 = INREC.0 - 1 End Return /* */ /* Subroutine to make sure last record in a */ /* member does not end in a comma and that all */ /* other records in a member does end in a comma. */ /* */ CHECK_COMMAS: NUMRECS = INREC.0 LASTREC = Substr(INREC.NUMRECS,1,71) LEN = Length(Strip(LASTREC,T)) TEST = Index(LASTREC,',',LEN) If TEST <> 0 then do Say 'LNKLST ERROR - THE LAST LIBRARY NAME (LINE' NUMRECS') DOES', 'NOT END IN A BLANK' Say '(MEMBER' CURMBR')' Say LASTREC Say 'VERIFICATION TERMINATED' Exit 12 End Do CHECK = 1 to NUMRECS - 1 REC = Substr(INREC.CHECK,1,71) Call CHECK_COMMENTS LEN = Length(Strip(REC,T)) TEST = Index(REC,',',LEN) If TEST = 0 then do Say 'LNKLST ERROR - MISSING CONTINUATION ON LINE' CHECK , '(MEMBER' CURMBR')' Say REC Say 'VERIFICATION TERMINATED' Exit 12 End End Return CHECK_COMMENTS: /****************************************/ /* Look for comments. If they are on */ /* the same line as other data, remove */ /* them. If the entire line is comments,*/ /* skip it. If there are not matching */ /* delimiters, flag it as an error. */ /****************************************/ If Pos('/*',REC) <> 0 then do If Pos('*/',REC) = 0 then do Say 'LNKLST ERROR - INVALID COMMENTS EXIST ON LINE' CHECK , '(MEMBER' CURMBR')' Say REC Say 'VERIFICATION TERMINATED' Exit 12 End /* remove comments from record */ SCOM = Pos('/*',REC) /* start col of comments */ ECOM = Pos('*/',REC) /* end col of cumments */ REC = Overlay(' ',REC,SCOM,ECOM) End If Pos('*/',REC) <> 0 then do If Pos('/*',REC) = 0 then do Say 'LNKLST ERROR - INVALID COMMENTS EXIST ON LINE' CHECK , '(MEMBER' CURMBR')' Say REC Say 'VERIFICATION TERMINATED' Exit 12 End End If Pos('*/',REC) <> 0 | , /* check for mult comments */ Pos('/*',REC) <> 0 then call CHECK_COMMENTS Return