YodelAdministratorImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Carl Hauser, February 13, 1986 1:33:56 pm PST
Hauser, April 12, 1985 10:17:48 am PST
Bob Hagmann June 11, 1985 11:38:12 am PDT
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;
};
};
};
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 => {
};
filler to use all the variants so the compiler won't blow up
(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;
};
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;
[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;
};
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;
[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
};
END.
December 14, 1984 Converting from AlpineInterimDirectory to AlpineDirectory.
Bob Hagmann June 10, 1985 4:55:48 pm PDT
reformatted