! ----- PIGGY.BAS ----- ! ----- DISK QUOTA "DISK PIG" UTILITY ----- ! ----- Last Change 04/08/92 by Brian Lomasky ----- ! ----- Restrictions: 1) Requires VMS V5.0 or higher ----- ! ----- 2) Requires BASIC V3.0 or higher ----- ! ----- 3) Disk Quotas must be enabled on all ----- ! ----- disks that are being processed by PIGGY ----- ! ----- 4) Must be installed or executed with ----- ! ----- BYPASS privilege (or equiv) ----- ! ----- 5) Must be linked with GET_RMS_STATUS ----- ! ----- 6) The TOOLS logical must point to the ----- ! ----- directory where the PIGGY.DAT data file ----- ! ----- will reside ----- ! ----- EXITS WITH APPROPRIATE STATUS IF ANY SYSTEM ERROR OCCURS ----- ! ----- EXITS WITH %X10000002 IF ANY BASIC ERROR OCCURS ----- OPTION TYPE = EXPLICIT %LET %DEBUG = 0% ! 1 IF DEBUG ON, 0 IF NO DEBUG ON ERROR GOTO ERROR_ROUTINE %INCLUDE "$DCDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" %INCLUDE "$DVIDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" %INCLUDE "$FABDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" %INCLUDE "$LNMDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" %INCLUDE "$NAMDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB" ! ----- EXTERNAL CONSTANTS ----- EXTERNAL LONG CONSTANT SS$_IVDEVNAM ! INVALID DEVICE NAME EXTERNAL LONG CONSTANT SS$_IVIDENT ! INVALID IDENTIFIER FORMAT EXTERNAL LONG CONSTANT SS$_IVLOGNAM ! INVALID LOGICAL NAME EXTERNAL LONG CONSTANT SS$_NOLOGNAM ! NO LOGICAL NAME TRANSLATION EXTERNAL LONG CONSTANT SS$_NONLOCAL ! DEVICE IS ON A REMOTE SYSTEM EXTERNAL LONG CONSTANT SS$_NORMAL ! NORMAL EXIT STATUS EXTERNAL LONG CONSTANT SS$_NOSUCHDEV ! NO SUCH DEVICE EXTERNAL LONG CONSTANT SS$_NOSUCHID ! NO IDENTIFIER FOUND RECORD DVIBUF ! $GETDVIW RECORD WORD BUFFER_LENGTH1 WORD ITEM_CODE1 LONG BUFFER_ADDRESS1 LONG RETURN_LENGTH_ADDRESS1 WORD BUFFER_LENGTH2 WORD ITEM_CODE2 LONG BUFFER_ADDRESS2 LONG RETURN_LENGTH_ADDRESS2 WORD BUFFER_LENGTH3 WORD ITEM_CODE3 LONG BUFFER_ADDRESS3 LONG RETURN_LENGTH_ADDRESS3 LONG LIST_TERMINATOR END RECORD DVIBUF RECORD TRNBUF ! $TRNLNM RECORD WORD BUFFER_LENGTH1 WORD ITEM_CODE1 LONG BUFFER_ADDRESS1 LONG RETURN_LENGTH_ADDRESS1 LONG LIST_TERMINATOR END RECORD TRNBUF ! ----- DEFINE COMMON CONSTANTS ----- DECLARE WORD CONSTANT TRUE = (1% = 1%) DECLARE WORD CONSTANT FALSE = NOT TRUE ! ----- DEFINE VALUE TO BE USED WITH SYS$EXIT ----- DECLARE LONG CONSTANT ERR_NO_PUTMSG = X"10000002"L ! ----- DEFINE BASIC ERROR CODES ----- DECLARE WORD CONSTANT BUCKET_LOCKED = 154% DECLARE WORD CONSTANT CANNOT_OPEN_FILE = 162% DECLARE WORD CONSTANT DUPLICATE_KEY = 134% DECLARE WORD CONSTANT END_OF_FILE = 11% DECLARE WORD CONSTANT FILE_NOT_FOUND = 5% DECLARE WORD CONSTANT REC_NOT_FOUND = 155% ! ----- DEFINE PIGGY EXECUTION MODE CODES ----- DECLARE WORD CONSTANT COMPARE_MODE = 0% ! DEFINE PIGGY MODE DECLARE WORD CONSTANT UPDATE_MODE = 1% ! DEFINE PIGGY MODE DECLARE WORD CONSTANT INIT_MODE = 2% ! DEFINE PIGGY MODE ! ----- DEFINE MISCELLANEOUS STRING CONSTANTS ----- DECLARE STRING CONSTANT PIGGY_FORMAT1 = & "'LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL ###########" + & " ########### ########## 'LLLL" DECLARE STRING CONSTANT PIGGY_FORMAT2 = & "'LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL ###########" + & " ########## 'LLLL" DECLARE STRING CONSTANT SKIP_NAME = "%Skipping non-username: " ! ----- DEFINE PIGGY VARIABLES ----- DECLARE STRING CAPTIVE_USER ! "Y" IF RESTRICTED/CAPTIVE USER DECLARE STRING COMMAND_STRING ! FOREIGN DCL COMMAND STRING DECLARE WORD COMMAND_STRING_LEN ! LENGTH OF COMMAND_STRING DECLARE LONG DEC_DIV ! FOR DEC_TO_OCT FUNCTION DECLARE LONG DEC_INPUT ! FOR DEC_TO_OCT FUNCTION DECLARE LONG DEVICE_CLASS_LENGTH ! LENGTH OF DEVICE_CLASS DECLARE STRING DISK_WANTED ! DISK TO BE ACCESSED DECLARE STRING DISMAIL_USER ! "Y" IF USERNAME HAS DISMAIL DECLARE WORD DUMP_MODE ! TRUE TO DUMP DATA DECLARE DVIBUF DVIITEM ! EQUATE $GETDVIW RECORD DECLARE WORD ERROR_FLAG ! ERROR TRAP FLAG DECLARE STRING ERROR_LINE ! ERROR LINE DESCRIPTION DECLARE FABDEF FAB ! DEFINE THE FAB BLOCK DECLARE WORD FIRST_REC_WANTED ! TRUE TO READ WITH FIRST RECORD DECLARE STRING IDENT_TO_UPDATE ! SPECIFIC IDENT/USER TO UPDATE DECLARE WORD ID_NAME_LENGTH ! LENGTH OF ID_NAME DECLARE WORD INCLUDE_NEGATIVE_DIFF ! TRUE TO INCLUDE NEGATIVE DIFFS DECLARE WORD LOG_LENGTH ! LENGTH OF LOGICAL NAME DECLARE WORD MOUNTED_LENGTH ! MOUNTED DEVICE BUFFER LENGTH DECLARE NAMDEF NAM ! DEFINE THE NAM BLOCK DECLARE WORD NO_XLATE_UIC ! TRUE TO NOT TRANSLATE UIC DECLARE STRING NUMERIC_EDIT ! FOR NUMERIC FUNCTION DECLARE LONG NUMERIC_TEMP ! FOR NUMERIC FUNCTION DECLARE LONG OCT_OUTPUT ! FOR DEC_TO_OCT FUNCTION DECLARE STRING PIGGY_ARGUMENT ! PIGGY ARGUMENT SPECIFIED DECLARE LONG PIG_BLOCK_LIMIT ! BLOCK LIMIT FOR NO REPORT DECLARE WORD PIGGY_MODE ! MODE OF PIGGY EXECUTION DECLARE WORD PIG_PCT_LIMIT ! PCT LIMIT FOR NO REPORT DECLARE STRING PREV_DATE_TIME ! PREVIOUS DATE/TIME PIGGY RAN DECLARE STRING RJLB_STRING ! FOR RJLB FUNCTION DECLARE WORD SKIP_REPORT_LINE ! TRUE IF REPORT LINE SKIPPED DECLARE WORD SPACE_POS ! POSITION OF SPACE IN ARGUMENT DECLARE LONG SYS_STATUS ! SYSTEM SERVICE EXIT STATUS DECLARE STRING SYSUAF_FILE_SPEC ! SYSUAF/NETUAF TRANSLATIONS DECLARE WORD TEMP ! TEMPORARY WORD VARIABLE DECLARE LONG TEMP_LONG ! TEMPORARY LONGWORD VARIABLE DECLARE STRING TEMP_STRING ! TEMPORARY STRING VARIABLE DECLARE TRNBUF TRNITEM ! EQUATE $TRNLNM RECORD DECLARE LONG UIC_GROUP ! OCTAL UIC GROUP DECLARE LONG UIC_MEMBER ! OCTAL UIC MEMBER DECLARE STRING UIC_TO_STORE ! UIC TO PRINT ON THE REPORT DECLARE WORD UPDATED_IDENTIFIER ! TRUE IF IDENTIFIER WAS UPDATED DECLARE WORD USERS_MODE ! TRUE TO CREATE USERNAME OUTPUT DECLARE WORD USER_TYPE ! 1=USERNAME, 2=IDENT, 0=NEITHER DECLARE WORD VOLUME_NAME_LENGTH ! LENGTH OF VOLUME_NAME EXTERNAL LONG FUNCTION LIB$GET_FOREIGN ! GET FOREIGN DCL COMMAND STRING EXTERNAL LONG FUNCTION SYS$GETDVIW ! GET DEVICE INFORMATION/WAIT EXTERNAL LONG FUNCTION SYS$IDTOASC ! CONVERT IDENTIFIER TO ASCII EXTERNAL LONG FUNCTION SYS$PARSE ! $PARSE SYSTEM SERVICE EXTERNAL LONG FUNCTION SYS$SEARCH ! $SEARCH SYSTEM SERVICE EXTERNAL LONG FUNCTION SYS$TRNLNM ! TRANSLATE LOGICAL NAME ! ----- FIXED-LENGTH STRINGS PASSED TO/FROM RMS ----- MAP (FPARSE) STRING PASSED_SPEC = 255%, & STRING EXPANDED_SPEC = 255%, & STRING RESULT_SPEC = 255% MAP (GDVI) LONG MOUNTED, ! MOUNTED DEVICE? & LONG DEVICE_CLASS, ! DEVICE CLASS & STRING VOLUME_NAME = 12%! VOLUME NAME MAP (IDNAME) STRING ID_NAME = 32% ! IDENTIFIER NAME BUFFER ! ----- DEFINE MAP FOR PIGGY DATA FILE ----- MAP (PIGMAP) STRING PIG_DISK = 12%, ! PIGGY DISK STORAGE & STRING PIG_UIC = 32%, ! PIGGY UIC STORAGE & LONG PIG_BLOCKS ! PIGGY BLOCKS USED MAP (PIGMAP) STRING PIG_KEY = 44% ! PIGGY PRIMARY KEY ! ----- DEFINE MAP FOR DISK QUOTA DATA FILE ----- MAP (QUOMAP) LONG QUOTA_FLAG, ! DISK QUOTA FLAGS & LONG QUOTA_UIC, ! UIC & LONG QUOTA_USAGE, ! BLOCKS IN USE & LONG PERMQUOTA, ! PERMANENT QUOTA LIMIT & LONG OVERDRAFT, ! OVERDRAFT LIMIT & STRING FILL = 12% MAP (QUOMAP) LONG FILL, & WORD QUOTA_UIC_MEMBER, & WORD QUOTA_UIC_GROUP MAP (TRNLNM) STRING LOG_NAME = 255% ! LOGICAL NAME FROM $TRNLNM ! ----- MAP FOR SYSUAF.DAT DATA FILE ----- MAP (UAF) STRING UAF_REC = 1412% MAP (UAF) STRING FILL = 4%, & STRING USER_NAME_NO_TAG = 31%, & STRING FILL = 1%, & WORD OCT_UIC_MEMBER, & WORD OCT_UIC_GROUP MAP (UAF) STRING FILL = 4%, & ! ----- USER_NAME IS THE PRIMARY ----- & ! ----- KEY (NO DUPLICATES, NO ----- & ! ----- CHANGES) ----- & STRING USER_NAME = 32%, ! ALJTB & STRING FILL = 432%, & BYTE FLAGS(3%) ! ----- RIGHT-JUSTIFY/LEADING-ZEROS FUNCTION ----- DEF STRING RJLB(LONG RJLB_INPUT, LONG RJLB_LENGTH) RJLB_STRING = NUM1$(RJLB_INPUT) IF LEN(RJLB_STRING) < RJLB_LENGTH THEN RJLB=SPACE$(RJLB_LENGTH-LEN(RJLB_STRING))+RJLB_STRING ELSE RJLB=RJLB_STRING END IF RJLB_STRING = "" END DEF ! ----- DECIMAL-TO-OCTAL CONVERSION FUNCTION ----- DEF LONG DEC_TO_OCT(LONG DEC_UIC) DEC_INPUT = DEC_UIC OCT_OUTPUT = 0% FOR TEMP = 6% TO 0% STEP -1% DEC_DIV = INT(DEC_INPUT / 8^TEMP) IF DEC_DIV > 0% THEN OCT_OUTPUT = OCT_OUTPUT + 10^TEMP * DEC_DIV DEC_INPUT = DEC_INPUT - 8^TEMP * DEC_DIV END IF NEXT TEMP DEC_TO_OCT = OCT_OUTPUT END DEF ! ----- LOCAL FUNCTION THAT RETURNS TRUE IF THE PASSED ARGUMENT ----- ! ----- IS AN EXISTING FILESPEC ----- DEF WORD VALID_FILE(STRING FILE_SPEC) %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_FILE: file_spec="; file_spec %END %IF PASSED_SPEC = FILE_SPEC ! STORE PASSED FILE SPEC EXPANDED_SPEC = "" ! CLEAR EXPANDED FILE SPEC RESULT_SPEC = "" ! CLEAR RESULTING FILE SPEC %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_FILE: FAB" %END %IF ! ----- SET UP THE FAB BLOCK ----- FAB::FAB$B_BID = FAB$C_BID ! FAB BLOCK IDENTIFIER FAB::FAB$B_BLN = FAB$C_BLN ! FAB BLOCK LENGTH FAB::FAB$L_FNA = LOC(PASSED_SPEC) ! LOCATION OF PASSED FILE SPEC FAB::FAB$B_FNS = LEN(FILE_SPEC) ! LENGTH OF PASSED FILE SPEC FAB::FAB$L_NAM = LOC(NAM) ! LOCATION OF NAM BLOCK %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_FILE: NAM" %END %IF ! ----- SET UP THE NAM BLOCK ----- NAM::NAM$B_BID = NAM$C_BID ! NAM BLOCK IDENTIFIER NAM::NAM$B_BLN = NAM$C_BLN ! NAM BLOCK LENGTH IF NAM$C_MAXRSS > 127% THEN ! ----- SIZE OF RESULTING SPEC ----- NAM::NAM$B_RSS = NAM$C_MAXRSS - 256% ELSE ! ----- SIZE OF RESULTING SPEC ----- NAM::NAM$B_RSS = NAM$C_MAXRSS END IF NAM::NAM$L_RSA = LOC(RESULT_SPEC) ! LOCATION OF RESULTING SPEC IF NAM$C_MAXRSS > 127% THEN ! ----- SIZE OF EXPANDED SPEC ----- NAM::NAM$B_ESS = NAM$C_MAXRSS - 256% ELSE ! ----- SIZE OF EXPANDED SPEC ----- NAM::NAM$B_ESS = NAM$C_MAXRSS END IF NAM::NAM$L_ESA = LOC(EXPANDED_SPEC) ! LOCATION OF EXPANDED SPEC %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_FILE: sys$parse" %END %IF ERROR_LINE = "SYS$PARSE" SYS_STATUS = SYS$PARSE(FAB) ! GET INITIAL FILE INFORMATION IF (SYS_STATUS AND 1%) = 0% THEN %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_FILE: return false" %END %IF VALID_FILE = FALSE ! RETURN 0 (FALSE) IF ERROR ELSE ! ----- GET THE REST OF THE FILE INFORMATION ----- %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_FILE: sys$search" %END %IF ERROR_LINE = "SYS$SEARCH" SYS_STATUS = SYS$SEARCH(FAB) IF (SYS_STATUS AND 1%) = 0% THEN %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_FILE: return false" %END %IF ! ----- RETURN FALSE IF ERROR ----- VALID_FILE = FALSE ELSE %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_FILE: return true" %END %IF ! ----- RETURN TRUE IF SUCCESS ----- VALID_FILE = TRUE END IF END IF %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_FILE: exit" %END %IF END DEF ! ----- LOCAL FUNCTION THAT RETURNS TRUE IF THE PASSED ARGUMENT ----- ! ----- IS A VALID DISK DEVICE ----- DEF WORD VALID_DISK(STRING DISK_TO_USE) VALID_DISK = FALSE ! ASSUME ERROR STATUS EXIT DEF IF DISK_TO_USE = "" ! EXIT WITH ERROR IF NO ARGUMENT %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_DISK: disk_to_use="; disk_to_use %END %IF ! ----- GET DEVICE INFO FOR THE PASSED ARGUMENT ----- SYS_STATUS = SYS$GETDVIW(, , DISK_TO_USE, DVIITEM, , , , ) SELECT SYS_STATUS CASE SS$_NOSUCHDEV PRINT "ERROR -- Device " + DISK_TO_USE + & " does not exist" + BEL EXIT DEF ! EXIT WITH ERROR STATUS CASE SS$_NONLOCAL PRINT "ERROR -- Device " + DISK_TO_USE + & " is on a remote system" + BEL EXIT DEF ! EXIT WITH ERROR STATUS CASE SS$_IVDEVNAM, SS$_IVLOGNAM PRINT "ERROR -- Invalid Device: " + DISK_TO_USE + BEL EXIT DEF ! EXIT WITH ERROR STATUS CASE SS$_NORMAL CASE ELSE PRINT "Error from SYS$GETDVIW:" + BEL CALL LIB$STOP(SYS_STATUS BY VALUE) END SELECT IF DEVICE_CLASS <> DC$_DISK THEN! ENSURE A DISK DEVICE PRINT "ERROR -- Device " + DISK_TO_USE + & " is not a disk" + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF IF MOUNTED = 0% THEN PRINT "ERROR -- Device " + DISK_TO_USE + & " is not mounted" + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF IF VOLUME_NAME_LENGTH = 0% THEN PRINT "ERROR -- Disk " + DISK_TO_USE + & " has no volume name" + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF IF LEFT(VOLUME_NAME, VOLUME_NAME_LENGTH) = "" THEN PRINT "ERROR -- Disk " + DISK_TO_USE + & " has no volume name" + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF ! ----- ERROR IF QUOTA FILE DOES NOT EXIST ON THE DISK ----- TEMP_STRING = DISK_TO_USE + "[000000]QUOTA.SYS" %IF %DEBUG = 1% %THEN PRINT "DEBUG>VALID_DISK: temp_string="; temp_string %END %IF ERROR_LINE = "VALID_DISK: temp_string=>" + temp_string + "<" IF NOT VALID_FILE(TEMP_STRING) THEN PRINT "ERROR -- Device " + DISK_TO_USE + & " does not have quotas enabled" + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF ERROR_LINE = "EXIT VALID_DISK" VALID_DISK = TRUE ! RETURN SUCCESS STATUS END DEF ! ----- LOCAL FUNCTION TO READ MATCHING PIGGY RECORD ----- ! ----- RETURNS TRUE IF MATCH, FALSE IF NO MATCH ----- DEF WORD LOCATE_PIGGY_REC LOCATE_PIGGY_REC = FALSE ! ASSUME ERROR STATUS ON ERROR GOTO LOCATE_PIGGY_REC_ERR %IF %DEBUG = 1% %THEN PRINT "DEBUG>search PIGGY for:" PRINT "*"; PIG_KEY; "*" %END %IF GET #2%, KEY #0% EQ PIG_KEY %IF %DEBUG = 1% %THEN PRINT "DEBUG>found matching PIGGY rec" %END %IF LOCATE_PIGGY_REC = TRUE ! RETURN SUCCESS STATUS EXIT DEF LOCATE_PIGGY_REC_ERR: IF ERR = BUCKET_LOCKED THEN SLEEP 1% RESUME END IF RESUME LOCATE_PIGGY_REC_EXIT IF ERR = REC_NOT_FOUND OR & ERR = END_OF_FILE ON ERROR GO BACK LOCATE_PIGGY_REC_EXIT: %IF %DEBUG = 1% %THEN PRINT "DEBUG>NO matching PIGGY rec" %END %IF END DEF ! ----- LOCAL FUNCTION TO CALCULATE THE PERCENT DIFFERENCE IN ----- ! ----- BLOCKS USED BETWEEN THE CURRENT AND THE PREVIOUS DISK ----- ! ----- USAGE ----- DEF LONG CALC_PERCENTAGE_DIFF ON ERROR GOTO CALC_PERCENTAGE_DIFF_ERR IF PIG_BLOCKS = 0% THEN IF QUOTA_USAGE = 0% THEN CALC_PERCENTAGE_DIFF = 0% ELSE CALC_PERCENTAGE_DIFF = 999% END IF ELSE TEMP_LONG = (QUOTA_USAGE - PIG_BLOCKS) / & (PIG_BLOCKS / 100%) TEMP_LONG = 999% IF TEMP_LONG > 999% TEMP_LONG = -999% IF TEMP_LONG < -999% CALC_PERCENTAGE_DIFF = TEMP_LONG END IF EXIT DEF CALC_PERCENTAGE_DIFF_ERR: RESUME CALC_PERCENTAGE_DIFF_EXIT CALC_PERCENTAGE_DIFF_EXIT: ! ----- ASSUME INTEGER OVERFLOW ERROR OCCURRED ----- IF QUOTA_USAGE >= PIG_BLOCKS THEN CALC_PERCENTAGE_DIFF = 999% ELSE CALC_PERCENTAGE_DIFF = -999% END IF END DEF ! ----- LOCAL FUNCTION TO CHECK FOR NUMERIC DATA ----- ! ----- (RETURNS TRUE IF PASSED STRING CONTAINS ONLY NUMERIC DATA) ----- DEF WORD NUMERIC(STRING VALUE_TO_TEST) ! ----- REMOVE ANY SPACES ----- NUMERIC_EDIT = EDIT$(VALUE_TO_TEST, 136%) IF LEN(NUMERIC_EDIT) > 0% THEN NUMERIC = TRUE FOR NUMERIC_TEMP = 1% TO LEN(NUMERIC_EDIT) NUMERIC = FALSE IF POS("0123456789", & MID(NUMERIC_EDIT, NUMERIC_TEMP, & 1%), 1%) = 0% NEXT NUMERIC_TEMP ELSE NUMERIC = FALSE END IF END DEF ! ----- LOCAL FUNCTION TO READ THE SYSUAF FILE FOR A USERNAME ----- ! ----- RETURNS FALSE IF PASSED USERNAME MATCHES A SYSUAF RECORD ----- DEF WORD READ_UAF(STRING USERNAME_TO_CHECK) READ_UAF = TRUE ! ASSUME ERROR STATUS ON ERROR GOTO READ_UAF_ERROR ! ----- SEE IF USER NAME CAN NOT BE IN THE SYSUAF FILE ----- EXIT DEF IF LEN(TRM$(USERNAME_TO_CHECK)) = 0% EXIT DEF IF POS(TRM$(USERNAME_TO_CHECK), " ", 1%) > 0% EXIT DEF IF POS(USERNAME_TO_CHECK, ".", 1%) > 0% USER_NAME = USERNAME_TO_CHECK GET #9%, KEY #0% GE USER_NAME, REGARDLESS EXIT DEF IF TRM$(USER_NAME_NO_TAG) <> TRM$(USERNAME_TO_CHECK) ! ----- INVALID USERNAME IF ACCOUNT IS DISUSER-ED ----- ! ----- (DISACNT) ----- EXIT DEF IF (FLAGS(0%) AND 16%) = 16% READ_UAF = FALSE ! RETURN SUCCESS STATUS EXIT DEF ! AND EXIT FUNCTION READ_UAF_ERROR: IF ERR = BUCKET_LOCKED THEN ! IF BUCKET IS LOCKED? SLEEP 15% RESUME END IF RESUME READ_UAF_EXIT IF ERR = REC_NOT_FOUND OR ERR = END_OF_FILE PRINT "Unexpected error from READ_UAF"; ERR; TIME$(0%) ON ERROR GO BACK READ_UAF_EXIT: END DEF ! ----- LOCAL FUNCTION THAT RETURNS TRUE IF THE PASSED ARGUMENT ----- ! ----- IS A VALID PCTnnn ARGUMENT ----- DEF WORD VALID_PERCENT(STRING PCT_TO_USE) VALID_PERCENT = FALSE ! ASSUME ERROR STATUS ! ----- ERROR IF ARGUMENT IS TOO LONG ----- IF LEN(PCT_TO_USE) < 4% OR LEN(PCT_TO_USE) > 6% THEN PRINT "Error - Percentage argument is out" + & " of range: " + PCT_TO_USE + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF ! ----- EXTRACT (SUPPOSED) NUMERIC PERCENTAGE CHARS ----- TEMP_STRING = RIGHT(PCT_TO_USE, 4%) ! ----- ERROR IF ARGUMENT IS NON-NUMERIC ----- IF NOT NUMERIC(TEMP_STRING) THEN PRINT "Error - Percentage argument is" + & " non-numeric: " + PCT_TO_USE + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF ! ----- CONVERT TO LONGWORD ----- TEMP_LONG = INTEGER(TEMP_STRING, LONG) ! ----- ERROR IF ARGUMENT IS OUT OF RANGE ----- IF TEMP_LONG < 0% OR TEMP_LONG > 999% THEN PRINT "Error - Percentage argument is out" + & " of range: " + PCT_TO_USE + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF PIG_PCT_LIMIT = TEMP_LONG ! STORE PERCENTAGE LIMIT VALID_PERCENT = TRUE ! RETURN SUCCESS STATUS END DEF ! ----- LOCAL FUNCTION THAT RETURNS TRUE IF THE PASSED ARGUMENT ----- ! ----- IS A VALID UPDATE= ARGUMENT ----- DEF WORD VALID_IDENT(STRING THE_USER) VALID_IDENT = FALSE ! ASSUME ERROR STATUS ! ----- ERROR IF ARGUMENT IS TOO LONG ----- IF LEN(THE_USER) < 8% OR LEN(THE_USER) > 19% THEN PRINT "Error - UPDATE= argument is" + & " out of range: " + THE_USER + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF ! ----- EXTRACT (SUPPOSED) IDENTIFIER CHARS ----- TEMP_STRING = RIGHT(THE_USER, 8%) ! ----- PRINT WARNING IF IDENTIFIER IS NOT A USERNAME ----- IF READ_UAF(TEMP_STRING) THEN PRINT "Warning: " + TEMP_STRING + & " is not an existing username" END IF PIGGY_MODE = UPDATE_MODE ! STORE REQUESTED MODE IDENT_TO_UPDATE = TEMP_STRING ! STORE IDENT/USERNAME TO UPDATE INCLUDE_NEGATIVE_DIFF = TRUE ! ALSO INCLUDE NEGATIVE DIFFS VALID_IDENT = TRUE ! RETURN SUCCESS STATUS END DEF ! ----- LOCAL FUNCTION THAT RETURNS TRUE IF THE PASSED ARGUMENT ----- ! ----- IS A VALID BLOCKn ARGUMENT ----- DEF WORD VALID_BLOCK(STRING BLOCK_TO_USE) VALID_BLOCK = FALSE ! ASSUME ERROR STATUS ! ----- ERROR IF ARGUMENT IS TOO LONG ----- IF LEN(BLOCK_TO_USE) < 6% OR LEN(BLOCK_TO_USE) > 14% THEN PRINT "Error - Disk Block argument is out" + & " of range: " + BLOCK_TO_USE + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF ! ----- EXTRACT (SUPPOSED) NUMERIC DISK BLOCK CHARS ----- TEMP_STRING = RIGHT(BLOCK_TO_USE, 6%) ! ----- ERROR IF ARGUMENT IS NON-NUMERIC ----- IF NOT NUMERIC(TEMP_STRING) THEN PRINT "Error - Disk Block argument is" + & " non-numeric: " + BLOCK_TO_USE + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF ! ----- CONVERT TO LONGWORD ----- TEMP_LONG = INTEGER(TEMP_STRING, LONG) ! ----- ERROR IF ARGUMENT IS OUT OF RANGE ----- IF TEMP_LONG < 0% OR TEMP_LONG > 999999999% THEN PRINT "Error - Disk Block argument is out" + & " of range: " + BLOCK_TO_USE + BEL EXIT DEF ! EXIT WITH ERROR STATUS END IF PIG_BLOCK_LIMIT = TEMP_LONG ! STORE DISK BLOCK LIMIT VALID_BLOCK = TRUE ! RETURN SUCCESS STATUS END DEF ! ----- LOCAL FUNCTION TO LOCATE THE LAST UPDATE DATE/TIME OF ----- ! ----- PIGGY'S DATA FILE (RETURNS "" IF NO ----- ! ----- LAST DATE/TIME FOUND) ----- DEF WORD LOCATE_LAST_UPDATE_DATE_TIME ON ERROR GOTO LOCATE_LAST_UPDATE_ERR ! ----- ALWAYS RETURN ZERO ----- LOCATE_LAST_UPDATE_DATE_TIME = 0% GET #2%, KEY #0% GE "............", REGARDLESS IF PIG_DISK <> "............" THEN %IF %DEBUG = 1% %THEN PRINT "DEBUG>no date found" %END %IF PREV_DATE_TIME = "" EXIT DEF END IF %IF %DEBUG = 1% %THEN PRINT "DEBUG>found date: "; TRM$(PIG_UIC) %END %IF PREV_DATE_TIME = TRM$(PIG_UIC) EXIT DEF LOCATE_LAST_UPDATE_ERR: IF ERR = BUCKET_LOCKED THEN SLEEP 1% RESUME END IF RESUME LOCATE_LAST_UPDATE_EXIT IF ERR = REC_NOT_FOUND & OR ERR = END_OF_FILE ON ERROR GO BACK LOCATE_LAST_UPDATE_EXIT: PREV_DATE_TIME = "" %IF %DEBUG = 1% %THEN PRINT "DEBUG>no date found" %END %IF END DEF ! ----- LOCAL FUNCTION TO UPDATE THE "LAST UPDATE DATE/TIME" ----- ! ----- IN THE DATA FILE ----- DEF WORD UPDATE_LAST_DATE_TIME ON ERROR GOTO UPDATE_LAST_DATE_TIME_ERR UPDATE_LAST_DATE_TIME = 0% ! ALWAYS RETURN ZERO TEMP = 0% ! INIT RETRY COUNTER UPDATE_LAST_DATE_TIME_DUPL: TEMP = TEMP + 1% ! INCREMENT RETRY COUNTER ! ----- DELETE ANY EXISTING DATE/TIME RECORD(S) ----- FIND #2%, KEY #0% GE "............" GET #2% WHILE PIG_DISK = "............" DELETE #2% GET #2% NEXT UNLOCK #2% UPDATE_LAST_DATE_TIME_ADD: ! ----- STORE NEW DATE/TIME ----- PIG_DISK = "............" PIG_UIC = DATE$(0%) + " " + TIME$(0%) PIG_BLOCKS = 0% PUT #2% %IF %DEBUG = 1% %THEN PRINT "DEBUG>stored date: "; pig_key %END %IF EXIT DEF UPDATE_LAST_DATE_TIME_ERR: RESUME UPDATE_LAST_DATE_TIME_ADD IF ERR = REC_NOT_FOUND & OR ERR = END_OF_FILE RESUME UPDATE_LAST_DATE_TIME_DUPL & IF ERR = DUPLICATE_KEY AND TEMP < 2% RESUME UPDATE_LAST_DATE_TIME_EXIT UPDATE_LAST_DATE_TIME_EXIT: END DEF ! ----- LOCAL FUNCTION TO READ THE FIRST/NEXT PIGGY.DAT RECORD ----- ! ----- USUALLY RETURNS FALSE, RETURNS TRUE AT END-OF-FILE ----- DEF WORD READ_NEXT_PIGGY_RECORD(WORD FIRST_RECORD_WANTED) READ_NEXT_PIGGY_RECORD = TRUE ! ASSUME END-OF-FILE ON ERROR GOTO READ_NEXT_PIGGY_RECORD_ERR FIND #2%, KEY #0% GE " ", REGARDLESS IF FIRST_RECORD_WANTED GET #2%, REGARDLESS WHILE PIG_DISK = "............" GET #2%, REGARDLESS NEXT %IF %DEBUG = 1% %THEN PRINT "DEBUG>found piggy key: "; PIG_KEY %END %IF READ_NEXT_PIGGY_RECORD = FALSE ! RETURN SUCCESS STATUS EXIT DEF READ_NEXT_PIGGY_RECORD_ERR: RESUME IF ERR = BUCKET_LOCKED RESUME READ_NEXT_PIGGY_RECORD_EXIT IF ERR = END_OF_FILE & OR ERR = REC_NOT_FOUND ON ERROR GO BACK READ_NEXT_PIGGY_RECORD_EXIT: END DEF ERROR_LINE = "INIT" DVIITEM::BUFFER_LENGTH1 = 4% ! STORE DATA FOR $GETDVIW DVIITEM::ITEM_CODE1 = DVI$_MOUNTCNT DVIITEM::BUFFER_ADDRESS1 = LOC(MOUNTED) DVIITEM::RETURN_LENGTH_ADDRESS1 = LOC(MOUNTED_LENGTH) DVIITEM::BUFFER_LENGTH2 = 4% DVIITEM::ITEM_CODE2 = DVI$_DEVCLASS DVIITEM::BUFFER_ADDRESS2 = LOC(DEVICE_CLASS) DVIITEM::RETURN_LENGTH_ADDRESS2 = LOC(DEVICE_CLASS_LENGTH) DVIITEM::BUFFER_LENGTH3 = 12% DVIITEM::ITEM_CODE3 = DVI$_VOLNAM DVIITEM::BUFFER_ADDRESS3 = LOC(VOLUME_NAME) DVIITEM::RETURN_LENGTH_ADDRESS3 = LOC(VOLUME_NAME_LENGTH) DVIITEM::LIST_TERMINATOR = 0% ERROR_FLAG = 0% ! INIT ERROR TRAP FLAG PRINT "Disk Piggy Utility V1.1" %IF %DEBUG = 1% %THEN PRINT "DEBUG>get foreign" %END %IF ! ----- GET ANY FOREIGN DCL COMMAND STRING ----- ERROR_LINE = "GET_FOREIGN" SYS_STATUS = LIB$GET_FOREIGN(COMMAND_STRING,, COMMAND_STRING_LEN) IF SYS_STATUS <> SS$_NORMAL THEN PRINT "Error from LIB$GET_FOREIGN:" + BEL CALL LIB$STOP(SYS_STATUS BY VALUE) END IF IF COMMAND_STRING_LEN = 0% THEN PRINT "Error - No arguments specified. Valid arguments are:" PRINT PRINT " dddd = (where dddd=any disk" + & " name) Specifies disk to be reported on" PRINT " PCTnnn = (where nnn=0 to 100)" + & " Specifies smallest percent change in" PRINT " disk space usage that" + & " you want to appear on the report" PRINT " (Default of 20%)" PRINT " BLOCKn = (where n=0 to 999999999)" + & " Specifies smallest number of" PRINT " different disk blocks" + & " used that you want to appear on the" PRINT " report (Default of 1000)" PRINT " NEG = Also print any negative" + & " disk block differences" PRINT " NOXLATE = No uic-to-identifier" + & " translation is to be performed" PRINT PRINT " ----- Special" + & " Restricted Qualifiers Follow: -----" PRINT " UPDATE = Compare PIGGY values" + & " and then update the PIGGY database" PRINT " for all users" PRINT " UPDATE=ident = Compare PIGGY values" + & " and then update the PIGGY database" PRINT " with the info only for" + & " the specified identifier/username" PRINT " (The above 2 options not" + & " allowed with DUMP or NOXLATE)" PRINT " INIT = Initialize the PIGGY" + & " database with current disk quota values" PRINT " USERS = Create report containing" + & " list of usernames, block size diff," PRINT " and captive/dismail/ident" + & " flags, for existing PIGGY users" PRINT " (This option not" + & " allowed with INIT, DUMP, NEG, or NOXLATE)" ! ----- EXIT WITH %X10000002 $STATUS ----- CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) END IF ! ----- EXTRACT COMMAND STRING ARGUMENTS WITH EDITING: ----- ! ----- 1) REMOVE ALL LEADING AND TRAILING SPACES AND TABS ----- ! ----- 2) REMOVE ALL CONTROL CHARACTERS ----- ! ----- 3) CHANGE MULTIPLE SPACES AND TABS TO ONE SPACE ----- ! ----- 4) UPPERCASE ALL LOWER-CASE CHARACTERS ----- ! ----- 5) APPEND A SINGLE SPACE TO THE END OF THE STRING ----- COMMAND_STRING = & EDIT$(LEFT(COMMAND_STRING, COMMAND_STRING_LEN), 188%) + " " PIGGY_MODE = COMPARE_MODE ! ASSUME COMPARE MODE DISK_WANTED = "" ! ASSUME NO DISK SPECIFIED PIG_PCT_LIMIT = 20% ! ASSUME 20% LIMIT FOR NO REPORT PIG_BLOCK_LIMIT = 1000% ! ASSUME 1000 DISK BLOCK LIMIT DUMP_MODE = FALSE ! ASSUME NO DATA DUMP INCLUDE_NEGATIVE_DIFF = FALSE ! ASSUME NO NEGATIVE DIFFS NO_XLATE_UIC = FALSE ! ASSUME UIC TRANSLATION USERS_MODE = FALSE ! ASSUME NORMAL OUTPUT IDENT_TO_UPDATE = "" ! ASSUME NO IDENT/USER TO UPDATE UPDATED_IDENTIFIER = FALSE ! INIT "UPDATED IDENTIFIER" FLAG %IF %DEBUG = 1% %THEN PRINT "DEBUG>open sysuaf data file" %END %IF TRNITEM::BUFFER_LENGTH1 = 255% ! STORE DATA FOR $TRNLNM TRNITEM::ITEM_CODE1 = LNM$_STRING TRNITEM::BUFFER_ADDRESS1 = LOC(LOG_NAME) TRNITEM::RETURN_LENGTH_ADDRESS1 = LOC(LOG_LENGTH) TRNITEM::LIST_TERMINATOR = 0% ! ----- TRANSLATE ANY SYSUAF LOGICAL NAME ----- SYS_STATUS = SYS$TRNLNM(, "LNM$DCL_LOGICAL", "SYSUAF", , TRNITEM) SELECT SYS_STATUS CASE SS$_NOLOGNAM ! IF NO LOGICAL EQUIVALENT: SYS_STATUS = SS$_NORMAL ! CLEAR SYS_STATUS ERROR CONDITION SYSUAF_FILE_SPEC = "SYS$SYSTEM:SYSUAF.DAT" CASE SS$_NORMAL ! ----- EXTRACT LOGICAL NAME ----- IF LOG_LENGTH > 1% THEN SYSUAF_FILE_SPEC = LEFT(LOG_NAME, LOG_LENGTH) ELSE SYSUAF_FILE_SPEC = "SYS$SYSTEM:SYSUAF.DAT" END IF END SELECT ERROR_LINE = " trying to open " + SYSUAF_FILE_SPEC ERROR_FLAG = 5% ! SET FOR "OPENING SYSUAF FILE" OPEN SYSUAF_FILE_SPEC FOR INPUT AS FILE #9%, & RECORDSIZE 1412%, & ACCESS READ, & ALLOW MODIFY, & INDEXED VARIABLE, & MAP UAF, & RECORDTYPE ANY ERROR_FLAG = 0% ! INIT ERROR TRAP FLAG %IF %DEBUG = 1% %THEN PRINT "DEBUG>parse" %END %IF ! ----- PARSE COMMAND STRING FOR ARGUMENTS ----- SPACE_POS = POS(COMMAND_STRING, " ", 1%) WHILE SPACE_POS <> 0% IF SPACE_POS = 1% THEN ! DONE IF SPACE AT START OF LINE SPACE_POS = 0% ! SET TO EXIT LOOP ITERATE ! EXIT LOOP END IF %IF %DEBUG = 1% %THEN PRINT "DEBUG>command_string=>"; command_string; "<=" PRINT "DEBUG>space_pos="; space_pos %END %IF ! ----- EXTRACT NEXT PARAMETER ----- PIGGY_ARGUMENT = LEFT(COMMAND_STRING, SPACE_POS - 1%) COMMAND_STRING = RIGHT(COMMAND_STRING, SPACE_POS + 1%) ! ----- LOCATE NEXT SPACE IN STRING ----- SPACE_POS = POS(COMMAND_STRING, " ", 1%) %IF %DEBUG = 1% %THEN PRINT "DEBUG>next command_string=>"; & command_string; "<=" PRINT "DEBUG>next space_pos="; space_pos, & " piggy_argument="; piggy_argument %END %IF ! ----- SEE IF USER WANTS PIGGY TO RUN IN UPDATE MODE ----- IF PIGGY_ARGUMENT = "UPDATE" THEN PIGGY_MODE = UPDATE_MODE! STORE REQUESTED MODE ITERATE END IF ! ----- SEE IF USER WANTS TO INCLUDE NEGATIVE DIFFERENCES ----- IF PIGGY_ARGUMENT = "NEG" THEN INCLUDE_NEGATIVE_DIFF = TRUE ITERATE END IF ! ----- SEE IF USER DOES NOT WANT TO TRANSLATE UICS ----- IF PIGGY_ARGUMENT = "NOXLATE" THEN NO_XLATE_UIC = TRUE ITERATE END IF ! ----- SEE IF USER WANTS PIGGY TO RUN IN INIT MODE ----- IF PIGGY_ARGUMENT = "INIT" THEN PIGGY_MODE = INIT_MODE ! STORE REQUESTED MODE ITERATE END IF ! ----- SEE IF USER WANTS PIGGY TO RUN IN DUMP MODE ----- IF PIGGY_ARGUMENT = "DUMP" THEN DUMP_MODE = TRUE ! SET FOR DATA DUMP MODE ITERATE END IF ! ----- SEE IF USER WANTS PIGGY TO CREATE A SPECIAL ----- ! ----- USERNAME REPORT ----- IF PIGGY_ARGUMENT = "USERS" THEN USERS_MODE = TRUE ! CREATE USERNAME,BLOCKS OUTPUT ITERATE END IF ! ----- SEE IF USER WANTS TO CHANGE PIGGY PERCENT LIMIT ----- IF LEFT(PIGGY_ARGUMENT, 3%) = "PCT" THEN IF NOT VALID_PERCENT(PIGGY_ARGUMENT) THEN ! ----- (VALID_PERCENT WILL PRINT ITS ----- ! ----- OWN ERROR MSGS) ----- CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) END IF ITERATE END IF ! ----- SEE IF USER WANTS TO UPDATE DATA ONLY FOR 1 USER ----- IF LEFT(PIGGY_ARGUMENT, 7%) = "UPDATE=" THEN IF NOT VALID_IDENT(PIGGY_ARGUMENT) THEN ! ----- (VALID_IDENT WILL PRINT ITS ----- ! ----- OWN ERROR MSGS) ----- CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) END IF ITERATE END IF ! ----- SEE IF USER WANTS TO CHANGE PIGGY BLOCK LIMIT ----- IF LEFT(PIGGY_ARGUMENT, 5%) = "BLOCK" THEN IF NOT VALID_BLOCK(PIGGY_ARGUMENT) THEN ! ----- (VALID_BLOCK WILL PRINT ITS ----- ! ----- OWN ERROR MSGS) ----- CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) END IF ITERATE END IF ! ----- ENSURE PIGGY ARGUMENT ENDS WITH A COLON ----- PIGGY_ARGUMENT = PIGGY_ARGUMENT + ":" & IF RIGHT(PIGGY_ARGUMENT, LEN(PIGGY_ARGUMENT)) <> ":" ! ----- THE ONLY OTHER VALID PARAMETER IS A DISK DEVICE ----- IF VALID_DISK(PIGGY_ARGUMENT) THEN DISK_WANTED = PIGGY_ARGUMENT ELSE ! ----- (VALID_DISK WILL PRINT ITS OWN ERROR MSGS) ----- CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) END IF NEXT ! ----- CHECK FOR OPTIONS INCOMPATIBLE WITH UPDATE MODE ----- IF PIGGY_MODE = UPDATE_MODE THEN IF DUMP_MODE OR NO_XLATE_UIC THEN PRINT PRINT "Error - Invalid option(s)" + & " specified with UPDATE" ! ----- EXIT WITH %X10000002 $STATUS ----- CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) END IF END IF ! ----- CHECK FOR OPTIONS INCOMPATIBLE WITH "USERS" ----- IF USERS_MODE THEN IF PIGGY_MODE = INIT_MODE OR DUMP_MODE OR & INCLUDE_NEGATIVE_DIFF OR NO_XLATE_UIC THEN PRINT PRINT "Error - Invalid option(s)" + & " specified with USERS" ! ----- EXIT WITH %X10000002 $STATUS ----- CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) END IF END IF %IF %DEBUG = 1% %THEN PRINT "DEBUG>after parse" %END %IF IF DISK_WANTED = "" THEN ! ERROR IF NO DISK SPECIFIED PRINT PRINT "Error - No disk parameter was specified" + BEL ! ----- EXIT WITH %X10000002 $STATUS ----- CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) END IF ERROR_LINE = "OPEN QUOTA FILE" TEMP_STRING = DISK_WANTED + "[000000]QUOTA.SYS" ERROR_FLAG = 1% ! SET FOR "OPENING QUOTA FILE" OPEN TEMP_STRING FOR INPUT AS FILE #1%, SEQUENTIAL, & ACCESS READ, ALLOW MODIFY, RECORDTYPE ANY, MAP QUOMAP, & USEROPEN GET_RMS_STATUS ERROR_FLAG = 0% ! INIT ERROR TRAP FLAG %IF %DEBUG = 1% %THEN PRINT "DEBUG>open piggy data file" %END %IF ! ----- OPEN DATA FILES DEPENDING ON THE REQUESTED EXECUTION MODE ----- SELECT PIGGY_MODE CASE COMPARE_MODE, UPDATE_MODE ERROR_FLAG = 3% ! SET FOR "OPENING PIGGY FILE" OPEN "TOOLS:PIGGY.DAT" FOR INPUT AS FILE #2%, & INDEXED FIXED, & ACCESS MODIFY, & ALLOW MODIFY, & PRIMARY KEY PIG_KEY, & MAP PIGMAP ! PIGGY DATA STORAGE FILE ERROR_FLAG = 4% ! SET FOR "OPENING PIG.LIS FILE" OPEN "PIG.LIS" FOR OUTPUT AS FILE #10%, SEQUENTIAL ERROR_FLAG = 0% ! INIT ERROR TRAP FLAG IF NOT USERS_MODE THEN ! SEE IF NORMAL OUTPUT TEMP = LOCATE_LAST_UPDATE_DATE_TIME PRINT #10%, "PIGGY Report for " + DISK_WANTED + & " on " + DATE$(0%) + " " + TIME$(0%) + & " (" + NUM1$(PIG_PCT_LIMIT) + & "% limit, " + NUM1$(PIG_BLOCK_LIMIT) + & " blocks)" PRINT #10%, TAB(LEN(DISK_WANTED) + 4%); & "(Last update was " + PREV_DATE_TIME + ")"; IF INCLUDE_NEGATIVE_DIFF THEN PRINT #10% ! END DETAIL LINE ELSE PRINT #10%, TAB(LEN(DISK_WANTED) + 4%); & "(Skipping negative diffs)" END IF IF IDENT_TO_UPDATE <> "" THEN PRINT #10%, TAB(LEN(DISK_WANTED) + 4%); & "(Updating only: " + & IDENT_TO_UPDATE + ")" END IF PRINT #10% PRINT #10%, " " + & " Curr-Usage Prev-Usage Difference %Diff" END IF CASE INIT_MODE ERROR_FLAG = 2% ! SET FOR "OPENING PIGGY FILE" OPEN "TOOLS:PIGGY.DAT" FOR OUTPUT AS FILE #2%, & INDEXED FIXED, & ACCESS MODIFY, & ALLOW MODIFY, & PRIMARY KEY PIG_KEY, & MAP PIGMAP ! PIGGY DATA STORAGE FILE ERROR_FLAG = 0% ! INIT ERROR TRAP FLAG END SELECT %IF %DEBUG = 1% %THEN PRINT "DEBUG>see if dump" %END %IF ! ----- SEE IF DUMPING PIGGY DATA FILE ----- IF DUMP_MODE THEN SELECT PIGGY_MODE CASE COMPARE_MODE, UPDATE_MODE PRINT #10%, "===> Dump of TOOLS:PIGGY.DAT follows:" CASE INIT_MODE PRINT "===> Dump of TOOLS:PIGGY.DAT follows:" END SELECT FIRST_REC_WANTED = TRUE ! SET TO READ WITH FIRST RECORD WHILE NOT READ_NEXT_PIGGY_RECORD(FIRST_REC_WANTED) FIRST_REC_WANTED = FALSE! SET TO READ WITH NEXT RECORD ! ----- SKIP IF NON-MATCHING VOLUME NAME ----- ITERATE IF PIG_DISK <> & LEFT(VOLUME_NAME, VOLUME_NAME_LENGTH) SELECT PIGGY_MODE CASE COMPARE_MODE, UPDATE_MODE PRINT #10%, PIG_DISK; " "; PIG_UIC; & " "; PIG_BLOCKS CASE INIT_MODE PRINT PIG_DISK; " "; PIG_UIC; " "; PIG_BLOCKS END SELECT NEXT SELECT PIGGY_MODE CASE COMPARE_MODE, UPDATE_MODE PRINT #10%, "===> Dump of [000000]QUOTA.SYS follows:" CASE INIT_MODE PRINT "===> Dump of [000000]QUOTA.SYS follows:" END SELECT ELSE ! ----- UPDATE THE "LAST UPDATE DATE/TIME" IN THE DATA ----- ! ----- FILE ----- SELECT PIGGY_MODE CASE UPDATE_MODE, INIT_MODE TEMP = UPDATE_LAST_DATE_TIME END SELECT END IF %IF %DEBUG = 1% %THEN PRINT "DEBUG>read next quota rec" %END %IF ! ----- STORE VOLUME NAME OF PIGGY DISK TO BE ACCESSED ----- PIG_DISK = LEFT(VOLUME_NAME, VOLUME_NAME_LENGTH) READ_NEXT_QUOTA_REC: WHILE TRUE ERROR_LINE = "READ NEXT QUOTA REC" GET #1% ITERATE IF QUOTA_FLAG = 0% ! SKIP IF QUOTA NOT ACTIVE %IF %DEBUG = 1% %THEN PRINT "DEBUG>quota_uic="; quota_uic_group, & quota_uic_member %END %IF ! ----- SEE IF USER DOES NOT WANT TO TRANSLATE UICS ----- IF NO_XLATE_UIC THEN SYS_STATUS = SS$_NOSUCHID ELSE ! ----- SEE IF THERE IS AN IDENTIFIER FOR THIS ----- ! ----- UIC VALUE ----- SYS_STATUS = SYS$IDTOASC(QUOTA_UIC BY VALUE, & ID_NAME_LENGTH, ID_NAME,,,) END IF USER_TYPE = 0% ! ASSUME INVALID IDENTIFIER SELECT SYS_STATUS CASE SS$_NORMAL IF QUOTA_UIC >= 0% THEN ! SEE IF UIC FORMAT UIC_TO_STORE = "[" + LEFT(ID_NAME, & ID_NAME_LENGTH) + "]" TEMP_STRING = LEFT(ID_NAME, ID_NAME_LENGTH) ! ----- SKIP IF UNWANTED USERNAME ----- IF IDENT_TO_UPDATE <> "" THEN IF IDENT_TO_UPDATE <> TEMP_STRING THEN ITERATE END IF END IF ! ----- SEE IF THIS IDENTIFIER NAME IS A ----- ! ----- USERNAME ----- IF NOT READ_UAF(TEMP_STRING) THEN ! ----- SEE IF CAPTIVE FLAG SET ----- IF (FLAGS(0%) AND 8%) = 8% THEN CAPTIVE_USER = "Y" ELSE ! ----- SEE IF RESTRICTED ----- ! ----- FLAG IS SET ----- IF (FLAGS(2%) AND 1%) = 1% THEN CAPTIVE_USER = "Y" ELSE CAPTIVE_USER = "N" END IF END IF ! ----- SEE IF DISMAIL FLAG SET ----- IF (FLAGS(0%) AND -128%) = -128% THEN DISMAIL_USER = "Y" ELSE DISMAIL_USER = "N" END IF ! ----- SKIP IF UIC GROUP IS 1 ----- IF OCT_UIC_GROUP <> 1% THEN ! ----- IDENTIFIER IS A ----- ! ----- VALID USERNAME ----- USER_TYPE = 1% END IF END IF ELSE ! ----- MUST BE IDENTIFIER FORMAT QUOTA ----- UIC_TO_STORE = LEFT(ID_NAME, ID_NAME_LENGTH) ! ----- IDENTIFIER IS A VALID IDENTIFIER ----- USER_TYPE = 2% ! ----- SKIP IF UNWANTED IDENTIFIER ----- IF IDENT_TO_UPDATE <> "" THEN IF IDENT_TO_UPDATE <> UIC_TO_STORE THEN ITERATE END IF END IF END IF CASE SS$_NOSUCHID, SS$_IVIDENT ! ----- SKIP IF IDENTIFIER DOES NOT EXIST ----- ITERATE IF IDENT_TO_UPDATE <> "" IF QUOTA_UIC >= 0% THEN ! SEE IF UIC FORMAT UIC_GROUP = DEC_TO_OCT(QUOTA_UIC_GROUP) UIC_MEMBER = DEC_TO_OCT(QUOTA_UIC_MEMBER) UIC_TO_STORE = "[" + NUM1$(UIC_GROUP) + & "," + NUM1$(UIC_MEMBER) + "]" ELSE ! THIS "UIC" IS AN IDENTIFIER UIC_TO_STORE = NUM1$(QUOTA_UIC) END IF CASE ELSE PRINT "Error from SYS$IDTOASC:" + BEL CALL LIB$STOP(SYS_STATUS BY VALUE) END SELECT ! ----- SEE IF DUMPING QUOTA FILE ----- IF DUMP_MODE THEN SELECT PIGGY_MODE CASE COMPARE_MODE, UPDATE_MODE PRINT #10%, UIC_TO_STORE; TAB(34%); QUOTA_USAGE CASE INIT_MODE PRINT UIC_TO_STORE; TAB(34%); QUOTA_USAGE END SELECT ITERATE END IF ! ----- SEE IF CALCULATED UIC IS TOO LONG FOR DATA FILE ----- IF LEN(UIC_TO_STORE) > LEN(PIG_UIC) THEN PRINT #10%, "%Warning: Truncating long UIC: " & + UIC_TO_STORE + BEL PIG_UIC = UIC_TO_STORE UIC_TO_STORE = PIG_UIC END IF %IF %DEBUG = 1% %THEN PRINT "DEBUG>process data" %END %IF ! ----- PROCESS DATA DEPENDING ON THE REQUESTED ----- ! ----- EXECUTION MODE ----- SELECT PIGGY_MODE CASE COMPARE_MODE, UPDATE_MODE ! ----- ASSUME REPORT LINE IS TO BE PRINTED ----- SKIP_REPORT_LINE = FALSE ! ----- SEARCH FOR MATCHING PIGGY RECORD IN FILE ----- PIG_UIC = UIC_TO_STORE ! PIGGY UIC TO SEARCH FOR IF LOCATE_PIGGY_REC THEN! IF A MATCH WAS FOUND: ! ----- SKIP IF BLOCK USAGE IS BELOW LIMIT ----- IF ABS%(QUOTA_USAGE - PIG_BLOCKS) < & PIG_BLOCK_LIMIT THEN ! ----- SET FLAG TO SKIP REPORT ----- ! ----- LINE ----- SKIP_REPORT_LINE = TRUE END IF ! ----- SKIP IF NEGATIVE DISK BLOCKS USED ----- ! ----- AND NO NEGATIVE DISK BLOCKS WANTED ----- IF QUOTA_USAGE < PIG_BLOCKS THEN IF NOT INCLUDE_NEGATIVE_DIFF THEN ! ----- SET FLAG TO SKIP ----- ! ----- REPORT LINE ----- SKIP_REPORT_LINE = TRUE END IF END IF ! ----- CALCULATE PERCENT DIFFERENCE IN ----- ! ----- BLOCKS USED ----- TEMP_LONG = CALC_PERCENTAGE_DIFF ! ----- SKIP REPORT LINE IF USAGE CHANGE ----- ! ----- IS BELOW LIMIT ----- IF ABS%(TEMP_LONG) < PIG_PCT_LIMIT THEN ! ----- SET FLAG TO SKIP REPORT ----- ! ----- LINE ----- SKIP_REPORT_LINE = TRUE END IF IF NOT SKIP_REPORT_LINE THEN ! ----- SEE IF SPECIAL USERNAME ----- ! ----- REPORT WANTED ----- IF USERS_MODE THEN ! ----- SKIP IF IDENTIFIER ----- ! ----- NOT A VALID ----- ! ----- USERNAME OR ----- ! ----- IDENTIFIER ----- IF USER_TYPE = 0% THEN PRINT SKIP_NAME & + UIC_TO_STORE ITERATE END IF ! ----- IF IDENTIFIER: ----- IF USER_TYPE = 2% THEN TEMP_STRING = "Y" ELSE TEMP_STRING = "N" END IF ! ----- PRINT DETAIL LINE ----- PRINT #10%, & LEFT(ID_NAME, & ID_NAME_LENGTH);& ","; NUM1$( & QUOTA_USAGE - & PIG_BLOCKS); & ","; & CAPTIVE_USER; & ","; & DISMAIL_USER; & ","; TEMP_STRING ELSE ! ----- FORMAT PERCENTAGE ----- ! ----- AS A STRING ----- TEMP_STRING = RJLB( & TEMP_LONG, 4%) + "%" ! ----- PRINT DETAIL LINE ----- PRINT #10% USING & PIGGY_FORMAT1, & UIC_TO_STORE, & QUOTA_USAGE, & PIG_BLOCKS, & QUOTA_USAGE - & PIG_BLOCKS, & TEMP_STRING END IF END IF SELECT PIGGY_MODE CASE UPDATE_MODE ! ----- UPDATE CURRENT PIGGY ----- ! ----- BLOCKS USED ----- PRINT "%Updating " + & UIC_TO_STORE + " with " & + NUM1$(QUOTA_USAGE) + " blocks" PIG_BLOCKS = QUOTA_USAGE UPDATE #2% ! ----- SET FLAG IF DESIRED ----- ! ----- IDENTIFIER/USERNAME WAS ----- ! ----- UPDATED ----- IF IDENT_TO_UPDATE <> "" THEN UPDATED_IDENTIFIER = TRUE END IF END SELECT ELSE ! IF NO MATCH WAS FOUND: ! ----- SKIP IF BLOCK USAGE IS BELOW LIMIT ----- IF QUOTA_USAGE < PIG_BLOCK_LIMIT THEN ! ----- SET FLAG TO SKIP REPORT ----- ! ----- LINE ----- SKIP_REPORT_LINE = TRUE END IF PRINT #10% USING PIGGY_FORMAT2, & UIC_TO_STORE, & QUOTA_USAGE, & QUOTA_USAGE, & " 999%" & IF NOT SKIP_REPORT_LINE SELECT PIGGY_MODE CASE UPDATE_MODE ! ----- STORE CURRENT PIGGY ----- ! ----- BLOCKS USED ----- PRINT "%Storing " + & NUM1$(QUOTA_USAGE) + & " blocks for " + UIC_TO_STORE PIG_BLOCKS = QUOTA_USAGE PUT #2% END SELECT ! ----- SET FLAG IF DESIRED ----- ! ----- IDENTIFIER/USERNAME WAS UPDATED ----- IF IDENT_TO_UPDATE <> "" THEN UPDATED_IDENTIFIER = TRUE END IF END IF CASE INIT_MODE PIG_UIC = UIC_TO_STORE ! STORE PIGGY UIC PIG_BLOCKS = QUOTA_USAGE! STORE PIGGY BLOCKS USED PUT #2% END SELECT NEXT ERROR_ROUTINE: RESUME IF ERR = BUCKET_LOCKED ! RE-READ IF BUCKET IS LOCKED RESUME END_PROGRAM IF ERR = END_OF_FILE ! DONE IF END-OF-FILE REACHED IF ERR = FILE_NOT_FOUND THEN ! IF FILE NOT FOUND? SELECT ERROR_FLAG CASE 1% ! IF OPENING QUOTA FILE PRINT "Error - Disk " + DISK_WANTED + & " has no quota file" + BEL CASE 2% ! IF OPENING NEW PIGGY FILE PRINT "Error - Can't open new" + & " TOOLS:PIGGY.DAT file" + BEL CASE 3% ! IF OPENING EXISTING PIGGY FILE PRINT "Error - Can't open any existing" + & " TOOLS:PIGGY.DAT file" + BEL CASE 4% ! IF OPENING PIG.LIS FILE PRINT "Error - Can't open PIG.LIS file" + BEL CASE 5% ! IF OPENING SYSUAF FILE PRINT "Error - Can't find " + SYSUAF_FILE_SPEC + BEL END SELECT PRINT "VMS error status value:"; VMSSTATUS RESUME ABORT_PROGRAM END IF IF ERR = CANNOT_OPEN_FILE THEN ! IF FILE CAN NOT BE OPENED? SELECT ERROR_FLAG CASE 1% ! IF OPENING QUOTA FILE PRINT "Error - Can't open " + TEMP_STRING + BEL CASE 2% ! IF OPENING NEW PIGGY FILE PRINT "Error - Can't open new" + & " TOOLS:PIGGY.DAT file" + BEL CASE 3% ! IF OPENING EXISTING PIGGY FILE PRINT "Error - Can't open any existing" + & " TOOLS:PIGGY.DAT file" + BEL CASE 4% ! IF OPENING PIG.LIS FILE PRINT "Error - Can't open PIG.LIS file" + BEL CASE 5% ! IF OPENING SYSUAF FILE PRINT "Error - Can't open " + SYSUAF_FILE_SPEC + BEL END SELECT PRINT "VMS error status value:"; VMSSTATUS RESUME ABORT_PROGRAM END IF IF ERR = DUPLICATE_KEY THEN PRINT "%Skipping " + DISK_WANTED + "|" + UIC_TO_STORE + & " (" + NUM1$(QUOTA_USAGE) + & ") which is a dupl key..." + BEL RESUME READ_NEXT_QUOTA_REC END IF PRINT "BASIC ERROR "; ERR; " OCCURRED IN PIGGY" + BEL PRINT "ERROR_FLAG="; NUM1$(ERROR_FLAG) PRINT "VMS error status value:"; VMSSTATUS PRINT "After "; ERROR_LINE PRINT ERT$(ERR) RESUME ABORT_PROGRAM ABORT_PROGRAM: CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) ! EXIT WITH %X10000002 $STATUS END_PROGRAM: ON ERROR GOTO 0 ! DISABLE SUBSEQUENT ERROR TRAP ERROR_FLAG = 0% ! INIT ERROR TRAP FLAG CLOSE #1%, 2%, 10% ! CLOSE ALL OPEN FILES ! ----- SEE IF DESIRED IDENTIFIER/USERNAME WAS NOT FOUND ----- IF IDENT_TO_UPDATE <> "" THEN IF NOT UPDATED_IDENTIFIER THEN PRINT "Error - No matching" + & " identifier/username: " + IDENT_TO_UPDATE + BEL END IF END IF SELECT PIGGY_MODE CASE COMPARE_MODE PRINT "Done - Created PIG.LIS" CASE UPDATE_MODE PRINT "Done - Created PIG.LIS" CASE INIT_MODE PRINT "Done - Created new version of TOOLS:PIGGY.DAT" END SELECT ! ----- SEE IF DESIRED IDENTIFIER/USERNAME WAS NOT FOUND ----- IF IDENT_TO_UPDATE <> "" THEN IF NOT UPDATED_IDENTIFIER THEN ! ----- EXIT WITH %X10000002 $STATUS ----- CALL SYS$EXIT(ERR_NO_PUTMSG BY VALUE) END IF END IF END