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