extern afs_rwlock_t afs_xcbhash;
extern struct afs_exporter *afs_nfsexporter;
extern char *afs_sysname;
+extern char *afs_sysnamelist[];
+extern int afs_sysnamecount;
extern struct afs_q VLRU; /*vcache LRU*/
#ifdef AFS_LINUX22_ENV
extern struct inode_operations afs_symlink_iops, afs_dir_iops;
return 1;
}
-Check_AtSys(avc, aname, outb, areq)
- register struct vcache *avc;
- char *aname, **outb;
- struct vrequest *areq;
-{
- register char *tname;
- register int error = 0, offset = -1;
-
- for (tname=aname; *tname; tname++) /*Move to the end of the string*/;
-
- /*
- * If the current string is 4 chars long or more, check to see if the
- * tail end is "@sys".
- */
- if ((tname >= aname + 4) && (AFS_EQ_ATSYS(tname-4)))
- offset = (tname - 4) - aname;
- if (offset < 0) {
- tname = aname;
- } else {
- tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
- if (offset)
- strncpy(tname, aname, offset);
- if (!afs_nfsexporter)
- strcpy(tname+offset, (afs_sysname ? afs_sysname : SYS_NAME ));
- else {
- register struct unixuser *au;
- register afs_int32 error;
- au = afs_GetUser(areq->uid, avc->fid.Cell, 0); afs_PutUser(au, 0);
- if (au->exporter) {
- error = EXP_SYSNAME(au->exporter, (char *)0, tname+offset);
- if (error)
- strcpy(tname+offset, "@sys");
- } else {
- strcpy(tname+offset, (afs_sysname ? afs_sysname : SYS_NAME ));
- }
- }
- error = 1;
- }
- *outb = tname;
- return error;
-}
-
-
-char *afs_getsysname(areq, adp)
+afs_getsysname(areq, adp, bufp)
register struct vrequest *areq;
- register struct vcache *adp; {
+ register struct vcache *adp;
+ register char *bufp;
+{
static char sysname[MAXSYSNAME];
register struct unixuser *au;
register afs_int32 error;
+ if (!afs_nfsexporter) {
+ strcpy(bufp, afs_sysname);
+ return 0;
+ }
AFS_STATCNT(getsysname);
- /* this whole interface is wrong, it should take a buffer ptr and copy
- * the data out.
- */
au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
afs_PutUser(au, 0);
if (au->exporter) {
- error = EXP_SYSNAME(au->exporter, (char *)0, sysname);
- if (error) return "@sys";
- else return sysname;
+ error = EXP_SYSNAME(au->exporter, (char *)0, bufp);
+ if (error)
+ strcpy(bufp, "@sys");
+ return -1;
} else {
- return (afs_sysname == 0? SYS_NAME : afs_sysname);
+ strcpy(bufp, afs_sysname);
+ return 0;
}
}
-void afs_HandleAtName(aname, aresult, areq, adp)
- register char *aname;
- register char *aresult;
- register struct vrequest *areq;
- register struct vcache *adp; {
- register int tlen;
- AFS_STATCNT(HandleAtName);
- tlen = strlen(aname);
- if (tlen >= 4 && strcmp(aname+tlen-4, "@sys")==0) {
- strncpy(aresult, aname, tlen-4);
- strcpy(aresult+tlen-4, afs_getsysname(areq, adp));
- }
- else strcpy(aresult, aname);
+Check_AtSys(avc, aname, state, areq)
+ register struct vcache *avc;
+ char *aname;
+ struct sysname_info *state;
+ struct vrequest *areq;
+{
+ if (AFS_EQ_ATSYS(aname)) {
+ state->offset = 0;
+ state->name = (char *) osi_AllocLargeSpace(AFS_SMALLOCSIZ);
+ state->allocked = 1;
+ state->index = afs_getsysname(areq, avc, state->name);
+ } else {
+ state->offset = -1;
+ state->allocked = 0;
+ state->index = 0;
+ state->name = aname;
}
+}
+
+Next_AtSys(avc, areq, state)
+ register struct vcache *avc;
+ struct vrequest *areq;
+ struct sysname_info *state;
+{
+ if (state->index == -1)
+ return 0; /* No list */
+
+ /* Check for the initial state of aname != "@sys" in Check_AtSys*/
+ if (state->offset == -1 && state->allocked == 0) {
+ register char *tname;
+ /* Check for .*@sys */
+ for (tname=state->name; *tname; tname++)
+ /*Move to the end of the string*/;
+ if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname-4))) {
+ state->offset = (tname - 4) - state->name;
+ tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+ strncpy(tname, state->name, state->offset);
+ state->name = tname;
+ state->allocked = 1;
+ state->index = afs_getsysname(areq, avc, state->name+state->offset);
+ return 1;
+ } else
+ return 0; /* .*@sys doesn't match either */
+ } else if (++(state->index) >= afs_sysnamecount
+ || !afs_sysnamelist[state->index])
+ return 0; /* end of list */
+ strcpy(state->name+state->offset, afs_sysnamelist[state->index]);
+ return 1;
+}
#if (defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV))
extern int BlobScan(ino64_t *afile, afs_int32 ablob);
OSI_VC_CONVERT(adp)
afs_hyper_t versionNo;
int no_read_access = 0;
+ struct sysname_info sysState; /* used only for @sys checking */
AFS_STATCNT(afs_lookup);
#ifdef AFS_OSF_ENV
goto done;
}
- /* lookup the name aname in the appropriate dir, and return a cache entry
- on the resulting fid */
-
- /*
- * check for, and handle "@sys" if it's there. We should be able
- * to avoid the alloc and the strcpy with a little work, but it's
- * not pressing. If there aren't any remote users (ie, via the
- * NFS translator), we have a slightly easier job.
- * the faster way to do this is to check for *aname == '@' and if
- * it's there, check for @sys, otherwise, assume there's no @sys
- * then, if the lookup fails, check for .*@sys...
- */
- if (!AFS_EQ_ATSYS(aname)) {
- tname = aname;
- }
- else {
- tname = (char *) osi_AllocLargeSpace(AFS_SMALLOCSIZ);
- if (!afs_nfsexporter)
- strcpy(tname, (afs_sysname ? afs_sysname : SYS_NAME ));
- else {
- register struct unixuser *au;
- register afs_int32 error;
- au = afs_GetUser(treq.uid, adp->fid.Cell, 0); afs_PutUser(au, 0);
- if (au->exporter) {
- error = EXP_SYSNAME(au->exporter, (char *)0, tname);
- if (error)
- strcpy(tname, "@sys");
- } else {
- strcpy(tname, (afs_sysname ? afs_sysname : SYS_NAME ));
- }
- }
- }
-
/* come back to here if we encounter a non-existent object in a read-only
volume's directory */
else code = 0;
/* watch for ".." in a volume root */
- if (adp->mvstat == 2 && tname[0] == '.' && tname[1] == '.' && !tname[2]) {
+ if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
/* looking up ".." in root via special hacks */
if (adp->mvid == (struct VenusFid *) 0 || adp->mvid->Fid.Volume == 0) {
#ifdef AFS_OSF_ENV
* I'm not fiddling with the LRUQ here, either, perhaps I should, or else
* invent a lightweight version of GetVCache.
*/
- if (tname[0] == '.' && !tname[1]) { /* special case */
+ if (aname[0] == '.' && !aname[1]) { /* special case */
ObtainReadLock(&afs_xvcache);
osi_vnhold(adp, 0);
ReleaseReadLock(&afs_xvcache);
goto done;
}
+ Check_AtSys(adp, aname, &sysState, &treq);
+ tname = sysState.name;
+
+ /* 1st Check_AtSys and lookup by tname is required here, for now,
+ because the dnlc is *not* told to remove entries for the parent
+ dir of file/dir op that afs_LocalHero likes, but dnlc is informed
+ if the cached entry for the parent dir is invalidated for a
+ non-local change.
+ Otherwise, we'd be able to do a dnlc lookup on an entry ending
+ w/@sys and know the dnlc was consistent with reality. */
tvc = osi_dnlc_lookup (adp, tname, WRITE_LOCK);
*avcp = tvc; /* maybe wasn't initialized, but it is now */
if (tvc) {
/* now we will just call dir package with appropriate inode.
Dirs are always fetched in their entirety for now */
- /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
ObtainReadLock(&adp->lock);
/*
/* Save the version number for when we call osi_dnlc_enter */
hset(versionNo, tdc->f.versionNo);
+ /*
+ * check for, and handle "@sys" if it's there. We should be able
+ * to avoid the alloc and the strcpy with a little work, but it's
+ * not pressing. If there aren't any remote users (ie, via the
+ * NFS translator), we have a slightly easier job.
+ * the faster way to do this is to check for *aname == '@' and if
+ * it's there, check for @sys, otherwise, assume there's no @sys
+ * then, if the lookup fails, check for .*@sys...
+ */
+ /* above now implemented by Check_AtSys and Next_AtSys */
+
+ /* lookup the name in the appropriate dir, and return a cache entry
+ on the resulting fid */
theDir = tdc->f.inode;
- code = afs_dir_LookupOffset(&theDir, tname, &tfid.Fid, &dirCookie);
- if (code == ENOENT && tname == aname) {
- int len;
- len = strlen(aname);
- if (len >= 4 && AFS_EQ_ATSYS(aname+len-4)) {
- tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
- afs_HandleAtName(aname, tname, &treq, adp);
- code = afs_dir_LookupOffset(&theDir, tname, &tfid.Fid, &dirCookie);
- }
+ code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
+
+ /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
+ while (code == ENOENT && Next_AtSys(adp, &treq, &sysState)) {
+ code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
}
+ tname = sysState.name;
+
ReleaseReadLock(&adp->lock);
afs_PutDCache(tdc);
#define PIGGYSIZE 1350 /* max piggyback size */
#define MAXVOLS 128 /* max vols we can store */
#define MAXSYSNAME 128 /* max sysname (i.e. @sys) size */
+#define MAXNUMSYSNAMES 16 /* max that current constants allow */
#define NOTOKTIMEOUT (2*3600) /* time after which to timeout conns sans tokens */
#define NOPAG 0xffffffff
#define AFS_NCBRS 300 /* max # of call back return entries */
#define AFS_RXDEADTIME 50
#define AFS_HARDDEADTIME 120
+struct sysname_info {
+ char *name;
+ short offset;
+ char index, allocked;
+};
/* flags to use with AFSOP_CACHEINIT */
#define AFSCALL_INIT_MEMCACHE 0x1 /* use a memory-based cache */
afs_rwlock_t afs_puttofileLock; /* not used */
char *afs_sysname = 0; /* So that superuser may change the
* local value of @sys */
+char *afs_sysnamelist[MAXNUMSYSNAMES]; /* For support of a list of sysname */
+int afs_sysnamecount = 0;
struct volume *Initialafs_freeVolList;
int afs_memvolumes = 0;
afs_resourceinit_flag = 1;
for (i=0;i<NFENTRIES;i++)
fvTable[i] = 0;
- afs_sysname = afs_osi_Alloc(MAXSYSNAME);
+ for(i=0;i<MAXNUMSYSNAMES;i++)
+ afs_sysnamelist[i] = afs_osi_Alloc(MAXSYSNAME);
+ afs_sysname = afs_sysnamelist[0];
strcpy(afs_sysname, SYS_NAME);
+ afs_sysnamecount = 1;
QInit(&CellLRU);
#if defined(AFS_AIX32_ENV) || defined(AFS_HPUX_ENV)
{ extern afs_int32 afs_preallocs;
for (i=0; i<NFENTRIES; i++)
fvTable[i] = 0;
/* Reinitialize local globals to defaults */
- afs_osi_Free(afs_sysname, MAXSYSNAME);
+ for(i=0; i<MAXNUMSYSNAMES; i++)
+ afs_osi_Free(afs_sysnamelist[i], MAXSYSNAME);
afs_sysname = 0;
+ afs_sysnamecount = 0;
afs_marinerHost = 0;
QInit(&CellLRU);
afs_setTimeHost = (struct server *)0;
register struct vcache *tvc;
register struct dcache *tdc;
struct VenusFid tfid;
- char *bufp = 0;
- afs_int32 offset, len, hasatsys=0;
+ char *bufp;
+ struct sysname_info sysState;
+ afs_int32 offset, len;
AFS_STATCNT(PNewStatMount);
if (!avc) return EINVAL;
}
tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
if (!tdc) return ENOENT;
- hasatsys = Check_AtSys(avc, ain, &bufp, areq);
- code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
+ Check_AtSys(avc, ain, &sysState, areq);
+ do {
+ code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+ } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
+ bufp = sysState.name;
if (code) {
afs_PutDCache(tdc);
goto out;
ReleaseWriteLock(&tvc->lock);
afs_PutVCache(tvc, WRITE_LOCK);
out:
- if (hasatsys) osi_FreeLargeSpace(bufp);
+ if (sysState.allocked) osi_FreeLargeSpace(bufp);
return code;
}
afs_int32 ainSize;
afs_int32 *aoutSize; /* set this */ {
register afs_int32 code;
- char *bufp = 0;
- afs_int32 offset, len, hasatsys = 0;
+ char *bufp;
+ struct sysname_info sysState;
+ afs_int32 offset, len;
register struct conn *tc;
register struct dcache *tdc;
register struct vcache *tvc;
tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1); /* test for error below */
if (!tdc) return ENOENT;
- hasatsys = Check_AtSys(avc, ain, &bufp, areq);
- code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
+ Check_AtSys(avc, ain, &sysState, areq);
+ do {
+ code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+ } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
+ bufp = sysState.name;
if (code) {
afs_PutDCache(tdc);
goto out;
ReleaseWriteLock(&avc->lock);
code = 0;
out:
- if (hasatsys) osi_FreeLargeSpace(bufp);
+ if (sysState.allocked) osi_FreeLargeSpace(bufp);
return code;
}
/* (since we don't really believe remote uids anyway) */
/* outname[] shouldn't really be needed- this is left as an excercise */
/* for the reader. */
-
static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
struct vcache *avc;
int afun;
register struct afs_exporter *exporter;
extern struct unixuser *afs_FindUser();
extern char *afs_sysname;
+ extern char *afs_sysnamelist[];
+ extern int afs_sysnamecount;
register struct unixuser *au;
register afs_int32 pag, error;
- int t;
+ int t, count;
AFS_STATCNT(PSetSysName);
bcopy(ain, (char *)&setsysname, sizeof(afs_int32));
ain += sizeof(afs_int32);
if (setsysname) {
- t = strlen(ain);
- if (t > MAXSYSNAME)
+
+ /* Check my args */
+ if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
return EINVAL;
+ for(cp = ain,count = 0;count < setsysname;count++) {
+ /* won't go past end of ain since maxsysname*num < ain length */
+ t = strlen(cp);
+ if (t >= MAXSYSNAME || t <= 0)
+ return EINVAL;
+ /* check for names that can shoot us in the foot */
+ if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
+ return EINVAL;
+ cp += t+1;
+ }
+ /* args ok */
+
+ /* inname gets first entry in case we're being a translater */
+ t = strlen(ain);
bcopy(ain, inname, t+1); /* include terminating null */
ain += t + 1;
}
else foundname = 1;
afs_PutUser(au, READ_LOCK);
} else {
+
+ /* Not xlating, so local case */
if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
- if (!setsysname) {
+ if (!setsysname) { /* user just wants the info */
strcpy(outname, afs_sysname);
- foundname = 1;
- } else {
- if (!afs_osi_suser(acred)) /* Local guy; only root can change sysname */
+ foundname = afs_sysnamecount;
+ } else { /* Local guy; only root can change sysname */
+ if (!afs_osi_suser(acred))
return EACCES;
+
+ /* clear @sys entries from the dnlc, once afs_lookup can
+ do lookups of @sys entries and thinks it can trust them */
+ /* privs ok, store the entry, ... */
strcpy(afs_sysname, inname);
+ if (setsysname > 1) { /* ... or list */
+ cp = ain;
+ for(count=1; count < setsysname;++count) {
+ if (!afs_sysnamelist[count])
+ osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
+ t = strlen(cp);
+ bcopy(cp, afs_sysnamelist[count], t+1); /* include null */
+ cp += t+1;
+ }
+ }
+ afs_sysnamecount = setsysname;
}
}
if (!setsysname) {
- cp = aout;
+ cp = aout; /* not changing so report back the count and ... */
bcopy((char *)&foundname, cp, sizeof(afs_int32));
cp += sizeof(afs_int32);
if (foundname) {
- strcpy(cp, outname);
+ strcpy(cp, outname); /* ... the entry, ... */
cp += strlen(outname)+1;
+ for(count=1; count < foundname; ++count) { /* ... or list. */
+ /* Note: we don't support @sys lists for exporters */
+ if (!afs_sysnamelist[count])
+ osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
+ t = strlen(afs_sysnamelist[count]);
+ if (t >= MAXSYSNAME)
+ osi_Panic("PSetSysName: sysname entry garbled\n");
+ strcpy(cp, afs_sysnamelist[count]);
+ cp += t + 1;
+ }
}
*aoutSize = cp - aout;
}
register struct vcache *tvc;
register struct dcache *tdc;
struct VenusFid tfid;
- char *bufp = 0;
- afs_int32 offset, len, hasatsys=0;
+ char *bufp;
+ struct sysname_info sysState;
+ afs_int32 offset, len;
AFS_STATCNT(PFlushMount);
if (!avc) return EINVAL;
}
tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
if (!tdc) return ENOENT;
- hasatsys = Check_AtSys(avc, ain, &bufp, areq);
- code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
+ Check_AtSys(avc, ain, &sysState, areq);
+ do {
+ code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+ } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
+ bufp = sysState.name;
if (code) {
afs_PutDCache(tdc);
goto out;
#endif
afs_PutVCache(tvc, WRITE_LOCK);
out:
- if (hasatsys) osi_FreeLargeSpace(bufp);
+ if (sysState.allocked) osi_FreeLargeSpace(bufp);
return code;
}
struct ViceIoctl blob;
struct cmd_item *ti;
char *input = space;
- afs_int32 setp = 1;
+ afs_int32 setp = 0;
ti = as->parms[0].items;
- if (!ti) setp = 0;
blob.in = space;
blob.out = space;
blob.out_size = MAXSIZE;
blob.in_size = sizeof(afs_int32);
- bcopy(&setp, input, sizeof(afs_int32));
input += sizeof(afs_int32);
- if (ti) {
- strcpy(input, ti->data);
+ for(; ti; ti=ti->next) {
+ setp++;
blob.in_size += strlen(ti->data) + 1;
+ if (blob.in_size > MAXSIZE) {
+ fprintf(stderr, "%s: sysname%s too long.\n", pn, setp > 1 ? "s" : "");
+ return 1;
+ }
+ strcpy(input, ti->data);
input += strlen(ti->data);
*(input++) = '\0';
}
+ bcopy(&setp, space, sizeof(afs_int32));
code = pioctl(0, VIOC_AFS_SYSNAME, &blob, 1);
if (code) {
Die(errno, 0);
return 1;
}
if (setp) {
- printf("%s: new sysname set.\n", pn);
+ printf("%s: new sysname%s set.\n", pn, setp > 1 ? " list" : "");
return 0;
}
input = space;
fprintf(stderr, "No sysname name value was found\n");
return 1;
}
- printf("Current sysname is '%s'\n", input);
+ printf("Current sysname%s is:", setp>1 ? " list" : "");
+ for(;setp>0;--setp) {
+ printf(" %s", input);
+ input += strlen(input) + 1;
+ }
+ printf("\n");
return 0;
}
cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
ts = cmd_CreateSyntax("sysname", SysNameCmd, 0, "get/set sysname (i.e. @sys) value");
- cmd_AddParm(ts, "-newsys", CMD_SINGLE, CMD_OPTIONAL, "new sysname");
+ cmd_AddParm(ts, "-newsys", CMD_LIST, CMD_OPTIONAL, "new sysname");
ts = cmd_CreateSyntax("exportafs", ExportAfsCmd, 0, "enable/disable translators to AFS");
cmd_AddParm(ts, "-type", CMD_SINGLE, 0, "exporter name");