ARJAN@HROEUR51.BITNET (06/30/88)
My posting about scanning the rightsdatabase for finding unused uic's in a given group has ripened for exacly two months (posting of 29-apr-1988) before I received it back myself via infovax, though some people must have received it earlier (some reactions a few days after the posting), but with the original posting yesterday (29-jun-1988) I received another amount of reactions. For all those people who sent me the key to the answer: Thanks a lot. For all those interested I'll give a short recipe plus the code I knocked together. First, one has to set up the FAB/RAB/XABKEY structures and have them point to each other. Since you'll be reading, the various fields in those structu- res need not (all) be defined -RMS will handle that for you. Open the file, start record stream, find the group uic ([xxx,177777]), using a sys$find (record access mode = KEYED). (This is a check to be sure that the group exists.) Then you sys$find [xxx,0] with record processing option KEY GREATER THAN OR EQUAL TO. From there you sys$get the next record with record access mode SEQUENTIAL i.o KEYED and record processing option KEY GREATER THAN. whenever you find [xxx,177777] again, you know that the previous record was the record of the last uic in that group. Follows the program. (I know it's not not that elegant, but at least it does what I want it to do, and it does so real fast) -No privs needed, because rightslist.dat is protected w:re ------------------------------------------------------------------ /* FIND_UIC.C -- Find first free uic for a given group. */ /* and set symbol FULL_UIC to be this new uic. */ # include rms /* = fab + rab + nam + xab + rmsdef */ # include ssdef # include stdio # include descrip int int_group, int_rec_mem_val, n, status, suc(), fail(); short int group[2], rec_grp_val[2]; int swtch; /* for switching record buffers */ struct FAB rdbfab; /* File access block */ struct XABKEY rdbxab_key_1; /* Extended attributes block */ struct RAB rdbrab; /* Record access block */ static char filename[] = { "SYS$SYSTEM:RIGHTSLIST.DAT" }; char record[2][65]; /* The record(s) to find */ main() { rdbfab = cc$rms_fab; /* Initialize structures */ rdbrab = cc$rms_rab; rdbxab_key_1 = cc$rms_xabkey; rdbfab.fab$l_xab = &rdbxab_key_1; /* Define fab's xab (key) pointer */ rdbrab.rab$l_fab = &rdbfab; /* Rab's fab pointer */ rdbfab.fab$b_fac = FAB$M_GET; /* File access: read only , share */ rdbfab.fab$b_shr = FAB$M_SHRGET; rdbxab_key_1.xab$b_dtp = XAB$C_BN4; /* Unsigned 4 byte binary ascending */ rdbfab.fab$l_fna = filename; /* predefined file name */ rdbfab.fab$b_fns = strlen(filename); printf("UIC group: "); scanf("%o",&group[1]); /* Inquire for octal uic group */ int_group = group[1]; group[0] = -1; /* Group identifier */ status = sys$open(&rdbfab); /* Opens for (shared) read only */ if(status!=RMS$_NORMAL) lib$stop(status); rdbrab.rab$b_mbf = 5; /* Multibuffer count (?) (Minim. 2 for indexed files) */ status = sys$connect(&rdbrab); /* Start record stream */ if(status!=RMS$_NORMAL) lib$stop(status); find_highest_mem(group,record[swtch=0]); } find_highest_mem(gr,rc) int *gr; char *rc; { rdbrab.rab$b_krf = 0; /* Key of referece; - Identifier field (Okay, default) */ rdbrab.rab$l_kbf = gr; /* Key value of the key of reference - (Identifier) */ rdbrab.rab$b_ksz = 4; rdbrab.rab$b_rac = RAB$C_KEY; /* record access mode: random access by key */ rdbrab.rab$l_ubf = rc; /* record buffer address */ rdbrab.rab$w_usz = 64; /* record length */ if(int_group!=1) /* No group identifier for [1,*] */ { sys$clref(1); status = sys$find(&rdbrab,&fail,&suc); if(status!=RMS$_NORMAL && status!=RMS$_PENDING) { puts("%FIND_NEW_UIC-F-NOGRP, specified group does not exist"); exit(); } sys$waitfr(1); } group[0] = 0; /* Group exists */ rdbrab.rab$l_rop = RAB$M_KGE; /* Rec. proc. opt: key gr than or eq. to */ sys$clref(1); status = sys$find(&rdbrab,&fail,&suc); if(status!=RMS$_NORMAL && status!=RMS$_PENDING) { puts("%FIND_NEW_UIC-W-UNKNWN, unknown error"); exit(); } sys$waitfr(1); rdbrab.rab$l_ubf = record[swtch=1]; /* second record buffer address */ while(1) { sys$clref(1); rdbrab.rab$b_rac = RAB$C_SEQ; /* Found first record, now read seqential. */ rdbrab.rab$l_rop = RAB$M_KGT; /* Rec. processing option: key greater than */ rdbrab.rab$l_ubf = record[swtch]; /* one of the two record buff addresses */ status = sys$get(&rdbrab,&fail,&suc); if(status!=RMS$_NORMAL && status!=RMS$_PENDING) lib$stop(status); sys$waitfr(1); } status = sys$close(&rdbfab); if(status!=RMS$_NORMAL) lib$stop(status); } suc() /* RMS completed (successfully) -- AST success routine */ { int n; rec_grp_val[0] = record[swtch][0] + record[swtch][1]*256; rec_grp_val[1] = record[swtch][2] + record[swtch][3]*256; if(rec_grp_val[0]==-257) { if(swtch==0) swtch=1; else swtch=0; int_rec_mem_val = record[swtch][0] + record[swtch][1]*256 + 1; set_uic_symbol(); exit(); } if(swtch==0) swtch=1; else swtch=0; sys$setef(1); } fail() /* RMS completed (unsuccessfully) -- AST error routine */ { puts("%FIND_NEW_UIC-F-NOGRP, specified group does not exist"); exit(); } set_uic_symbol() { int global=2; char newuic[16], memnum[7], grpnum[7]; struct dsc$descriptor_s uic_desc, symbol_desc; static char brace[]={ "]" }, comma[]={ "," }, uic_symbol[]={ "FULL_UIC" }; otoa(int_group,&grpnum); otoa(int_rec_mem_val,&memnum); newuic[0]='['; newuic[1]='\0'; strcat(newuic,grpnum); strcat(newuic,comma); strcat(newuic,memnum); strcat(newuic,brace); uic_desc.dsc$w_length=strlen(uic_symbol); /* Symbol name length */ uic_desc.dsc$b_dtype=DSC$K_DTYPE_T; uic_desc.dsc$b_class=DSC$K_CLASS_S; uic_desc.dsc$a_pointer=uic_symbol; symbol_desc.dsc$w_length=strlen(newuic); /* Symbol length */ symbol_desc.dsc$b_dtype=DSC$K_DTYPE_T; symbol_desc.dsc$b_class=DSC$K_CLASS_S; symbol_desc.dsc$a_pointer=newuic; status=lib$set_symbol(&uic_desc,&symbol_desc,&global); /* set global symbol */ if (status!=SS$_NORMAL) lib$stop(status); }
carl@CITHEX.CALTECH.EDU (Carl J Lydick) (07/05/88)
> Whenever we want to add new users to sysuaf.dat, we try to find > the next uic available for this new user. (For accounting reasons > we do NOT use any uic that has been used before). The only way I > could think of was to scan sysuaf.dat completely, using $IDTOASC > in a wildcard operation, translate the usernames back to individual > UIC's with $ASCTOID, then examining the group and member value, thus > finding the highest member value of the specified group. > But this takes about THIRTY times as much cpu time as does AUTHORIZE > with a SHOW [XXXX,*]/BRIEF > > Does anybody know which calls authorize might be using ? Since there's been one response to the net describing how to do this in C, and one in MACRO, I just thought I'd show how it's done in FORTRAN, viz., much more easily than in either of the other two languages. I tried doing it in DCL, which would have been as simple as the FORTRAN code, but the DCL read statement doesn't like the key value to have null bytes in it (It sees the null and decides that's the end of the command line! Is this a bug or a feature?). At any rate, here's the FORTRAN program: ******************************************************************************** PROGRAM NEXT_FREE_UIC CHARACTER*6 MEMBER INTEGER GROUP, KEYNUM, UIC, NEXT_UIC OPEN(UNIT=1,FILE='SYS$SYSTEM:RIGHTSLIST.DAT',SHARED,READONLY, 1 ACCESS='KEYED',STATUS='OLD',FORM='UNFORMATTED') TYPE 10 10 FORMAT(' GROUP: ',$) READ 20, GROUP 20 FORMAT(O6) KEYNUM = GROUP * '10000'X UIC = KEYNUM READ(1,KEYGE=KEYNUM,KEYID=0,ERR=900) NEXT_UIC 30 IF ((NEXT_UIC/'10000'X) .NE. GROUP) GOTO 900 IF (IAND(NEXT_UIC,'FFFF'X) .EQ. 'FFFF'X) GOTO 900 UIC = NEXT_UIC READ(1,ERR=900) NEXT_UIC GOTO 30 900 UIC = UIC + 1 IF (IAND(UIC,'FFFF'X) .EQ. 'FFFF'X) GOTO 950 TYPE 910, UIC/'10000'X, IAND(UIC,'FFFF'X) 910 FORMAT(1X,'THE NEXT UIC IN THE GROUP IS [',O6.6,',',O6.6,']') WRITE(MEMBER,920) IAND(UIC,'FFFF'X) 920 FORMAT(O6.6) CALL LIB$SET_SYMBOL('MEMBER', MEMBER) GOTO 999 950 TYPE 960, GROUP 960 FORMAT(' GROUP', O6.6, ' IS FULL') 999 END ******************************************************************************** If there were a KEYLT specifier, the loop could be eliminated, and it could all be done with a single read from the file, by setting KEYNUM equal to GROUP * '10000'X + 'FFFF'X.