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