<> <> <> <> <> <> DIRECTORY AlpFile, AlpineEnvironment, AlpineFile, AlpDirectory, AlpineOwnerRpcControl, AlpInstance, AlpTransaction, Basics, BasicTime, Buttons, IO, List, Real, Rope, ViewerClasses, ViewerTools, YodelData; YodelAdministratorImpl: CEDAR PROGRAM IMPORTS AlpFile, AlpInstance, AlpDirectory, AlpineOwnerRpcControl, AlpTransaction, Buttons, IO, List, Real, Rope, ViewerTools, YodelData EXPORTS YodelData = BEGIN OPEN YodelData; ROPE: TYPE = Rope.ROPE; OwnerPropertyValuePairList: TYPE = LIST OF AlpineEnvironment.OwnerPropertyValuePair; CompareProc: SAFE PROC [ref1, ref2: REF ANY] RETURNS [Basics.Comparison] = CHECKED { RETURN [Rope.Compare[NARROW[ref1], NARROW[ref2], FALSE]]; }; trimWedges: PROC [inRope: ROPE] RETURNS [outRope: ROPE _NIL] = { len: INT _ inRope.InlineLength[]; IF len < 2 OR inRope.Fetch[0] ~= '< OR inRope.Fetch[len-1] ~= '> THEN ERROR; RETURN [ inRope.Substr[start: 1, len: len-2]]; }; ChangeAssertWheel: PUBLIC Buttons.ButtonProc = { d: MyData = NARROW[clientData]; p: ViewerClasses.Viewer = NARROW[parent]; d.assertWheel _ NOT d.assertWheel ; IF d.assertWheel THEN Buttons.SetDisplayStyle[p, $WhiteOnBlack] ELSE Buttons.SetDisplayStyle[p, $BlackOnWhite]; }; ChangeBreakLocks: PUBLIC Buttons.ButtonProc = { d: MyData = NARROW[clientData]; p: ViewerClasses.Viewer = NARROW[parent]; d.breakLocks _ NOT d.breakLocks ; IF d.breakLocks THEN Buttons.SetDisplayStyle[p, $WhiteOnBlack] ELSE Buttons.SetDisplayStyle[p, $BlackOnWhite]; }; createOwner: PROC [trans: AlpTransaction.Handle, server: ROPE, directory: ROPE, user: ROPE _ NIL, password: ROPE _ NIL , properties: OwnerPropertyValuePairList, d: MyData] RETURNS [resultList: LIST OF REF ANY] = { spaceLeftOnVolumeGroup: INT; owner: ROPE _ trimWedges[directory]; IF trans = NIL THEN RETURN [CONS[NARROW["Bad Server Name", ROPE], NIL]]; trans.AssertAlpineWheel[TRUE]; [spaceLeftOnVolumeGroup: spaceLeftOnVolumeGroup] _ trans.CreateOwner[ volumeGroupID: trans.GetNextVolumeGroup[previousGroup: AlpineEnvironment.nullVolumeGroupID, lock: [none, wait]], owner: owner, properties: properties]; AlpDirectory.CreateDirectory[ volume: server, owner: owner, transHandle: trans ]; IF (trans.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN { resultList _ CONS[ first: NARROW["Alpine transaction aborted -- owner NOT created", ROPE], rest: NIL]; } ELSE resultList _ CONS[ first: IO.PutFR["Owner added; space left on volume group is %g", IO.int[spaceLeftOnVolumeGroup]], rest: NIL]; }; CreateOwnerProc: PUBLIC Buttons.ButtonProc = { resultList: LIST OF REF ANY _ NIL; d: MyData = NARROW[clientData]; server, user, password: ROPE; directory: ROPE; properties: OwnerPropertyValuePairList ; pageLimit: INT; newPageLimitRope: ROPE; scratchStream: IO.STREAM _ NIL; file: ROPE; parseError: BOOL; errorExplanation: ROPE; callCreate: YodelData.PerformProc = { RETURN[createOwner[trans, server, directory, user, password, properties, d]]; }; typeParseError: PROC [] = { d.out.PutF["\nBad name in Create Owner because %g\n", IO.rope[errorExplanation]]; }; d.stopFlag _ FALSE; [user, password, server, directory, file, parseError, errorExplanation] _ ParseSArgs[d]; IF parseError THEN { typeParseError[]; GOTO badParse;}; newPageLimitRope _ ViewerTools.GetContents[viewer: d.oQuota]; IF newPageLimitRope.IsEmpty[] THEN { d.out.PutF["\nCreate Owner has no quota specified\n"]; } ELSE { IF directory.Size[] <= 2 OR hasPattern[directory] THEN { d.out.PutF["\nCreate Owner has an invalid owner name to create. Name is %g\n", IO.rope[directory]]; } ELSE { scratchStream _ IO.RIS[newPageLimitRope, scratchStream]; pageLimit _ IO.GetInt[scratchStream]; properties _ LIST[[quota[pageLimit]]]; d.out.PutF["\nCreate Owner of [%g]%g for %g pages\n", IO.rope[server], IO.rope[directory], IO.int[pageLimit]]; resultList _ PerformOp[performProc: callCreate, server: server, user: user, password: password]; DO nowRope: ROPE _ NARROW[IF resultList = NIL THEN NIL ELSE resultList.first]; IF resultList = NIL THEN EXIT; resultList _ resultList.rest; d.out.PutF[" %g\n", IO.rope[nowRope]]; ENDLOOP; }; }; EXITS badParse => {}; }; destroyOwner: PROC [trans: AlpTransaction.Handle, server: ROPE, directory: ROPE, user: ROPE _ NIL, password: ROPE _ NIL , d: MyData] RETURNS [resultList: LIST OF REF ANY] = { owner: ROPE _ trimWedges[directory]; thereIsAFile: BOOL _ FALSE; properties: LIST OF AlpineEnvironment.OwnerPropertyValuePair; rootFile: AlpineEnvironment.UniversalFile _ AlpineEnvironment.nullUniversalFile ; IF trans = NIL THEN RETURN [CONS[NARROW["Bad Server Name", ROPE], NIL]]; trans.AssertAlpineWheel[TRUE]; TRUSTED { userdirectory: ROPE _ Rope.Concat["[",Rope.Concat[server,Rope.Concat["]",directory]]]; IF AlpDirectory.Enumerate[ transHandle: trans, pattern: userdirectory.Concat["*!H"], previousFile: userdirectory.Concat["$$$.btree"]].file # AlpineEnvironment.nullUniversalFile THEN RETURN [ CONS[ NARROW["Delete all files in the directory before destroying the owner",ROPE] ,NIL]]; }; properties _ AlpTransaction.ReadOwnerProperties[ handle: trans, volumeGroupID: AlpTransaction.GetNextVolumeGroup[handle: trans, previousGroup: AlpineEnvironment.nullVolumeGroupID, lock: [none, fail]], owner: owner]; UNTIL properties = NIL DO -- because ReadOwnerProperties does not sort them yet ... WITH properties.first SELECT FROM q: AlpineEnvironment.OwnerPropertyValuePair.createAccessList => { }; s: AlpineEnvironment.OwnerPropertyValuePair.modifyAccessList => { }; <> <<(this is the cedar version of the "don't delete this line" comment>> r: AlpineEnvironment.OwnerPropertyValuePair.rootFile => { rootFile _ r.rootFile ; }; t: AlpineEnvironment.OwnerPropertyValuePair.quota => {}; u: AlpineEnvironment.OwnerPropertyValuePair.spaceInUse => {}; ENDCASE ; properties _ properties.rest; ENDLOOP; IF rootFile # AlpineEnvironment.nullUniversalFile THEN { fileHandle: AlpFile.Handle _ NIL; [fileHandle] _ AlpFile.Open[transHandle: trans, universalFile: rootFile, access: readWrite, lock: [write, fail] ! AlpInstance.Unknown => CONTINUE; ]; IF fileHandle # NIL THEN AlpFile.Delete[fileHandle ! AlpInstance.Unknown => CONTINUE;]; }; [] _ trans.DestroyOwner[ volumeGroupID: trans.GetNextVolumeGroup[ previousGroup: AlpineEnvironment.nullVolumeGroupID, lock: [none, wait]], owner: owner]; IF (trans.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN { resultList _ CONS[ first: NARROW["Alpine transaction aborted -- owner NOT destroyed", ROPE], rest: NIL]; } ELSE resultList _ CONS[ first: NARROW["Owner destroyed", ROPE], rest: NIL]; }; DestroyOwnerProc: PUBLIC Buttons.ButtonProc = { resultList: LIST OF REF ANY _ NIL; d: MyData = NARROW[clientData]; server, user, file, password: ROPE; directory: ROPE; parseError: BOOL; errorExplanation: ROPE; callDestroy: YodelData.PerformProc = { RETURN[destroyOwner[trans, server, directory, user, password, d]]; }; typeParseError: PROC [] = { d.out.PutF["\nBad pattern in Destroy Owner because %g\n", IO.rope[errorExplanation]]; }; d.stopFlag _ FALSE; [user, password, server, directory, file, parseError, errorExplanation] _ ParseSArgs[d]; IF parseError THEN { typeParseError[]; GOTO badParse;}; d.out.PutF["\nDestroy Owner of [%g]%g \n", IO.rope[server], IO.rope[directory]]; resultList _ PerformOp[performProc: callDestroy, server: server, user: user, password: password]; DO nowRope: ROPE _ NARROW[IF resultList = NIL THEN NIL ELSE resultList.first]; IF resultList = NIL THEN EXIT; resultList _ resultList.rest; d.out.PutF[" %g\n", IO.rope[nowRope]]; ENDLOOP; EXITS badParse => {}; }; writeQuota: PROC [trans: AlpTransaction.Handle, server: ROPE, directory: ROPE, user: ROPE _ NIL, password: ROPE _ NIL , properties: OwnerPropertyValuePairList, d: MyData] RETURNS [resultList: LIST OF REF ANY] = { owner: ROPE _ trimWedges[directory]; IF trans = NIL THEN RETURN [CONS[NARROW["Bad Server Name", ROPE], NIL]]; trans.AssertAlpineWheel[TRUE]; [] _ trans.WriteOwnerProperties[ volumeGroupID: trans.GetNextVolumeGroup[previousGroup: AlpineEnvironment.nullVolumeGroupID, lock: [none, wait]], owner: owner, properties: properties]; IF (trans.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN { resultList _ CONS[ first: NARROW["Alpine transaction aborted -- quota NOT changed", ROPE], rest: NIL]; } ELSE resultList _ CONS[ first: NARROW["Quota changed", ROPE], rest: NIL]; }; WriteQuotaProc: PUBLIC Buttons.ButtonProc = { resultList: LIST OF REF ANY _ NIL; d: MyData = NARROW[clientData]; server, user, password: ROPE; directory: ROPE; properties: OwnerPropertyValuePairList ; pageLimit: INT; newPageLimitRope: ROPE; scratchStream: IO.STREAM _ NIL; file: ROPE; parseError: BOOL; errorExplanation: ROPE; callWriteQuota: YodelData.PerformProc = { RETURN[writeQuota[trans, server, directory, user, password, properties, d]]; }; typeParseError: PROC [] = { d.out.PutF["\nBad name in Write Quota because %g\n", IO.rope[errorExplanation]]; }; { d.stopFlag _ FALSE; [user, password, server, directory, file, parseError, errorExplanation] _ ParseSArgs[d]; IF parseError THEN { typeParseError[]; GOTO badParse;}; newPageLimitRope _ ViewerTools.GetContents[viewer: d.oQuota]; scratchStream _ IO.RIS[newPageLimitRope, scratchStream]; pageLimit _ IO.GetInt[scratchStream ! IO.EndOfStream, IO.Error => GOTO badInt]; properties _ LIST[[quota[pageLimit]]]; d.out.PutF["\nWrite quota for Owner of [%g]%g to %g pages\n", IO.rope[server], IO.rope[directory], IO.int[pageLimit]]; resultList _ PerformOp[performProc: callWriteQuota, server: server, user: user, password: password]; DO nowRope: ROPE _ NARROW[ IF resultList = NIL THEN NIL ELSE resultList.first]; IF resultList = NIL THEN EXIT; resultList _ resultList.rest; d.out.PutF[" %g\n", IO.rope[nowRope]]; ENDLOOP; EXITS badInt => { d.out.PutF["\nWrite quota: bad quota specified\n"]; }; badParse => {}; }; }; listOwners: PROC [trans: AlpTransaction.Handle] RETURNS [resultList: LIST OF REF ANY] = { owner: ROPE _ NIL ; properties: LIST OF AlpineEnvironment.OwnerPropertyValuePair; result: ROPE; totalQuota: INT _ 0 ; totalSpaceInUse: INT _ 0 ; IF trans = NIL THEN RETURN [CONS[NARROW["Bad Server Name", ROPE], NIL]]; trans.AssertAlpineWheel[TRUE]; DO quota: INT _ 0; spaceInUse: INT _ 0; [owner, properties] _ trans.ReadNextOwner[ volumeGroupID: trans.GetNextVolumeGroup[previousGroup: AlpineEnvironment.nullVolumeGroupID, lock: [none, wait]], previousOwner: owner, desiredProperties: ALL [TRUE]]; IF owner = NIL THEN EXIT; result _ IO.PutFR["%g\t\t", IO.rope[owner]]; UNTIL properties = NIL DO property: AlpineEnvironment.OwnerPropertyValuePair _ properties.first ; junk: REF AlpineEnvironment.OwnerPropertyValuePair _ NEW[AlpineEnvironment.OwnerPropertyValuePair]; -- black magic inserted by compiler wizard to prevent fatal error in pass 4. properties _ properties.rest; SELECT property.property FROM quota => { quota _ NARROW[property, AlpineEnvironment.OwnerPropertyValuePair.quota].quota; totalQuota _ totalQuota + quota ; result _ Rope.Concat[result, IO.PutFR["quota %5g ", IO.int[quota]]]; }; spaceInUse => { spaceInUse _ NARROW[property, AlpineEnvironment.OwnerPropertyValuePair.spaceInUse].spaceInUse; totalSpaceInUse _ totalSpaceInUse + spaceInUse ; result _ Rope.Concat[result, IO.PutFR["spaceInUse %5g ", IO.int[spaceInUse]]]; }; ENDCASE; ENDLOOP; IF quota > 0 THEN { percent: INT _ Real.Fix[(spaceInUse * 100.0)/quota]; result _ Rope.Concat[result, IO.PutFR[" (%2g%%) ", IO.int[percent]]]; IF percent > 90 THEN result _ Rope.Concat[result, " <-----"]; }; resultList _ CONS[ first: result, rest: resultList]; ENDLOOP; resultList _ CONS[ first: IO.PutFR[" totals\t\tspaceInUse %5g\tquota %5g\n", IO.int[totalSpaceInUse], IO.int[totalQuota] ], rest: resultList]; }; ListOwnersProc: PUBLIC Buttons.ButtonProc = { callListOwners: YodelData.PerformProc = { RETURN[listOwners[trans]]; }; typeParseError: PROC [] = { d.out.PutF["\nBad pattern in List Owners because %g\n", IO.rope[errorExplanation]]; }; resultList: LIST OF REF ANY _ NIL; d: MyData = NARROW[clientData]; server, user, password: ROPE; parseError: BOOL; errorExplanation: ROPE; d.stopFlag _ FALSE; [user: user, password: password, srcServer: server, parseError: parseError, errorExplanation: errorExplanation] _ ParseSArgs[d]; IF parseError THEN { typeParseError[]; GOTO badParse;}; d.out.PutF["\nList Owners for server %g\n", IO.rope[server]]; resultList _ PerformOp[performProc: callListOwners, server: server, user: user, password: password]; resultList _ List.Sort[resultList, CompareProc]; DO nowRope: ROPE _ NARROW[IF resultList = NIL THEN NIL ELSE resultList.first]; IF resultList = NIL THEN EXIT; resultList _ resultList.rest; d.out.PutF[" %g\n", IO.rope[nowRope]]; ENDLOOP; EXITS badParse => {}; }; readDBProperties: PROC [trans: AlpTransaction.Handle] RETURNS [resultList: LIST OF REF ANY] = { nOwners, nEntriesUsed, nEntries: NAT; totalQuota, totalSpaceInUse, volumeGroupSize: AlpineEnvironment.PageCount; IF trans = NIL THEN RETURN [CONS[NARROW["Bad Server Name", ROPE], NIL]]; trans.AssertAlpineWheel[TRUE]; TRUSTED { [nOwners, nEntriesUsed, nEntries, totalQuota, totalSpaceInUse, volumeGroupSize] _ trans.inst.owner.ReadDBProperties[conversation: trans.inst.conversation, transID: trans.transID, volumeGroupID: trans.GetNextVolumeGroup[previousGroup: AlpineEnvironment.nullVolumeGroupID, lock: [none, wait]]]; }; resultList _ CONS[ first: IO.PutFR[" owners %g, entries used %g, entries %g", IO.int[nOwners], IO.int[nEntriesUsed], IO.int[nEntries]], rest: CONS[ IO.PutFR[" total quota %g, total space in use %g, volume group size %g", IO.int[totalQuota], IO.int[totalSpaceInUse], IO.int[volumeGroupSize]], NIL] ]; }; ReadDBPropertiesProc: PUBLIC Buttons.ButtonProc = { callReadDBPropertiesProc: YodelData.PerformProc = { RETURN[readDBProperties[trans]]; }; typeParseError: PROC [] = { d.out.PutF["\nBad pattern in Read Statistics because %g\n", IO.rope[errorExplanation]]; }; resultList: LIST OF REF ANY _ NIL; d: MyData = NARROW[clientData]; server, user, password: ROPE; parseError: BOOL; errorExplanation: ROPE; d.stopFlag _ FALSE; [user: user, password: password, srcServer: server, parseError: parseError, errorExplanation: errorExplanation] _ ParseSArgs[d]; IF parseError THEN { typeParseError[]; GOTO badParse;}; d.out.PutF["\nRead Statistics for server %g\n", IO.rope[server]]; resultList _ PerformOp[performProc: callReadDBPropertiesProc, server: server, user: user, password: password]; resultList _ List.Sort[resultList, CompareProc]; DO nowRope: ROPE _ NARROW[IF resultList = NIL THEN NIL ELSE resultList.first]; IF resultList = NIL THEN EXIT; resultList _ resultList.rest; d.out.PutF[" %g\n", IO.rope[nowRope]]; ENDLOOP EXITS badParse => {}; }; END. <> <> <> <<>> <<>>