Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / afs_dynroot.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 /*
11 * Dynamic /afs volume support.
12 *
13 * Implements:
14 * afs_IsDynrootFid
15 * afs_IsDynrootMountFid
16 * afs_IsDynrootAnyFid
17 * afs_GetDynrootFid
18 * afs_GetDynrootMountFid
19 * afs_IsDynroot
20 * afs_IsDynrootMount
21 * afs_IsDynrootAny
22 * afs_DynrootInvalidate
23 * afs_GetDynroot
24 * afs_PutDynroot
25 * afs_DynrootNewVnode
26 * afs_SetDynrootEnable
27 * afs_GetDynrootEnable
28 * afs_DynrootVOPRemove
29 * afs_DynrootVOPSymlink
30 *
31 */
32
33 #include <afsconfig.h>
34 #include "afs/param.h"
35
36 #include "afs/stds.h"
37 #include "afs/sysincludes.h" /* Standard vendor system headers */
38 #include "afsincludes.h"
39 #include "afs/afs_osi.h"
40 #include "afsint.h"
41 #include "afs/lock.h"
42
43 #include "afs/prs_fs.h"
44 #include "afs/dir.h"
45 #include "afs/afs_dynroot.h"
46
47 #define AFS_DYNROOT_CELLNAME "dynroot"
48 #define AFS_DYNROOT_VOLUME 1
49 #define AFS_DYNROOT_VNODE 1
50 #define AFS_DYNROOT_MOUNT_VNODE 3
51 #define AFS_DYNROOT_UNIQUE 1
52
53 static int afs_dynrootInit = 0;
54 static int afs_dynrootEnable = 0;
55 static int afs_dynrootCell = 0;
56
57 afs_rwlock_t afs_dynrootDirLock;
58 /* Start of variables protected by afs_dynrootDirLock */
59 static char *afs_dynrootDir = NULL;
60 static int afs_dynrootDirLen;
61 static char *afs_dynrootMountDir = NULL;
62 static int afs_dynrootMountDirLen;
63 static int afs_dynrootDirLinkcnt;
64 static int afs_dynrootDirVersion;
65 static int afs_dynrootVersion = 1;
66 static int afs_dynrootVersionHigh = 1;
67 /* End of variables protected by afs_dynrootDirLock */
68
69 /* A dynamically-created symlink in a dynroot /afs */
70 struct afs_dynSymlink {
71 struct afs_dynSymlink *next;
72 int index;
73 char *name;
74 char *target;
75 };
76
77 afs_rwlock_t afs_dynSymlinkLock;
78 /* Start of variables protected by afs_dynSymlinkLock */
79 static struct afs_dynSymlink *afs_dynSymlinkBase = NULL;
80 static int afs_dynSymlinkIndex = 0;
81 /* End of variables protected by afs_dynSymlinkLock */
82
83 /*
84 * Set up a cell for dynroot if it's not there yet.
85 */
86 static int
87 afs_dynrootCellInit(void)
88 {
89 if (!afs_dynrootCell) {
90 afs_int32 cellHosts[AFS_MAXCELLHOSTS];
91 struct cell *tc;
92 int code;
93
94 memset(cellHosts, 0, sizeof(cellHosts));
95 code =
96 afs_NewCell(AFS_DYNROOT_CELLNAME, cellHosts, CNoSUID | CNoAFSDB,
97 NULL, 0, 0, 0);
98 if (code)
99 return code;
100 tc = afs_GetCellByName(AFS_DYNROOT_CELLNAME, READ_LOCK);
101 if (!tc)
102 return ENODEV;
103 afs_dynrootCell = tc->cellNum;
104 afs_PutCell(tc, READ_LOCK);
105 }
106
107 return 0;
108 }
109
110 /*!
111 * Returns non-zero if the volume is the dynroot volume.
112 */
113 int
114 afs_IsDynrootVolume(struct volume *v)
115 {
116 return (afs_dynrootEnable
117 && v->cell == afs_dynrootCell
118 && v->volume == AFS_DYNROOT_VOLUME);
119 }
120
121 /*
122 * Returns non-zero iff fid corresponds to the top of the dynroot volume.
123 */
124 static int
125 _afs_IsDynrootFid(struct VenusFid *fid)
126 {
127 return (fid->Cell == afs_dynrootCell
128 && fid->Fid.Volume == AFS_DYNROOT_VOLUME
129 && fid->Fid.Vnode == AFS_DYNROOT_VNODE
130 && fid->Fid.Unique == AFS_DYNROOT_UNIQUE);
131 }
132
133 int
134 afs_IsDynrootFid(struct VenusFid *fid)
135 {
136 return (afs_dynrootEnable && _afs_IsDynrootFid(fid));
137 }
138
139 int
140 afs_IsDynrootMountFid(struct VenusFid *fid)
141 {
142 return (fid->Cell == afs_dynrootCell
143 && fid->Fid.Volume == AFS_DYNROOT_VOLUME
144 && fid->Fid.Vnode == AFS_DYNROOT_MOUNT_VNODE
145 && fid->Fid.Unique == AFS_DYNROOT_UNIQUE);
146 }
147
148 int
149 afs_IsDynrootAnyFid(struct VenusFid *fid)
150 {
151 return (fid->Cell == afs_dynrootCell
152 && fid->Fid.Volume == AFS_DYNROOT_VOLUME);
153 }
154
155 /*
156 * Obtain the magic dynroot volume Fid.
157 */
158 void
159 afs_GetDynrootFid(struct VenusFid *fid)
160 {
161 fid->Cell = afs_dynrootCell;
162 fid->Fid.Volume = AFS_DYNROOT_VOLUME;
163 fid->Fid.Vnode = AFS_DYNROOT_VNODE;
164 fid->Fid.Unique = AFS_DYNROOT_UNIQUE;
165 }
166
167 void
168 afs_GetDynrootMountFid(struct VenusFid *fid)
169 {
170 fid->Cell = afs_dynrootCell;
171 fid->Fid.Volume = AFS_DYNROOT_VOLUME;
172 fid->Fid.Vnode = AFS_DYNROOT_MOUNT_VNODE;
173 fid->Fid.Unique = AFS_DYNROOT_UNIQUE;
174 }
175
176 /*
177 * Returns non-zero iff avc is a pointer to the dynroot /afs vnode.
178 */
179 int
180 afs_IsDynroot(struct vcache *avc)
181 {
182 return afs_IsDynrootFid(&avc->f.fid);
183 }
184
185 int
186 afs_IsDynrootMount(struct vcache *avc)
187 {
188 return afs_IsDynrootMountFid(&avc->f.fid);
189 }
190
191 int
192 afs_IsDynrootAny(struct vcache *avc)
193 {
194 return afs_IsDynrootAnyFid(&avc->f.fid);
195 }
196
197 /*
198 * Given the current page and chunk pointers in a directory, adjust them
199 * appropriately so that the given file name can be appended. Used for
200 * computing the size of a directory.
201 */
202 static void
203 afs_dynroot_computeDirEnt(char *name, int *curPageP, int *curChunkP)
204 {
205 int esize;
206
207 esize = afs_dir_NameBlobs(name);
208 if (*curChunkP + esize > EPP) {
209 *curPageP += 1;
210 *curChunkP = 1;
211 }
212 *curChunkP += esize;
213 }
214
215 /*
216 * Add directory entry by given name to a directory. Assumes the
217 * caller has allocated the directory to be large enough to hold
218 * the necessary entry.
219 */
220 static void
221 afs_dynroot_addDirEnt(struct DirHeader *dirHeader, int *curPageP,
222 int *curChunkP, char *name, int vnode)
223 {
224 char *dirBase = (char *)dirHeader;
225 struct PageHeader *pageHeader;
226 struct DirEntry *dirEntry;
227 int sizeOfEntry, i, t1, t2;
228 int curPage = *curPageP;
229 int curChunk = *curChunkP;
230 int didNewPage = 0;
231
232 /*
233 * Check if we need to flip pages.. If so, init the new page.
234 */
235 sizeOfEntry = afs_dir_NameBlobs(name);
236 if (curChunk + sizeOfEntry > EPP) {
237 curPage++;
238 curChunk = 1;
239 didNewPage = 1;
240 }
241
242 pageHeader = (struct PageHeader *)(dirBase + curPage * AFS_PAGESIZE);
243 if (didNewPage) {
244 pageHeader->pgcount = 0;
245 pageHeader->tag = htons(1234);
246 pageHeader->freecount = 0;
247 pageHeader->freebitmap[0] = 0x01;
248 for (i = 1; i < EPP / 8; i++)
249 pageHeader->freebitmap[i] = 0;
250
251 dirHeader->alloMap[curPage] = EPP - 1;
252 }
253
254 dirEntry = (struct DirEntry *)(pageHeader + curChunk);
255 dirEntry->flag = 1;
256 dirEntry->length = 0;
257 dirEntry->next = 0;
258 dirEntry->fid.vnode = htonl(vnode);
259 dirEntry->fid.vunique = htonl(1);
260 strcpy(dirEntry->name, name);
261
262 for (i = curChunk; i < curChunk + sizeOfEntry; i++) {
263 t1 = i / 8;
264 t2 = i % 8;
265 pageHeader->freebitmap[t1] |= (1 << t2);
266 }
267
268 /*
269 * Add the new entry to the correct hash chain.
270 */
271 i = afs_dir_DirHash(name);
272 dirEntry->next = dirHeader->hashTable[i];
273 dirHeader->hashTable[i] = htons(curPage * EPP + curChunk);
274
275 curChunk += sizeOfEntry;
276 dirHeader->alloMap[curPage] -= sizeOfEntry;
277
278 *curPageP = curPage;
279 *curChunkP = curChunk;
280 }
281
282 /*
283 * Invalidate the /afs vnode for dynroot; called when the underlying
284 * directory has changed and needs to be re-read.
285 */
286 void
287 afs_DynrootInvalidate(void)
288 {
289 afs_int32 retry;
290 struct vcache *tvc;
291 struct VenusFid tfid;
292
293 if (!afs_dynrootEnable)
294 return;
295
296 ObtainWriteLock(&afs_dynrootDirLock, 687);
297 afs_dynrootVersion++;
298 afs_dynrootVersionHigh = osi_Time();
299 ReleaseWriteLock(&afs_dynrootDirLock);
300
301 afs_GetDynrootFid(&tfid);
302 do {
303 retry = 0;
304 ObtainReadLock(&afs_xvcache);
305 tvc = afs_FindVCache(&tfid, &retry, 0);
306 ReleaseReadLock(&afs_xvcache);
307 } while (retry);
308 if (tvc) {
309 afs_StaleVCacheFlags(tvc, AFS_STALEVC_NOCB, CUnique);
310 afs_PutVCache(tvc);
311 }
312 }
313
314 /*
315 * Regenerates the dynroot contents from the current list of
316 * cells. Useful when the list of cells has changed due to
317 * an AFSDB lookup, for instance.
318 */
319 static void
320 afs_RebuildDynroot(void)
321 {
322 int cellidx, maxcellidx, i;
323 int aliasidx, maxaliasidx;
324 struct cell *c;
325 struct cell_alias *ca;
326 int curChunk, curPage;
327 int dirSize, dotLen;
328 char *newDir, *dotCell;
329 struct DirHeader *dirHeader;
330 int linkCount = 0;
331 struct afs_dynSymlink *ts;
332 int newVersion;
333
334 ObtainReadLock(&afs_dynrootDirLock);
335 newVersion = afs_dynrootVersion;
336 ReleaseReadLock(&afs_dynrootDirLock);
337
338 /*
339 * Compute the amount of space we need for the fake dir
340 */
341 curChunk = 13;
342 curPage = 0;
343
344 /* Reserve space for "." and ".." */
345 curChunk += 2;
346
347 /* Reserve space for the dynamic-mount directory */
348 afs_dynroot_computeDirEnt(AFS_DYNROOT_MOUNTNAME, &curPage, &curChunk);
349
350 for (cellidx = 0;; cellidx++) {
351 c = afs_GetCellByIndex(cellidx, READ_LOCK);
352 if (!c)
353 break;
354 if ((c->cellNum == afs_dynrootCell) || (c->states & CHush)) {
355 afs_PutCell(c, READ_LOCK);
356 continue;
357 }
358 dotLen = strlen(c->cellName) + 2;
359 dotCell = afs_osi_Alloc(dotLen);
360 osi_Assert(dotCell != NULL);
361 strcpy(dotCell, ".");
362 afs_strcat(dotCell, c->cellName);
363
364 afs_dynroot_computeDirEnt(c->cellName, &curPage, &curChunk);
365 afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk);
366
367 afs_osi_Free(dotCell, dotLen);
368 afs_PutCell(c, READ_LOCK);
369 }
370 maxcellidx = cellidx;
371
372 for (aliasidx = 0;; aliasidx++) {
373 ca = afs_GetCellAlias(aliasidx);
374 if (!ca)
375 break;
376
377 dotLen = strlen(ca->alias) + 2;
378 dotCell = afs_osi_Alloc(dotLen);
379 osi_Assert(dotCell != NULL);
380 strcpy(dotCell, ".");
381 afs_strcat(dotCell, ca->alias);
382
383 afs_dynroot_computeDirEnt(ca->alias, &curPage, &curChunk);
384 afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk);
385
386 afs_osi_Free(dotCell, dotLen);
387 afs_PutCellAlias(ca);
388 }
389 maxaliasidx = aliasidx;
390
391 ObtainReadLock(&afs_dynSymlinkLock);
392 ts = afs_dynSymlinkBase;
393 while (ts) {
394 afs_dynroot_computeDirEnt(ts->name, &curPage, &curChunk);
395 ts = ts->next;
396 }
397
398 dirSize = (curPage + 1) * AFS_PAGESIZE;
399 newDir = afs_osi_Alloc(dirSize);
400 osi_Assert(newDir != NULL);
401
402 /*
403 * Now actually construct the directory.
404 */
405 curChunk = 13;
406 curPage = 0;
407 dirHeader = (struct DirHeader *)newDir;
408
409 dirHeader->header.pgcount = 0;
410 dirHeader->header.tag = htons(1234);
411 dirHeader->header.freecount = 0;
412
413 dirHeader->header.freebitmap[0] = 0xff;
414 dirHeader->header.freebitmap[1] = 0x1f;
415 for (i = 2; i < EPP / 8; i++)
416 dirHeader->header.freebitmap[i] = 0;
417 dirHeader->alloMap[0] = EPP - DHE - 1;
418 for (i = 1; i < MAXPAGES; i++)
419 dirHeader->alloMap[i] = EPP;
420 memset(dirHeader->hashTable, 0, NHASHENT * sizeof(dirHeader->hashTable[0]));
421
422 /* Install ".", "..", and the dynamic mount directory */
423 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1);
424 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1);
425 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk,
426 AFS_DYNROOT_MOUNTNAME, AFS_DYNROOT_MOUNT_VNODE);
427 linkCount += 3;
428
429 for (cellidx = 0; cellidx < maxcellidx; cellidx++) {
430 c = afs_GetCellByIndex(cellidx, READ_LOCK);
431 if (!c)
432 continue;
433 if ((c->cellNum == afs_dynrootCell) || (c->states & CHush)) {
434 afs_PutCell(c, READ_LOCK);
435 continue;
436 }
437
438 dotLen = strlen(c->cellName) + 2;
439 dotCell = afs_osi_Alloc(dotLen);
440 osi_Assert(dotCell != NULL);
441 strcpy(dotCell, ".");
442 afs_strcat(dotCell, c->cellName);
443 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, c->cellName,
444 VNUM_FROM_CIDX_RW(cellidx, 0));
445 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
446 VNUM_FROM_CIDX_RW(cellidx, 1));
447 afs_osi_Free(dotCell, dotLen);
448
449 linkCount += 2;
450 afs_PutCell(c, READ_LOCK);
451 }
452
453 for (aliasidx = 0; aliasidx < maxaliasidx; aliasidx++) {
454 ca = afs_GetCellAlias(aliasidx);
455 if (!ca)
456 continue;
457
458 dotLen = strlen(ca->alias) + 2;
459 dotCell = afs_osi_Alloc(dotLen);
460 osi_Assert(dotCell != NULL);
461 strcpy(dotCell, ".");
462 afs_strcat(dotCell, ca->alias);
463 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ca->alias,
464 VNUM_FROM_CAIDX_RW(aliasidx, 0));
465 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell,
466 VNUM_FROM_CAIDX_RW(aliasidx, 1));
467 afs_osi_Free(dotCell, dotLen);
468 afs_PutCellAlias(ca);
469 }
470
471 ts = afs_dynSymlinkBase;
472 while (ts) {
473 int vnum = VNUM_FROM_TYPEID(VN_TYPE_SYMLINK, ts->index);
474 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ts->name, vnum);
475 ts = ts->next;
476 }
477
478 ReleaseReadLock(&afs_dynSymlinkLock);
479
480 ObtainWriteLock(&afs_dynrootDirLock, 549);
481 if (afs_dynrootDir)
482 afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen);
483 afs_dynrootDir = newDir;
484 afs_dynrootDirLen = dirSize;
485 afs_dynrootDirLinkcnt = linkCount;
486 afs_dynrootDirVersion = newVersion;
487 ReleaseWriteLock(&afs_dynrootDirLock);
488 }
489
490 static void
491 afs_RebuildDynrootMount(void)
492 {
493 int i;
494 int curChunk, curPage;
495 char *newDir;
496 struct DirHeader *dirHeader;
497
498 newDir = afs_osi_Alloc(AFS_PAGESIZE);
499 osi_Assert(newDir != NULL);
500
501 /*
502 * Now actually construct the directory.
503 */
504 curChunk = 13;
505 curPage = 0;
506 dirHeader = (struct DirHeader *)newDir;
507
508 dirHeader->header.pgcount = 0;
509 dirHeader->header.tag = htons(1234);
510 dirHeader->header.freecount = 0;
511
512 dirHeader->header.freebitmap[0] = 0xff;
513 dirHeader->header.freebitmap[1] = 0x1f;
514 for (i = 2; i < EPP / 8; i++)
515 dirHeader->header.freebitmap[i] = 0;
516 dirHeader->alloMap[0] = EPP - DHE - 1;
517 for (i = 1; i < MAXPAGES; i++)
518 dirHeader->alloMap[i] = EPP;
519 memset(dirHeader->hashTable, 0, NHASHENT * sizeof(dirHeader->hashTable[0]));
520
521 /* Install "." and ".." */
522 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1);
523 afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1);
524
525 ObtainWriteLock(&afs_dynrootDirLock, 549);
526 if (afs_dynrootMountDir)
527 afs_osi_Free(afs_dynrootMountDir, afs_dynrootMountDirLen);
528 afs_dynrootMountDir = newDir;
529 afs_dynrootMountDirLen = AFS_PAGESIZE;
530 ReleaseWriteLock(&afs_dynrootDirLock);
531 }
532
533 /*
534 * Returns a pointer to the base of the dynroot directory in memory,
535 * length thereof, and a FetchStatus.
536 */
537 void
538 afs_GetDynroot(char **dynrootDir, int *dynrootLen,
539 struct AFSFetchStatus *status)
540 {
541 ObtainReadLock(&afs_dynrootDirLock);
542 if (!afs_dynrootDir || afs_dynrootDirVersion != afs_dynrootVersion) {
543 ReleaseReadLock(&afs_dynrootDirLock);
544 afs_RebuildDynroot();
545 ObtainReadLock(&afs_dynrootDirLock);
546 }
547
548 if (dynrootDir)
549 *dynrootDir = afs_dynrootDir;
550 if (dynrootLen)
551 *dynrootLen = afs_dynrootDirLen;
552
553 if (status) {
554 memset(status, 0, sizeof(struct AFSFetchStatus));
555 status->FileType = Directory;
556 status->LinkCount = afs_dynrootDirLinkcnt;
557 status->Length = afs_dynrootDirLen;
558 status->DataVersion = afs_dynrootVersion;
559 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
560 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
561 status->UnixModeBits = 0755;
562 status->ParentVnode = 1;
563 status->ParentUnique = 1;
564 status->dataVersionHigh = afs_dynrootVersionHigh;
565 }
566 }
567
568 void
569 afs_GetDynrootMount(char **dynrootDir, int *dynrootLen,
570 struct AFSFetchStatus *status)
571 {
572 ObtainReadLock(&afs_dynrootDirLock);
573 if (!afs_dynrootMountDir) {
574 ReleaseReadLock(&afs_dynrootDirLock);
575 afs_RebuildDynrootMount();
576 ObtainReadLock(&afs_dynrootDirLock);
577 }
578
579 if (dynrootDir)
580 *dynrootDir = afs_dynrootMountDir;
581 if (dynrootLen)
582 *dynrootLen = afs_dynrootMountDirLen;
583
584 if (status) {
585 memset(status, 0, sizeof(struct AFSFetchStatus));
586 status->FileType = Directory;
587 status->LinkCount = 1;
588 status->Length = afs_dynrootMountDirLen;
589 status->DataVersion = 1;
590 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
591 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
592 status->UnixModeBits = 0755;
593 status->ParentVnode = 1;
594 status->ParentUnique = 1;
595 status->dataVersionHigh = 0;
596 }
597 }
598
599 /*
600 * Puts back the dynroot read lock.
601 */
602 void
603 afs_PutDynroot(void)
604 {
605 ReleaseReadLock(&afs_dynrootDirLock);
606 }
607
608 /*
609 * Inform dynroot that a new vnode is being created. Return value
610 * is non-zero if this vnode is handled by dynroot, in which case
611 * FetchStatus will be filled in.
612 */
613 int
614 afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status)
615 {
616 char *bp, tbuf[CVBS];
617
618 if (_afs_IsDynrootFid(&avc->f.fid)) {
619 if (!afs_dynrootEnable)
620 return 0;
621 afs_GetDynroot(0, 0, status);
622 afs_PutDynroot();
623 goto succeed;
624 }
625
626 if (afs_IsDynrootMount(avc)) {
627 afs_GetDynrootMount(0, 0, status);
628 afs_PutDynroot();
629 goto succeed;
630 }
631
632 /*
633 * Check if this is an entry under /afs, e.g. /afs/cellname.
634 */
635 if (avc->f.fid.Cell == afs_dynrootCell
636 && avc->f.fid.Fid.Volume == AFS_DYNROOT_VOLUME) {
637
638 struct cell *c;
639 struct cell_alias *ca;
640 int namelen, linklen, cellidx, rw;
641
642 memset(status, 0, sizeof(struct AFSFetchStatus));
643
644 status->FileType = SymbolicLink;
645 status->LinkCount = 1;
646 status->DataVersion = 1;
647 status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ;
648 status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ;
649 status->ParentVnode = 1;
650 status->ParentUnique = 1;
651
652 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_SYMLINK) {
653 struct afs_dynSymlink *ts;
654 int index = VNUM_TO_VNID(avc->f.fid.Fid.Vnode);
655
656 ObtainReadLock(&afs_dynSymlinkLock);
657 ts = afs_dynSymlinkBase;
658 while (ts) {
659 if (ts->index == index)
660 break;
661 ts = ts->next;
662 }
663
664 if (ts) {
665 linklen = strlen(ts->target);
666 avc->linkData = afs_osi_Alloc(linklen + 1);
667 osi_Assert(avc->linkData != NULL);
668 strcpy(avc->linkData, ts->target);
669
670 status->Length = linklen;
671 status->UnixModeBits = 0755;
672 }
673 ReleaseReadLock(&afs_dynSymlinkLock);
674
675 if (ts)
676 goto succeed;
677
678 return 0;
679 }
680
681 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_CELL
682 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_ALIAS
683 && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_MOUNT) {
684 afs_warn("dynroot vnode inconsistency, unknown VNTYPE %d\n",
685 VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode));
686 return 0;
687 }
688
689 cellidx = VNUM_TO_CIDX(avc->f.fid.Fid.Vnode);
690 rw = VNUM_TO_RW(avc->f.fid.Fid.Vnode);
691
692 if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_ALIAS) {
693 char *realName;
694
695 ca = afs_GetCellAlias(cellidx);
696 if (!ca) {
697 afs_warn("dynroot vnode inconsistency, can't find alias %d\n",
698 cellidx);
699 return 0;
700 }
701
702 /*
703 * linkData needs to contain the name of the cell
704 * we're aliasing for.
705 */
706 realName = ca->cell;
707 if (!realName) {
708 afs_warn("dynroot: alias %s missing real cell name\n",
709 ca->alias);
710 avc->linkData = afs_strdup("unknown");
711 linklen = 7;
712 } else {
713 int namelen = strlen(realName);
714 linklen = rw + namelen;
715 avc->linkData = afs_osi_Alloc(linklen + 1);
716 osi_Assert(avc->linkData != NULL);
717 strcpy(avc->linkData, rw ? "." : "");
718 afs_strcat(avc->linkData, realName);
719 }
720
721 status->UnixModeBits = 0755;
722 afs_PutCellAlias(ca);
723
724 } else if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
725 c = afs_GetCellByIndex(cellidx, READ_LOCK);
726 if (!c) {
727 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
728 cellidx);
729 return 0;
730 }
731
732 /*
733 * linkData needs to contain "%cell:volumeid"
734 */
735 namelen = strlen(c->cellName);
736 bp = afs_cv2string(&tbuf[CVBS], avc->f.fid.Fid.Unique);
737 linklen = 2 + namelen + strlen(bp);
738 avc->linkData = afs_osi_Alloc(linklen + 1);
739 osi_Assert(avc->linkData != NULL);
740 strcpy(avc->linkData, "%");
741 afs_strcat(avc->linkData, c->cellName);
742 afs_strcat(avc->linkData, ":");
743 afs_strcat(avc->linkData, bp);
744
745 status->UnixModeBits = 0644;
746 status->ParentVnode = AFS_DYNROOT_MOUNT_VNODE;
747 afs_PutCell(c, READ_LOCK);
748
749 } else {
750 c = afs_GetCellByIndex(cellidx, READ_LOCK);
751 if (!c) {
752 afs_warn("dynroot vnode inconsistency, can't find cell %d\n",
753 cellidx);
754 return 0;
755 }
756
757 /*
758 * linkData needs to contain "#cell:root.cell" or "%cell:root.cell"
759 */
760 namelen = strlen(c->cellName);
761 linklen = 1 + namelen + 10;
762 avc->linkData = afs_osi_Alloc(linklen + 1);
763 osi_Assert(avc->linkData != NULL);
764 strcpy(avc->linkData, rw ? "%" : "#");
765 afs_strcat(avc->linkData, c->cellName);
766 afs_strcat(avc->linkData, ":root.cell");
767
768 status->UnixModeBits = 0644;
769 afs_PutCell(c, READ_LOCK);
770 }
771
772 status->Length = linklen;
773 goto succeed;
774 }
775
776 return 0;
777
778 /* make sure we set type correctly when we do this. used to stay VREG */
779 succeed:
780 switch (status->FileType) {
781 case File:
782 vSetType(avc, VREG);
783 break;
784 case Directory:
785 vSetType(avc, VDIR);
786 break;
787 case SymbolicLink:
788 if (afs_fakestat_enable && (avc->f.m.Mode & 0111) == 0)
789 vSetType(avc, VDIR);
790 else
791 vSetType(avc, VLNK);
792 break;
793 default:
794 /* shouldn't happen */
795 ;
796 }
797 return 1;
798 }
799
800 /*
801 * Make sure dynroot initialization has been done.
802 */
803 int
804 afs_InitDynroot(void)
805 {
806 if (afs_dynrootInit)
807 return 0;
808 AFS_RWLOCK_INIT(&afs_dynrootDirLock, "afs_dynrootDirLock");
809 AFS_RWLOCK_INIT(&afs_dynSymlinkLock, "afs_dynSymlinkLock");
810 afs_dynrootInit = 0;
811 return afs_dynrootCellInit();
812 }
813
814 /*
815 * Enable or disable dynroot. Returns 0 if successful.
816 */
817 int
818 afs_SetDynrootEnable(int enable)
819 {
820 afs_dynrootEnable = enable;
821 return afs_InitDynroot();
822 }
823
824 /*
825 * Check if dynroot support is enabled.
826 */
827 int
828 afs_GetDynrootEnable(void)
829 {
830 return afs_dynrootEnable;
831 }
832
833 /*
834 * Remove a temporary symlink entry from /afs.
835 */
836 int
837 afs_DynrootVOPRemove(struct vcache *avc, afs_ucred_t *acred, char *aname)
838 {
839 struct afs_dynSymlink **tpps;
840 struct afs_dynSymlink *tps;
841 int found = 0;
842
843 #if defined(AFS_SUN510_ENV)
844 if (crgetruid(acred))
845 #else
846 if (afs_cr_uid(acred))
847 #endif
848 return EPERM;
849
850 ObtainWriteLock(&afs_dynSymlinkLock, 97);
851 tpps = &afs_dynSymlinkBase;
852 while (*tpps) {
853 tps = *tpps;
854 if (afs_strcasecmp(aname, tps->name) == 0) {
855 afs_osi_Free(tps->name, strlen(tps->name) + 1);
856 afs_osi_Free(tps->target, strlen(tps->target) + 1);
857 *tpps = tps->next;
858 afs_osi_Free(tps, sizeof(*tps));
859 afs_dynSymlinkIndex++;
860 found = 1;
861 break;
862 }
863 tpps = &(tps->next);
864 }
865 ReleaseWriteLock(&afs_dynSymlinkLock);
866 if (found) {
867 afs_DynrootInvalidate();
868 return 0;
869 }
870
871 if (afs_CellOrAliasExists(aname))
872 return EROFS;
873 else
874 return ENOENT;
875 }
876
877 /*
878 * Create a temporary symlink entry in /afs.
879 */
880 int
881 afs_DynrootVOPSymlink(struct vcache *avc, afs_ucred_t *acred,
882 char *aname, char *atargetName)
883 {
884 struct afs_dynSymlink *tps;
885
886 if (afs_cr_uid(acred))
887 return EPERM;
888 if (afs_CellOrAliasExists(aname))
889 return EEXIST;
890
891 /* Check if it's already a symlink */
892 ObtainWriteLock(&afs_dynSymlinkLock, 91);
893 tps = afs_dynSymlinkBase;
894 while (tps) {
895 if (afs_strcasecmp(aname, tps->name) == 0) {
896 ReleaseWriteLock(&afs_dynSymlinkLock);
897 return EEXIST;
898 }
899 tps = tps->next;
900 }
901
902 /* Doesn't already exist -- go ahead and create it */
903 tps = afs_osi_Alloc(sizeof(*tps));
904 osi_Assert(tps != NULL);
905 tps->index = afs_dynSymlinkIndex++;
906 tps->next = afs_dynSymlinkBase;
907 tps->name = afs_osi_Alloc(strlen(aname) + 1);
908 osi_Assert(tps->name != NULL);
909 strcpy(tps->name, aname);
910 tps->target = afs_osi_Alloc(strlen(atargetName) + 1);
911 osi_Assert(tps->target != NULL);
912 strcpy(tps->target, atargetName);
913 afs_dynSymlinkBase = tps;
914 ReleaseWriteLock(&afs_dynSymlinkLock);
915
916 afs_DynrootInvalidate();
917 return 0;
918 }