81c3cb6700cdd2b741644cbb079ced47fdda934a
[openafs.git] / src / afs / UKERNEL / afs_usrops.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  * User space client specific interface glue
12  */
13
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17 RCSID
18     ("$Header$");
19
20
21 #ifdef  UKERNEL
22
23 #include "afs/sysincludes.h"    /* Standard vendor system headers */
24 #include <net/if.h>
25 #include "afsincludes.h"        /* Afs-based standard headers */
26 #include "afs_usrops.h"
27 #include "afs/afs_stats.h"
28 #include "afs/auth.h"
29 #include "afs/cellconfig.h"
30 #include "afs/vice.h"
31 #include "afs/kautils.h"
32 #include "afs/afsutil.h"
33 #include "rx/rx_globals.h"
34
35 #define VFS 1
36 #undef  VIRTUE
37 #undef  VICE
38
39 #define CACHEINFOFILE   "cacheinfo"
40 #define AFSLOGFILE      "AFSLog"
41 #define DCACHEFILE      "CacheItems"
42 #define VOLINFOFILE     "VolumeItems"
43 #define CELLINFOFILE    "CellItems"
44 #define MAXIPADDRS 64
45
46 #ifndef MIN
47 #define MIN(A,B)        ((A)<(B)?(A):(B))
48 #endif
49 #ifndef MAX
50 #define MAX(A,B)        ((A)>(B)?(A):(B))
51 #endif
52
53 extern int cacheDiskType;
54
55 char afs_LclCellName[64];
56
57 struct usr_vnode *afs_FileTable[MAX_OSI_FILES];
58 int afs_FileFlags[MAX_OSI_FILES];
59 int afs_FileOffsets[MAX_OSI_FILES];
60
61 #define MAX_CACHE_LOOPS 4
62
63 struct usr_vfs afs_RootVfs;
64 struct usr_vnode *afs_RootVnode = NULL;
65 struct usr_vnode *afs_CurrentDir = NULL;
66
67 afs_int32 cacheBlocks;          /* Num blocks in cache */
68 afs_int32 cacheFiles = 1000;    /* Num files in workstation cache */
69 afs_int32 cacheStatEntries = 300;       /* Num of stat cache entries */
70 char cacheBaseDir[1024];        /* AFS cache directory */
71 char confDir[1024];             /* AFS configuration directory */
72 char afs_mountDir[1024];        /* AFS mount point */
73 int afs_mountDirLen;            /* strlen of AFS mount point */
74 char fullpn_DCacheFile[1024];   /* Full pathname of DCACHEFILE */
75 char fullpn_VolInfoFile[1024];  /* Full pathname of VOLINFOFILE */
76 char fullpn_CellInfoFile[1024]; /* Full pathname of CELLINFOFILE */
77 char fullpn_AFSLogFile[1024];   /* Full pathname of AFSLOGFILE */
78 char fullpn_CacheInfo[1024];    /* Full pathname of CACHEINFO */
79 char fullpn_VFile[1024];        /* Full pathname of data cache files */
80 char *vFileNumber;              /* Ptr to number in file pathname */
81 char rootVolume[64] = "root.afs";       /* AFS root volume name */
82 afs_int32 isHomeCell;           /* Is current cell info for home cell */
83 int createAndTrunc = O_CREAT | O_TRUNC; /* Create & truncate on open */
84 int ownerRWmode = 0600;         /* Read/write OK by owner */
85 static int nDaemons = 2;        /* Number of background daemons */
86 static int chunkSize = 0;       /* 2^chunkSize bytes per chunk */
87 static int dCacheSize = 300;    /* # of dcache entries */
88 static int vCacheSize = 50;     /* # of volume cache entries */
89 static int cacheFlags = 0;      /* Flags to cache manager */
90 static int preallocs = 400;     /* Def # of allocated memory blocks */
91 int afsd_verbose = 0;           /* Are we being chatty? */
92 int afsd_debug = 0;             /* Are we printing debugging info? */
93 int afsd_CloseSynch = 0;        /* Are closes synchronous or not? */
94
95 #define AFSD_INO_T afs_uint32
96 char **pathname_for_V;          /* Array of cache file pathnames */
97 int missing_DCacheFile = 1;     /* Is the DCACHEFILE missing? */
98 int missing_VolInfoFile = 1;    /* Is the VOLINFOFILE missing? */
99 int missing_CellInfoFile = 1;
100 struct afs_cacheParams cparams; /* params passed to cache manager */
101 struct afsconf_dir *afs_cdir;   /* config dir */
102
103 static int HandleMTab();
104
105 int afs_bufferpages = 100;
106 int usr_udpcksum = 0;
107
108 usr_key_t afs_global_u_key;
109
110 struct usr_proc *afs_global_procp;
111 struct usr_ucred *afs_global_ucredp;
112 struct usr_sysent usr_sysent[200];
113
114 #ifdef AFS_USR_OSF_ENV
115 char V = 'V';
116 #else /* AFS_USR_OSF_ENV */
117 long V = 'V';
118 #endif /* AFS_USR_OSF_ENV */
119
120 struct usr_ucred afs_osi_cred, *afs_osi_credp;
121 usr_mutex_t afs_global_lock;
122 usr_thread_t afs_global_owner;
123 usr_mutex_t rx_global_lock;
124 usr_thread_t rx_global_owner;
125 usr_mutex_t osi_inode_lock;
126 usr_mutex_t osi_waitq_lock;
127 usr_mutex_t osi_authenticate_lock;
128 afs_lock_t afs_ftf;
129 afs_lock_t osi_flplock;
130 afs_lock_t osi_fsplock;
131 void *vnodefops;
132
133 #ifndef NETSCAPE_NSAPI
134
135 /*
136  * Mutex and condition variable used to implement sleep
137  */
138 pthread_mutex_t usr_sleep_mutex;
139 pthread_cond_t usr_sleep_cond;
140
141 #endif /* !NETSCAPE_NSAPI */
142
143 int call_syscall(long, long, long, long, long, long);
144
145
146 /*
147  * Hash table mapping addresses onto wait structures for
148  * osi_Sleep/osi_Wakeup and osi_Wait/osi_Wakeup
149  */
150 typedef struct osi_wait {
151     caddr_t addr;
152     usr_cond_t cond;
153     int flag;
154     struct osi_wait *next;
155     struct osi_wait *prev;
156     time_t expiration;
157     struct osi_wait *timedNext;
158     struct osi_wait *timedPrev;
159 } osi_wait_t;
160
161 /*
162  * Head of the linked list of available waitq structures.
163  */
164 osi_wait_t *osi_waithash_avail;
165
166 /*
167  * List of timed waits, NSAPI does not provide a cond_timed
168  * wait, so we need to keep track of the timed waits ourselves and
169  * periodically check for expirations
170  */
171 osi_wait_t *osi_timedwait_head;
172 osi_wait_t *osi_timedwait_tail;
173
174 struct {
175     osi_wait_t *head;
176     osi_wait_t *tail;
177 } osi_waithash_table[OSI_WAITHASH_SIZE];
178
179 /*
180  * Never call afs_brelse
181  */
182 int
183 ufs_brelse(struct usr_vnode *vp, struct usr_buf *bp)
184 {
185     usr_assert(0);
186 }
187
188 /*
189  * I am not sure what to do with these, they assert for now
190  */
191 int
192 iodone(struct usr_buf *bp)
193 {
194     usr_assert(0);
195 }
196
197 struct usr_file *
198 getf(int fd)
199 {
200     usr_assert(0);
201 }
202
203 /*
204  * Every user is a super user
205  */
206 int
207 afs_osi_suser(void *credp)
208 {
209     return 1;
210 }
211
212 int
213 afs_suser(void *credp)
214 {
215     return 1;
216 }
217
218 /*
219  * These are no-ops in user space
220  */
221
222 void
223 afs_osi_SetTime(osi_timeval_t * atv)
224 {
225     return;
226 }
227
228 /*
229  * xflock should never fall through, the only files we know
230  * about are AFS files
231  */
232 int
233 usr_flock(void)
234 {
235     usr_assert(0);
236 }
237
238 /*
239  * ioctl should never fall through, the only files we know
240  * about are AFS files
241  */
242 int
243 usr_ioctl(void)
244 {
245     usr_assert(0);
246 }
247
248 /*
249  * We do not support the inode related system calls
250  */
251 int
252 afs_syscall_icreate(void)
253 {
254     usr_assert(0);
255 }
256
257 int
258 afs_syscall_iincdec(void)
259 {
260     usr_assert(0);
261 }
262
263 int
264 afs_syscall_iopen(void)
265 {
266     usr_assert(0);
267 }
268
269 int
270 afs_syscall_ireadwrite(void)
271 {
272     usr_assert(0);
273 }
274
275 /*
276  * these routines are referenced in the vfsops structure, but
277  * should never get called
278  */
279 int
280 vno_close(void)
281 {
282     usr_assert(0);
283 }
284
285 int
286 vno_ioctl(void)
287 {
288     usr_assert(0);
289 }
290
291 int
292 vno_rw(void)
293 {
294     usr_assert(0);
295 }
296
297 int
298 vno_select(void)
299 {
300     usr_assert(0);
301 }
302
303 /*
304  * uiomove copies data between kernel buffers and uio buffers
305  */
306 int
307 usr_uiomove(char *kbuf, int n, int rw, struct usr_uio *uio)
308 {
309     int nio;
310     int len;
311     char *ptr;
312     struct iovec *iovp;
313
314     nio = uio->uio_iovcnt;
315     iovp = uio->uio_iov;
316
317     if (nio <= 0)
318         return EFAULT;
319
320     /*
321      * copy the data
322      */
323     ptr = kbuf;
324     while (nio > 0 && n > 0) {
325         len = MIN(n, iovp->iov_len);
326         if (rw == UIO_READ) {
327             memcpy(iovp->iov_base, ptr, len);
328         } else {
329             memcpy(ptr, iovp->iov_base, len);
330         }
331         n -= len;
332         ptr += len;
333         uio->uio_resid -= len;
334         uio->uio_offset += len;
335         iovp->iov_base = (char *)(iovp->iov_base) + len;
336         iovp->iov_len -= len;
337         iovp++;
338         nio--;
339     }
340
341     if (n > 0)
342         return EFAULT;
343     return 0;
344 }
345
346 /*
347  * routines to manage user credentials
348  */
349 struct usr_ucred *
350 usr_crcopy(struct usr_ucred *credp)
351 {
352     struct usr_ucred *newcredp;
353
354     newcredp = (struct usr_ucred *)afs_osi_Alloc(sizeof(struct usr_ucred));
355     *newcredp = *credp;
356     newcredp->cr_ref = 1;
357     return newcredp;
358 }
359
360 struct usr_ucred *
361 usr_crget(void)
362 {
363     struct usr_ucred *newcredp;
364
365     newcredp = (struct usr_ucred *)afs_osi_Alloc(sizeof(struct usr_ucred));
366     newcredp->cr_ref = 1;
367     return newcredp;
368 }
369
370 int
371 usr_crfree(struct usr_ucred *credp)
372 {
373     credp->cr_ref--;
374     if (credp->cr_ref == 0) {
375         afs_osi_Free((char *)credp, sizeof(struct usr_ucred));
376     }
377 }
378
379 int
380 usr_crhold(struct usr_ucred *credp)
381 {
382     credp->cr_ref++;
383 }
384
385 void
386 usr_vattr_null(struct usr_vattr *vap)
387 {
388     int n;
389     char *cp;
390
391     n = sizeof(struct usr_vattr);
392     cp = (char *)vap;
393     while (n--) {
394         *cp++ = -1;
395     }
396 }
397
398 /*
399  * Initialize the thread specific data used to simulate the
400  * kernel environment for each thread. The user structure
401  * is stored in the thread specific data.
402  */
403 void
404 uafs_InitThread(void)
405 {
406     int st;
407     struct usr_user *uptr;
408
409     /*
410      * initialize the thread specific user structure. Use malloc to
411      * allocate the data block, so pthread_finish can free the buffer
412      * when this thread terminates.
413      */
414     uptr =
415         (struct usr_user *)malloc(sizeof(struct usr_user) +
416                                   sizeof(struct usr_ucred));
417     usr_assert(uptr != NULL);
418     uptr->u_error = 0;
419     uptr->u_prio = 0;
420     uptr->u_procp = afs_global_procp;
421     uptr->u_cred = (struct usr_ucred *)(uptr + 1);
422     *uptr->u_cred = *afs_global_ucredp;
423     st = usr_setspecific(afs_global_u_key, (void *)uptr);
424     usr_assert(st == 0);
425 }
426
427 /*
428  * routine to get the user structure from the thread specific data.
429  * this routine is used to implement the global 'u' structure. Initializes
430  * the thread if needed.
431  */
432 struct usr_user *
433 get_user_struct(void)
434 {
435     struct usr_user *uptr;
436     int st;
437     st = usr_getspecific(afs_global_u_key, (void **)&uptr);
438     usr_assert(st == 0);
439     if (uptr == NULL) {
440         uafs_InitThread();
441         st = usr_getspecific(afs_global_u_key, (void **)&uptr);
442         usr_assert(st == 0);
443         usr_assert(uptr != NULL);
444     }
445     return uptr;
446 }
447
448 /*
449  * Hash an address for the waithash table
450  */
451 #define WAITHASH(X)     \
452         (((long)(X)^((long)(X)>>4)^((long)(X)<<4))&(OSI_WAITHASH_SIZE-1))
453
454 /*
455  * Sleep on an event
456  */
457 void
458 afs_osi_Sleep(void *x)
459 {
460     int index;
461     osi_wait_t *waitp;
462     int rxGlockOwner = ISAFS_RXGLOCK();
463     int glockOwner = ISAFS_GLOCK();
464
465     usr_mutex_lock(&osi_waitq_lock);
466     if (glockOwner) {
467         AFS_GUNLOCK();
468     }
469     if (rxGlockOwner) {
470         AFS_RXGUNLOCK();
471     }
472     index = WAITHASH(x);
473     if (osi_waithash_avail == NULL) {
474         waitp = (osi_wait_t *) afs_osi_Alloc(sizeof(osi_wait_t));
475         usr_cond_init(&waitp->cond);
476     } else {
477         waitp = osi_waithash_avail;
478         osi_waithash_avail = osi_waithash_avail->next;
479     }
480     waitp->addr = x;
481     waitp->flag = 0;
482     DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
483                     osi_waithash_table[index].tail, next, prev);
484     waitp->expiration = 0;
485     waitp->timedNext = NULL;
486     waitp->timedPrev = NULL;
487     while (waitp->flag == 0) {
488         usr_cond_wait(&waitp->cond, &osi_waitq_lock);
489     }
490     DLL_DELETE(waitp, osi_waithash_table[index].head,
491                osi_waithash_table[index].tail, next, prev);
492     waitp->next = osi_waithash_avail;
493     osi_waithash_avail = waitp;
494     usr_mutex_unlock(&osi_waitq_lock);
495     if (glockOwner) {
496         AFS_GLOCK();
497     }
498     if (rxGlockOwner) {
499         AFS_RXGLOCK();
500     }
501 }
502
503 int
504 afs_osi_SleepSig(void *x)
505 {
506     afs_osi_Sleep(x);
507     return 0;
508 }
509
510 int
511 afs_osi_Wakeup(void *x)
512 {
513     int index;
514     osi_wait_t *waitp;
515
516     index = WAITHASH(x);
517     usr_mutex_lock(&osi_waitq_lock);
518     waitp = osi_waithash_table[index].head;
519     while (waitp) {
520         if (waitp->addr == x && waitp->flag == 0) {
521             waitp->flag = 1;
522             usr_cond_signal(&waitp->cond);
523         }
524         waitp = waitp->next;
525     }
526     usr_mutex_unlock(&osi_waitq_lock);
527 }
528
529 int
530 afs_osi_Wait(afs_int32 msec, struct afs_osi_WaitHandle *handle, int intok)
531 {
532     int index;
533     osi_wait_t *waitp;
534     struct timespec tv;
535     int ret;
536     int rxGlockOwner = ISAFS_RXGLOCK();
537     int glockOwner = ISAFS_GLOCK();
538
539     tv.tv_sec = msec / 1000;
540     tv.tv_nsec = (msec % 1000) * 1000000;
541     if (handle == NULL) {
542         if (glockOwner) {
543             AFS_GUNLOCK();
544         }
545         if (rxGlockOwner) {
546             AFS_RXGUNLOCK();
547         }
548         usr_thread_sleep(&tv);
549         ret = 0;
550         if (glockOwner) {
551             AFS_GLOCK();
552         }
553         if (rxGlockOwner) {
554             AFS_RXGLOCK();
555         }
556     } else {
557         usr_mutex_lock(&osi_waitq_lock);
558         if (glockOwner) {
559             AFS_GUNLOCK();
560         }
561         if (rxGlockOwner) {
562             AFS_RXGUNLOCK();
563         }
564         index = WAITHASH((caddr_t) handle);
565         if (osi_waithash_avail == NULL) {
566             waitp = (osi_wait_t *) afs_osi_Alloc(sizeof(osi_wait_t));
567             usr_cond_init(&waitp->cond);
568         } else {
569             waitp = osi_waithash_avail;
570             osi_waithash_avail = osi_waithash_avail->next;
571         }
572         waitp->addr = (caddr_t) handle;
573         waitp->flag = 0;
574         DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
575                         osi_waithash_table[index].tail, next, prev);
576         tv.tv_sec += time(NULL);
577         waitp->expiration = tv.tv_sec + ((tv.tv_nsec == 0) ? 0 : 1);
578         DLL_INSERT_TAIL(waitp, osi_timedwait_head, osi_timedwait_tail,
579                         timedNext, timedPrev);
580         usr_cond_wait(&waitp->cond, &osi_waitq_lock);
581         if (waitp->flag) {
582             ret = 2;
583         } else {
584             ret = 0;
585         }
586         DLL_DELETE(waitp, osi_waithash_table[index].head,
587                    osi_waithash_table[index].tail, next, prev);
588         DLL_DELETE(waitp, osi_timedwait_head, osi_timedwait_tail, timedNext,
589                    timedPrev);
590         waitp->next = osi_waithash_avail;
591         osi_waithash_avail = waitp;
592         usr_mutex_unlock(&osi_waitq_lock);
593         if (glockOwner) {
594             AFS_GLOCK();
595         }
596         if (rxGlockOwner) {
597             AFS_RXGLOCK();
598         }
599     }
600     return ret;
601 }
602
603 void
604 afs_osi_CancelWait(struct afs_osi_WaitHandle *handle)
605 {
606     afs_osi_Wakeup(handle);
607 }
608
609 /*
610  * Netscape NSAPI doesn't have a cond_timed_wait, so we need
611  * to explicitly signal cond_timed_waits when their timers expire
612  */
613 int
614 afs_osi_CheckTimedWaits(void)
615 {
616     time_t curTime;
617     osi_wait_t *waitp;
618
619     curTime = time(NULL);
620     usr_mutex_lock(&osi_waitq_lock);
621     waitp = osi_timedwait_head;
622     while (waitp != NULL) {
623         usr_assert(waitp->expiration != 0);
624         if (waitp->expiration <= curTime) {
625             waitp->flag = 1;
626             usr_cond_signal(&waitp->cond);
627         }
628         waitp = waitp->timedNext;
629     }
630     usr_mutex_unlock(&osi_waitq_lock);
631 }
632
633 /*
634  * I-node numbers are indeces into a table containing a filename
635  * i-node structure and a vnode structure. When we create an i-node,
636  * we copy the name into the array and initialize enough of the fields
637  * in the inode and vnode structures to get the client to work.
638  */
639 typedef struct {
640     struct usr_inode i_node;
641     char *name;
642 } osi_file_table_t;
643 osi_file_table_t *osi_file_table;
644 int n_osi_files = 0;
645 int max_osi_files = 0;
646
647 /*
648  * Allocate a slot in the file table if there is not one there already,
649  * copy in the file name and kludge up the vnode and inode structures
650  */
651 int
652 lookupname(char *fnamep, int segflg, int followlink,
653            struct usr_vnode **dirvpp, struct usr_vnode **compvpp)
654 {
655     int i;
656     int code;
657     struct usr_inode *ip;
658     struct usr_vnode *vp;
659
660     /*usr_assert(followlink == 0); */
661     usr_assert(dirvpp == NULL);
662
663     /*
664      * Assume relative pathnames refer to files in AFS
665      */
666     if (*fnamep != '/' || uafs_afsPathName(fnamep) != NULL) {
667         AFS_GLOCK();
668         code = uafs_LookupName(fnamep, afs_CurrentDir, compvpp, 0, 0);
669         AFS_GUNLOCK();
670         return code;
671     }
672
673     usr_mutex_lock(&osi_inode_lock);
674
675     for (i = 0; i < n_osi_files; i++) {
676         if (strcmp(fnamep, osi_file_table[i].name) == 0) {
677             *compvpp = &osi_file_table[i].i_node.i_vnode;
678             (*compvpp)->v_count++;
679             usr_mutex_unlock(&osi_inode_lock);
680             return 0;
681         }
682     }
683
684     if (n_osi_files == max_osi_files) {
685         usr_mutex_unlock(&osi_inode_lock);
686         return ENOSPC;
687     }
688
689     osi_file_table[n_osi_files].name = afs_osi_Alloc(strlen(fnamep) + 1);
690     usr_assert(osi_file_table[n_osi_files].name != NULL);
691     strcpy(osi_file_table[n_osi_files].name, fnamep);
692     ip = &osi_file_table[i].i_node;
693     vp = &ip->i_vnode;
694     vp->v_data = (caddr_t) ip;
695     ip->i_dev = -1;
696     n_osi_files++;
697     ip->i_number = n_osi_files;
698     vp->v_count = 2;
699     usr_mutex_unlock(&osi_inode_lock);
700     *compvpp = vp;
701     return 0;
702 }
703
704 /*
705  * open a file given its i-node number
706  */
707 void *
708 osi_UFSOpen(afs_int32 ino)
709 {
710     int rc;
711     struct osi_file *fp;
712     struct stat st;
713
714     AFS_ASSERT_GLOCK();
715
716     if (ino > n_osi_files) {
717         u.u_error = ENOENT;
718         return NULL;
719     }
720
721     AFS_GUNLOCK();
722     fp = (struct osi_file *)afs_osi_Alloc(sizeof(struct osi_file));
723     usr_assert(fp != NULL);
724     fp->fd = open(osi_file_table[ino - 1].name, O_RDWR | O_CREAT, 0);
725     if (fp->fd < 0) {
726         u.u_error = errno;
727         afs_osi_Free((char *)fp, sizeof(struct osi_file));
728         AFS_GLOCK();
729         return NULL;
730     }
731     rc = fstat(fp->fd, &st);
732     if (rc < 0) {
733         u.u_error = errno;
734         afs_osi_Free((void *)fp, sizeof(struct osi_file));
735         AFS_GLOCK();
736         return NULL;
737     }
738     fp->size = st.st_size;
739     fp->offset = 0;
740     fp->inum = ino;
741     fp->vnode = (struct usr_vnode *)fp;
742
743     AFS_GLOCK();
744     return fp;
745 }
746
747 int
748 osi_UFSClose(struct osi_file *fp)
749 {
750     int rc;
751
752     AFS_ASSERT_GLOCK();
753
754     AFS_GUNLOCK();
755     rc = close(fp->fd);
756     if (rc < 0) {
757         u.u_error = errno;
758         afs_osi_Free((void *)fp, sizeof(struct osi_file));
759         AFS_GLOCK();
760         return -1;
761     }
762     afs_osi_Free((void *)fp, sizeof(struct osi_file));
763     AFS_GLOCK();
764     return 0;
765 }
766
767 int
768 osi_UFSTruncate(struct osi_file *fp, afs_int32 len)
769 {
770     int rc;
771
772     AFS_ASSERT_GLOCK();
773
774     AFS_GUNLOCK();
775     rc = ftruncate(fp->fd, len);
776     if (rc < 0) {
777         u.u_error = errno;
778         AFS_GLOCK();
779         return -1;
780     }
781     fp->size = len;
782     AFS_GLOCK();
783     return 0;
784 }
785
786 int
787 afs_osi_Read(struct osi_file *fp, int offset, void *buf, afs_int32 len)
788 {
789     int rc, ret;
790     int code;
791     struct stat st;
792
793     AFS_ASSERT_GLOCK();
794
795     AFS_GUNLOCK();
796     if (offset >= 0) {
797         rc = lseek(fp->fd, offset, SEEK_SET);
798     } else {
799         rc = lseek(fp->fd, fp->offset, SEEK_SET);
800     }
801     if (rc < 0) {
802         u.u_error = errno;
803         AFS_GLOCK();
804         return -1;
805     }
806     fp->offset = rc;
807     ret = read(fp->fd, buf, len);
808     if (ret < 0) {
809         u.u_error = errno;
810         AFS_GLOCK();
811         return -1;
812     }
813     fp->offset += ret;
814     rc = fstat(fp->fd, &st);
815     if (rc < 0) {
816         u.u_error = errno;
817         AFS_GLOCK();
818         return -1;
819     }
820     fp->size = st.st_size;
821     AFS_GLOCK();
822     return ret;
823 }
824
825 int
826 afs_osi_Write(struct osi_file *fp, afs_int32 offset, void *buf, afs_int32 len)
827 {
828     int rc, ret;
829     int code;
830     struct stat st;
831
832     AFS_ASSERT_GLOCK();
833
834     AFS_GUNLOCK();
835     if (offset >= 0) {
836         rc = lseek(fp->fd, offset, SEEK_SET);
837     } else {
838         rc = lseek(fp->fd, fp->offset, SEEK_SET);
839     }
840     if (rc < 0) {
841         u.u_error = errno;
842         AFS_GLOCK();
843         return -1;
844     }
845     fp->offset = rc;
846     ret = write(fp->fd, buf, len);
847     if (ret < 0) {
848         u.u_error = errno;
849         AFS_GLOCK();
850         return -1;
851     }
852     fp->offset += ret;
853     rc = fstat(fp->fd, &st);
854     if (rc < 0) {
855         u.u_error = errno;
856         AFS_GLOCK();
857         return -1;
858     }
859     fp->size = st.st_size;
860     AFS_GLOCK();
861     return ret;
862 }
863
864 int
865 afs_osi_Stat(struct osi_file *fp, struct osi_stat *stp)
866 {
867     int rc;
868     struct stat st;
869
870     AFS_GUNLOCK();
871     rc = fstat(fp->fd, &st);
872     if (rc < 0) {
873         u.u_error = errno;
874         AFS_GLOCK();
875         return -1;
876     }
877     stp->size = st.st_size;
878     stp->blksize = st.st_blksize;
879     stp->mtime = st.st_mtime;
880     stp->atime = st.st_atime;
881     AFS_GLOCK();
882     return 0;
883 }
884
885 /*
886  * VOP_RDWR routine
887  */
888 int
889 afs_osi_VOP_RDWR(struct usr_vnode *vnodeP, struct usr_uio *uioP, int rw,
890                  int flags, struct usr_ucred *credP)
891 {
892     int rc;
893     struct osi_file *fp = (struct osi_file *)vnodeP;
894
895     /*
896      * We don't support readv/writev.
897      */
898     usr_assert(uioP->uio_iovcnt == 1);
899     usr_assert(uioP->uio_resid == uioP->uio_iov[0].iov_len);
900
901     if (rw == UIO_WRITE) {
902         usr_assert(uioP->uio_fmode == FWRITE);
903         rc = afs_osi_Write(fp, uioP->uio_offset, uioP->uio_iov[0].iov_base,
904                            uioP->uio_iov[0].iov_len);
905     } else {
906         usr_assert(uioP->uio_fmode == FREAD);
907         rc = afs_osi_Read(fp, uioP->uio_offset, uioP->uio_iov[0].iov_base,
908                           uioP->uio_iov[0].iov_len);
909     }
910     if (rc < 0) {
911         return u.u_error;
912     }
913
914     uioP->uio_resid -= rc;
915     uioP->uio_offset += rc;
916     uioP->uio_iov[0].iov_base = (char *)(uioP->uio_iov[0].iov_base) + rc;
917     uioP->uio_iov[0].iov_len -= rc;
918     return 0;
919 }
920
921 /*
922  * Use malloc/free routines with check patterns before and after each block
923  */
924
925 static char *afs_check_string1 = "UAFS";
926 static char *afs_check_string2 = "AFS_OSI_";
927
928 void *
929 afs_osi_Alloc(size_t size)
930 {
931     return malloc(size);
932 }
933
934 void
935 afs_osi_Free(void *ptr, size_t size)
936 {
937     free(ptr);
938 }
939
940 void
941 afs_osi_FreeStr(char *ptr)
942 {
943     free(ptr);
944 }
945
946 void *
947 osi_AllocLargeSpace(size_t size)
948 {
949     AFS_STATCNT(osi_AllocLargeSpace);
950     return afs_osi_Alloc(size);
951 }
952
953 void
954 osi_FreeLargeSpace(void *ptr)
955 {
956     AFS_STATCNT(osi_FreeLargeSpace);
957     afs_osi_Free(ptr, 0);
958 }
959
960 void *
961 osi_AllocSmallSpace(size_t size)
962 {
963     AFS_STATCNT(osi_AllocSmallSpace);
964     return afs_osi_Alloc(size);
965 }
966
967 void
968 osi_FreeSmallSpace(void *ptr)
969 {
970     AFS_STATCNT(osi_FreeSmallSpace);
971     afs_osi_Free(ptr, 0);
972 }
973
974 void
975 shutdown_osi(void)
976 {
977     AFS_STATCNT(shutdown_osi);
978     return;
979 }
980
981 void
982 shutdown_osinet(void)
983 {
984     AFS_STATCNT(shutdown_osinet);
985     return;
986 }
987
988 void
989 shutdown_osifile(void)
990 {
991     AFS_STATCNT(shutdown_osifile);
992     return;
993 }
994
995 int
996 afs_nfsclient_init(void)
997 {
998     return 0;
999 }
1000
1001 void
1002 shutdown_nfsclnt(void)
1003 {
1004     return;
1005 }
1006
1007 void
1008 afs_osi_Invisible(void)
1009 {
1010     return;
1011 }
1012
1013 int
1014 osi_GetTime(struct timeval *tv)
1015 {
1016     gettimeofday(tv, NULL);
1017     return 0;
1018 }
1019
1020 int
1021 osi_SetTime(struct timeval *tv)
1022 {
1023     return 0;
1024 }
1025
1026 int
1027 osi_Active(struct vcache *avc)
1028 {
1029     AFS_STATCNT(osi_Active);
1030     if (avc->opens > 0)
1031         return (1);
1032     return 0;
1033 }
1034
1035 int
1036 afs_osi_MapStrategy(int (*aproc) (), struct usr_buf *bp)
1037 {
1038     afs_int32 returnCode;
1039     returnCode = (*aproc) (bp);
1040     return returnCode;
1041 }
1042
1043 void
1044 osi_FlushPages(register struct vcache *avc, struct AFS_UCRED *credp)
1045 {
1046     ObtainSharedLock(&avc->lock, 555);
1047     if ((hcmp((avc->m.DataVersion), (avc->mapDV)) <= 0)
1048         || ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
1049         ReleaseSharedLock(&avc->lock);
1050         return;
1051     }
1052     UpgradeSToWLock(&avc->lock, 565);
1053     hset(avc->mapDV, avc->m.DataVersion);
1054     ReleaseWriteLock(&avc->lock);
1055     return;
1056 }
1057
1058 void
1059 osi_FlushText_really(register struct vcache *vp)
1060 {
1061     if (hcmp(vp->m.DataVersion, vp->flushDV) > 0) {
1062         hset(vp->flushDV, vp->m.DataVersion);
1063     }
1064     return;
1065 }
1066
1067 int
1068 osi_SyncVM(struct vcache *avc)
1069 {
1070     return 0;
1071 }
1072
1073 void
1074 osi_ReleaseVM(struct vcache *avc, int len, struct usr_ucred *credp)
1075 {
1076     return;
1077 }
1078
1079 void
1080 osi_Init(void)
1081 {
1082     int i;
1083     int rc;
1084     usr_thread_t tid;
1085
1086     /*
1087      * Allocate the table used to implement psuedo-inodes.
1088      */
1089     max_osi_files = cacheFiles + 100;
1090     osi_file_table = (osi_file_table_t *)
1091         afs_osi_Alloc(max_osi_files * sizeof(osi_file_table_t));
1092     usr_assert(osi_file_table != NULL);
1093
1094 #ifndef NETSCAPE_NSAPI
1095     /*
1096      * Initialize the mutex and condition variable used to implement
1097      * time sleeps.
1098      */
1099     pthread_mutex_init(&usr_sleep_mutex, NULL);
1100     pthread_cond_init(&usr_sleep_cond, NULL);
1101 #endif /* !NETSCAPE_NSAPI */
1102
1103     /*
1104      * Initialize the hash table used for sleep/wakeup
1105      */
1106     for (i = 0; i < OSI_WAITHASH_SIZE; i++) {
1107         DLL_INIT_LIST(osi_waithash_table[i].head, osi_waithash_table[i].tail);
1108     }
1109     DLL_INIT_LIST(osi_timedwait_head, osi_timedwait_tail);
1110     osi_waithash_avail = NULL;
1111
1112     /*
1113      * Initialize the AFS file table
1114      */
1115     for (i = 0; i < MAX_OSI_FILES; i++) {
1116         afs_FileTable[i] = NULL;
1117     }
1118
1119     /*
1120      * Initialize the global locks
1121      */
1122     usr_mutex_init(&afs_global_lock);
1123     usr_mutex_init(&rx_global_lock);
1124     usr_mutex_init(&osi_inode_lock);
1125     usr_mutex_init(&osi_waitq_lock);
1126     usr_mutex_init(&osi_authenticate_lock);
1127
1128     /*
1129      * Initialize the AFS OSI credentials
1130      */
1131     afs_osi_cred = *afs_global_ucredp;
1132     afs_osi_credp = &afs_osi_cred;
1133 }
1134
1135 /* ParseArgs is now obsolete, being handled by cmd */
1136
1137 /*---------------------------------------------------------------------
1138   * GetVFileNumber
1139   *
1140   * Description:
1141   *     Given the final component of a filename expected to be a data cache file,
1142   *     return the integer corresponding to the file.  Note: we reject names that
1143   *     are not a ``V'' followed by an integer.  We also reject those names having
1144   *     the right format but lying outside the range [0..cacheFiles-1].
1145   *
1146   * Arguments:
1147   *     fname : Char ptr to the filename to parse.
1148   *
1149   * Returns:
1150   *     >= 0 iff the file is really a data cache file numbered from 0 to cacheFiles-1, or
1151   *     -1      otherwise.
1152   *
1153   * Environment:
1154   *     Nothing interesting.
1155   *
1156   * Side Effects:
1157   *     None.
1158   *------------------------------------------------------------------------*/
1159
1160 int
1161 GetVFileNumber(char *fname)
1162 {
1163     int computedVNumber;        /*The computed file number we return */
1164     int filenameLen;            /*Number of chars in filename */
1165     int currDigit;              /*Current digit being processed */
1166
1167     /*
1168      * The filename must have at least two characters, the first of which must be a ``V''
1169      * and the second of which cannot be a zero unless the file is exactly two chars long.
1170      */
1171     filenameLen = strlen(fname);
1172     if (filenameLen < 2)
1173         return (-1);
1174     if (fname[0] != 'V')
1175         return (-1);
1176     if ((filenameLen > 2) && (fname[1] == '0'))
1177         return (-1);
1178
1179     /*
1180      * Scan through the characters in the given filename, failing immediately if a non-digit
1181      * is found.
1182      */
1183     for (currDigit = 1; currDigit < filenameLen; currDigit++)
1184         if (isdigit(fname[currDigit]) == 0)
1185             return (-1);
1186
1187     /*
1188      * All relevant characters are digits.  Pull out the decimal number they represent.
1189      * Reject it if it's out of range, otherwise return it.
1190      */
1191     computedVNumber = atoi(++fname);
1192     if (computedVNumber < cacheFiles)
1193         return (computedVNumber);
1194     else
1195         return (-1);
1196 }
1197
1198 /*---------------------------------------------------------------------
1199   * CreateCacheFile
1200   *
1201   * Description:
1202   *     Given a full pathname for a file we need to create for the workstation AFS
1203   *     cache, go ahead and create the file.
1204   *
1205   * Arguments:
1206   *     fname : Full pathname of file to create.
1207   *
1208   * Returns:
1209   *     0   iff the file was created,
1210   *     -1  otherwise.
1211   *
1212   * Environment:
1213   *     The given cache file has been found to be missing.
1214   *
1215   * Side Effects:
1216   *     As described.
1217   *------------------------------------------------------------------------*/
1218
1219 int
1220 CreateCacheFile(char *fname)
1221 {
1222     static char rn[] = "CreateCacheFile";       /*Routine name */
1223     int cfd;                    /*File descriptor to AFS cache file */
1224     int closeResult;            /*Result of close() */
1225
1226     if (afsd_verbose)
1227         printf("%s: Creating cache file '%s'\n", rn, fname);
1228     cfd = open(fname, createAndTrunc, ownerRWmode);
1229     if (cfd <= 0) {
1230         printf("%s: Can't create '%s', error return is %d (%d)\n", rn, fname,
1231                cfd, errno);
1232         return (-1);
1233     }
1234     closeResult = close(cfd);
1235     if (closeResult) {
1236         printf
1237             ("%s: Can't close newly-created AFS cache file '%s' (code %d)\n",
1238              rn, fname, errno);
1239         return (-1);
1240     }
1241
1242     return (0);
1243 }
1244
1245 /*---------------------------------------------------------------------
1246   * SweepAFSCache
1247   *
1248   * Description:
1249   *     Sweep through the AFS cache directory, recording the inode number for
1250   *     each valid data cache file there.  Also, delete any file that doesn't beint32
1251   *     in the cache directory during this sweep, and remember which of the other
1252   *     residents of this directory were seen.  After the sweep, we create any data
1253   *     cache files that were missing.
1254   *
1255   * Arguments:
1256   *     vFilesFound : Set to the number of data cache files found.
1257   *
1258   * Returns:
1259   *     0   if everything went well,
1260   *     -1 otherwise.
1261   *
1262   * Environment:
1263   *     This routine may be called several times.  If the number of data cache files
1264   *     found is less than the global cacheFiles, then the caller will need to call it
1265   *     again to record the inodes of the missing zero-length data cache files created
1266   *     in the previous call.
1267   *
1268   * Side Effects:
1269   *     Fills up the global pathname_for_V array, may create and/or
1270   *     delete files as explained above.
1271   *------------------------------------------------------------------------*/
1272
1273 int
1274 SweepAFSCache(int *vFilesFound)
1275 {
1276     static char rn[] = "SweepAFSCache"; /*Routine name */
1277     char fullpn_FileToDelete[1024];     /*File to be deleted from cache */
1278     char *fileToDelete;         /*Ptr to last component of above */
1279     DIR *cdirp;                 /*Ptr to cache directory structure */
1280 #undef dirent
1281     struct dirent *currp;       /*Current directory entry */
1282     int vFileNum;               /*Data cache file's associated number */
1283
1284     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1285         if (afsd_debug)
1286             printf("%s: Memory Cache, no cache sweep done\n", rn);
1287         *vFilesFound = 0;
1288         return 0;
1289     }
1290
1291     if (afsd_debug)
1292         printf("%s: Opening cache directory '%s'\n", rn, cacheBaseDir);
1293
1294     if (chmod(cacheBaseDir, 0700)) {    /* force it to be 700 */
1295         printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n", rn,
1296                cacheBaseDir);
1297         return (-1);
1298     }
1299     cdirp = opendir(cacheBaseDir);
1300     if (cdirp == (DIR *) 0) {
1301         printf("%s: Can't open AFS cache directory, '%s'.\n", rn,
1302                cacheBaseDir);
1303         return (-1);
1304     }
1305
1306     /*
1307      * Scan the directory entries, remembering data cache file inodes and the existance
1308      * of other important residents.  Delete all files that don't belong here.
1309      */
1310     *vFilesFound = 0;
1311     sprintf(fullpn_FileToDelete, "%s/", cacheBaseDir);
1312     fileToDelete = fullpn_FileToDelete + strlen(fullpn_FileToDelete);
1313
1314     for (currp = readdir(cdirp); currp; currp = readdir(cdirp)) {
1315         if (afsd_debug) {
1316             printf("%s: Current directory entry:\n", rn);
1317             printf("\tinode=%d, reclen=%d, name='%s'\n", currp->d_ino,
1318                    currp->d_reclen, currp->d_name);
1319         }
1320
1321         /*
1322          * Guess current entry is for a data cache file.
1323          */
1324         vFileNum = GetVFileNumber(currp->d_name);
1325         if (vFileNum >= 0) {
1326             /*
1327              * Found a valid data cache filename.  Remember this file's name
1328              * and bump the number of files found.
1329              */
1330             pathname_for_V[vFileNum] =
1331                 afs_osi_Alloc(strlen(currp->d_name) + strlen(cacheBaseDir) +
1332                               2);
1333             usr_assert(pathname_for_V[vFileNum] != NULL);
1334             sprintf(pathname_for_V[vFileNum], "%s/%s", cacheBaseDir,
1335                     currp->d_name);
1336             (*vFilesFound)++;
1337         } else if (strcmp(currp->d_name, DCACHEFILE) == 0) {
1338             /*
1339              * Found the file holding the dcache entries.
1340              */
1341             missing_DCacheFile = 0;
1342         } else if (strcmp(currp->d_name, VOLINFOFILE) == 0) {
1343             /*
1344              * Found the file holding the volume info.
1345              */
1346             missing_VolInfoFile = 0;
1347         } else if (strcmp(currp->d_name, CELLINFOFILE) == 0) {
1348             missing_CellInfoFile = 0;
1349         } else if ((strcmp(currp->d_name, ".") == 0)
1350                    || (strcmp(currp->d_name, "..") == 0)
1351                    || (strcmp(currp->d_name, "lost+found") == 0)) {
1352             /*
1353              * Don't do anything - this file is legit, and is to be left alone.
1354              */
1355         } else {
1356             /*
1357              * This file doesn't belong in the cache.  Nuke it.
1358              */
1359             sprintf(fileToDelete, "%s", currp->d_name);
1360             if (afsd_verbose)
1361                 printf("%s: Deleting '%s'\n", rn, fullpn_FileToDelete);
1362             if (unlink(fullpn_FileToDelete)) {
1363                 printf("%s: Can't unlink '%s', errno is %d\n", rn,
1364                        fullpn_FileToDelete, errno);
1365             }
1366         }
1367     }
1368
1369     /*
1370      * Create all the cache files that are missing.
1371      */
1372     if (missing_DCacheFile) {
1373         if (afsd_verbose)
1374             printf("%s: Creating '%s'\n", rn, fullpn_DCacheFile);
1375         if (CreateCacheFile(fullpn_DCacheFile))
1376             printf("%s: Can't create '%s'\n", rn, fullpn_DCacheFile);
1377     }
1378     if (missing_VolInfoFile) {
1379         if (afsd_verbose)
1380             printf("%s: Creating '%s'\n", rn, fullpn_VolInfoFile);
1381         if (CreateCacheFile(fullpn_VolInfoFile))
1382             printf("%s: Can't create '%s'\n", rn, fullpn_VolInfoFile);
1383     }
1384     if (missing_CellInfoFile) {
1385         if (afsd_verbose)
1386             printf("%s: Creating '%s'\n", rn, fullpn_CellInfoFile);
1387         if (CreateCacheFile(fullpn_CellInfoFile))
1388             printf("%s: Can't create '%s'\n", rn, fullpn_CellInfoFile);
1389     }
1390
1391     if (*vFilesFound < cacheFiles) {
1392         /*
1393          * We came up short on the number of data cache files found.  Scan through the inode
1394          * list and create all missing files.
1395          */
1396         for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++)
1397             if (pathname_for_V[vFileNum] == (AFSD_INO_T) 0) {
1398                 sprintf(vFileNumber, "%d", vFileNum);
1399                 if (afsd_verbose)
1400                     printf("%s: Creating '%s'\n", rn, fullpn_VFile);
1401                 if (CreateCacheFile(fullpn_VFile))
1402                     printf("%s: Can't create '%s'\n", rn, fullpn_VFile);
1403             }
1404     }
1405
1406     /*
1407      * Close the directory, return success.
1408      */
1409     if (afsd_debug)
1410         printf("%s: Closing cache directory.\n", rn);
1411     closedir(cdirp);
1412     return (0);
1413 }
1414
1415 static
1416 ConfigCell(register struct afsconf_cell *aci, char *arock,
1417            struct afsconf_dir *adir)
1418 {
1419     register int isHomeCell;
1420     register int i;
1421     afs_int32 cellFlags = 0;
1422     afs_int32 hosts[MAXHOSTSPERCELL];
1423
1424     /* figure out if this is the home cell */
1425     isHomeCell = (strcmp(aci->name, afs_LclCellName) == 0);
1426     if (!isHomeCell)
1427         cellFlags = 2;          /* not home, suid is forbidden */
1428
1429     /* build address list */
1430     for (i = 0; i < MAXHOSTSPERCELL; i++)
1431         memcpy(&hosts[i], &aci->hostAddr[i].sin_addr, sizeof(afs_int32));
1432
1433     if (aci->linkedCell)
1434         cellFlags |= 4;         /* Flag that linkedCell arg exists,
1435                                  * for upwards compatibility */
1436
1437     /* configure one cell */
1438     call_syscall(AFSCALL_CALL, AFSOP_ADDCELL2, (long)hosts,     /* server addresses */
1439                  (long)aci->name,       /* cell name */
1440                  (long)cellFlags,       /* is this the home cell? */
1441                  (long)aci->linkedCell);        /* Linked cell, if any */
1442     return 0;
1443 }
1444
1445 static int
1446 ConfigCellAlias(aca, arock, adir)
1447         struct afsconf_cellalias *aca;
1448         char *arock;
1449         struct afsconf_dir *adir;
1450 {
1451         call_syscall(AFSOP_ADDCELLALIAS, (long)aca->aliasName, 
1452                      (long)aca->realName, 0, 0, 0);
1453         return 0;
1454 }
1455
1456 /*
1457  * Set the UDP port number RX uses for UDP datagrams
1458  */
1459 void
1460 uafs_SetRxPort(int port)
1461 {
1462     usr_assert(usr_rx_port == 0);
1463     usr_rx_port = port;
1464 }
1465
1466
1467 /*
1468  * Initialize the user space client.
1469  */
1470 void
1471 uafs_Init(char *rn, char *mountDirParam, char *confDirParam,
1472           char *cacheBaseDirParam, int cacheBlocksParam, int cacheFilesParam,
1473           int cacheStatEntriesParam, int dCacheSizeParam, int vCacheSizeParam,
1474           int chunkSizeParam, int closeSynchParam, int debugParam,
1475           int nDaemonsParam, int cacheFlagsParam, char *logFile)
1476 {
1477     int st;
1478     struct usr_proc *procp;
1479     struct usr_ucred *ucredp;
1480     int i;
1481     int rc;
1482     int currVFile;              /* Current AFS cache file number */
1483     int lookupResult;           /* Result of GetLocalCellName() */
1484     int cacheIteration;         /* cache verification loop counter */
1485     int vFilesFound;            /* Num data cache files found in sweep */
1486     FILE *logfd;
1487     afs_int32 vfs1_type = -1;
1488     struct afs_ioctl iob;
1489     char tbuffer[1024];
1490     char *p;
1491     char lastchar;
1492     afs_int32 buffer[MAXIPADDRS];
1493     afs_int32 maskbuffer[MAXIPADDRS];
1494     afs_int32 mtubuffer[MAXIPADDRS];
1495
1496     /*
1497      * Use the thread specific data to implement the user structure
1498      */
1499     usr_keycreate(&afs_global_u_key, free);
1500
1501     /*
1502      * Initialize the global ucred structure
1503      */
1504     afs_global_ucredp = (struct usr_ucred *)
1505         afs_osi_Alloc(sizeof(struct usr_ucred));
1506     usr_assert(afs_global_ucredp != NULL);
1507     afs_global_ucredp->cr_ref = 1;
1508     afs_global_ucredp->cr_uid = geteuid();
1509     afs_global_ucredp->cr_gid = getegid();
1510     afs_global_ucredp->cr_ruid = getuid();
1511     afs_global_ucredp->cr_rgid = getgid();
1512     afs_global_ucredp->cr_suid = afs_global_ucredp->cr_ruid;
1513     afs_global_ucredp->cr_sgid = afs_global_ucredp->cr_rgid;
1514     st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
1515     usr_assert(st >= 0);
1516     afs_global_ucredp->cr_ngroups = (unsigned long)st;
1517     for (i = st; i < NGROUPS; i++) {
1518         afs_global_ucredp->cr_groups[i] = NOGROUP;
1519     }
1520
1521     /*
1522      * Initialize the global process structure
1523      */
1524     afs_global_procp = (struct usr_proc *)
1525         afs_osi_Alloc(sizeof(struct usr_proc));
1526     usr_assert(afs_global_procp != NULL);
1527     afs_global_procp->p_pid = getpid();
1528     afs_global_procp->p_ppid = (pid_t) 1;
1529     afs_global_procp->p_ucred = afs_global_ucredp;
1530
1531     /*
1532      * Initialize the AFS mount point, default is '/afs'.
1533      * Strip duplicate/trailing slashes from mount point string.
1534      * afs_mountDirLen is set to strlen(afs_mountDir).
1535      */
1536     if (mountDirParam) {
1537         sprintf(tbuffer, "%s", mountDirParam);
1538     } else {
1539         sprintf(tbuffer, "afs");
1540     }
1541     afs_mountDir[0] = '/';
1542     afs_mountDirLen = 1;
1543     for (lastchar = '/', p = &tbuffer[0]; *p != '\0'; p++) {
1544         if (lastchar != '/' || *p != '/') {
1545             afs_mountDir[afs_mountDirLen++] = lastchar = *p;
1546         }
1547     }
1548     if (lastchar == '/' && afs_mountDirLen > 1)
1549         afs_mountDirLen--;
1550     afs_mountDir[afs_mountDirLen] = '\0';
1551     usr_assert(afs_mountDirLen > 1);
1552
1553     /*
1554      * Initialize cache parameters using the input arguments
1555      */
1556
1557     cacheBlocks = cacheBlocksParam;
1558     if (cacheFilesParam != 0) {
1559         cacheFiles = cacheFilesParam;
1560     } else {
1561         cacheFiles = cacheBlocks / 10;
1562     }
1563     if (cacheStatEntriesParam != 0) {
1564         cacheStatEntries = cacheStatEntriesParam;
1565     }
1566     strcpy(cacheBaseDir, cacheBaseDirParam);
1567     if (nDaemons != 0) {
1568         nDaemons = nDaemonsParam;
1569     } else {
1570         nDaemons = 3;
1571     }
1572     afsd_verbose = debugParam;
1573     afsd_debug = debugParam;
1574     chunkSize = chunkSizeParam;
1575     if (dCacheSizeParam != 0) {
1576         dCacheSize = dCacheSizeParam;
1577     } else {
1578         dCacheSize = cacheFiles / 2;
1579     }
1580     if (vCacheSizeParam != 0) {
1581         vCacheSize = vCacheSizeParam;
1582     }
1583     strcpy(confDir, confDirParam);
1584     afsd_CloseSynch = closeSynchParam;
1585     if (cacheFlagsParam >= 0) {
1586         cacheFlags = cacheFlagsParam;
1587     }
1588     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1589         cacheFiles = dCacheSize;
1590     }
1591
1592     sprintf(fullpn_CacheInfo, "%s/%s", confDir, CACHEINFOFILE);
1593     if (logFile == NULL) {
1594         sprintf(fullpn_AFSLogFile, "%s/%s", confDir, AFSLOGFILE);
1595     } else {
1596         strcpy(fullpn_AFSLogFile, logFile);
1597     }
1598
1599     printf("\n%s: Initializing user space AFS client\n\n", rn);
1600     printf("    mountDir:           %s\n", afs_mountDir);
1601     printf("    confDir:            %s\n", confDir);
1602     printf("    cacheBaseDir:       %s\n", cacheBaseDir);
1603     printf("    cacheBlocks:        %d\n", cacheBlocks);
1604     printf("    cacheFiles:         %d\n", cacheFiles);
1605     printf("    cacheStatEntries:   %d\n", cacheStatEntries);
1606     printf("    dCacheSize:         %d\n", dCacheSize);
1607     printf("    vCacheSize:         %d\n", vCacheSize);
1608     printf("    chunkSize:          %d\n", chunkSize);
1609     printf("    afsd_CloseSynch:    %d\n", afsd_CloseSynch);
1610     printf("    afsd_debug/verbose: %d/%d\n", afsd_debug, afsd_verbose);
1611     printf("    nDaemons:           %d\n", nDaemons);
1612     printf("    cacheFlags:         %d\n", cacheFlags);
1613     printf("    logFile:            %s\n", fullpn_AFSLogFile);
1614     printf("\n");
1615     fflush(stdout);
1616
1617     /*
1618      * Initialize the AFS client
1619      */
1620     osi_Init();
1621
1622     /*
1623      * Pull out all the configuration info for the workstation's AFS cache and
1624      * the cellular community we're willing to let our users see.
1625      */
1626     afs_cdir = afsconf_Open(confDir);
1627     if (!afs_cdir) {
1628         printf("afsd: some file missing or bad in %s\n", confDir);
1629         exit(1);
1630     }
1631
1632     lookupResult =
1633         afsconf_GetLocalCell(afs_cdir, afs_LclCellName,
1634                              sizeof(afs_LclCellName));
1635     if (lookupResult) {
1636         printf("%s: Can't get my home cell name!  [Error is %d]\n", rn,
1637                lookupResult);
1638     } else {
1639         if (afsd_verbose)
1640             printf("%s: My home cell is '%s'\n", rn, afs_LclCellName);
1641     }
1642
1643     /*
1644      * Set the primary cell name.
1645      */
1646     call_syscall(AFSOP_SET_THISCELL, (long)afs_LclCellName, 0, 0, 0, 0);
1647
1648     if ((logfd = fopen(fullpn_AFSLogFile, "r+")) == 0) {
1649         if (afsd_verbose)
1650             printf("%s: Creating '%s'\n", rn, fullpn_AFSLogFile);
1651         if (CreateCacheFile(fullpn_AFSLogFile)) {
1652             printf
1653                 ("%s: Can't create '%s' (You may want to use the -logfile option)\n",
1654                  rn, fullpn_AFSLogFile);
1655             exit(1);
1656         }
1657     } else
1658         fclose(logfd);
1659
1660     /*
1661      * Create and zero the pathname table for the desired cache files.
1662      */
1663     pathname_for_V = (char **)afs_osi_Alloc(cacheFiles * sizeof(char *));
1664     if (pathname_for_V == NULL) {
1665         printf("%s: malloc() failed for cache file table with %d entries.\n",
1666                rn, cacheFiles);
1667         exit(1);
1668     }
1669     memset(pathname_for_V, 0, (cacheFiles * sizeof(char *)));
1670     if (afsd_debug)
1671         printf("%s: %d pathname_for_V entries at 0x%x, %d bytes\n", rn,
1672                cacheFiles, pathname_for_V, (cacheFiles * sizeof(AFSD_INO_T)));
1673
1674     /*
1675      * Set up all the pathnames we'll need for later.
1676      */
1677     sprintf(fullpn_DCacheFile, "%s/%s", cacheBaseDir, DCACHEFILE);
1678     sprintf(fullpn_VolInfoFile, "%s/%s", cacheBaseDir, VOLINFOFILE);
1679     sprintf(fullpn_CellInfoFile, "%s/%s", cacheBaseDir, CELLINFOFILE);
1680     sprintf(fullpn_VFile, "%s/V", cacheBaseDir);
1681     vFileNumber = fullpn_VFile + strlen(fullpn_VFile);
1682
1683     /*
1684      * Start the RX listener.
1685      */
1686     if (afsd_debug)
1687         printf("%s: Calling AFSOP_RXLISTENER_DAEMON\n", rn);
1688     fork_syscall(AFSCALL_CALL, AFSOP_RXLISTENER_DAEMON, FALSE, FALSE, FALSE);
1689
1690     /*
1691      * Start the RX event handler.
1692      */
1693     if (afsd_debug)
1694         printf("%s: Calling AFSOP_RXEVENT_DAEMON\n", rn);
1695     fork_syscall(AFSCALL_CALL, AFSOP_RXEVENT_DAEMON, FALSE);
1696
1697     /*
1698      * Set up all the kernel processes needed for AFS.
1699      */
1700
1701     /* initialize AFS callback interface */
1702     {
1703         /* parse multihomed address files */
1704         char reason[1024];
1705         st = parseNetFiles((afs_uint32*)buffer,(afs_uint32*) maskbuffer, (afs_uint32*)mtubuffer, MAXIPADDRS, reason,
1706                            AFSDIR_CLIENT_NETINFO_FILEPATH,
1707                            AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
1708         if (st > 0)
1709             call_syscall(AFSCALL_CALL, AFSOP_ADVISEADDR, st,
1710                          (long)(&buffer[0]), (long)(&maskbuffer[0]),
1711                          (long)(&mtubuffer[0]));
1712         else {
1713             printf("ADVISEADDR: Error in specifying interface addresses:%s\n",
1714                    reason);
1715             exit(1);
1716         }
1717     }
1718
1719     if (afsd_verbose)
1720         printf("%s: Forking rx callback listener.\n", rn);
1721     /* Child */
1722     if (preallocs < cacheStatEntries + 50)
1723         preallocs = cacheStatEntries + 50;
1724     fork_syscall(AFSCALL_CALL, AFSOP_START_RXCALLBACK, preallocs);
1725
1726     if (afsd_verbose)
1727         printf("%s: Initializing AFS daemon.\n", rn);
1728     call_syscall(AFSCALL_CALL, AFSOP_BASIC_INIT, 1, 0, 0, 0);
1729
1730     /*
1731      * Tell the kernel some basic information about the workstation's cache.
1732      */
1733     if (afsd_verbose)
1734         printf("%s: Calling AFSOP_CACHEINIT: %d stat cache entries,"
1735                " %d optimum cache files, %d blocks in the cache,"
1736                " flags = 0x%x, dcache entries %d\n", rn, cacheStatEntries,
1737                cacheFiles, cacheBlocks, cacheFlags, dCacheSize);
1738     memset(&cparams, 0, sizeof(cparams));
1739     cparams.cacheScaches = cacheStatEntries;
1740     cparams.cacheFiles = cacheFiles;
1741     cparams.cacheBlocks = cacheBlocks;
1742     cparams.cacheDcaches = dCacheSize;
1743     cparams.cacheVolumes = vCacheSize;
1744     cparams.chunkSize = chunkSize;
1745     cparams.setTimeFlag = FALSE;
1746     cparams.memCacheFlag = cacheFlags;
1747     call_syscall(AFSCALL_CALL, AFSOP_CACHEINIT, (long)&cparams, 0, 0, 0);
1748     if (afsd_CloseSynch)
1749         call_syscall(AFSCALL_CALL, AFSOP_CLOSEWAIT, 0, 0, 0, 0);
1750
1751     /*
1752      * Sweep the workstation AFS cache directory, remembering the inodes of
1753      * valid files and deleting extraneous files.  Keep sweeping until we
1754      * have the right number of data cache files or we've swept too many
1755      * times.
1756      */
1757     if (afsd_verbose)
1758         printf("%s: Sweeping workstation's AFS cache directory.\n", rn);
1759     cacheIteration = 0;
1760     /* Memory-cache based system doesn't need any of this */
1761     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
1762         do {
1763             cacheIteration++;
1764             if (SweepAFSCache(&vFilesFound)) {
1765                 printf("%s: Error on sweep %d of workstation AFS cache \
1766                        directory.\n", rn, cacheIteration);
1767                 exit(1);
1768             }
1769             if (afsd_verbose)
1770                 printf
1771                     ("%s: %d out of %d data cache files found in sweep %d.\n",
1772                      rn, vFilesFound, cacheFiles, cacheIteration);
1773         } while ((vFilesFound < cacheFiles)
1774                  && (cacheIteration < MAX_CACHE_LOOPS));
1775     } else if (afsd_verbose)
1776         printf("%s: Using memory cache, not swept\n", rn);
1777
1778     /*
1779      * Pass the kernel the name of the workstation cache file holding the 
1780      * dcache entries.
1781      */
1782     if (afsd_debug)
1783         printf("%s: Calling AFSOP_CACHEINFO: dcache file is '%s'\n", rn,
1784                fullpn_DCacheFile);
1785     /* once again, meaningless for a memory-based cache. */
1786     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))
1787         call_syscall(AFSCALL_CALL, AFSOP_CACHEINFO, (long)fullpn_DCacheFile,
1788                      0, 0, 0);
1789
1790     call_syscall(AFSCALL_CALL, AFSOP_CELLINFO, (long)fullpn_CellInfoFile, 0,
1791                  0, 0);
1792
1793     /*
1794      * Pass the kernel the name of the workstation cache file holding the
1795      * volume information.
1796      */
1797     if (afsd_debug)
1798         printf("%s: Calling AFSOP_VOLUMEINFO: volume info file is '%s'\n", rn,
1799                fullpn_VolInfoFile);
1800     call_syscall(AFSCALL_CALL, AFSOP_VOLUMEINFO, (long)fullpn_VolInfoFile, 0,
1801                  0, 0);
1802
1803     /*
1804      * Pass the kernel the name of the afs logging file holding the volume
1805      * information.
1806      */
1807     if (afsd_debug)
1808         printf("%s: Calling AFSOP_AFSLOG: volume info file is '%s'\n", rn,
1809                fullpn_AFSLogFile);
1810     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))  /* ... nor this ... */
1811         call_syscall(AFSCALL_CALL, AFSOP_AFSLOG, (long)fullpn_AFSLogFile, 0,
1812                      0, 0);
1813
1814     /*
1815      * Tell the kernel about each cell in the configuration.
1816      */
1817     afsconf_CellApply(afs_cdir, ConfigCell, NULL);
1818     afsconf_CellAliasApply(afs_cdir, ConfigCellAlias, NULL);
1819
1820     if (afsd_verbose)
1821         printf("%s: Forking AFS daemon.\n", rn);
1822     fork_syscall(AFSCALL_CALL, AFSOP_START_AFS);
1823
1824     if (afsd_verbose)
1825         printf("%s: Forking check server daemon.\n", rn);
1826     fork_syscall(AFSCALL_CALL, AFSOP_START_CS);
1827
1828     if (afsd_verbose)
1829         printf("%s: Forking %d background daemons.\n", rn, nDaemons);
1830     for (i = 0; i < nDaemons; i++) {
1831         fork_syscall(AFSCALL_CALL, AFSOP_START_BKG);
1832     }
1833
1834     if (afsd_verbose)
1835         printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n", rn, rootVolume);
1836     call_syscall(AFSCALL_CALL, AFSOP_ROOTVOLUME, (long)rootVolume, 0, 0, 0);
1837
1838     /*
1839      * Give the kernel the names of the AFS files cached on the workstation's
1840      * disk.
1841      */
1842     if (afsd_debug)
1843         printf
1844             ("%s: Calling AFSOP_CACHEFILES for each of the %d files in '%s'\n",
1845              rn, cacheFiles, cacheBaseDir);
1846     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))  /* ... and again ... */
1847         for (currVFile = 0; currVFile < cacheFiles; currVFile++) {
1848             call_syscall(AFSCALL_CALL, AFSOP_CACHEFILE,
1849                          (long)pathname_for_V[currVFile], 0, 0, 0);
1850         }
1851     /*end for */
1852 #ifndef NETSCAPE_NSAPI
1853     /*
1854      * Copy our tokens from the kernel to the user space client
1855      */
1856     for (i = 0; i < 200; i++) {
1857         /*
1858          * Get the i'th token from the kernel
1859          */
1860         memset((void *)&tbuffer[0], 0, sizeof(tbuffer));
1861         memcpy((void *)&tbuffer[0], (void *)&i, sizeof(int));
1862         iob.in = tbuffer;
1863         iob.in_size = sizeof(int);
1864         iob.out = tbuffer;
1865         iob.out_size = sizeof(tbuffer);
1866
1867 #if defined(AFS_USR_SUN5_ENV) || defined(AFS_USR_OSF_ENV) || defined(AFS_USR_HPUX_ENV) || defined(AFS_USR_LINUX22_ENV) || defined(AFS_USR_DARWIN_ENV) || defined(AFS_USR_FBSD_ENV)
1868         rc = syscall(AFS_SYSCALL, AFSCALL_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
1869 #elif defined(AFS_USR_SGI_ENV)
1870         rc = syscall(AFS_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
1871 #else /* AFS_USR_AIX_ENV */
1872         rc = lpioctl(0, _VICEIOCTL(8), &iob, 0);
1873 #endif
1874         if (rc < 0) {
1875             usr_assert(errno == EDOM || errno == ENOSYS);
1876             break;
1877         }
1878
1879         /*
1880          * Now pass the token into the user space kernel
1881          */
1882         rc = uafs_SetTokens(tbuffer, iob.out_size);
1883         usr_assert(rc == 0);
1884     }
1885 #endif /* !NETSCAPE_NSAPI */
1886
1887     /*
1888      * All the necessary info has been passed into the kernel to run an AFS
1889      * system.  Give the kernel our go-ahead.
1890      */
1891     if (afsd_debug)
1892         printf("%s: Calling AFSOP_GO\n", rn);
1893     call_syscall(AFSCALL_CALL, AFSOP_GO, FALSE, 0, 0, 0);
1894
1895     /*
1896      * At this point, we have finished passing the kernel all the info 
1897      * it needs to set up the AFS.  Mount the AFS root.
1898      */
1899     printf("%s: All AFS daemons started.\n", rn);
1900
1901     if (afsd_verbose)
1902         printf("%s: Forking trunc-cache daemon.\n", rn);
1903     fork_syscall(AFSCALL_CALL, AFSOP_START_TRUNCDAEMON);
1904
1905     /*
1906      * Mount the AFS filesystem
1907      */
1908     AFS_GLOCK();
1909     rc = afs_mount(&afs_RootVfs, NULL, NULL);
1910     usr_assert(rc == 0);
1911     rc = afs_root(&afs_RootVfs, &afs_RootVnode);
1912     usr_assert(rc == 0);
1913     AFS_GUNLOCK();
1914
1915     /*
1916      * initialize the current directory to the AFS root
1917      */
1918     afs_CurrentDir = afs_RootVnode;
1919     VN_HOLD(afs_CurrentDir);
1920
1921     return;
1922 }
1923
1924 void
1925 uafs_Shutdown(void)
1926 {
1927     int rc;
1928
1929     printf("\n");
1930
1931     AFS_GLOCK();
1932     VN_RELE(afs_CurrentDir);
1933     rc = afs_unmount(&afs_RootVfs);
1934     usr_assert(rc == 0);
1935     AFS_GUNLOCK();
1936
1937     printf("\n");
1938 }
1939
1940 /*
1941  * Donate the current thread to the RX server pool.
1942  */
1943 void
1944 uafs_RxServerProc(void)
1945 {
1946     osi_socket sock;
1947     int threadID;
1948     struct rx_call *newcall = NULL;
1949
1950     rxi_MorePackets(2);         /* alloc more packets */
1951     threadID = rxi_availProcs++;
1952
1953     while (1) {
1954         sock = OSI_NULLSOCKET;
1955         rxi_ServerProc(threadID, newcall, &sock);
1956         if (sock == OSI_NULLSOCKET) {
1957             break;
1958         }
1959         newcall = NULL;
1960         threadID = -1;
1961         rxi_ListenerProc(sock, &threadID, &newcall);
1962         /* assert(threadID != -1); */
1963         /* assert(newcall != NULL); */
1964     }
1965 }
1966
1967 struct syscallThreadArgs {
1968     long syscall;
1969     long afscall;
1970     long param1;
1971     long param2;
1972     long param3;
1973     long param4;
1974 };
1975
1976 #ifdef NETSCAPE_NSAPI
1977 void
1978 syscallThread(void *argp)
1979 #else /* NETSCAPE_NSAPI */
1980 void *
1981 syscallThread(void *argp)
1982 #endif                          /* NETSCAPE_NSAPI */
1983 {
1984     int i;
1985     struct usr_ucred *crp;
1986     struct syscallThreadArgs *sysArgsP = (struct syscallThreadArgs *)argp;
1987
1988     /*
1989      * AFS daemons run authenticated
1990      */
1991     u.u_viceid = getuid();
1992     crp = u.u_cred;
1993     crp->cr_uid = getuid();
1994     crp->cr_ruid = getuid();
1995     crp->cr_suid = getuid();
1996     crp->cr_groups[0] = getgid();
1997     crp->cr_ngroups = 1;
1998     for (i = 1; i < NGROUPS; i++) {
1999         crp->cr_groups[i] = NOGROUP;
2000     }
2001
2002     call_syscall(sysArgsP->syscall, sysArgsP->afscall, sysArgsP->param1,
2003                  sysArgsP->param2, sysArgsP->param3, sysArgsP->param4);
2004
2005     afs_osi_Free(argp, -1);
2006 }
2007
2008 fork_syscall(syscall, afscall, param1, param2, param3, param4)
2009      long syscall, afscall, param1, param2, param3, param4;
2010 {
2011     usr_thread_t tid;
2012     struct syscallThreadArgs *sysArgsP;
2013
2014     sysArgsP = (struct syscallThreadArgs *)
2015         afs_osi_Alloc(sizeof(struct syscallThreadArgs));
2016     usr_assert(sysArgsP != NULL);
2017     sysArgsP->syscall = syscall;
2018     sysArgsP->afscall = afscall;
2019     sysArgsP->param1 = param1;
2020     sysArgsP->param2 = param2;
2021     sysArgsP->param3 = param3;
2022     sysArgsP->param4 = param4;
2023
2024     usr_thread_create(&tid, syscallThread, sysArgsP);
2025     usr_thread_detach(tid);
2026 }
2027
2028 call_syscall(syscall, afscall, param1, param2, param3, param4)
2029      long syscall, afscall, param1, param2, param3, param4;
2030 {
2031     int code = 0;
2032     struct a {
2033         long syscall;
2034         long afscall;
2035         long parm1;
2036         long parm2;
2037         long parm3;
2038         long parm4;
2039     } a;
2040
2041     a.syscall = syscall;
2042     a.afscall = afscall;
2043     a.parm1 = param1;
2044     a.parm2 = param2;
2045     a.parm3 = param3;
2046     a.parm4 = param4;
2047
2048     u.u_error = 0;
2049     u.u_ap = (char *)&a;
2050
2051     code = Afs_syscall();
2052     return code;
2053 }
2054
2055 int
2056 uafs_SetTokens(char *tbuffer, int tlen)
2057 {
2058     int rc;
2059     struct afs_ioctl iob;
2060     char outbuf[1024];
2061
2062     iob.in = tbuffer;
2063     iob.in_size = tlen;
2064     iob.out = &outbuf[0];
2065     iob.out_size = sizeof(outbuf);
2066     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(3), (long)&iob, 0, 0);
2067     if (rc != 0) {
2068         errno = rc;
2069         return -1;
2070     }
2071     return 0;
2072 }
2073
2074 int
2075 uafs_RPCStatsEnableProc(void)
2076 {
2077     int rc;
2078     struct afs_ioctl iob;
2079     afs_int32 flag;
2080
2081     flag = AFSCALL_RXSTATS_ENABLE;
2082     iob.in = (char *)&flag;
2083     iob.in_size = sizeof(afs_int32);
2084     iob.out = NULL;
2085     iob.out_size = 0;
2086     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2087     if (rc != 0) {
2088         errno = rc;
2089         return -1;
2090     }
2091     return rc;
2092 }
2093
2094 int
2095 uafs_RPCStatsDisableProc(void)
2096 {
2097     int rc;
2098     struct afs_ioctl iob;
2099     afs_int32 flag;
2100
2101     flag = AFSCALL_RXSTATS_DISABLE;
2102     iob.in = (char *)&flag;
2103     iob.in_size = sizeof(afs_int32);
2104     iob.out = NULL;
2105     iob.out_size = 0;
2106     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2107     if (rc != 0) {
2108         errno = rc;
2109         return -1;
2110     }
2111     return rc;
2112 }
2113
2114 int
2115 uafs_RPCStatsClearProc(void)
2116 {
2117     int rc;
2118     struct afs_ioctl iob;
2119     afs_int32 flag;
2120
2121     flag = AFSCALL_RXSTATS_CLEAR;
2122     iob.in = (char *)&flag;
2123     iob.in_size = sizeof(afs_int32);
2124     iob.out = NULL;
2125     iob.out_size = 0;
2126     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2127     if (rc != 0) {
2128         errno = rc;
2129         return -1;
2130     }
2131     return rc;
2132 }
2133
2134 int
2135 uafs_RPCStatsEnablePeer(void)
2136 {
2137     int rc;
2138     struct afs_ioctl iob;
2139     afs_int32 flag;
2140
2141     flag = AFSCALL_RXSTATS_ENABLE;
2142     iob.in = (char *)&flag;
2143     iob.in_size = sizeof(afs_int32);
2144     iob.out = NULL;
2145     iob.out_size = 0;
2146     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2147     if (rc != 0) {
2148         errno = rc;
2149         return -1;
2150     }
2151     return rc;
2152 }
2153
2154 int
2155 uafs_RPCStatsDisablePeer(void)
2156 {
2157     int rc;
2158     struct afs_ioctl iob;
2159     afs_int32 flag;
2160
2161     flag = AFSCALL_RXSTATS_DISABLE;
2162     iob.in = (char *)&flag;
2163     iob.in_size = sizeof(afs_int32);
2164     iob.out = NULL;
2165     iob.out_size = 0;
2166     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2167     if (rc != 0) {
2168         errno = rc;
2169         return -1;
2170     }
2171     return rc;
2172 }
2173
2174 int
2175 uafs_RPCStatsClearPeer(void)
2176 {
2177     int rc;
2178     struct afs_ioctl iob;
2179     afs_int32 flag;
2180
2181     flag = AFSCALL_RXSTATS_CLEAR;
2182     iob.in = (char *)&flag;
2183     iob.in_size = sizeof(afs_int32);
2184     iob.out = NULL;
2185     iob.out_size = 0;
2186     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2187     if (rc != 0) {
2188         errno = rc;
2189         return -1;
2190     }
2191     return rc;
2192 }
2193
2194 /*
2195  * Lookup a file or directory given its path.
2196  * Call VN_HOLD on the output vnode if successful.
2197  * Returns zero on success, error code on failure.
2198  *
2199  * Note: Caller must hold the AFS global lock.
2200  */
2201 int
2202 uafs_LookupName(char *path, struct usr_vnode *parentVp,
2203                 struct usr_vnode **vpp, int follow, int no_eval_mtpt)
2204 {
2205     int code;
2206     int linkCount;
2207     struct usr_vnode *vp;
2208     struct usr_vnode *nextVp;
2209     struct usr_vnode *linkVp;
2210     char *tmpPath;
2211     char *pathP;
2212     char *nextPathP;
2213
2214     AFS_ASSERT_GLOCK();
2215
2216     /*
2217      * Absolute paths must start with the AFS mount point.
2218      */
2219     if (path[0] != '/') {
2220         vp = parentVp;
2221     } else {
2222         path = uafs_afsPathName(path);
2223         if (path == NULL) {
2224             return ENOENT;
2225         }
2226         vp = afs_RootVnode;
2227     }
2228
2229     /*
2230      * Loop through the path looking for the new directory
2231      */
2232     tmpPath = afs_osi_Alloc(strlen(path) + 1);
2233     usr_assert(tmpPath != NULL);
2234     strcpy(tmpPath, path);
2235     VN_HOLD(vp);
2236     pathP = tmpPath;
2237     while (pathP != NULL && *pathP != '\0') {
2238         usr_assert(*pathP != '/');
2239
2240         /*
2241          * terminate the current component and skip over slashes
2242          */
2243         nextPathP = afs_strchr(pathP, '/');
2244         if (nextPathP != NULL) {
2245             while (*nextPathP == '/') {
2246                 *(nextPathP++) = '\0';
2247             }
2248         }
2249
2250         /*
2251          * Don't call afs_lookup on non-directories
2252          */
2253         if (vp->v_type != VDIR) {
2254             VN_RELE(vp);
2255             afs_osi_Free(tmpPath, strlen(path) + 1);
2256             return ENOTDIR;
2257         }
2258
2259         if (vp == afs_RootVnode && strcmp(pathP, "..") == 0) {
2260             /*
2261              * The AFS root is its own parent
2262              */
2263             nextVp = afs_RootVnode;
2264         } else {
2265             /*
2266              * We need execute permission to search a directory
2267              */
2268             code = afs_access(VTOAFS(vp), VEXEC, u.u_cred);
2269             if (code != 0) {
2270                 VN_RELE(vp);
2271                 afs_osi_Free(tmpPath, strlen(path) + 1);
2272                 return code;
2273             }
2274
2275             /*
2276              * lookup the next component in the path, we can release the
2277              * subdirectory since we hold the global lock
2278              */
2279             nextVp = NULL;
2280 #ifdef AFS_WEB_ENHANCEMENTS
2281             if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
2282                 code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0);
2283             else
2284                 code =
2285                     afs_lookup(vp, pathP, &nextVp, u.u_cred,
2286                                AFS_LOOKUP_NOEVAL);
2287 #else
2288             code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0);
2289 #endif /* AFS_WEB_ENHANCEMENTS */
2290             if (code != 0) {
2291                 VN_RELE(vp);
2292                 afs_osi_Free(tmpPath, strlen(path) + 1);
2293                 return code;
2294             }
2295         }
2296
2297         /*
2298          * Follow symbolic links for parent directories and
2299          * for leaves when the follow flag is set.
2300          */
2301         if ((nextPathP != NULL && *nextPathP != '\0') || follow) {
2302             linkCount = 0;
2303             while (nextVp->v_type == VLNK) {
2304                 if (++linkCount > MAX_OSI_LINKS) {
2305                     VN_RELE(vp);
2306                     VN_RELE(nextVp);
2307                     afs_osi_Free(tmpPath, strlen(path) + 1);
2308                     return code;
2309                 }
2310                 code = uafs_LookupLink(nextVp, vp, &linkVp);
2311                 if (code) {
2312                     VN_RELE(vp);
2313                     VN_RELE(nextVp);
2314                     afs_osi_Free(tmpPath, strlen(path) + 1);
2315                     return code;
2316                 }
2317                 VN_RELE(nextVp);
2318                 nextVp = linkVp;
2319             }
2320         }
2321
2322         VN_RELE(vp);
2323         vp = nextVp;
2324         pathP = nextPathP;
2325     }
2326
2327     /*
2328      * Special case, nextPathP is non-null if pathname ends in slash
2329      */
2330     if (nextPathP != NULL && vp->v_type != VDIR) {
2331         VN_RELE(vp);
2332         afs_osi_Free(tmpPath, strlen(path) + 1);
2333         return ENOTDIR;
2334     }
2335
2336     afs_osi_Free(tmpPath, strlen(path) + 1);
2337     *vpp = vp;
2338     return 0;
2339 }
2340
2341 /*
2342  * Lookup the target of a symbolic link
2343  * Call VN_HOLD on the output vnode if successful.
2344  * Returns zero on success, error code on failure.
2345  *
2346  * Note: Caller must hold the AFS global lock.
2347  */
2348 int
2349 uafs_LookupLink(struct usr_vnode *vp, struct usr_vnode *parentVp,
2350                 struct usr_vnode **vpp)
2351 {
2352     int code;
2353     int len;
2354     char *pathP;
2355     struct usr_vnode *linkVp;
2356     struct usr_uio uio;
2357     struct iovec iov[1];
2358
2359     AFS_ASSERT_GLOCK();
2360
2361     pathP = afs_osi_Alloc(MAX_OSI_PATH + 1);
2362     usr_assert(pathP != NULL);
2363
2364     /*
2365      * set up the uio buffer
2366      */
2367     iov[0].iov_base = pathP;
2368     iov[0].iov_len = MAX_OSI_PATH + 1;
2369     uio.uio_iov = &iov[0];
2370     uio.uio_iovcnt = 1;
2371     uio.uio_offset = 0;
2372     uio.uio_segflg = 0;
2373     uio.uio_fmode = FREAD;
2374     uio.uio_resid = MAX_OSI_PATH + 1;
2375
2376     /*
2377      * Read the link data
2378      */
2379     code = afs_readlink(vp, &uio, u.u_cred);
2380     if (code) {
2381         afs_osi_Free(pathP, MAX_OSI_PATH + 1);
2382         return code;
2383     }
2384     len = MAX_OSI_PATH + 1 - uio.uio_resid;
2385     pathP[len] = '\0';
2386
2387     /*
2388      * Find the target of the symbolic link
2389      */
2390     code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0);
2391     if (code) {
2392         afs_osi_Free(pathP, MAX_OSI_PATH + 1);
2393         return code;
2394     }
2395
2396     afs_osi_Free(pathP, MAX_OSI_PATH + 1);
2397     *vpp = linkVp;
2398     return 0;
2399 }
2400
2401 /*
2402  * Lookup the parent of a file or directory given its path
2403  * Call VN_HOLD on the output vnode if successful.
2404  * Returns zero on success, error code on failure.
2405  *
2406  * Note: Caller must hold the AFS global lock.
2407  */
2408 int
2409 uafs_LookupParent(char *path, struct usr_vnode **vpp)
2410 {
2411     int len;
2412     int code;
2413     char *pathP;
2414     struct usr_vnode *parentP;
2415
2416     AFS_ASSERT_GLOCK();
2417
2418     /*
2419      * Absolute path names must start with the AFS mount point.
2420      */
2421     if (*path == '/') {
2422         pathP = uafs_afsPathName(path);
2423         if (pathP == NULL) {
2424             return ENOENT;
2425         }
2426     }
2427
2428     /*
2429      * Find the length of the parent path
2430      */
2431     len = strlen(path);
2432     while (len > 0 && path[len - 1] == '/') {
2433         len--;
2434     }
2435     if (len == 0) {
2436         return EINVAL;
2437     }
2438     while (len > 0 && path[len - 1] != '/') {
2439         len--;
2440     }
2441     if (len == 0) {
2442         return EINVAL;
2443     }
2444
2445     pathP = afs_osi_Alloc(len);
2446     usr_assert(pathP != NULL);
2447     memcpy(pathP, path, len - 1);
2448     pathP[len - 1] = '\0';
2449
2450     /*
2451      * look up the parent
2452      */
2453     code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0);
2454     afs_osi_Free(pathP, len);
2455     if (code != 0) {
2456         return code;
2457     }
2458     if (parentP->v_type != VDIR) {
2459         VN_RELE(parentP);
2460         return ENOTDIR;
2461     }
2462
2463     *vpp = parentP;
2464     return 0;
2465 }
2466
2467 /*
2468  * Return a pointer to the first character in the last component
2469  * of a pathname
2470  */
2471 char *
2472 uafs_LastPath(char *path)
2473 {
2474     int len;
2475
2476     len = strlen(path);
2477     while (len > 0 && path[len - 1] == '/') {
2478         len--;
2479     }
2480     while (len > 0 && path[len - 1] != '/') {
2481         len--;
2482     }
2483     if (len == 0) {
2484         return NULL;
2485     }
2486     return path + len;
2487 }
2488
2489 /*
2490  * Set the working directory.
2491  */
2492 int
2493 uafs_chdir(char *path)
2494 {
2495     int retval;
2496     AFS_GLOCK();
2497     retval = uafs_chdir_r(path);
2498     AFS_GUNLOCK();
2499     return retval;
2500 }
2501
2502 int
2503 uafs_chdir_r(char *path)
2504 {
2505     int code;
2506     struct vnode *dirP;
2507
2508     code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0);
2509     if (code != 0) {
2510         errno = code;
2511         return -1;
2512     }
2513     if (dirP->v_type != VDIR) {
2514         VN_RELE(dirP);
2515         errno = ENOTDIR;
2516         return -1;
2517     }
2518     VN_RELE(afs_CurrentDir);
2519     afs_CurrentDir = dirP;
2520     return 0;
2521 }
2522
2523 /*
2524  * Create a directory.
2525  */
2526 int
2527 uafs_mkdir(char *path, int mode)
2528 {
2529     int retval;
2530     AFS_GLOCK();
2531     retval = uafs_mkdir_r(path, mode);
2532     AFS_GUNLOCK();
2533     return retval;
2534 }
2535
2536 int
2537 uafs_mkdir_r(char *path, int mode)
2538 {
2539     int code;
2540     char *nameP;
2541     struct vnode *parentP;
2542     struct vnode *dirP;
2543     struct usr_vattr attrs;
2544
2545     if (uafs_IsRoot(path)) {
2546         return EACCES;
2547     }
2548
2549     /*
2550      * Look up the parent directory.
2551      */
2552     nameP = uafs_LastPath(path);
2553     if (nameP != NULL) {
2554         code = uafs_LookupParent(path, &parentP);
2555         if (code != 0) {
2556             errno = code;
2557             return -1;
2558         }
2559     } else {
2560         parentP = afs_CurrentDir;
2561         nameP = path;
2562         VN_HOLD(parentP);
2563     }
2564
2565     /*
2566      * Make sure the directory has at least one character
2567      */
2568     if (*nameP == '\0') {
2569         VN_RELE(parentP);
2570         errno = EINVAL;
2571         return -1;
2572     }
2573
2574     /*
2575      * Create the directory
2576      */
2577     usr_vattr_null(&attrs);
2578     attrs.va_type = VREG;
2579     attrs.va_mode = mode;
2580     attrs.va_uid = u.u_cred->cr_uid;
2581     attrs.va_gid = u.u_cred->cr_gid;
2582     dirP = NULL;
2583     code = afs_mkdir(parentP, nameP, &attrs, &dirP, u.u_cred);
2584     VN_RELE(parentP);
2585     if (code != 0) {
2586         errno = code;
2587         return -1;
2588     }
2589     VN_RELE(dirP);
2590     return 0;
2591 }
2592
2593 /*
2594  * Return 1 if path is the AFS root, otherwise return 0
2595  */
2596 int
2597 uafs_IsRoot(char *path)
2598 {
2599     while (*path == '/' && *(path + 1) == '/') {
2600         path++;
2601     }
2602     if (strncmp(path, afs_mountDir, afs_mountDirLen) != 0) {
2603         return 0;
2604     }
2605     path += afs_mountDirLen;
2606     while (*path == '/') {
2607         path++;
2608     }
2609     if (*path != '\0') {
2610         return 0;
2611     }
2612     return 1;
2613 }
2614
2615 /*
2616  * Open a file
2617  * Note: file name may not end in a slash.
2618  */
2619 int
2620 uafs_open(char *path, int flags, int mode)
2621 {
2622     int retval;
2623     AFS_GLOCK();
2624     retval = uafs_open_r(path, flags, mode);
2625     AFS_GUNLOCK();
2626     return retval;
2627 }
2628
2629 int
2630 uafs_open_r(char *path, int flags, int mode)
2631 {
2632     int fd;
2633     int code;
2634     int openFlags;
2635     int fileMode;
2636     struct usr_vnode *fileP;
2637     struct usr_vnode *dirP;
2638     struct usr_vattr attrs;
2639     char *nameP;
2640
2641     struct vcache* vc;
2642
2643     if (uafs_IsRoot(path)) {
2644         fileP = afs_RootVnode;
2645         VN_HOLD(fileP);
2646     } else {
2647         /*
2648          * Look up the parent directory.
2649          */
2650         nameP = uafs_LastPath(path);
2651         if (nameP != NULL) {
2652             code = uafs_LookupParent(path, &dirP);
2653             if (code != 0) {
2654                 errno = code;
2655                 return -1;
2656             }
2657         } else {
2658             dirP = afs_CurrentDir;
2659             nameP = path;
2660             VN_HOLD(dirP);
2661         }
2662
2663         /*
2664          * Make sure the filename has at least one character
2665          */
2666         if (*nameP == '\0') {
2667             VN_RELE(dirP);
2668             errno = EINVAL;
2669             return -1;
2670         }
2671
2672         /*
2673          * Get the VNODE for this file
2674          */
2675         if (flags & O_CREAT) {
2676             usr_vattr_null(&attrs);
2677             attrs.va_type = VREG;
2678             attrs.va_mode = mode;
2679             attrs.va_uid = u.u_cred->cr_uid;
2680             attrs.va_gid = u.u_cred->cr_gid;
2681             if (flags & O_TRUNC) {
2682                 attrs.va_size = 0;
2683             }
2684             fileP = NULL;
2685             vc=VTOAFS(fileP);
2686             code =
2687                 afs_create(VTOAFS(dirP), nameP, &attrs,
2688                            (flags & O_EXCL) ? usr_EXCL : usr_NONEXCL, mode,
2689                            &vc, u.u_cred);
2690             VN_RELE(dirP);
2691             if (code != 0) {
2692                 errno = code;
2693                 return -1;
2694             }
2695         } else {
2696             fileP = NULL;
2697             code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
2698             VN_RELE(dirP);
2699             if (code != 0) {
2700                 errno = code;
2701                 return -1;
2702             }
2703
2704             /*
2705              * Check whether we have access to this file
2706              */
2707             fileMode = 0;
2708             if (flags & (O_RDONLY | O_RDWR)) {
2709                 fileMode |= VREAD;
2710             }
2711             if (flags & (O_WRONLY | O_RDWR)) {
2712                 fileMode |= VWRITE;
2713             }
2714             if (!fileMode)
2715                 fileMode = VREAD;       /* since O_RDONLY is 0 */
2716             code = afs_access(VTOAFS(fileP), fileMode, u.u_cred);
2717             if (code != 0) {
2718                 VN_RELE(fileP);
2719                 errno = code;
2720                 return -1;
2721             }
2722
2723             /*
2724              * Get the file attributes, all we need is the size
2725              */
2726             code = afs_getattr(VTOAFS(fileP), &attrs, u.u_cred);
2727             if (code != 0) {
2728                 VN_RELE(fileP);
2729                 errno = code;
2730                 return -1;
2731             }
2732         }
2733     }
2734
2735     /*
2736      * Setup the open flags
2737      */
2738     openFlags = 0;
2739     if (flags & O_TRUNC) {
2740         openFlags |= FTRUNC;
2741     }
2742     if (flags & O_APPEND) {
2743         openFlags |= FAPPEND;
2744     }
2745     if (flags & O_SYNC) {
2746         openFlags |= FSYNC;
2747     }
2748     if (flags & O_SYNC) {
2749         openFlags |= FSYNC;
2750     }
2751     if (flags & (O_RDONLY | O_RDWR)) {
2752         openFlags |= FREAD;
2753     }
2754     if (flags & (O_WRONLY | O_RDWR)) {
2755         openFlags |= FWRITE;
2756     }
2757     if ((openFlags & (FREAD | FWRITE)) == 0) {
2758         /* O_RDONLY is 0, so ... */
2759         openFlags |= FREAD;
2760     }
2761
2762     /*
2763      * Truncate if necessary
2764      */
2765     if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
2766         usr_vattr_null(&attrs);
2767         attrs.va_size = 0;
2768         code = afs_setattr(VTOAFS(fileP), &attrs, u.u_cred);
2769         if (code != 0) {
2770             VN_RELE(fileP);
2771             errno = code;
2772             return -1;
2773         }
2774     }
2775
2776     vc=VTOAFS(fileP);   
2777     /*
2778      * do the open
2779      */
2780     code = afs_open(&vc, openFlags, u.u_cred);
2781     if (code != 0) {
2782         VN_RELE(fileP);
2783         errno = code;
2784         return -1;
2785     }
2786
2787     /*
2788      * Put the vnode pointer into the file table
2789      */
2790     for (fd = 0; fd < MAX_OSI_FILES; fd++) {
2791         if (afs_FileTable[fd] == NULL) {
2792             afs_FileTable[fd] = fileP;
2793             afs_FileFlags[fd] = openFlags;
2794             if (flags & O_APPEND) {
2795                 afs_FileOffsets[fd] = attrs.va_size;
2796             } else {
2797                 afs_FileOffsets[fd] = 0;
2798             }
2799             break;
2800         }
2801     }
2802     if (fd == MAX_OSI_FILES) {
2803         VN_RELE(fileP);
2804         errno = ENFILE;
2805         return -1;
2806     }
2807
2808     return fd;
2809 }
2810
2811 /*
2812  * Create a file
2813  */
2814 int
2815 uafs_creat(char *path, int mode)
2816 {
2817     int rc;
2818     rc = uafs_open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2819     return rc;
2820 }
2821
2822 int
2823 uafs_creat_r(char *path, int mode)
2824 {
2825     int rc;
2826     rc = uafs_open_r(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2827     return rc;
2828 }
2829
2830 /*
2831  * Write to a file
2832  */
2833 int
2834 uafs_write(int fd, char *buf, int len)
2835 {
2836     int retval;
2837     AFS_GLOCK();
2838     retval = uafs_write_r(fd, buf, len);
2839     AFS_GUNLOCK();
2840     return retval;
2841 }
2842
2843 int
2844 uafs_write_r(int fd, char *buf, int len)
2845 {
2846     int code;
2847     struct usr_uio uio;
2848     struct iovec iov[1];
2849     struct usr_vnode *fileP;
2850
2851     /*
2852      * Make sure this is an open file
2853      */
2854     fileP = afs_FileTable[fd];
2855     if (fileP == NULL) {
2856         errno = EBADF;
2857         return -1;
2858     }
2859
2860     /*
2861      * set up the uio buffer
2862      */
2863     iov[0].iov_base = buf;
2864     iov[0].iov_len = len;
2865     uio.uio_iov = &iov[0];
2866     uio.uio_iovcnt = 1;
2867     uio.uio_offset = afs_FileOffsets[fd];
2868     uio.uio_segflg = 0;
2869     uio.uio_fmode = FWRITE;
2870     uio.uio_resid = len;
2871
2872     /*
2873      * do the write
2874      */
2875
2876     code = afs_write(VTOAFS(fileP), &uio, afs_FileFlags[fd], u.u_cred, 0);
2877     if (code) {
2878         errno = code;
2879         return -1;
2880     }
2881
2882     afs_FileOffsets[fd] = uio.uio_offset;
2883     return (len - uio.uio_resid);
2884 }
2885
2886 /*
2887  * Read from a file
2888  */
2889 int
2890 uafs_read(int fd, char *buf, int len)
2891 {
2892     int retval;
2893     AFS_GLOCK();
2894     retval = uafs_read_r(fd, buf, len);
2895     AFS_GUNLOCK();
2896     return retval;
2897 }
2898
2899 int
2900 uafs_read_r(int fd, char *buf, int len)
2901 {
2902     int code;
2903     struct usr_uio uio;
2904     struct iovec iov[1];
2905     struct usr_vnode *fileP;
2906     struct usr_buf *bufP;
2907
2908     /*
2909      * Make sure this is an open file
2910      */
2911     fileP = afs_FileTable[fd];
2912     if (fileP == NULL) {
2913         errno = EBADF;
2914         return -1;
2915     }
2916
2917     /*
2918      * set up the uio buffer
2919      */
2920     iov[0].iov_base = buf;
2921     iov[0].iov_len = len;
2922     uio.uio_iov = &iov[0];
2923     uio.uio_iovcnt = 1;
2924     uio.uio_offset = afs_FileOffsets[fd];
2925     uio.uio_segflg = 0;
2926     uio.uio_fmode = FREAD;
2927     uio.uio_resid = len;
2928
2929     /*
2930      * do the read
2931      */
2932     code = afs_read(VTOAFS(fileP), &uio, u.u_cred, 0, &bufP, 0);
2933     if (code) {
2934         errno = code;
2935         return -1;
2936     }
2937
2938     afs_FileOffsets[fd] = uio.uio_offset;
2939     return (len - uio.uio_resid);
2940 }
2941
2942 /*
2943  * Copy the attributes of a file into a stat structure.
2944  *
2945  * NOTE: Caller must hold the global AFS lock.
2946  */
2947 int
2948 uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2949 {
2950     int code;
2951     struct usr_vattr attrs;
2952
2953     AFS_ASSERT_GLOCK();
2954
2955     /*
2956      * Get the attributes
2957      */
2958     code = afs_getattr(VTOAFS(vp), &attrs, u.u_cred);
2959     if (code != 0) {
2960         return code;
2961     }
2962
2963     /*
2964      * Copy the attributes, zero fields that aren't set
2965      */
2966     memset((void *)stats, 0, sizeof(struct stat));
2967     stats->st_dev = -1;
2968     stats->st_ino = attrs.va_nodeid;
2969     stats->st_mode = attrs.va_mode;
2970     stats->st_nlink = attrs.va_nlink;
2971     stats->st_uid = attrs.va_uid;
2972     stats->st_gid = attrs.va_gid;
2973     stats->st_rdev = attrs.va_rdev;
2974     stats->st_size = attrs.va_size;
2975     stats->st_atime = attrs.va_atime.tv_sec;
2976     stats->st_mtime = attrs.va_mtime.tv_sec;
2977     stats->st_ctime = attrs.va_ctime.tv_sec;
2978     stats->st_blksize = attrs.va_blocksize;
2979     stats->st_blocks = attrs.va_blocks;
2980
2981     return 0;
2982 }
2983
2984 /*
2985  * Get the attributes of a file, do follow links
2986  */
2987 int
2988 uafs_stat(char *path, struct stat *buf)
2989 {
2990     int retval;
2991     AFS_GLOCK();
2992     retval = uafs_stat_r(path, buf);
2993     AFS_GUNLOCK();
2994     return retval;
2995 }
2996
2997 int
2998 uafs_stat_r(char *path, struct stat *buf)
2999 {
3000     int code;
3001     struct vnode *vp;
3002
3003     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3004     if (code != 0) {
3005         errno = code;
3006         return -1;
3007     }
3008     code = uafs_GetAttr(vp, buf);
3009     VN_RELE(vp);
3010     if (code) {
3011         errno = code;
3012         return -1;
3013     }
3014     return 0;
3015 }
3016
3017 /*
3018  * Get the attributes of a file, don't follow links
3019  */
3020 int
3021 uafs_lstat(char *path, struct stat *buf)
3022 {
3023     int retval;
3024     AFS_GLOCK();
3025     retval = uafs_lstat_r(path, buf);
3026     AFS_GUNLOCK();
3027     return retval;
3028 }
3029
3030 int
3031 uafs_lstat_r(char *path, struct stat *buf)
3032 {
3033     int code;
3034     struct vnode *vp;
3035
3036     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3037     if (code != 0) {
3038         errno = code;
3039         return -1;
3040     }
3041     code = uafs_GetAttr(vp, buf);
3042     VN_RELE(vp);
3043     if (code) {
3044         errno = code;
3045         return -1;
3046     }
3047     return 0;
3048 }
3049
3050 /*
3051  * Get the attributes of an open file
3052  */
3053 int
3054 uafs_fstat(int fd, struct stat *buf)
3055 {
3056     int retval;
3057     AFS_GLOCK();
3058     retval = uafs_fstat_r(fd, buf);
3059     AFS_GUNLOCK();
3060     return retval;
3061 }
3062
3063 int
3064 uafs_fstat_r(int fd, struct stat *buf)
3065 {
3066     int code;
3067     struct vnode *vp;
3068
3069     vp = afs_FileTable[fd];
3070     if (vp == NULL) {
3071         errno = EBADF;
3072         return -1;
3073     }
3074     code = uafs_GetAttr(vp, buf);
3075     if (code) {
3076         errno = code;
3077         return -1;
3078     }
3079     return 0;
3080 }
3081
3082 /*
3083  * change the permissions on a file
3084  */
3085 int
3086 uafs_chmod(char *path, int mode)
3087 {
3088     int retval;
3089     AFS_GLOCK();
3090     retval = uafs_chmod_r(path, mode);
3091     AFS_GUNLOCK();
3092     return retval;
3093 }
3094
3095 int
3096 uafs_chmod_r(char *path, int mode)
3097 {
3098     int code;
3099     struct vnode *vp;
3100     struct usr_vattr attrs;
3101
3102     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3103     if (code != 0) {
3104         errno = code;
3105         return -1;
3106     }
3107     usr_vattr_null(&attrs);
3108     attrs.va_mode = mode;
3109     code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
3110     VN_RELE(vp);
3111     if (code != 0) {
3112         errno = code;
3113         return -1;
3114     }
3115     return 0;
3116 }
3117
3118 /*
3119  * change the permissions on an open file
3120  */
3121 int
3122 uafs_fchmod(int fd, int mode)
3123 {
3124     int retval;
3125     AFS_GLOCK();
3126     retval = uafs_fchmod_r(fd, mode);
3127     AFS_GUNLOCK();
3128     return retval;
3129 }
3130
3131 int
3132 uafs_fchmod_r(int fd, int mode)
3133 {
3134     int code;
3135     struct vnode *vp;
3136     struct usr_vattr attrs;
3137
3138     vp = afs_FileTable[fd];
3139     if (vp == NULL) {
3140         errno = EBADF;
3141         return -1;
3142     }
3143     usr_vattr_null(&attrs);
3144     attrs.va_mode = mode;
3145     code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
3146     if (code != 0) {
3147         errno = code;
3148         return -1;
3149     }
3150     return 0;
3151 }
3152
3153 /*
3154  * truncate a file
3155  */
3156 int
3157 uafs_truncate(char *path, int length)
3158 {
3159     int retval;
3160     AFS_GLOCK();
3161     retval = uafs_truncate_r(path, length);
3162     AFS_GUNLOCK();
3163     return retval;
3164 }
3165
3166 int
3167 uafs_truncate_r(char *path, int length)
3168 {
3169     int code;
3170     struct vnode *vp;
3171     struct usr_vattr attrs;
3172
3173     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3174     if (code != 0) {
3175         errno = code;
3176         return -1;
3177     }
3178     usr_vattr_null(&attrs);
3179     attrs.va_size = length;
3180     code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
3181     VN_RELE(vp);
3182     if (code != 0) {
3183         errno = code;
3184         return -1;
3185     }
3186     return 0;
3187 }
3188
3189 /*
3190  * truncate an open file
3191  */
3192 int
3193 uafs_ftruncate(int fd, int length)
3194 {
3195     int retval;
3196     AFS_GLOCK();
3197     retval = uafs_ftruncate_r(fd, length);
3198     AFS_GUNLOCK();
3199     return retval;
3200 }
3201
3202 int
3203 uafs_ftruncate_r(int fd, int length)
3204 {
3205     int code;
3206     struct vnode *vp;
3207     struct usr_vattr attrs;
3208
3209     vp = afs_FileTable[fd];
3210     if (vp == NULL) {
3211         errno = EBADF;
3212         return -1;
3213     }
3214     usr_vattr_null(&attrs);
3215     attrs.va_size = length;
3216     code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
3217     if (code != 0) {
3218         errno = code;
3219         return -1;
3220     }
3221     return 0;
3222 }
3223
3224 /*
3225  * set the read/write file pointer of an open file
3226  */
3227 int
3228 uafs_lseek(int fd, int offset, int whence)
3229 {
3230     int retval;
3231     AFS_GLOCK();
3232     retval = uafs_lseek_r(fd, offset, whence);
3233     AFS_GUNLOCK();
3234     return retval;
3235 }
3236
3237 int
3238 uafs_lseek_r(int fd, int offset, int whence)
3239 {
3240     int code;
3241     int newpos;
3242     struct usr_vattr attrs;
3243     struct usr_vnode *vp;
3244
3245     vp = afs_FileTable[fd];
3246     if (vp == NULL) {
3247         errno = EBADF;
3248         return -1;
3249     }
3250     switch (whence) {
3251     case SEEK_CUR:
3252         newpos = afs_FileOffsets[fd] + offset;
3253         break;
3254     case SEEK_SET:
3255         newpos = offset;
3256         break;
3257     case SEEK_END:
3258         code = afs_getattr(VTOAFS(vp), &attrs, u.u_cred);
3259         if (code != 0) {
3260             errno = code;
3261             return -1;
3262         }
3263         newpos = attrs.va_size + offset;
3264         break;
3265     default:
3266         errno = EINVAL;
3267         return -1;
3268     }
3269     if (newpos < 0) {
3270         errno = EINVAL;
3271         return -1;
3272     }
3273     afs_FileOffsets[fd] = newpos;
3274     return newpos;
3275 }
3276
3277 /*
3278  * sync a file
3279  */
3280 int
3281 uafs_fsync(int fd)
3282 {
3283     int retval;
3284     AFS_GLOCK();
3285     retval = uafs_fsync_r(fd);
3286     AFS_GUNLOCK();
3287     return retval;
3288 }
3289
3290 int
3291 uafs_fsync_r(int fd)
3292 {
3293     int code;
3294     struct usr_vnode *fileP;
3295
3296
3297     fileP = afs_FileTable[fd];
3298     if (fileP == NULL) {
3299         errno = EBADF;
3300         return -1;
3301     }
3302
3303     code = afs_fsync(fileP, u.u_cred);
3304     if (code != 0) {
3305         errno = code;
3306         return -1;
3307     }
3308
3309     return 0;
3310 }
3311
3312 /*
3313  * Close a file
3314  */
3315 int
3316 uafs_close(int fd)
3317 {
3318     int retval;
3319     AFS_GLOCK();
3320     retval = uafs_close_r(fd);
3321     AFS_GUNLOCK();
3322     return retval;
3323 }
3324
3325 int
3326 uafs_close_r(int fd)
3327 {
3328     int code;
3329     struct usr_vnode *fileP;
3330
3331     fileP = afs_FileTable[fd];
3332     if (fileP == NULL) {
3333         errno = EBADF;
3334         return -1;
3335     }
3336     afs_FileTable[fd] = NULL;
3337
3338     code = afs_close(fileP, afs_FileFlags[fd], u.u_cred);
3339     VN_RELE(fileP);
3340     if (code != 0) {
3341         errno = code;
3342         return -1;
3343     }
3344
3345     return 0;
3346 }
3347
3348 /*
3349  * Create a hard link from the source to the target
3350  * Note: file names may not end in a slash.
3351  */
3352 int
3353 uafs_link(char *existing, char *new)
3354 {
3355     int retval;
3356     AFS_GLOCK();
3357     retval = uafs_link_r(existing, new);
3358     AFS_GUNLOCK();
3359     return retval;
3360 }
3361
3362 int
3363 uafs_link_r(char *existing, char *new)
3364 {
3365     int code;
3366     struct usr_vnode *existP;
3367     struct usr_vnode *dirP;
3368     char *nameP;
3369
3370     if (uafs_IsRoot(new)) {
3371         return EACCES;
3372     }
3373
3374     /*
3375      * Look up the existing node.
3376      */
3377     code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
3378     if (code != 0) {
3379         errno = code;
3380         return -1;
3381     }
3382
3383     /*
3384      * Look up the parent directory.
3385      */
3386     nameP = uafs_LastPath(new);
3387     if (nameP != NULL) {
3388         code = uafs_LookupParent(new, &dirP);
3389         if (code != 0) {
3390             VN_RELE(existP);
3391             errno = code;
3392             return -1;
3393         }
3394     } else {
3395         dirP = afs_CurrentDir;
3396         nameP = new;
3397         VN_HOLD(dirP);
3398     }
3399
3400     /*
3401      * Make sure the filename has at least one character
3402      */
3403     if (*nameP == '\0') {
3404         VN_RELE(existP);
3405         VN_RELE(dirP);
3406         errno = EINVAL;
3407         return -1;
3408     }
3409
3410     /*
3411      * Create the link
3412      */
3413     code = afs_link(existP, dirP, nameP, u.u_cred);
3414     VN_RELE(existP);
3415     VN_RELE(dirP);
3416     if (code != 0) {
3417         errno = code;
3418         return -1;
3419     }
3420     return 0;
3421 }
3422
3423 /*
3424  * Create a symbolic link from the source to the target
3425  * Note: file names may not end in a slash.
3426  */
3427 int
3428 uafs_symlink(char *target, char *source)
3429 {
3430     int retval;
3431     AFS_GLOCK();
3432     retval = uafs_symlink_r(target, source);
3433     AFS_GUNLOCK();
3434     return retval;
3435 }
3436
3437 int
3438 uafs_symlink_r(char *target, char *source)
3439 {
3440     int code;
3441     struct usr_vnode *dirP;
3442     struct usr_vattr attrs;
3443     char *nameP;
3444
3445     if (uafs_IsRoot(source)) {
3446         return EACCES;
3447     }
3448
3449     /*
3450      * Look up the parent directory.
3451      */
3452     nameP = uafs_LastPath(source);
3453     if (nameP != NULL) {
3454         code = uafs_LookupParent(source, &dirP);
3455         if (code != 0) {
3456             errno = code;
3457             return -1;
3458         }
3459     } else {
3460         dirP = afs_CurrentDir;
3461         nameP = source;
3462         VN_HOLD(dirP);
3463     }
3464
3465     /*
3466      * Make sure the filename has at least one character
3467      */
3468     if (*nameP == '\0') {
3469         VN_RELE(dirP);
3470         errno = EINVAL;
3471         return -1;
3472     }
3473
3474     /*
3475      * Create the link
3476      */
3477     usr_vattr_null(&attrs);
3478     attrs.va_type = VLNK;
3479     attrs.va_mode = 0777;
3480     attrs.va_uid = u.u_cred->cr_uid;
3481     attrs.va_gid = u.u_cred->cr_gid;
3482     code = afs_symlink(dirP, nameP, &attrs, target, u.u_cred);
3483     VN_RELE(dirP);
3484     if (code != 0) {
3485         errno = code;
3486         return -1;
3487     }
3488     return 0;
3489 }
3490
3491 /*
3492  * Read a symbolic link into the buffer
3493  */
3494 int
3495 uafs_readlink(char *path, char *buf, int len)
3496 {
3497     int retval;
3498     AFS_GLOCK();
3499     retval = uafs_readlink_r(path, buf, len);
3500     AFS_GUNLOCK();
3501     return retval;
3502 }
3503
3504 int
3505 uafs_readlink_r(char *path, char *buf, int len)
3506 {
3507     int code;
3508     struct usr_vnode *vp;
3509     struct usr_uio uio;
3510     struct iovec iov[1];
3511
3512     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3513     if (code != 0) {
3514         errno = code;
3515         return -1;
3516     }
3517
3518     if (vp->v_type != VLNK) {
3519         VN_RELE(vp);
3520         errno = EINVAL;
3521         return -1;
3522     }
3523
3524     /*
3525      * set up the uio buffer
3526      */
3527     iov[0].iov_base = buf;
3528     iov[0].iov_len = len;
3529     uio.uio_iov = &iov[0];
3530     uio.uio_iovcnt = 1;
3531     uio.uio_offset = 0;
3532     uio.uio_segflg = 0;
3533     uio.uio_fmode = FREAD;
3534     uio.uio_resid = len;
3535
3536     /*
3537      * Read the the link
3538      */
3539     code = afs_readlink(vp, &uio, u.u_cred);
3540     VN_RELE(vp);
3541     if (code) {
3542         errno = code;
3543         return -1;
3544     }
3545
3546     /*
3547      * return the number of bytes read
3548      */
3549     return (len - uio.uio_resid);
3550 }
3551
3552 /*
3553  * Remove a file (or directory)
3554  * Note: file name may not end in a slash.
3555  */
3556 int
3557 uafs_unlink(char *path)
3558 {
3559     int retval;
3560     AFS_GLOCK();
3561     retval = uafs_unlink_r(path);
3562     AFS_GUNLOCK();
3563     return retval;
3564 }
3565
3566 int
3567 uafs_unlink_r(char *path)
3568 {
3569     int code;
3570     int openFlags;
3571     struct usr_vnode *fileP;
3572     struct usr_vnode *dirP;
3573     char *nameP;
3574
3575     if (uafs_IsRoot(path)) {
3576         return EACCES;
3577     }
3578
3579     /*
3580      * Look up the parent directory.
3581      */
3582     nameP = uafs_LastPath(path);
3583     if (nameP != NULL) {
3584         code = uafs_LookupParent(path, &dirP);
3585         if (code != 0) {
3586             errno = code;
3587             return -1;
3588         }
3589     } else {
3590         dirP = afs_CurrentDir;
3591         nameP = path;
3592         VN_HOLD(dirP);
3593     }
3594
3595     /*
3596      * Make sure the filename has at least one character
3597      */
3598     if (*nameP == '\0') {
3599         VN_RELE(dirP);
3600         errno = EINVAL;
3601         return -1;
3602     }
3603
3604     /*
3605      * Remove the file
3606      */
3607     code = afs_remove(dirP, nameP, u.u_cred);
3608     VN_RELE(dirP);
3609     if (code != 0) {
3610         errno = code;
3611         return -1;
3612     }
3613
3614     return 0;
3615 }
3616
3617 /*
3618  * Rename a file (or directory)
3619  */
3620 int
3621 uafs_rename(char *old, char *new)
3622 {
3623     int retval;
3624     AFS_GLOCK();
3625     retval = uafs_rename_r(old, new);
3626     AFS_GUNLOCK();
3627     return retval;
3628 }
3629
3630 int
3631 uafs_rename_r(char *old, char *new)
3632 {
3633     int code;
3634     char *onameP;
3635     char *nnameP;
3636     struct usr_vnode *odirP;
3637     struct usr_vnode *ndirP;
3638
3639     if (uafs_IsRoot(new)) {
3640         return EACCES;
3641     }
3642
3643     /*
3644      * Look up the parent directories.
3645      */
3646     onameP = uafs_LastPath(old);
3647     if (onameP != NULL) {
3648         code = uafs_LookupParent(old, &odirP);
3649         if (code != 0) {
3650             errno = code;
3651             return -1;
3652         }
3653     } else {
3654         odirP = afs_CurrentDir;
3655         onameP = old;
3656         VN_HOLD(odirP);
3657     }
3658     nnameP = uafs_LastPath(new);
3659     if (nnameP != NULL) {
3660         code = uafs_LookupParent(new, &ndirP);
3661         if (code != 0) {
3662             errno = code;
3663             return -1;
3664         }
3665     } else {
3666         ndirP = afs_CurrentDir;
3667         nnameP = new;
3668         VN_HOLD(ndirP);
3669     }
3670
3671     /*
3672      * Make sure the filename has at least one character
3673      */
3674     if (*onameP == '\0' || *nnameP == '\0') {
3675         VN_RELE(odirP);
3676         VN_RELE(ndirP);
3677         errno = EINVAL;
3678         return -1;
3679     }
3680
3681     /*
3682      * Rename the file
3683      */
3684     code = afs_rename(odirP, onameP, ndirP, nnameP, u.u_cred);
3685     VN_RELE(odirP);
3686     VN_RELE(ndirP);
3687     if (code != 0) {
3688         errno = code;
3689         return -1;
3690     }
3691
3692     return 0;
3693 }
3694
3695 /*
3696  * Remove a or directory
3697  * Note: file name may not end in a slash.
3698  */
3699 int
3700 uafs_rmdir(char *path)
3701 {
3702     int retval;
3703     AFS_GLOCK();
3704     retval = uafs_rmdir_r(path);
3705     AFS_GUNLOCK();
3706     return retval;
3707 }
3708
3709 int
3710 uafs_rmdir_r(char *path)
3711 {
3712     int code;
3713     int openFlags;
3714     struct usr_vnode *fileP;
3715     struct usr_vnode *dirP;
3716     char *nameP;
3717
3718     if (uafs_IsRoot(path)) {
3719         return EACCES;
3720     }
3721
3722     /*
3723      * Look up the parent directory.
3724      */
3725     nameP = uafs_LastPath(path);
3726     if (nameP != NULL) {
3727         code = uafs_LookupParent(path, &dirP);
3728         if (code != 0) {
3729             errno = code;
3730             return -1;
3731         }
3732     } else {
3733         dirP = afs_CurrentDir;
3734         nameP = path;
3735         VN_HOLD(dirP);
3736     }
3737
3738     /*
3739      * Make sure the directory name has at least one character
3740      */
3741     if (*nameP == '\0') {
3742         VN_RELE(dirP);
3743         errno = EINVAL;
3744         return -1;
3745     }
3746
3747     /*
3748      * Remove the directory
3749      */
3750     code = afs_rmdir(dirP, nameP, u.u_cred);
3751     VN_RELE(dirP);
3752     if (code != 0) {
3753         errno = code;
3754         return -1;
3755     }
3756
3757     return 0;
3758 }
3759
3760 /*
3761  * Flush a file from the AFS cache
3762  */
3763 int
3764 uafs_FlushFile(char *path)
3765 {
3766     int code;
3767     struct afs_ioctl iob;
3768
3769     iob.in = NULL;
3770     iob.in_size = 0;
3771     iob.out = NULL;
3772     iob.out_size = 0;
3773
3774     code =
3775         call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6), (long)&iob, 0,
3776                      0);
3777     if (code != 0) {
3778         errno = code;
3779         return -1;
3780     }
3781
3782     return 0;
3783 }
3784
3785 int
3786 uafs_FlushFile_r(char *path)
3787 {
3788     int retval;
3789     AFS_GUNLOCK();
3790     retval = uafs_FlushFile(path);
3791     AFS_GLOCK();
3792     return retval;
3793 }
3794
3795 /*
3796  * open a directory
3797  */
3798 usr_DIR *
3799 uafs_opendir(char *path)
3800 {
3801     usr_DIR *retval;
3802     AFS_GLOCK();
3803     retval = uafs_opendir_r(path);
3804     AFS_GUNLOCK();
3805     return retval;
3806 }
3807
3808 usr_DIR *
3809 uafs_opendir_r(char *path)
3810 {
3811     usr_DIR *dirp;
3812     struct usr_vnode *fileP;
3813     int fd;
3814
3815     /*
3816      * Open the directory for reading
3817      */
3818     fd = uafs_open_r(path, O_RDONLY, 0);
3819     if (fd < 0) {
3820         return NULL;
3821     }
3822
3823     fileP = afs_FileTable[fd];
3824     if (fileP == NULL) {
3825         return NULL;
3826     }
3827
3828     if (fileP->v_type != VDIR) {
3829         uafs_close_r(fd);
3830         errno = ENOTDIR;
3831         return NULL;
3832     }
3833
3834     /*
3835      * Set up the directory structures
3836      */
3837     dirp =
3838         (usr_DIR *) afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3839                                   sizeof(struct usr_dirent));
3840     usr_assert(dirp != NULL);
3841     dirp->dd_buf = (char *)(dirp + 1);
3842     dirp->dd_fd = fd;
3843     dirp->dd_loc = 0;
3844     dirp->dd_size = 0;
3845
3846     errno = 0;
3847     return dirp;
3848 }
3849
3850 /*
3851  * Read directory entries into a file system independent format.
3852  * This routine was developed to support AFS cache consistency testing.
3853  * You should use uafs_readdir instead.
3854  */
3855 int
3856 uafs_getdents(int fd, struct min_direct *buf, int len)
3857 {
3858     int retval;
3859     AFS_GLOCK();
3860     retval = uafs_getdents_r(fd, buf, len);
3861     AFS_GUNLOCK();
3862     return retval;
3863 }
3864
3865 int
3866 uafs_getdents_r(int fd, struct min_direct *buf, int len)
3867 {
3868     int code;
3869     struct usr_uio uio;
3870     struct usr_vnode *vp;
3871     struct iovec iov[1];
3872
3873     /*
3874      * Make sure this is an open file
3875      */
3876     vp = afs_FileTable[fd];
3877     if (vp == NULL) {
3878         AFS_GUNLOCK();
3879         errno = EBADF;
3880         return -1;
3881     }
3882
3883     /*
3884      * set up the uio buffer
3885      */
3886     iov[0].iov_base = (char *)buf;
3887     iov[0].iov_len = len;
3888     uio.uio_iov = &iov[0];
3889     uio.uio_iovcnt = 1;
3890     uio.uio_offset = afs_FileOffsets[fd];
3891     uio.uio_segflg = 0;
3892     uio.uio_fmode = FREAD;
3893     uio.uio_resid = len;
3894
3895     /*
3896      * read the next chunk from the directory
3897      */
3898     code = afs_readdir(vp, &uio, u.u_cred);
3899     if (code != 0) {
3900         errno = code;
3901         return -1;
3902     }
3903
3904     afs_FileOffsets[fd] = uio.uio_offset;
3905     return (len - uio.uio_resid);
3906 }
3907
3908 /*
3909  * read from a directory (names only)
3910  */
3911 struct usr_dirent *
3912 uafs_readdir(usr_DIR * dirp)
3913 {
3914     struct usr_dirent *retval;
3915     AFS_GLOCK();
3916     retval = uafs_readdir_r(dirp);
3917     AFS_GUNLOCK();
3918     return retval;
3919 }
3920
3921 struct usr_dirent *
3922 uafs_readdir_r(usr_DIR * dirp)
3923 {
3924     int rc;
3925     int code;
3926     int len;
3927     struct usr_uio uio;
3928     struct usr_vnode *vp;
3929     struct iovec iov[1];
3930     struct usr_dirent *direntP;
3931     struct min_direct *directP;
3932
3933     /*
3934      * Make sure this is an open file
3935      */
3936     vp = afs_FileTable[dirp->dd_fd];
3937     if (vp == NULL) {
3938         errno = EBADF;
3939         return NULL;
3940     }
3941
3942     /*
3943      * If there are no entries in the stream buffer
3944      * then read another chunk
3945      */
3946     directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3947     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3948         /*
3949          * set up the uio buffer
3950          */
3951         iov[0].iov_base = dirp->dd_buf;
3952         iov[0].iov_len = USR_DIRSIZE;
3953         uio.uio_iov = &iov[0];
3954         uio.uio_iovcnt = 1;
3955         uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3956         uio.uio_segflg = 0;
3957         uio.uio_fmode = FREAD;
3958         uio.uio_resid = USR_DIRSIZE;
3959
3960         /*
3961          * read the next chunk from the directory
3962          */
3963         code = afs_readdir(vp, &uio, u.u_cred);
3964         if (code != 0) {
3965             errno = code;
3966             return NULL;
3967         }
3968         afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3969
3970         dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3971         dirp->dd_loc = 0;
3972         directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3973     }
3974
3975     /*
3976      * Check for end of file
3977      */
3978     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3979         errno = 0;
3980         return NULL;
3981     }
3982     len = ((sizeof(struct min_direct) + directP->d_namlen + 4) & (~3));
3983     usr_assert(len <= dirp->dd_size);
3984
3985     /*
3986      * Copy the next entry into the usr_dirent structure and advance
3987      */
3988     direntP = (struct usr_dirent *)(dirp->dd_buf + USR_DIRSIZE);
3989     direntP->d_ino = directP->d_fileno;
3990     direntP->d_off = direntP->d_reclen;
3991     direntP->d_reclen =
3992         sizeof(struct usr_dirent) - MAXNAMLEN + directP->d_namlen + 1;
3993     memcpy(&direntP->d_name[0], (void *)(directP + 1), directP->d_namlen);
3994     direntP->d_name[directP->d_namlen] = '\0';
3995     dirp->dd_loc += len;
3996     dirp->dd_size -= len;
3997
3998     return direntP;
3999 }
4000
4001 /*
4002  * Close a directory
4003  */
4004 int
4005 uafs_closedir(usr_DIR * dirp)
4006 {
4007     int retval;
4008     AFS_GLOCK();
4009     retval = uafs_closedir_r(dirp);
4010     AFS_GUNLOCK();
4011     return retval;
4012 }
4013
4014 int
4015 uafs_closedir_r(usr_DIR * dirp)
4016 {
4017     int fd;
4018     int rc;
4019
4020     fd = dirp->dd_fd;
4021     afs_osi_Free((char *)dirp,
4022                  sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
4023     rc = uafs_close_r(fd);
4024     return rc;
4025 }
4026
4027 /*
4028  * Do AFS authentication
4029  */
4030 int
4031 uafs_klog(char *user, char *cell, char *passwd, char **reason)
4032 {
4033     int code;
4034     afs_int32 password_expires = -1;
4035
4036     usr_mutex_lock(&osi_authenticate_lock);
4037     code =
4038         ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION +
4039                                    KA_USERAUTH_DOSETPAG2, user, NULL, cell,
4040                                    passwd, 0, &password_expires, 0, reason);
4041     usr_mutex_unlock(&osi_authenticate_lock);
4042     return code;
4043 }
4044
4045 int
4046 uafs_klog_r(char *user, char *cell, char *passwd, char **reason)
4047 {
4048     int retval;
4049     AFS_GUNLOCK();
4050     retval = uafs_klog(user, cell, passwd, reason);
4051     AFS_GLOCK();
4052     return retval;
4053 }
4054
4055 /*
4056  * Destroy AFS credentials from the kernel cache
4057  */
4058 int
4059 uafs_unlog(void)
4060 {
4061     int code;
4062
4063     usr_mutex_lock(&osi_authenticate_lock);
4064     code = ktc_ForgetAllTokens();
4065     usr_mutex_unlock(&osi_authenticate_lock);
4066     return code;
4067 }
4068
4069 int
4070 uafs_unlog_r(void)
4071 {
4072     int retval;
4073     AFS_GUNLOCK();
4074     retval = uafs_unlog();
4075     AFS_GLOCK();
4076     return retval;
4077 }
4078
4079 /*
4080  * Strip the AFS mount point from a pathname string. Return
4081  * NULL if the path is a relative pathname or if the path
4082  * doesn't start with the AFS mount point string.
4083  */
4084 char *
4085 uafs_afsPathName(char *path)
4086 {
4087     char *p;
4088     char lastchar;
4089     int i;
4090
4091     if (path[0] != '/')
4092         return NULL;
4093     lastchar = '/';
4094     for (i = 1, p = path + 1; *p != '\0'; p++) {
4095         /* Ignore duplicate slashes */
4096         if (*p == '/' && lastchar == '/')
4097             continue;
4098         /* Is this a subdirectory of the AFS mount point? */
4099         if (afs_mountDir[i] == '\0' && *p == '/') {
4100             /* strip leading slashes */
4101             while (*(++p) == '/');
4102             return p;
4103         }
4104         /* Reject paths that are not within AFS */
4105         if (*p != afs_mountDir[i])
4106             return NULL;
4107         lastchar = *p;
4108         i++;
4109     }
4110     /* Is this the AFS mount point? */
4111     if (afs_mountDir[i] == '\0') {
4112         usr_assert(*p == '\0');
4113         return p;
4114     }
4115     return NULL;
4116 }
4117
4118 #ifdef AFS_WEB_ENHANCEMENTS
4119 /*
4120  * uafs_klog_nopag
4121  * klog but don't allocate a new pag
4122  */
4123 int
4124 uafs_klog_nopag(char *user, char *cell, char *passwd, char **reason)
4125 {
4126     int code;
4127     afs_int32 password_expires = -1;
4128
4129     usr_mutex_lock(&osi_authenticate_lock);
4130     code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
4131                                       /*+KA_USERAUTH_DOSETPAG2 */ , user,
4132                                       NULL, cell, passwd, 0,
4133                                       &password_expires, 0, reason);
4134     usr_mutex_unlock(&osi_authenticate_lock);
4135     return code;
4136 }
4137
4138 /*
4139  * uafs_getcellstatus
4140  * get the cell status
4141  */
4142 int
4143 uafs_getcellstatus(char *cell, afs_int32 * status)
4144 {
4145     int rc;
4146     struct afs_ioctl iob;
4147
4148     iob.in = cell;
4149     iob.in_size = strlen(cell) + 1;
4150     iob.out = 0;
4151     iob.out_size = 0;
4152
4153     rc = call_syscall(AFSCALL_PIOCTL, /*path */ 0, _VICEIOCTL(35),
4154                       (long)&iob, 0, 0);
4155
4156     if (rc < 0) {
4157         errno = rc;
4158         return -1;
4159     }
4160
4161     *status = (afs_int32) iob.out;
4162     return 0;
4163 }
4164
4165 /*
4166  * uafs_getvolquota
4167  * Get quota of volume associated with path
4168  */
4169 int
4170 uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
4171 {
4172     int rc;
4173     struct afs_ioctl iob;
4174     VolumeStatus *status;
4175     char buf[1024];
4176
4177     iob.in = 0;
4178     iob.in_size = 0;
4179     iob.out = buf;
4180     iob.out_size = 1024;
4181
4182     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(4), (long)&iob,
4183                       0, 0);
4184
4185     if (rc != 0) {
4186         errno = rc;
4187         return -1;
4188     }
4189
4190     status = (VolumeStatus *) buf;
4191     *BlocksInUse = status->BlocksInUse;
4192     *MaxQuota = status->MaxQuota;
4193     return 0;
4194 }
4195
4196 /*
4197  * uafs_setvolquota
4198  * Set quota of volume associated with path
4199  */
4200 int
4201 uafs_setvolquota(char *path, afs_int32 MaxQuota)
4202 {
4203     int rc;
4204     struct afs_ioctl iob;
4205     VolumeStatus *status;
4206     char buf[1024];
4207
4208     iob.in = buf;
4209     iob.in_size = 1024;
4210     iob.out = 0;
4211     iob.out_size = 0;
4212
4213     memset(buf, 0, sizeof(VolumeStatus));
4214     status = (VolumeStatus *) buf;
4215     status->MaxQuota = MaxQuota;
4216     status->MinQuota = -1;
4217
4218     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(5), (long)&iob,
4219                       0, 0);
4220
4221     if (rc != 0) {
4222         errno = rc;
4223         return -1;
4224     }
4225
4226     return 0;
4227 }
4228
4229 /*
4230  * uafs_statmountpoint
4231  * Determine whether a dir. is a mount point or not
4232  * return 1 if mount point, 0 if not
4233  */
4234 int
4235 uafs_statmountpoint(char *path)
4236 {
4237     int retval;
4238     int code;
4239     char buf[256];
4240
4241     AFS_GLOCK();
4242     retval = uafs_statmountpoint_r(path);
4243     AFS_GUNLOCK();
4244     return retval;
4245 }
4246
4247 int
4248 uafs_statmountpoint_r(char *path)
4249 {
4250     int code;
4251     struct vnode *vp;
4252     struct vcache *avc;
4253     struct vrequest treq;
4254     int r;
4255
4256     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
4257     if (code != 0) {
4258         errno = code;
4259         return -1;
4260     }
4261
4262     avc = VTOAFS(vp);
4263
4264     r = avc->mvstat;
4265     VN_RELE(vp);
4266     return r;
4267 }
4268
4269 /*
4270  * uafs_getRights
4271  * Get a list of rights for the current user on path.
4272  */
4273 int
4274 uafs_getRights(char *path)
4275 {
4276     int code, rc;
4277     struct vnode *vp;
4278     int afs_rights;
4279
4280     AFS_GLOCK();
4281     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
4282     if (code != 0) {
4283         errno = code;
4284         AFS_GUNLOCK();
4285         return -1;
4286     }
4287
4288     afs_rights =
4289         PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
4290         | PRSFS_LOCK | PRSFS_ADMINISTER;
4291
4292     afs_rights = afs_getRights(vp, afs_rights, u.u_cred);
4293
4294     AFS_GUNLOCK();
4295     return afs_rights;
4296 }
4297 #endif /* AFS_WEB_ENHANCEMENTS */
4298
4299 #endif /* UKERNEL */