Initial fakestat support (fake mountpoint directory attributes).
[openafs.git] / src / afs / afs_pioctl.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 #include <afsconfig.h>
11 #include "../afs/param.h"
12
13 RCSID("$Header$");
14
15 #include "../afs/sysincludes.h" /* Standard vendor system headers */
16 #include "../afs/afsincludes.h" /* Afs-based standard headers */
17 #include "../afs/afs_stats.h"   /* afs statistics */
18 #include "../afs/vice.h"
19 #include "../rx/rx_globals.h"
20
21 extern void afs_ComputePAGStats();
22 extern struct vcache *afs_LookupVCache();
23 struct VenusFid afs_rootFid;
24 afs_int32 afs_waitForever=0;
25 short afs_waitForeverCount = 0;
26 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE;   /* show all messages */
27 extern afs_int32 PROBE_INTERVAL;
28
29 extern int cacheDiskType;
30 extern afs_int32 afs_cacheBlocks;
31 extern struct afs_q CellLRU;
32 extern char *afs_indexFlags; /* only one: is there data there? */
33 extern afs_int32 afs_blocksUsed;
34 extern struct unixuser *afs_users[NUSERS];
35 extern struct server *afs_servers[NSERVERS];
36 extern struct interfaceAddr afs_cb_interface; /* client interface addresses */
37 extern afs_rwlock_t afs_xserver;
38 extern afs_rwlock_t afs_xinterface;
39 extern afs_rwlock_t afs_xcell;
40 extern afs_rwlock_t afs_xuser;
41 #ifndef AFS_FINEG_SUNLOCK
42 extern afs_rwlock_t afs_xconn;
43 #endif
44 extern afs_rwlock_t afs_xvolume;
45 extern afs_lock_t afs_xdcache;              /* lock: alloc new disk cache entries */
46 extern afs_rwlock_t afs_xvcache;  
47 extern afs_rwlock_t afs_xcbhash;  
48 extern afs_int32 afs_mariner, afs_marinerHost;
49 extern struct srvAddr *afs_srvAddrs[NSERVERS];
50 extern int afs_resourceinit_flag;
51 extern afs_int32 cryptall;
52
53 static int PBogus(), PSetAcl(), PGetAcl(), PSetTokens(), PGetVolumeStatus();
54 static int PSetVolumeStatus(), PFlush(), PNewStatMount(), PGetTokens(), PUnlog();
55 static int PCheckServers(), PCheckVolNames(), PCheckAuth(), PFindVolume();
56 static int PViceAccess(), PSetCacheSize(), Prefetch();
57 static int PRemoveCallBack(), PNewCell(), PListCells(), PRemoveMount();
58 static int PMariner(), PGetUserCell(), PGetWSCell(), PGetFileCell();
59 static int PVenusLogging(), PNoop(), PSetCellStatus(), PGetCellStatus();
60 static int PFlushVolumeData(), PGetCacheSize();
61 static int PSetSysName(),PGetFID();
62 static int PGetVnodeXStatus();
63 static int PSetSPrefs(), PGetSPrefs(), PGag(), PTwiddleRx();
64 static int PSetSPrefs33(), PStoreBehind(), PGCPAGs();
65 static int PGetCPrefs(), PSetCPrefs(); /* client network addresses */
66 static int PGetInitParams(), PFlushMount(), PRxStatProc(), PRxStatPeer();
67 static int PGetRxkcrypt(), PSetRxkcrypt();
68 static int PPrefetchFromTape(), PResidencyCmd();
69 static int PNewAlias(), PListAliases();
70 int PExportAfs();
71
72 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp);
73
74 extern struct cm_initparams cm_initParams;
75
76 static int (*(VpioctlSw[]))() = {
77   PBogus,                       /* 0 */
78   PSetAcl,                      /* 1 */
79   PGetAcl,                      /* 2 */
80   PSetTokens,                   /* 3 */
81   PGetVolumeStatus,             /* 4 */
82   PSetVolumeStatus,             /* 5 */
83   PFlush,                       /* 6 */
84   PBogus,                       /* 7 */
85   PGetTokens,                   /* 8 */
86   PUnlog,                       /* 9 */
87   PCheckServers,                /* 10 */
88   PCheckVolNames,               /* 11 */
89   PCheckAuth,                   /* 12 */
90   PBogus,                       /* 13 -- used to be quick check time */
91   PFindVolume,          /* 14*/
92   PBogus,                       /* 15 -- prefetch is now special-cased; see pioctl code! */
93   PBogus,                       /* 16 -- used to be testing code */
94   PNoop,                        /* 17 -- used to be enable group */
95   PNoop,                        /* 18 -- used to be disable group */
96   PBogus,                       /* 19 -- used to be list group */
97   PViceAccess,          /* 20 */
98   PUnlog,                       /* 21 -- unlog *is* unpag in this system */
99   PGetFID,                      /* 22 -- get file ID */
100   PBogus,                       /* 23 -- used to be waitforever */
101   PSetCacheSize,                /* 24 */
102   PRemoveCallBack,              /* 25 -- flush only the callback */
103   PNewCell,                     /* 26 */
104   PListCells,                   /* 27 */
105   PRemoveMount,         /* 28 -- delete mount point */
106   PNewStatMount,                /* 29 -- new style mount point stat */
107   PGetFileCell,         /* 30 -- get cell name for input file */
108   PGetWSCell,                   /* 31 -- get cell name for workstation */
109   PMariner,                     /* 32 - set/get mariner host */
110   PGetUserCell,         /* 33 -- get cell name for user */
111   PVenusLogging,                /* 34 -- Enable/Disable logging */
112   PGetCellStatus,               /* 35 */
113   PSetCellStatus,               /* 36 */
114   PFlushVolumeData,             /* 37 -- flush all data from a volume */
115   PSetSysName,          /* 38 - Set system name */
116   PExportAfs,                   /* 39 - Export Afs to remote nfs clients */
117   PGetCacheSize,                /* 40 - get cache size and usage */
118   PGetVnodeXStatus,             /* 41 - get vcache's special status */
119   PSetSPrefs33,                 /* 42 - Set CM Server preferences... */
120   PGetSPrefs,                   /* 43 - Get CM Server preferences... */
121   PGag,                         /* 44 - turn off/on all CM messages */
122   PTwiddleRx,                   /* 45 - adjust some RX params       */
123   PSetSPrefs,                   /* 46 - Set CM Server preferences... */
124   PStoreBehind,                 /* 47 - set degree of store behind to be done */
125   PGCPAGs,                      /* 48 - disable automatic pag gc-ing */
126   PGetInitParams,               /* 49 - get initial cm params */
127   PGetCPrefs,                   /* 50 - get client interface addresses */
128   PSetCPrefs,                   /* 51 - set client interface addresses */
129   PFlushMount,                  /* 52 - flush mount symlink data */
130   PRxStatProc,                  /* 53 - control process RX statistics */
131   PRxStatPeer,                  /* 54 - control peer RX statistics */
132   PGetRxkcrypt,                 /* 55 -- Get rxkad encryption flag */
133   PSetRxkcrypt,                 /* 56 -- Set rxkad encryption flag */
134   PNoop,                        /* 57 -- arla: set file prio */
135   PNoop,                        /* 58 -- arla: fallback getfh */
136   PNoop,                        /* 59 -- arla: fallback fhopen */
137   PNoop,                        /* 60 -- arla: controls xfsdebug */
138   PNoop,                        /* 61 -- arla: controls arla debug */
139   PNoop,                        /* 62 -- arla: debug interface */
140   PNoop,                        /* 63 -- arla: print xfs status */
141   PNoop,                        /* 64 -- arla: force cache check */
142   PNoop,                        /* 65 -- arla: break callback */
143   PPrefetchFromTape,            /* 66 -- MR-AFS: prefetch file from tape */
144   PResidencyCmd,                /* 67 -- MR-AFS: generic commnd interface */
145   PNoop,                        /* 68 -- arla: fetch stats */
146 };
147
148 static int (*(CpioctlSw[]))() = {
149   PBogus,                       /* 0 */
150   PNewAlias,                    /* 1 -- create new cell alias */
151   PListAliases,                 /* 2 -- list cell aliases */
152 };
153
154 #define PSetClientContext 99    /*  Special pioctl to setup caller's creds  */
155 int afs_nobody = NFS_NOBODY;
156
157 static void
158 afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst)
159 {
160         dst->in       = (char *)(unsigned long)src->in;
161         dst->out      = (char *)(unsigned long)src->out;
162         dst->in_size  = src->in_size;
163         dst->out_size = src->out_size;
164 }
165
166 /*
167  * If you need to change copyin_afs_ioctl(), you may also need to change
168  * copyin_iparam().
169  */
170
171 static int
172 copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
173 {
174         int code;
175
176 #if defined(AFS_HPUX_64BIT_ENV)
177         struct afs_ioctl32 dst32;
178
179         if (is_32bit(u.u_procp))        /* is_32bit() in proc_iface.h */
180         {
181                 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
182                 if (!code)
183                         afs_ioctl32_to_afs_ioctl(&dst32, dst);
184                 return code;
185         }
186 #endif /* defined(AFS_HPUX_64BIT_ENV) */
187
188 #if defined(AFS_SUN57_64BIT_ENV)
189         struct afs_ioctl32 dst32;
190
191         if (get_udatamodel() == DATAMODEL_ILP32) {
192                 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
193                 if (!code)
194                         afs_ioctl32_to_afs_ioctl(&dst32, dst);
195                 return code;
196         }
197 #endif /* defined(AFS_SUN57_64BIT_ENV) */
198
199 #if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)
200         struct afs_ioctl32 dst32;
201
202         if (!ABI_IS_64BIT(get_current_abi()))
203         {
204                 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
205                 if (!code)
206                         afs_ioctl32_to_afs_ioctl(&dst32, dst);
207                 return code;
208         }
209 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
210
211 #if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV)
212         struct afs_ioctl32 dst32;
213
214 #ifdef AFS_SPARC64_LINUX24_ENV
215         if (current->thread.flags & SPARC_FLAG_32BIT)
216 #elif AFS_SPARC64_LINUX20_ENV
217         if (current->tss.flags & SPARC_FLAG_32BIT) 
218 #else
219 #error Not done for this linux type
220 #endif /* AFS_SPARC64_LINUX20_ENV */
221           {
222                 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
223                 if (!code)
224                         afs_ioctl32_to_afs_ioctl(&dst32, dst);
225                 return code;
226         }
227 #endif /* defined(AFS_LINUX_64BIT_KERNEL) */
228
229         AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
230         return code;
231 }
232
233 HandleIoctl(avc, acom, adata)
234      register struct vcache *avc;
235      register afs_int32 acom;
236      struct afs_ioctl *adata; {
237        register afs_int32 code;
238        
239        code = 0;
240        AFS_STATCNT(HandleIoctl);
241        
242        switch(acom & 0xff) {
243        case 1:
244          avc->states |= CSafeStore;
245          avc->asynchrony = 0;
246          break;
247          
248          /* case 2 used to be abort store, but this is no longer provided,
249             since it is impossible to implement under normal Unix.
250             */
251          
252        case 3: {
253          /* return the name of the cell this file is open on */
254          register struct cell *tcell;
255          register afs_int32 i;
256          
257          tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
258          if (tcell) {
259            i = strlen(tcell->cellName) + 1;    /* bytes to copy out */
260
261            if (i > adata->out_size) {
262              /* 0 means we're not interested in the output */
263              if (adata->out_size != 0) code = EFAULT;
264            }
265            else {
266              /* do the copy */
267              AFS_COPYOUT(tcell->cellName, adata->out, i, code);
268            }
269            afs_PutCell(tcell, READ_LOCK);
270          }
271          else code = ENOTTY;
272        }
273          break;
274          
275      case 49: /* VIOC_GETINITPARAMS */
276          if (adata->out_size < sizeof(struct cm_initparams)) {
277              code = EFAULT;
278          }
279          else {
280              AFS_COPYOUT(&cm_initParams, adata->out,
281                          sizeof(struct cm_initparams), code);
282          }
283          break;
284          
285        default:
286
287          code = EINVAL;
288          break;
289        }
290        return code;             /* so far, none implemented */
291      }
292      
293      
294 #ifdef  AFS_AIX_ENV
295 /* For aix we don't temporarily bypass ioctl(2) but rather do our
296  * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
297  * is now called from afs_gn_ioctl.
298  */
299 afs_ioctl(tvc, cmd, arg)
300      struct     vcache *tvc;
301      int        cmd;
302      int        arg;
303 {
304   struct afs_ioctl data;
305   int error = 0;
306   
307   AFS_STATCNT(afs_ioctl);
308   if (((cmd >> 8) & 0xff) == 'V') {
309     /* This is a VICEIOCTL call */
310     AFS_COPYIN(arg, (caddr_t) &data, sizeof(data), error);
311     if (error)
312       return(error);
313     error = HandleIoctl(tvc, cmd, &data);
314     return(error);
315   } else {
316     /* No-op call; just return. */
317     return(ENOTTY);
318   }
319 }
320 #endif /* AFS_AIX_ENV */
321
322 #if defined(AFS_SGI_ENV)
323 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void * arg, int flag, cred_t *cr, rval_t *rvalp
324 #ifdef AFS_SGI65_ENV
325           , struct vopbd *vbds
326 #endif
327           )
328 {
329   struct afs_ioctl data;
330   int error = 0;
331   int locked;
332
333   OSI_VN_CONVERT(tvc);
334   
335   AFS_STATCNT(afs_ioctl);
336   if (((cmd >> 8) & 0xff) == 'V') {
337     /* This is a VICEIOCTL call */
338     error = copyin_afs_ioctl(arg, &data);
339     if (error)
340       return(error);
341     locked = ISAFS_GLOCK();
342     if (!locked)
343         AFS_GLOCK();
344     error = HandleIoctl(tvc, cmd, &data);
345     if (!locked)
346         AFS_GUNLOCK();
347     return(error);
348   } else {
349     /* No-op call; just return. */
350     return(ENOTTY);
351   }
352 }
353 #endif /* AFS_SGI_ENV */
354
355
356 /* unlike most calls here, this one uses u.u_error to return error conditions,
357    since this is really an intercepted chapter 2 call, rather than a vnode
358    interface call.
359    */
360 /* AFS_HPUX102 and up uses VNODE ioctl instead */
361 #ifndef AFS_HPUX102_ENV
362 #if !defined(AFS_SGI_ENV)
363 #ifdef  AFS_AIX32_ENV
364 kioctl(fdes, com, arg, ext)
365      int fdes, com;
366      caddr_t arg, ext;
367 {
368   struct a {
369     int fd, com;
370     caddr_t arg, ext;
371   } u_uap, *uap = &u_uap;
372 #else
373 #ifdef  AFS_SUN5_ENV
374
375 struct afs_ioctl_sys {
376     int fd;
377     int com;
378     int arg;
379 };
380
381 afs_xioctl (uap, rvp) 
382     struct afs_ioctl_sys *uap;
383     rval_t *rvp;
384 {
385 #else
386 #ifdef AFS_OSF_ENV
387 afs_xioctl (p, args, retval)
388         struct proc *p;
389         void *args;
390         long *retval;
391 {
392     struct a {
393         long fd;
394         u_long com;
395         caddr_t arg;
396     } *uap = (struct a *)args;
397 #else /* AFS_OSF_ENV */
398 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
399 struct ioctl_args {
400         int fd;
401         u_long com;
402         caddr_t arg;
403 };
404 afs_xioctl(p, uap, retval) 
405         struct proc *p; 
406         register struct ioctl_args *uap;
407         register_t *retval;
408 {
409 #else
410 #ifdef AFS_LINUX22_ENV
411 struct afs_ioctl_sys {
412     unsigned int com;
413     unsigned long arg;
414 };
415 asmlinkage int afs_xioctl(struct inode *ip, struct file *fp,
416                           unsigned int com, unsigned long arg)
417 {
418     struct afs_ioctl_sys ua, *uap = &ua;
419 #else
420 afs_xioctl () 
421     {
422       register struct a {
423         int fd;
424         int com;
425         caddr_t arg;
426       } *uap = (struct a *)u.u_ap;
427 #endif /* AFS_LINUX22_ENV */
428 #endif /* AFS_DARWIN_ENV || AFS_FBSD_ENV */
429 #endif /* AFS_OSF_ENV */
430 #endif  /* AFS_SUN5_ENV */
431 #endif
432 #ifndef AFS_LINUX22_ENV
433 #if     defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
434       struct file *fd;
435 #else
436       register struct file *fd;
437 #endif
438 #endif
439 #if defined(AFS_FBSD_ENV)
440       register struct filedesc *fdp;
441 #endif
442       register struct vcache *tvc;
443       register int ioctlDone = 0, code = 0;
444       
445       AFS_STATCNT(afs_xioctl);
446 #if defined(AFS_FBSD_ENV)
447         fdp=p->p_fd;
448         if ((u_int)uap->fd >= fdp->fd_nfiles ||
449             (fd = fdp->fd_ofiles[uap->fd]) == NULL)
450                 return EBADF;
451         if ((fd->f_flag & (FREAD | FWRITE)) == 0)
452                 return EBADF;
453 #else
454 #if defined(AFS_DARWIN_ENV)
455         if ((code=fdgetf(p, uap->fd, &fd)))
456            return code;
457 #else
458 #ifdef AFS_LINUX22_ENV
459     ua.com = com;
460     ua.arg = arg;
461 #else
462 #ifdef  AFS_AIX32_ENV
463       uap->fd = fdes;
464       uap->com = com;
465       uap->arg = arg;
466       if (setuerror(getf(uap->fd, &fd))) {
467         return -1;
468     }
469 #else
470 #ifdef  AFS_OSF_ENV
471     fd = NULL;
472     if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
473         return code;
474 #else   /* AFS_OSF_ENV */
475 #ifdef  AFS_SUN5_ENV
476 #if defined(AFS_SUN57_ENV)
477         fd = getf(uap->fd);
478         if (!fd) return(EBADF);
479 #elif defined(AFS_SUN54_ENV)
480       fd = GETF(uap->fd);
481       if (!fd) return(EBADF);
482 #else
483       if (code = getf(uap->fd, &fd)) {
484           return (code);
485       }
486 #endif
487 #else
488       fd = getf(uap->fd);
489       if (!fd) return;
490 #endif
491 #endif
492 #endif
493 #endif
494 #endif
495 #endif
496       /* first determine whether this is any sort of vnode */
497 #ifdef AFS_LINUX22_ENV
498       tvc = VTOAFS(ip);
499       {
500 #else
501 #ifdef  AFS_SUN5_ENV
502       if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
503 #else
504       if (fd->f_type == DTYPE_VNODE) {
505 #endif
506         /* good, this is a vnode; next see if it is an AFS vnode */
507 #if     defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
508         tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
509 #else
510         tvc = VTOAFS((struct vnode*)fd->f_data);        /* valid, given a vnode */
511 #endif
512 #endif /* AFS_LINUX22_ENV */
513         if (tvc && IsAfsVnode(AFSTOV(tvc))) {
514 #ifdef AFS_DEC_ENV
515           tvc = VTOAFS(afs_gntovn((struct gnode *) tvc));
516           if (!tvc) {   /* shouldn't happen with held gnodes */
517             u.u_error = ENOENT;
518             return;
519           }
520 #endif
521           /* This is an AFS vnode */
522           if (((uap->com >> 8) & 0xff) == 'V') {
523             register struct afs_ioctl *datap;
524             AFS_GLOCK();
525             datap = (struct afs_ioctl *) osi_AllocSmallSpace(AFS_SMALLOCSIZ);
526             AFS_COPYIN((char *)uap->arg, (caddr_t) datap, sizeof (struct afs_ioctl), code);
527             if (code) {
528               osi_FreeSmallSpace(datap);
529               AFS_GUNLOCK();
530 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
531               return code;
532 #else 
533 #if     defined(AFS_SUN5_ENV)
534 #ifdef  AFS_SUN54_ENV
535               releasef(uap->fd);
536 #else
537               releasef(fd);
538 #endif
539               return (EFAULT);
540 #else
541 #ifdef  AFS_OSF_ENV
542 #ifdef  AFS_OSF30_ENV
543               FP_UNREF_ALWAYS(fd);
544 #else
545               FP_UNREF(fd);
546 #endif
547               return code;
548 #else   /* AFS_OSF_ENV */
549 #ifdef  AFS_AIX41_ENV
550               ufdrele(uap->fd);
551 #endif
552 #ifdef AFS_LINUX22_ENV
553               return -code;
554 #else
555               setuerror(code);
556               return;
557 #endif
558 #endif
559 #endif
560 #endif
561             }
562             code = HandleIoctl(tvc, uap->com, datap);
563             osi_FreeSmallSpace(datap);
564             AFS_GUNLOCK();
565             ioctlDone = 1;
566 #ifdef  AFS_AIX41_ENV
567             ufdrele(uap->fd);
568 #endif
569 #ifdef  AFS_OSF_ENV
570 #ifdef  AFS_OSF30_ENV
571               FP_UNREF_ALWAYS(fd);
572 #else
573               FP_UNREF(fd);
574 #endif
575 #endif
576           }
577 #if defined(AFS_LINUX22_ENV)
578           else 
579             code = EINVAL;
580 #endif
581         }
582       }
583
584       if (!ioctlDone) {
585 #ifdef  AFS_AIX41_ENV
586           ufdrele(uap->fd);
587           code = okioctl(fdes, com, arg, ext);
588           return code;
589 #else
590 #ifdef  AFS_AIX32_ENV
591           okioctl(fdes, com, arg, ext);
592 #else
593 #if     defined(AFS_SUN5_ENV)
594 #if defined(AFS_SUN57_ENV)
595         releasef(uap->fd);
596 #elif defined(AFS_SUN54_ENV)
597           RELEASEF(uap->fd);
598 #else
599           releasef(fd);
600 #endif
601           code = ioctl(uap, rvp);
602 #else
603 #if defined(AFS_FBSD_ENV)
604         return ioctl(p, uap);
605 #else
606 #if defined(AFS_DARWIN_ENV) 
607         return ioctl(p, uap, retval);
608 #else
609 #ifdef  AFS_OSF_ENV
610           code = ioctl(p, args, retval);
611 #ifdef  AFS_OSF30_ENV
612           FP_UNREF_ALWAYS(fd);
613 #else
614           FP_UNREF(fd);
615 #endif
616           return code;
617 #else   /* AFS_OSF_ENV */
618 #ifndef AFS_LINUX22_ENV
619           ioctl();
620 #endif
621 #endif
622 #endif
623 #endif
624 #endif
625 #endif
626 #endif
627       }
628 #ifdef  AFS_SUN5_ENV
629       if (ioctlDone)
630 #ifdef  AFS_SUN54_ENV
631           releasef(uap->fd);
632 #else
633           releasef(fd);
634 #endif
635       return (code);
636 #else
637 #ifdef AFS_LINUX22_ENV
638       return -code;
639 #else
640 #if    !defined(AFS_OSF_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
641       if (!getuerror())
642           setuerror(code);
643 #if     defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
644       return (getuerror() ? -1 : u.u_ioctlrv);
645 #else
646       return getuerror() ? -1 : 0;
647 #endif
648 #endif
649 #endif /* AFS_LINUX22_ENV */
650 #endif  /* AFS_SUN5_ENV */
651 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
652       return (code);
653 #endif
654     }
655 #endif /* AFS_SGI_ENV */
656 #endif /* AFS_HPUX102_ENV */
657   
658 #if defined(AFS_SGI_ENV)
659   /* "pioctl" system call entry point; just pass argument to the parameterized
660                  call below */
661 struct pioctlargs {
662         char            *path;
663         sysarg_t        cmd;
664         caddr_t         cmarg;
665         sysarg_t        follow;
666 };
667 int
668 afs_pioctl(struct pioctlargs *uap, rval_t *rvp)
669 {
670     int code;
671
672     AFS_STATCNT(afs_pioctl);
673     AFS_GLOCK();
674     code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
675     AFS_GUNLOCK();
676 #ifdef AFS_SGI64_ENV
677     return code;
678 #else
679     return u.u_error;
680 #endif
681 }
682 #endif /* AFS_SGI_ENV */
683
684 #ifdef AFS_OSF_ENV
685 afs_pioctl(p, args, retval)
686         struct proc *p;
687         void *args;
688         int *retval;
689 {
690     struct a {
691         char    *path;
692         int     cmd;
693         caddr_t cmarg;
694         int     follow;
695     } *uap = (struct a *) args;
696
697     AFS_STATCNT(afs_pioctl);
698     return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
699 }
700
701 extern struct mount *afs_globalVFS;
702 #else   /* AFS_OSF_ENV */
703 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
704 afs_pioctl(p, args, retval)
705         struct proc *p;
706         void *args;
707         int *retval;
708 {
709     struct a {
710         char    *path;
711         int     cmd;
712         caddr_t cmarg;
713         int     follow; 
714     } *uap = (struct a *) args;
715     
716     AFS_STATCNT(afs_pioctl);
717     return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow, p->p_cred->pc_ucred));
718 }   
719
720 extern struct mount *afs_globalVFS;
721 #else   /* AFS_OSF_ENV */
722 extern struct vfs *afs_globalVFS;
723 #endif
724 #endif
725
726 /* macro to avoid adding any more #ifdef's to pioctl code. */
727 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
728 #define PIOCTL_FREE_CRED() crfree(credp)
729 #else
730 #define PIOCTL_FREE_CRED()
731 #endif
732
733 #ifdef  AFS_SUN5_ENV
734 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
735     rval_t *rvp;
736     struct AFS_UCRED *credp;
737 #else
738 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
739 afs_syscall_pioctl(path, com, cmarg, follow, credp)
740     struct AFS_UCRED *credp;
741 #else
742 afs_syscall_pioctl(path, com, cmarg, follow)
743 #endif
744 #endif
745     char *path;
746     unsigned int        com;
747     caddr_t cmarg;
748     int follow;
749 {
750     struct afs_ioctl data;
751     struct AFS_UCRED *tmpcred, *foreigncreds = 0;
752     register afs_int32 code = 0;
753     struct vnode *vp;
754 #ifdef AFS_DEC_ENV
755     struct vnode *gp;
756 #endif
757 #ifdef  AFS_AIX41_ENV
758     struct ucred *credp = crref(); /* don't free until done! */
759 #endif
760 #ifdef AFS_LINUX22_ENV
761     cred_t *credp = crref(); /* don't free until done! */
762     struct dentry *dp;
763
764 #endif
765     AFS_STATCNT(afs_syscall_pioctl);
766     if (follow) follow = 1;     /* compat. with old venus */
767     code = copyin_afs_ioctl(cmarg, &data);
768     if (code) {
769         PIOCTL_FREE_CRED();
770 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
771         return (code);
772 #else
773         setuerror(code);
774         return code;
775 #endif
776   }
777     if ((com & 0xff) == PSetClientContext) {
778 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
779         return EINVAL; /* Not handling these yet. */
780 #else
781 #if     defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
782         code = HandleClientContext(&data, &com, &foreigncreds, credp);
783 #else
784 #if     defined(AFS_HPUX101_ENV)
785         code=HandleClientContext(&data, &com, &foreigncreds, p_cred(u.u_procp));
786 #else
787 #ifdef AFS_SGI_ENV
788         code = HandleClientContext(&data, &com, &foreigncreds, OSI_GET_CURRENT_CRED());
789 #else
790         code = HandleClientContext(&data, &com, &foreigncreds, u.u_cred);
791 #endif /* AFS_SGI_ENV */
792 #endif
793 #endif
794 #endif
795       if (code) {
796           if (foreigncreds) {
797               crfree(foreigncreds);
798           }
799           PIOCTL_FREE_CRED();
800 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
801           return (code);
802 #else
803           return (setuerror(code), code);
804 #endif
805       }
806     } 
807 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
808     if (foreigncreds) {
809       /*
810        * We could have done without temporary setting the u.u_cred below
811        * (foreigncreds could be passed as param the pioctl modules)
812        * but calls such as afs_osi_suser() doesn't allow that since it
813        * references u.u_cred directly.  We could, of course, do something
814        * like afs_osi_suser(cred) which, I think, is better since it
815        * generalizes and supports multi cred environments...
816        */
817 #ifdef  AFS_SUN5_ENV
818         tmpcred = credp;
819         credp = foreigncreds;
820 #else
821 #ifdef  AFS_AIX41_ENV
822         tmpcred = crref();      /* XXX */
823         crset(foreigncreds);
824 #else
825 #if     defined(AFS_HPUX101_ENV)
826         tmpcred = p_cred(u.u_procp);
827         set_p_cred(u.u_procp, foreigncreds);
828 #else
829 #ifdef AFS_SGI_ENV
830         tmpcred = OSI_GET_CURRENT_CRED();
831         OSI_SET_CURRENT_CRED(foreigncreds);
832 #else
833         tmpcred = u.u_cred;
834         u.u_cred = foreigncreds;
835 #endif /* AFS_SGI64_ENV */
836 #endif /* AFS_HPUX101_ENV */
837 #endif
838 #endif
839     }
840 #endif
841     if ((com & 0xff) == 15) {
842       /* special case prefetch so entire pathname eval occurs in helper process.
843          otherwise, the pioctl call is essentially useless */
844 #if     defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
845         code =  Prefetch(path, &data, follow,
846                          foreigncreds ? foreigncreds : credp);
847 #else
848 #if     defined(AFS_HPUX101_ENV)
849         code =  Prefetch(path, &data, follow, p_cred(u.u_procp));
850 #else
851 #ifdef AFS_SGI_ENV 
852         code =  Prefetch(path, &data, follow, OSI_GET_CURRENT_CRED());
853 #else
854         code =  Prefetch(path, &data, follow, u.u_cred);
855 #endif /* AFS_SGI64_ENV */
856 #endif /* AFS_HPUX101_ENV */
857 #endif
858 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
859         if (foreigncreds) {
860 #ifdef  AFS_AIX41_ENV
861             crset(tmpcred);     /* restore original credentials */
862 #else
863 #if     defined(AFS_HPUX101_ENV)
864         set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
865 #else
866 #ifndef AFS_SUN5_ENV
867 #ifdef AFS_SGI_ENV
868             OSI_SET_CURRENT_CRED(tmpcred);          /* restore original credentials */
869 #else
870             u.u_cred = tmpcred;     /* restore original credentials */
871 #endif
872 #endif
873 #endif /* AFS_HPUX101_ENV */
874             crfree(foreigncreds);
875 #endif
876         }
877 #endif /* AFS_LINUX22_ENV */
878         PIOCTL_FREE_CRED();
879 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
880         return (code);
881 #else
882         return (setuerror(code), code);
883 #endif
884     }
885     if (path) {
886         AFS_GUNLOCK();
887 #ifdef  AFS_AIX41_ENV
888         code = lookupname(path, USR, follow, NULL, &vp,
889                         foreigncreds ? foreigncreds : credp);
890 #else
891 #ifdef AFS_LINUX22_ENV
892         code = gop_lookupname(path, AFS_UIOUSER, follow,  (struct vnode **) 0, &dp);
893         if (!code)
894             vp = (struct vnode *)dp->d_inode;
895 #else
896         code = gop_lookupname(path, AFS_UIOUSER, follow,  (struct vnode **) 0, &vp);
897 #endif /* AFS_LINUX22_ENV */
898 #endif /* AFS_AIX41_ENV */
899         AFS_GLOCK();
900         if (code) {
901 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
902             if (foreigncreds) {
903 #ifdef  AFS_AIX41_ENV
904                 crset(tmpcred); /* restore original credentials */
905 #else
906 #if     defined(AFS_HPUX101_ENV)
907         set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
908 #else
909 #if     !defined(AFS_SUN5_ENV)
910 #ifdef AFS_SGI_ENV
911                 OSI_SET_CURRENT_CRED(tmpcred);      /* restore original credentials */
912 #else
913                 u.u_cred = tmpcred;         /* restore original credentials */
914 #endif /* AFS_SGI64_ENV */
915 #endif
916 #endif /* AFS_HPUX101_ENV */
917                 crfree(foreigncreds);
918 #endif
919             }
920 #endif /* AFS_LINUX22_ENV */
921             PIOCTL_FREE_CRED();
922 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
923             return (code);
924 #else
925             return(setuerror(code), code);
926 #endif
927         }
928     }
929     else vp = (struct vnode *) 0;
930     
931     /* now make the call if we were passed no file, or were passed an AFS file */
932     if (!vp || IsAfsVnode(vp)) {
933 #ifdef AFS_DEC_ENV
934       /* Ultrix 4.0: can't get vcache entry unless we've got an AFS gnode.
935        * So, we must test in this part of the code.  Also, must arrange to
936        * GRELE the original gnode pointer when we're done, since in Ultrix 4.0,
937        * we hold gnodes, whose references hold our vcache entries.
938        */
939       if (vp) {
940         gp = vp;        /* remember for "put" */
941         vp = (struct vnode *) afs_gntovn(vp);   /* get vcache from gp */
942       }
943       else gp = (struct vnode *) 0;
944 #endif 
945 #ifdef  AFS_SUN5_ENV
946       code = afs_HandlePioctl(vp, com, &data, follow, &credp);
947 #else
948 #ifdef  AFS_AIX41_ENV
949       {
950           struct ucred *cred1, *cred2;
951  
952           if (foreigncreds) {
953               cred1 = cred2 = foreigncreds;
954           } else {
955               cred1 = cred2 = credp;
956           }
957           code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
958           if (cred1 != cred2) { 
959               /* something changed the creds */
960               crset(cred1);
961           }
962       }
963 #else
964 #if     defined(AFS_HPUX101_ENV)
965       {
966           struct ucred *cred = p_cred(u.u_procp);
967           code = afs_HandlePioctl(vp, com, &data, follow, &cred);
968       }
969 #else
970 #ifdef AFS_SGI_ENV
971       {
972       struct cred *credp;
973       credp = OSI_GET_CURRENT_CRED();
974       code = afs_HandlePioctl(vp, com, &data, follow, &credp);
975       }
976 #else
977 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
978       code = afs_HandlePioctl(vp, com, &data, follow, &credp);
979 #else
980       code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
981 #endif
982 #endif /* AFS_SGI_ENV */
983 #endif /* AFS_HPUX101_ENV */
984 #endif /* AFS_AIX41_ENV */
985 #endif /* AFS_SUN5_ENV */
986     } else {
987 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
988         code = EINVAL;  /* not in /afs */
989 #else
990         setuerror(EINVAL);
991 #endif
992 #ifdef AFS_DEC_ENV
993         if (vp) {
994             GRELE(vp);
995             vp = (struct vnode *) 0;
996         }
997 #endif
998     }
999
1000 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
1001     if (foreigncreds) {
1002 #ifdef  AFS_AIX41_ENV
1003         crset(tmpcred);
1004 #else
1005 #if     defined(AFS_HPUX101_ENV)
1006         set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
1007 #else
1008 #ifndef AFS_SUN5_ENV
1009 #ifdef AFS_SGI_ENV
1010         OSI_SET_CURRENT_CRED(tmpcred);      /* restore original credentials */
1011 #else
1012         u.u_cred = tmpcred;         /* restore original credentials */
1013 #endif /* ASF_SGI64_ENV */
1014 #endif
1015 #endif /* AFS_HPUX101_ENV */
1016         crfree(foreigncreds);
1017 #endif
1018     }
1019 #endif /* AFS_LINUX22_ENV */
1020     if (vp) {
1021 #ifdef AFS_LINUX22_ENV
1022         dput(dp);
1023 #else
1024         AFS_RELE(vp);   /* put vnode back */
1025 #endif
1026     }
1027     PIOCTL_FREE_CRED();
1028 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1029     return (code);
1030 #else
1031     if (!getuerror())   
1032         setuerror(code);
1033     return (getuerror());
1034 #endif
1035 }
1036   
1037   
1038 afs_HandlePioctl(avc, acom, ablob, afollow, acred)
1039      struct vcache *avc;
1040      afs_int32 acom;
1041      struct AFS_UCRED **acred;
1042      register struct afs_ioctl *ablob;
1043      int afollow;
1044 {
1045     struct vrequest treq;
1046     register afs_int32 code;
1047     register afs_int32 function, device;
1048     afs_int32 inSize, outSize;
1049     char *inData, *outData;
1050     int (*(*pioctlSw))();
1051     int pioctlSwSize;
1052     struct afs_fakestat_state fakestate;
1053
1054     afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1055                ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1056     AFS_STATCNT(HandlePioctl);
1057     if (code = afs_InitReq(&treq, *acred)) return code;
1058     afs_InitFakeStat(&fakestate);
1059     if (avc) {
1060         code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1061         if (code) {
1062             afs_PutFakeStat(&fakestate);
1063             return code;
1064         }
1065     }
1066     device = (acom & 0xff00) >> 8;
1067     switch (device) {
1068         case 'V':       /* Original pioctl's */
1069                 pioctlSw = VpioctlSw;
1070                 pioctlSwSize = sizeof(VpioctlSw);
1071                 break;
1072         case 'C':       /* Coordinated/common pioctl's */
1073                 pioctlSw = CpioctlSw;
1074                 pioctlSwSize = sizeof(CpioctlSw);
1075                 break;
1076         default:
1077                 afs_PutFakeStat(&fakestate);
1078                 return EINVAL;
1079     }
1080     function = acom & 0xff;
1081     if (function >= (pioctlSwSize / sizeof(char *))) {
1082         afs_PutFakeStat(&fakestate);
1083         return EINVAL;  /* out of range */
1084     }
1085     inSize = ablob->in_size;
1086     if (inSize >= PIGGYSIZE) return E2BIG;
1087     inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1088     if (inSize > 0) {
1089       AFS_COPYIN(ablob->in, inData, inSize, code);
1090     }
1091     else code = 0;
1092     if (code) {
1093         osi_FreeLargeSpace(inData);
1094         afs_PutFakeStat(&fakestate);
1095         return code;
1096     }
1097     outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1098     outSize = 0;
1099     if (function == 3 && device == 'V') /* PSetTokens */
1100         code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
1101     else
1102         code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, *acred);
1103     osi_FreeLargeSpace(inData);
1104     if (code == 0 && ablob->out_size > 0) {
1105       if (outSize > ablob->out_size) outSize = ablob->out_size;
1106       if (outSize >= PIGGYSIZE) code = E2BIG;
1107       else if   (outSize) 
1108         AFS_COPYOUT(outData, ablob->out, outSize, code);
1109     }
1110     osi_FreeLargeSpace(outData);
1111     afs_PutFakeStat(&fakestate);
1112     return afs_CheckCode(code, &treq, 41);
1113   }
1114   
1115 static PGetFID(avc, afun, areq, ain, aout, ainSize, aoutSize)
1116     struct vcache *avc;
1117   int afun;
1118   struct vrequest *areq;
1119   char *ain, *aout;
1120   afs_int32 ainSize;
1121   afs_int32 *aoutSize;  /* set this */ {
1122     register afs_int32 code;
1123     
1124     AFS_STATCNT(PGetFID);
1125     if (!avc) return EINVAL;
1126     memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1127     *aoutSize = sizeof(struct VenusFid);
1128     return 0;
1129   }
1130   
1131 static PSetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1132   struct vcache *avc;
1133   int afun;
1134   struct vrequest *areq;
1135   char *ain, *aout;
1136   afs_int32 ainSize;
1137   afs_int32 *aoutSize;  /* set this */ {
1138     register afs_int32 code;
1139     struct conn *tconn;
1140     struct AFSOpaque acl;
1141     struct AFSVolSync tsync;
1142     struct AFSFetchStatus OutStatus;
1143     XSTATS_DECLS;
1144     
1145     AFS_STATCNT(PSetAcl);
1146     if (!avc)
1147       return EINVAL;
1148     if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1149       return EINVAL;
1150
1151     acl.AFSOpaque_val = ain;
1152     do {
1153       tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1154       if (tconn) {
1155         XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1156         RX_AFS_GUNLOCK();
1157         code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1158                               &acl, &OutStatus, &tsync);
1159         RX_AFS_GLOCK();
1160         XSTATS_END_TIME;
1161       }
1162       else code = -1;
1163     } while
1164         (afs_Analyze(tconn, code, &avc->fid, areq,
1165                      AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, (struct cell *)0));
1166
1167     /* now we've forgotten all of the access info */
1168     ObtainWriteLock(&afs_xcbhash, 455);
1169     avc->callback = 0;
1170     afs_DequeueCallback(avc);
1171     avc->states &= ~(CStatd | CUnique);
1172     ReleaseWriteLock(&afs_xcbhash);
1173     if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1174         osi_dnlc_purgedp(avc);
1175     return code;
1176   }
1177
1178 int afs_defaultAsynchrony = 0;
1179
1180 static PStoreBehind(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1181      struct vcache *avc;
1182      int afun;
1183      struct vrequest *areq;
1184      char *ain, *aout;
1185      afs_int32 ainSize;
1186      afs_int32 *aoutSize;       /* set this */
1187      struct AFS_UCRED *acred;
1188 {
1189   afs_int32 code = 0;
1190   struct sbstruct *sbr;
1191
1192   sbr = (struct sbstruct *)ain;
1193   if (sbr->sb_default != -1) {
1194     if (afs_osi_suser(acred))
1195       afs_defaultAsynchrony = sbr->sb_default;
1196     else code = EPERM;
1197   }
1198
1199   if (avc && (sbr->sb_thisfile != -1)) {
1200     if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER, 
1201                       areq, DONT_CHECK_MODE_BITS))
1202       avc->asynchrony = sbr->sb_thisfile;
1203     else code = EACCES;
1204   }
1205
1206   *aoutSize = sizeof(struct sbstruct);
1207   sbr = (struct sbstruct *)aout;
1208   sbr->sb_default = afs_defaultAsynchrony;
1209   if (avc) {
1210     sbr->sb_thisfile = avc->asynchrony;
1211   }
1212
1213   return code;
1214 }
1215
1216 static PGCPAGs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1217      struct vcache *avc;
1218      int afun;
1219      struct vrequest *areq;
1220      char *ain, *aout;
1221      afs_int32 ainSize;
1222      afs_int32 *aoutSize;       /* set this */
1223      struct AFS_UCRED *acred;
1224 {
1225   if (!afs_osi_suser(acred)) {
1226     return EACCES;
1227   }
1228   afs_gcpags = AFS_GCPAGS_USERDISABLED;
1229   return 0;
1230 }
1231   
1232   static PGetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1233     struct vcache *avc;
1234   int afun;
1235   struct vrequest *areq;
1236   char *ain, *aout;
1237   afs_int32 ainSize;
1238   afs_int32 *aoutSize;  /* set this */ {
1239     struct AFSOpaque acl;
1240     struct AFSVolSync tsync;
1241     struct AFSFetchStatus OutStatus;
1242     afs_int32 code;
1243     struct conn *tconn;
1244     struct AFSFid Fid;
1245     XSTATS_DECLS;
1246
1247     AFS_STATCNT(PGetAcl);
1248     if (!avc) return EINVAL;
1249     Fid.Volume = avc->fid.Fid.Volume;
1250     Fid.Vnode = avc->fid.Fid.Vnode;
1251     Fid.Unique = avc->fid.Fid.Unique;
1252     if (avc->states & CForeign) {
1253         /*
1254          * For a dfs xlator acl we have a special hack so that the
1255          * xlator will distinguish which type of acl will return. So
1256          * we currently use the top 2-bytes (vals 0-4) to tell which
1257          * type of acl to bring back. Horrible hack but this will
1258          * cause the least number of changes to code size and interfaces.
1259          */
1260         if (Fid.Vnode & 0xc0000000)
1261             return ERANGE;
1262         Fid.Vnode |= (ainSize << 30);
1263     }
1264     acl.AFSOpaque_val = aout;
1265     do {
1266       tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1267       if (tconn) {
1268         *aout = 0;
1269         XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1270         RX_AFS_GUNLOCK();
1271         code = RXAFS_FetchACL(tconn->id, &Fid,
1272                               &acl, &OutStatus, &tsync);
1273         RX_AFS_GLOCK();
1274         XSTATS_END_TIME;
1275       }
1276       else code = -1;
1277     } while
1278         (afs_Analyze(tconn, code, &avc->fid, areq,
1279                      AFS_STATS_FS_RPCIDX_FETCHACL,
1280                      SHARED_LOCK, (struct cell *)0));
1281
1282     if (code == 0) {
1283       *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1284     }
1285     return code;
1286   }
1287   
1288   static PNoop() {
1289     AFS_STATCNT(PNoop);
1290     return 0;
1291   }
1292   
1293   static PBogus() {
1294     AFS_STATCNT(PBogus);
1295     return EINVAL;
1296   }
1297   
1298   static PGetFileCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1299     struct vcache *avc;
1300   int afun;
1301   struct vrequest *areq;
1302   register char *ain;
1303   char *aout;
1304   afs_int32 ainSize;
1305   afs_int32 *aoutSize;  /* set this */ {
1306     register struct cell *tcell;
1307     
1308     AFS_STATCNT(PGetFileCell);
1309     if (!avc) return EINVAL;
1310     tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1311     if (!tcell) return ESRCH;
1312     strcpy(aout, tcell->cellName);
1313     afs_PutCell(tcell, READ_LOCK);
1314     *aoutSize = strlen(aout) + 1;
1315     return 0;
1316   }
1317   
1318   static PGetWSCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1319     struct vcache *avc;
1320   int afun;
1321   struct vrequest *areq;
1322   register char *ain;
1323   char *aout;
1324   afs_int32 ainSize;
1325   afs_int32 *aoutSize;  /* set this */ {
1326     register struct cell *tcell=0, *cellOne=0;
1327     register struct afs_q *cq, *tq;
1328     
1329     AFS_STATCNT(PGetWSCell);
1330     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1331         return EIO;          /* Inappropriate ioctl for device */
1332
1333     ObtainReadLock(&afs_xcell);
1334     cellOne = (struct cell *) 0;
1335
1336     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
1337         tcell = QTOC(cq); tq = QNext(cq);
1338         if (tcell->states & CPrimary) break;
1339         if (tcell->cell == 1) cellOne = tcell;
1340         tcell = 0;
1341     }
1342     ReleaseReadLock(&afs_xcell);
1343     if (!tcell) {           /* no primary cell, use cell #1 */
1344       if (!cellOne) return ESRCH;
1345       tcell = cellOne;
1346     }
1347     strcpy(aout, tcell->cellName);
1348     *aoutSize = strlen(aout) + 1;
1349     return 0;
1350   }
1351   
1352   static PGetUserCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1353     struct vcache *avc;
1354   int afun;
1355   struct vrequest *areq;
1356   register char *ain;
1357   char *aout;
1358   afs_int32 ainSize;
1359   afs_int32 *aoutSize;  /* set this */ {
1360     register afs_int32 i;
1361     register struct unixuser *tu;
1362     register struct cell *tcell;
1363     
1364     AFS_STATCNT(PGetUserCell);
1365     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1366         return EIO;          /* Inappropriate ioctl for device */
1367
1368     /* return the cell name of the primary cell for this user */
1369     i = UHash(areq->uid);
1370     ObtainWriteLock(&afs_xuser,224);
1371     for(tu = afs_users[i]; tu; tu = tu->next) {
1372       if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1373         tu->refCount++;
1374         ReleaseWriteLock(&afs_xuser);
1375         break;
1376       }
1377     }
1378     if (tu) {
1379       tcell = afs_GetCell(tu->cell, READ_LOCK);
1380       afs_PutUser(tu, WRITE_LOCK);
1381       if (!tcell) return ESRCH;
1382       else {
1383         strcpy(aout, tcell->cellName);
1384         afs_PutCell(tcell, READ_LOCK);
1385         *aoutSize =     strlen(aout)+1;     /* 1 for the null */
1386       }
1387     }
1388     else {
1389       ReleaseWriteLock(&afs_xuser);
1390       *aout = 0;
1391       *aoutSize = 1;
1392     }
1393     return 0;
1394   }
1395   
1396   static PSetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1397     struct vcache *avc;
1398   int afun;
1399   struct vrequest *areq;
1400   register char *ain;
1401   char *aout;
1402   afs_int32 ainSize;
1403   afs_int32 *aoutSize;  /* set this */ 
1404   struct AFS_UCRED **acred;
1405 {
1406     afs_int32 i;
1407     register struct unixuser *tu;
1408     struct ClearToken clear;
1409     register struct cell *tcell;
1410     char *stp;
1411     int stLen;
1412     struct vrequest treq;
1413     afs_int32 flag, set_parent_pag = 0;
1414     
1415     AFS_STATCNT(PSetTokens);
1416     if (!afs_resourceinit_flag) {
1417       return EIO;
1418     }
1419     memcpy((char *)&i, ain, sizeof(afs_int32));
1420     ain += sizeof(afs_int32);
1421     stp = ain;  /* remember where the ticket is */
1422     if (i < 0 || i > 2000) return EINVAL;       /* malloc may fail */
1423     stLen = i;
1424     ain += i;   /* skip over ticket */
1425     memcpy((char *)&i, ain, sizeof(afs_int32));
1426     ain += sizeof(afs_int32);
1427     if (i != sizeof(struct ClearToken)) {
1428       return EINVAL;
1429     }
1430     memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1431     if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1432     ain += sizeof(struct ClearToken);
1433     if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1434       /* still stuff left?  we've got primary flag and cell name.  Set these */
1435       memcpy((char *)&flag, ain, sizeof(afs_int32));            /* primary id flag */
1436       ain += sizeof(afs_int32);                 /* skip id field */
1437       /* rest is cell name, look it up */
1438       if (flag & 0x8000) {                      /* XXX Use Constant XXX */
1439           flag &= ~0x8000;
1440           set_parent_pag = 1;
1441       }
1442       tcell = afs_GetCellByName(ain, READ_LOCK);
1443       if (tcell) {
1444         i = tcell->cell;
1445       }
1446       else {
1447         goto nocell;
1448       }
1449     }
1450     else {
1451       /* default to cell 1, primary id */
1452       flag = 1;         /* primary id */
1453       i = 1;            /* cell number */
1454       tcell = afs_GetCell(1, READ_LOCK);
1455       if (!tcell) goto nocell;
1456     }
1457     afs_PutCell(tcell, READ_LOCK);
1458     if (set_parent_pag) {
1459         int pag;
1460 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1461 #if defined(AFS_DARWIN_ENV)
1462         struct proc *p=current_proc(); /* XXX */
1463 #else
1464         struct proc *p=curproc; /* XXX */
1465 #endif
1466         uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1467                 p->p_pid, p->p_comm);
1468         if (!setpag(p, acred, -1, &pag, 1)) {
1469 #else   
1470 #ifdef  AFS_OSF_ENV
1471         if (!setpag(u.u_procp, acred, -1, &pag, 1)) {   /* XXX u.u_procp is a no-op XXX */
1472 #else
1473         if (!setpag(acred, -1, &pag, 1)) {
1474 #endif
1475 #endif
1476             afs_InitReq(&treq, *acred);
1477             areq = &treq;
1478         }
1479     }
1480     /* now we just set the tokens */
1481     tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1482     tu->vid = clear.ViceId;
1483     if (tu->stp != (char *) 0) {
1484       afs_osi_Free(tu->stp, tu->stLen);
1485     }
1486     tu->stp = (char *) afs_osi_Alloc(stLen);
1487     tu->stLen = stLen;
1488     memcpy(tu->stp, stp, stLen);
1489     tu->ct = clear;
1490 #ifndef AFS_NOSTATS
1491     afs_stats_cmfullperf.authent.TicketUpdates++;
1492     afs_ComputePAGStats();
1493 #endif /* AFS_NOSTATS */
1494     tu->states |= UHasTokens;
1495     tu->states &= ~UTokensBad;
1496     afs_SetPrimary(tu, flag);
1497     tu->tokenTime =osi_Time();
1498     afs_ResetUserConns(tu);
1499     afs_PutUser(tu, WRITE_LOCK);
1500
1501     return 0;
1502
1503   nocell:
1504     {
1505     int t1;
1506     t1 = afs_initState;
1507     if (t1 < 101)
1508       return EIO;
1509     else
1510       return ESRCH;
1511   }
1512 }  
1513
1514 static PGetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1515     struct vcache *avc;
1516   int afun;
1517   struct vrequest *areq;
1518   char *ain, *aout;
1519   afs_int32 ainSize;
1520   afs_int32 *aoutSize;  /* set this */ {
1521     char volName[32];
1522     char offLineMsg[256];
1523     char motd[256];
1524     register struct conn *tc;
1525     register afs_int32 code;
1526     struct VolumeStatus volstat;
1527     register char *cp;
1528     char *Name, *OfflineMsg, *MOTD;
1529     XSTATS_DECLS;
1530
1531     AFS_STATCNT(PGetVolumeStatus);
1532     if (!avc) return EINVAL;
1533     Name = volName;
1534     OfflineMsg = offLineMsg;
1535     MOTD = motd;
1536     do {
1537       tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1538       if (tc) {
1539         XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1540         RX_AFS_GUNLOCK();
1541         code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1542                                      &Name, &OfflineMsg, &MOTD);
1543         RX_AFS_GLOCK();
1544         XSTATS_END_TIME;
1545       }
1546       else code = -1;
1547     } while
1548       (afs_Analyze(tc, code, &avc->fid, areq,
1549                    AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1550                    SHARED_LOCK, (struct cell *)0));
1551
1552     if (code) return code;
1553     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1554     cp = aout;
1555     memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1556     cp += sizeof(VolumeStatus);
1557     strcpy(cp, volName);
1558     cp += strlen(volName)+1;
1559     strcpy(cp, offLineMsg);
1560     cp += strlen(offLineMsg)+1;
1561     strcpy(cp, motd);
1562     cp += strlen(motd)+1;
1563     *aoutSize = (cp - aout);
1564     return 0;
1565 }
1566
1567 static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1568     struct vcache *avc;
1569     int afun;
1570     struct vrequest *areq;
1571     char *ain, *aout;
1572     afs_int32 ainSize;
1573     afs_int32 *aoutSize;        /* set this */ {
1574     char volName[32];
1575     char offLineMsg[256];
1576     char motd[256];
1577     register struct conn *tc;
1578     register afs_int32 code;
1579     struct AFSFetchVolumeStatus volstat;
1580     struct AFSStoreVolumeStatus storeStat;
1581     register struct volume *tvp;
1582     register char *cp;
1583     XSTATS_DECLS;
1584
1585     AFS_STATCNT(PSetVolumeStatus);
1586     if (!avc) return EINVAL;
1587
1588     tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);       
1589     if (tvp) {
1590         if (tvp->states & (VRO | VBackup)) {
1591             afs_PutVolume(tvp, READ_LOCK);
1592             return EROFS;
1593         }
1594         afs_PutVolume(tvp, READ_LOCK);
1595     } else
1596         return ENODEV;
1597     /* Copy the junk out, using cp as a roving pointer. */
1598     cp = ain;
1599     memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1600     cp += sizeof(AFSFetchVolumeStatus);
1601     if (strlen(cp) >= sizeof(volName))
1602         return E2BIG;
1603     strcpy(volName, cp);
1604     cp += strlen(volName)+1;
1605     if (strlen(cp) >= sizeof(offLineMsg))
1606         return E2BIG;
1607     strcpy(offLineMsg, cp);
1608     cp +=  strlen(offLineMsg)+1;
1609     if (strlen(cp) >= sizeof(motd))
1610         return E2BIG;
1611     strcpy(motd, cp);
1612     storeStat.Mask = 0;
1613     if (volstat.MinQuota != -1) {
1614         storeStat.MinQuota = volstat.MinQuota;
1615         storeStat.Mask |= AFS_SETMINQUOTA;
1616     }
1617     if (volstat.MaxQuota != -1) {
1618         storeStat.MaxQuota = volstat.MaxQuota;
1619         storeStat.Mask |= AFS_SETMAXQUOTA;
1620     }
1621     do {
1622         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1623         if (tc) {
1624           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1625             RX_AFS_GUNLOCK();
1626             code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1627                                         &storeStat, volName, offLineMsg, motd);
1628             RX_AFS_GLOCK();
1629           XSTATS_END_TIME;
1630         }
1631         else code = -1;
1632     } while
1633       (afs_Analyze(tc, code, &avc->fid, areq,
1634                    AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1635                    SHARED_LOCK, (struct cell *)0));
1636
1637     if (code) return code;
1638     /* we are sending parms back to make compat. with prev system.  should
1639       change interface later to not ask for current status, just set new status */
1640     cp = aout;
1641     memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1642     cp += sizeof(VolumeStatus);
1643     strcpy(cp, volName);
1644     cp += strlen(volName)+1;
1645     strcpy(cp, offLineMsg);
1646     cp += strlen(offLineMsg)+1;
1647     strcpy(cp, motd);
1648     cp += strlen(motd)+1;
1649     *aoutSize = cp - aout;
1650     return 0;
1651 }
1652
1653 static PFlush(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1654     register struct vcache *avc;
1655     int afun;
1656     struct vrequest *areq;
1657     char *ain, *aout;
1658     afs_int32 ainSize;
1659     afs_int32 *aoutSize;        /* set this */ 
1660     struct AFS_UCRED *acred;
1661 {
1662
1663     AFS_STATCNT(PFlush);
1664     if (!avc) return EINVAL;
1665 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1666     afs_BozonLock(&avc->pvnLock, avc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
1667 #endif
1668     ObtainWriteLock(&avc->lock,225);
1669     ObtainWriteLock(&afs_xcbhash, 456);
1670     afs_DequeueCallback(avc);
1671     avc->states &= ~(CStatd | CDirty);  /* next reference will re-stat cache entry */
1672     ReleaseWriteLock(&afs_xcbhash);
1673     /* now find the disk cache entries */
1674     afs_TryToSmush(avc, acred, 1);
1675     osi_dnlc_purgedp(avc);
1676     afs_symhint_inval(avc);
1677     if (avc->linkData && !(avc->states & CCore)) {
1678         afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1679         avc->linkData = (char *) 0;
1680     }
1681     ReleaseWriteLock(&avc->lock);
1682 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1683     afs_BozonUnlock(&avc->pvnLock, avc);
1684 #endif
1685     return 0;
1686 }
1687
1688 static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
1689     struct vcache *avc;
1690     int afun;
1691     struct vrequest *areq;
1692     char *ain, *aout;
1693     afs_int32 ainSize;
1694     afs_int32 *aoutSize;        /* set this */ {
1695     register afs_int32 code;
1696     register struct vcache *tvc;
1697     register struct dcache *tdc;
1698     struct VenusFid tfid;
1699     char *bufp;
1700     struct sysname_info sysState;
1701     afs_size_t offset, len;
1702
1703     AFS_STATCNT(PNewStatMount);
1704     if (!avc) return EINVAL;
1705     code = afs_VerifyVCache(avc, areq);
1706     if (code) return code;
1707     if (vType(avc) != VDIR) {
1708         return ENOTDIR;
1709     }
1710     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1711     if (!tdc) return ENOENT;
1712     Check_AtSys(avc, ain, &sysState, areq);
1713     ObtainReadLock(&tdc->lock);
1714     do {
1715       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1716     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1717     ReleaseReadLock(&tdc->lock);
1718     afs_PutDCache(tdc);     /* we're done with the data */
1719     bufp = sysState.name;
1720     if (code) {
1721         goto out;
1722     }
1723     tfid.Cell = avc->fid.Cell;
1724     tfid.Fid.Volume = avc->fid.Fid.Volume;
1725     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1726         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
1727     } else {
1728         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
1729                             WRITE_LOCK);
1730     }
1731     if (!tvc) {
1732         code = ENOENT;
1733         goto out;
1734     }
1735     if (tvc->mvstat != 1) {
1736         afs_PutVCache(tvc, WRITE_LOCK);
1737         code = EINVAL;
1738         goto out;
1739     }
1740     ObtainWriteLock(&tvc->lock,226);
1741     code = afs_HandleLink(tvc, areq);
1742     if (code == 0) {
1743         if (tvc->linkData) {
1744             if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1745                 code =  EINVAL;
1746             else {
1747                 /* we have the data */
1748                 strcpy(aout, tvc->linkData);
1749                 *aoutSize = strlen(tvc->linkData)+1;
1750             }
1751         } else 
1752             code = EIO;
1753     }
1754     ReleaseWriteLock(&tvc->lock);
1755     afs_PutVCache(tvc, WRITE_LOCK);
1756 out:
1757     if (sysState.allocked) osi_FreeLargeSpace(bufp);
1758     return code;
1759 }
1760
1761 static PGetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize)
1762     struct vcache *avc;
1763     int afun;
1764     struct vrequest *areq;
1765     char *ain, *aout;
1766     afs_int32 ainSize;
1767     afs_int32 *aoutSize;        /* set this */ {
1768     register struct cell *tcell;
1769     register afs_int32 i;
1770     register struct unixuser *tu;
1771     register char *cp;
1772     afs_int32 iterator;
1773     int newStyle;
1774
1775     AFS_STATCNT(PGetTokens);
1776     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1777         return EIO;          /* Inappropriate ioctl for device */
1778
1779     /* weird interface.  If input parameter is present, it is an integer and
1780         we're supposed to return the parm'th tokens for this unix uid.
1781         If not present, we just return tokens for cell 1.
1782         If counter out of bounds, return EDOM.
1783         If no tokens for the particular cell, return ENOTCONN.
1784         Also, if this mysterious parm is present, we return, along with the
1785         tokens, the primary cell indicator (an afs_int32 0) and the cell name
1786         at the end, in that order.
1787     */
1788     if (newStyle = (ainSize > 0)) {
1789         memcpy((char *)&iterator, ain, sizeof(afs_int32));
1790     }
1791     i = UHash(areq->uid);
1792     ObtainReadLock(&afs_xuser);
1793     for(tu = afs_users[i]; tu; tu=tu->next) {
1794         if (newStyle) {
1795             if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1796                 if (iterator-- == 0) break;     /* are we done yet? */
1797             }
1798         }
1799         else {
1800             if (tu->uid == areq->uid && tu->cell == 1) break;
1801         }
1802     }
1803     if (tu) {
1804         /*
1805          * No need to hold a read lock on each user entry 
1806          */
1807         tu->refCount++;
1808     }
1809     ReleaseReadLock(&afs_xuser);
1810
1811     if (!tu) {
1812         return EDOM;
1813     }
1814     if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1815         tu->states |= (UTokensBad | UNeedsReset);
1816         afs_PutUser(tu, READ_LOCK);
1817         return ENOTCONN;
1818     }
1819     /* use iterator for temp */
1820     cp = aout;
1821     iterator = tu->stLen;       /* for compat, we try to return 56 byte tix if they fit */
1822     if (iterator < 56) iterator = 56;   /* # of bytes we're returning */
1823     memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1824     cp += sizeof(afs_int32);
1825     memcpy(cp, tu->stp, tu->stLen);     /* copy out st */
1826     cp += iterator;
1827     iterator = sizeof(struct ClearToken);
1828     memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1829     cp += sizeof(afs_int32);
1830     memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1831     cp += sizeof(struct ClearToken);
1832     if (newStyle) {
1833         /* put out primary id and cell name, too */
1834         iterator = (tu->states & UPrimary ? 1 : 0);
1835         memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1836         cp += sizeof(afs_int32);
1837         tcell = afs_GetCell(tu->cell, READ_LOCK);
1838         if (tcell) {
1839             strcpy(cp, tcell->cellName);
1840             cp += strlen(tcell->cellName)+1;
1841             afs_PutCell(tcell, READ_LOCK);
1842         }
1843         else *cp++ = 0;
1844     }
1845     *aoutSize = cp - aout;
1846     afs_PutUser(tu, READ_LOCK);
1847     return 0;
1848 }
1849
1850 static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
1851     struct vcache *avc;
1852     int afun;
1853     struct vrequest *areq;
1854     char *ain, *aout;
1855     afs_int32 ainSize;
1856     afs_int32 *aoutSize;        /* set this */ {
1857     register afs_int32 i;
1858     register struct unixuser *tu;
1859
1860     AFS_STATCNT(PUnlog);
1861     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1862         return EIO;          /* Inappropriate ioctl for device */
1863
1864     i = UHash(areq->uid);
1865     ObtainWriteLock(&afs_xuser,227);
1866     for(tu=afs_users[i]; tu; tu=tu->next) {
1867         if (tu->uid == areq->uid) {
1868             tu->vid = UNDEFVID;
1869             tu->states &= ~UHasTokens;
1870             /* security is not having to say you're sorry */
1871             memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
1872             tu->refCount++;
1873             ReleaseWriteLock(&afs_xuser);
1874             /* We have to drop the lock over the call to afs_ResetUserConns, since
1875              * it obtains the afs_xvcache lock.  We could also keep the lock, and
1876              * modify ResetUserConns to take parm saying we obtained the lock
1877              * already, but that is overkill.  By keeping the "tu" pointer
1878              * held over the released lock, we guarantee that we won't lose our
1879              * place, and that we'll pass over every user conn that existed when
1880              * we began this call.
1881              */
1882             afs_ResetUserConns(tu);
1883             tu->refCount--;
1884             ObtainWriteLock(&afs_xuser,228);
1885 #ifdef UKERNEL
1886             /* set the expire times to 0, causes
1887              * afs_GCUserData to remove this entry
1888              */
1889             tu->ct.EndTimestamp = 0;
1890             tu->tokenTime = 0;
1891 #endif  /* UKERNEL */
1892         }
1893     }
1894     ReleaseWriteLock(&afs_xuser);
1895     return 0;
1896 }
1897
1898 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1899     struct vcache *avc;
1900     int afun;
1901     struct vrequest *areq;
1902     char *ain, *aout;
1903     afs_int32 ainSize;
1904     afs_int32 *aoutSize;        /* set this */ {
1905     afs_int32 newHostAddr;
1906     afs_int32 oldHostAddr;
1907     
1908     AFS_STATCNT(PMariner);
1909     if (afs_mariner)
1910         memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost, sizeof(afs_int32));
1911     else
1912         oldHostAddr = 0xffffffff;   /* disabled */
1913     
1914     memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
1915     if (newHostAddr == 0xffffffff) {
1916         /* disable mariner operations */
1917         afs_mariner = 0;
1918     }
1919     else if (newHostAddr) {
1920         afs_mariner = 1;
1921         afs_marinerHost = newHostAddr;
1922     }
1923     memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
1924     *aoutSize = sizeof(afs_int32);
1925     return 0;
1926 }
1927
1928 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1929     struct vcache *avc;
1930     int afun;
1931     struct vrequest *areq;
1932     char *ain, *aout;
1933     afs_int32 ainSize;
1934     afs_int32 *aoutSize;        /* set this */ 
1935     struct AFS_UCRED *acred;
1936 {
1937     register char *cp = 0;
1938     register int i;
1939     register struct server *ts;
1940     afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1941     struct cell *cellp;
1942     struct chservinfo *pcheck;
1943
1944     AFS_STATCNT(PCheckServers);
1945
1946     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1947         return EIO;          /* Inappropriate ioctl for device */
1948
1949     if (*lp == 0x12345678) {    /* For afs3.3 version */
1950         pcheck=(struct chservinfo *)ain;
1951         if (pcheck->tinterval >= 0) {
1952             cp = aout;      
1953             memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
1954             *aoutSize = sizeof(afs_int32);
1955             if (pcheck->tinterval > 0) {
1956                 if (!afs_osi_suser(acred))
1957                     return EACCES;
1958                 PROBE_INTERVAL=pcheck->tinterval;
1959             }
1960             return 0;
1961         }
1962         if (pcheck->tsize)
1963             havecell = 1;
1964         temp=pcheck->tflags;
1965         cp = pcheck->tbuffer;
1966     } else {    /* For pre afs3.3 versions */
1967         memcpy((char *)&temp, ain, sizeof(afs_int32));
1968         cp = ain+sizeof(afs_int32);
1969         if (ainSize > sizeof(afs_int32)) 
1970             havecell = 1;
1971     }
1972
1973     /* 
1974      * 1: fast check, don't contact servers.
1975      * 2: local cell only.
1976      */
1977     if (havecell) {
1978         /* have cell name, too */
1979         cellp = afs_GetCellByName(cp, READ_LOCK);
1980         if (!cellp) return ENOENT;
1981     }
1982     else cellp = (struct cell *) 0;
1983     if (!cellp && (temp & 2)) {
1984         /* use local cell */
1985         cellp = afs_GetCell(1, READ_LOCK);
1986     }
1987     if (!(temp & 1)) {  /* if not fast, call server checker routine */
1988         afs_CheckServers(1, cellp);     /* check down servers */
1989         afs_CheckServers(0, cellp);     /* check up servers */
1990     }
1991     /* now return the current down server list */
1992     cp = aout;
1993     ObtainReadLock(&afs_xserver);
1994     for(i=0;i<NSERVERS;i++) {
1995         for(ts = afs_servers[i]; ts; ts=ts->next) {
1996             if (cellp && ts->cell != cellp) continue;   /* cell spec'd and wrong */
1997             if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1998                 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
1999                 cp += sizeof(afs_int32);
2000             }
2001         }
2002     }
2003     ReleaseReadLock(&afs_xserver);
2004     if (cellp) afs_PutCell(cellp, READ_LOCK);
2005     *aoutSize = cp - aout;
2006     return 0;
2007 }
2008
2009 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
2010     struct vcache *avc;
2011     int afun;
2012     struct vrequest *areq;
2013     char *ain, *aout;
2014     afs_int32 ainSize;
2015     afs_int32 *aoutSize;        /* set this */ {
2016     AFS_STATCNT(PCheckVolNames);
2017     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2018         return EIO;          /* Inappropriate ioctl for device */
2019
2020     afs_CheckRootVolume();
2021     afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
2022                          AFS_VOLCHECK_EXPIRED |
2023                          AFS_VOLCHECK_BUSY |
2024                          AFS_VOLCHECK_MTPTS);
2025     return 0;
2026 }
2027
2028 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
2029     struct vcache *avc;
2030     int afun;
2031     struct vrequest *areq;
2032     char *ain, *aout;
2033     afs_int32 ainSize;
2034     afs_int32 *aoutSize;        /* set this */ {
2035        int i;
2036        struct srvAddr *sa;
2037        struct conn *tc;
2038        struct unixuser *tu;
2039        afs_int32 retValue;
2040        extern afs_rwlock_t afs_xsrvAddr;        
2041
2042     AFS_STATCNT(PCheckAuth);
2043     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2044         return EIO;          /* Inappropriate ioctl for device */
2045
2046     retValue = 0;
2047     tu = afs_GetUser(areq->uid, 1, READ_LOCK);  /* check local cell authentication */
2048     if (!tu) retValue = EACCES;
2049     else {
2050         /* we have a user */
2051         ObtainReadLock(&afs_xsrvAddr);  
2052         ObtainReadLock(&afs_xconn);
2053
2054         /* any tokens set? */
2055         if ((tu->states & UHasTokens) == 0) retValue = EACCES;
2056         /* all connections in cell 1 working? */
2057         for(i=0;i<NSERVERS;i++) {
2058             for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
2059                for (tc = sa->conns; tc; tc=tc->next) {
2060                   if (tc->user == tu && (tu->states & UTokensBad))
2061                        retValue = EACCES;
2062                }
2063             }
2064         }
2065         ReleaseReadLock(&afs_xsrvAddr);
2066         ReleaseReadLock(&afs_xconn);
2067         afs_PutUser(tu, READ_LOCK);
2068     }
2069     memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2070     *aoutSize = sizeof(afs_int32);
2071     return 0;
2072 }
2073
2074 static Prefetch(apath, adata, afollow, acred)
2075 char *apath;
2076 struct afs_ioctl *adata;
2077 int afollow;
2078 struct AFS_UCRED *acred; 
2079 {
2080     register char *tp;
2081     register afs_int32 code;
2082 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2083     size_t bufferSize;
2084 #else
2085     u_int bufferSize;
2086 #endif
2087
2088     AFS_STATCNT(Prefetch);
2089     if (!apath) return EINVAL;
2090     tp = osi_AllocLargeSpace(1024);
2091     AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2092     if (code) {
2093         osi_FreeLargeSpace(tp);
2094         return code;
2095     }
2096     if (afs_BBusy()) {  /* do this as late as possible */
2097         osi_FreeLargeSpace(tp);
2098         return EWOULDBLOCK;     /* pretty close */
2099     }
2100     afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred,
2101                (afs_size_t) 0, (afs_size_t) 0, tp);
2102     return 0;
2103 }
2104
2105 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
2106     struct vcache *avc;
2107     int afun;
2108     struct vrequest *areq;
2109     char *ain, *aout;
2110     afs_int32 ainSize;
2111     afs_int32 *aoutSize;        /* set this */ {
2112     register struct volume *tvp;
2113     register struct server *ts;
2114     register afs_int32 i;
2115     register char *cp;
2116     
2117     AFS_STATCNT(PFindVolume);
2118     if (!avc) return EINVAL;
2119     tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2120     if (tvp) {
2121         cp = aout;
2122         for(i=0;i<MAXHOSTS;i++) {
2123             ts = tvp->serverHost[i];
2124             if (!ts) break;
2125             memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2126             cp += sizeof(afs_int32);
2127         }
2128         if (i<MAXHOSTS) {
2129             /* still room for terminating NULL, add it on */
2130             ainSize = 0;        /* reuse vbl */
2131             memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2132             cp += sizeof(afs_int32);
2133         }
2134         *aoutSize = cp - aout;
2135         afs_PutVolume(tvp, READ_LOCK);
2136         return 0;
2137     }
2138     return ENODEV;
2139 }
2140
2141 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
2142     struct vcache *avc;
2143     int afun;
2144     struct vrequest *areq;
2145     char *ain, *aout;
2146     afs_int32 ainSize;
2147     afs_int32 *aoutSize;        /* set this */ {
2148     register afs_int32 code;
2149     afs_int32 temp;
2150     
2151     AFS_STATCNT(PViceAccess);
2152     if (!avc) return EINVAL;
2153     code = afs_VerifyVCache(avc, areq);
2154     if (code) return code;
2155     memcpy((char *)&temp, ain, sizeof(afs_int32));
2156     code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2157     if (code) return 0;
2158     else return EACCES;
2159 }
2160
2161 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2162     struct vcache *avc;
2163     int afun;
2164     struct vrequest *areq;
2165     char *ain, *aout;
2166     afs_int32 ainSize;
2167     afs_int32 *aoutSize;        /* set this */ 
2168     struct AFS_UCRED *acred;
2169 {
2170     afs_int32 newValue;
2171     int waitcnt = 0;
2172     
2173     AFS_STATCNT(PSetCacheSize);
2174     if (!afs_osi_suser(acred))
2175         return EACCES;
2176     /* too many things are setup initially in mem cache version */
2177     if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2178     memcpy((char *)&newValue, ain, sizeof(afs_int32));
2179     if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2180     else {
2181         extern u_int afs_min_cache;
2182         if (newValue < afs_min_cache)
2183             afs_cacheBlocks = afs_min_cache;
2184         else
2185             afs_cacheBlocks = newValue;
2186     }
2187     afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2188     afs_ComputeCacheParms();    /* recompute basic cache parameters */
2189     afs_MaybeWakeupTruncateDaemon();
2190     while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2191         afs_osi_Wait(1000, 0, 0);
2192         afs_MaybeWakeupTruncateDaemon();
2193     }
2194     return 0;
2195 }
2196
2197 #define MAXGCSTATS      16
2198 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2199 struct vcache *avc;
2200 int afun;
2201 struct vrequest *areq;
2202 char *ain, *aout;
2203 afs_int32 ainSize;
2204 afs_int32 *aoutSize;    /* set this */ {
2205     afs_int32 results[MAXGCSTATS];
2206
2207     AFS_STATCNT(PGetCacheSize);
2208     memset((char *)results, 0, sizeof(results));
2209     results[0] = afs_cacheBlocks;
2210     results[1] = afs_blocksUsed;
2211     memcpy(aout, (char *)results, sizeof(results));
2212     *aoutSize = sizeof(results);
2213     return 0;
2214 }
2215
2216 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2217     struct vcache *avc;
2218     int afun;
2219     struct vrequest *areq;
2220     char *ain, *aout;
2221     afs_int32 ainSize;
2222     afs_int32 *aoutSize;        /* set this */ {
2223     register struct conn *tc;
2224     register afs_int32 code;
2225     struct AFSCallBack CallBacks_Array[1];
2226     struct AFSCBFids theFids;
2227     struct AFSCBs theCBs;
2228     XSTATS_DECLS;
2229
2230     AFS_STATCNT(PRemoveCallBack);
2231     if (!avc) return EINVAL;
2232     if (avc->states & CRO) return 0;    /* read-only-ness can't change */
2233     ObtainWriteLock(&avc->lock,229);
2234     theFids.AFSCBFids_len = 1;
2235     theCBs.AFSCBs_len = 1;
2236     theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2237     theCBs.AFSCBs_val = CallBacks_Array;
2238     CallBacks_Array[0].CallBackType = CB_DROPPED;
2239     if (avc->callback) {
2240         do {
2241             tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2242             if (tc) {
2243               XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2244               RX_AFS_GUNLOCK();
2245               code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2246               RX_AFS_GLOCK();
2247               XSTATS_END_TIME;
2248             }
2249             /* don't set code on failure since we wouldn't use it */
2250         } while
2251           (afs_Analyze(tc, code, &avc->fid, areq,
2252                        AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2253                        SHARED_LOCK, (struct cell *)0));
2254
2255         ObtainWriteLock(&afs_xcbhash, 457);
2256         afs_DequeueCallback(avc);
2257         avc->callback = 0;
2258         avc->states &= ~(CStatd | CUnique);
2259         ReleaseWriteLock(&afs_xcbhash);
2260         if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2261             osi_dnlc_purgedp(avc);
2262     }
2263     ReleaseWriteLock(&avc->lock);
2264     return 0;
2265 }
2266
2267 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2268     struct vcache *avc;
2269     int afun;
2270     struct vrequest *areq;
2271     register char *ain;
2272     char *aout;
2273     afs_int32 ainSize;
2274     struct AFS_UCRED *acred;
2275     afs_int32 *aoutSize;        /* set this */ {
2276     /* create a new cell */
2277     afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2278     register struct cell *tcell;
2279     char *newcell=0, *linkedcell=0, *tp= ain;
2280     register afs_int32 code, linkedstate=0, ls;
2281     u_short fsport = 0, vlport = 0;
2282     afs_int32 scount;
2283     
2284     AFS_STATCNT(PNewCell);
2285     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2286         return EIO;          /* Inappropriate ioctl for device */
2287
2288     if (!afs_osi_suser(acred))
2289         return EACCES;
2290
2291     memcpy((char *)&magic, tp, sizeof(afs_int32));
2292     tp += sizeof(afs_int32);
2293     if (magic != 0x12345678)
2294         return EINVAL;
2295
2296     /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2297      * server addresses while the 3.5 fs newcell command passes
2298      * MAXHOSTS. To figure out which is which, check if the cellname
2299      * is good.
2300      */
2301     newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2302     scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2303
2304     /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2305     memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2306     tp += (scount * sizeof(afs_int32));
2307
2308     lp = (afs_int32 *)tp;
2309     fsport = *lp++;
2310     vlport = *lp++;
2311     if (fsport < 1024) fsport = 0;      /* Privileged ports not allowed */
2312     if (vlport < 1024) vlport = 0;      /* Privileged ports not allowed */
2313     tp += (3 * sizeof(afs_int32));
2314     newcell = tp;
2315     if ((ls = *lp) & 1) {
2316        linkedcell = tp + strlen(newcell)+1;
2317        linkedstate |= CLinkedCell;
2318     }
2319
2320     linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2321     code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0, (char *) 0);
2322     return code;
2323 }
2324
2325 static PNewAlias(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2326     struct vcache *avc;
2327     int afun;
2328     struct vrequest *areq;
2329     register char *ain;
2330     char *aout;
2331     afs_int32 ainSize;
2332     struct AFS_UCRED *acred;
2333     afs_int32 *aoutSize;        /* set this */
2334 {
2335     /* create a new cell alias */
2336     register struct cell *tcell;
2337     char *tp = ain;
2338     register afs_int32 code;
2339     char *realName, *aliasName;
2340     register struct afs_q *cq, *tq;
2341     
2342     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2343         return EIO;          /* Inappropriate ioctl for device */
2344
2345     if (!afs_osi_suser(acred))
2346         return EACCES;
2347
2348     aliasName = tp;
2349     tp += strlen(aliasName) + 1;
2350     realName = tp;
2351
2352     /*
2353      * Prevent user from shooting themselves in the foot -- don't allow
2354      * creation of aliases when a real cell already exists with that name.
2355      */
2356     ObtainReadLock(&afs_xcell);
2357     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2358         tcell = QTOC(cq); tq = QNext(cq);
2359         if ((afs_strcasecmp(tcell->cellName, aliasName) == 0) &&
2360             !(tcell->states & CAlias)) {
2361             ReleaseReadLock(&afs_xcell);
2362             return EEXIST;
2363         }
2364     }
2365     ReleaseReadLock(&afs_xcell);
2366
2367     code = afs_NewCell(aliasName, 0, CAlias, 0, 0, 0, 0, realName);
2368     *aoutSize = 0;
2369     return code;
2370 }
2371
2372 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2373     struct vcache *avc;
2374     int afun;
2375     struct vrequest *areq;
2376     char *ain, *aout;
2377     afs_int32 ainSize;
2378     afs_int32 *aoutSize;        /* set this */ {
2379     afs_int32 whichCell;
2380     register struct cell *tcell=0;
2381     register afs_int32 i;
2382     register char *cp, *tp = ain;
2383     register struct afs_q *cq, *tq;
2384
2385     AFS_STATCNT(PListCells);
2386     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2387         return EIO;          /* Inappropriate ioctl for device */
2388
2389     memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2390     tp += sizeof(afs_int32);
2391     ObtainReadLock(&afs_xcell);
2392     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2393         tcell = QTOC(cq); tq = QNext(cq);
2394         if (tcell->states & CAlias) {
2395             tcell = 0;
2396             continue;
2397         }
2398         if (whichCell == 0) break;
2399         tcell = 0;
2400         whichCell--;
2401     }
2402     if (tcell) {
2403         cp = aout;
2404         memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2405         for(i=0;i<MAXCELLHOSTS;i++) {
2406             if (tcell->cellHosts[i] == 0) break;
2407             memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip, sizeof(afs_int32));
2408             cp += sizeof(afs_int32);
2409         }
2410         cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2411         strcpy(cp, tcell->cellName);
2412         cp += strlen(tcell->cellName)+1;
2413         *aoutSize = cp - aout;
2414     }
2415     ReleaseReadLock(&afs_xcell);
2416     if (tcell) return 0;
2417     else return EDOM;
2418 }
2419
2420 static PListAliases(avc, afun, areq, ain, aout, ainSize, aoutSize)
2421     struct vcache *avc;
2422     int afun;
2423     struct vrequest *areq;
2424     char *ain, *aout;
2425     afs_int32 ainSize;
2426     afs_int32 *aoutSize;        /* set this */
2427 {
2428     afs_int32 whichAlias;
2429     register struct cell *tcell=0;
2430     register char *cp, *tp = ain;
2431     register struct afs_q *cq, *tq;
2432
2433     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2434         return EIO;          /* Inappropriate ioctl for device */
2435     if (ainSize < sizeof(afs_int32))
2436         return EINVAL;
2437
2438     memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2439     tp += sizeof(afs_int32);
2440
2441     ObtainReadLock(&afs_xcell);
2442     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2443         tcell = QTOC(cq); tq = QNext(cq);
2444         if (!(tcell->states & CAlias)) {
2445             tcell = 0;
2446             continue;
2447         }
2448         if (whichAlias == 0) break;
2449         tcell = 0;
2450         whichAlias--;
2451     }
2452     if (tcell) {        
2453         cp = aout;
2454         strcpy(cp, tcell->cellName);
2455         cp += strlen(tcell->cellName)+1;
2456         strcpy(cp, tcell->realName);
2457         cp += strlen(tcell->realName)+1;
2458         *aoutSize = cp - aout;
2459     }
2460     ReleaseReadLock(&afs_xcell);
2461     if (tcell) return 0;
2462     else return EDOM;
2463 }
2464
2465 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2466     struct vcache *avc;
2467     int afun;
2468     struct vrequest *areq;
2469     register char *ain;
2470     char *aout;
2471     afs_int32 ainSize;
2472     afs_int32 *aoutSize;        /* set this */ {
2473     register afs_int32 code;
2474     char *bufp;
2475     struct sysname_info sysState;
2476     afs_size_t offset, len;
2477     register struct conn *tc;
2478     register struct dcache *tdc;
2479     register struct vcache *tvc;
2480     struct AFSFetchStatus OutDirStatus;
2481     struct VenusFid tfid;
2482     struct AFSVolSync tsync;
2483     XSTATS_DECLS;
2484
2485
2486     /* "ain" is the name of the file in this dir to remove */
2487
2488     AFS_STATCNT(PRemoveMount);
2489     if (!avc) return EINVAL;
2490     code = afs_VerifyVCache(avc, areq);
2491     if (code) return code;
2492     if (vType(avc) != VDIR) return ENOTDIR;
2493
2494     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);   /* test for error below */
2495     if (!tdc) return ENOENT;
2496     Check_AtSys(avc, ain, &sysState, areq);
2497     ObtainReadLock(&tdc->lock);
2498     do {
2499       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2500     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2501     ReleaseReadLock(&tdc->lock);
2502     bufp = sysState.name;
2503     if (code) {
2504         afs_PutDCache(tdc);
2505         goto out;
2506     }
2507     tfid.Cell = avc->fid.Cell;
2508     tfid.Fid.Volume = avc->fid.Fid.Volume;
2509     if (!tfid.Fid.Unique &&  (avc->states & CForeign)) {
2510         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2511     } else {
2512         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2513                             (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2514     }
2515     if (!tvc) {
2516         code = ENOENT;
2517         afs_PutDCache(tdc);
2518         goto out;
2519     }
2520     if (tvc->mvstat != 1) {
2521         afs_PutDCache(tdc);
2522         afs_PutVCache(tvc, WRITE_LOCK);
2523         code = EINVAL;
2524         goto out;
2525     }
2526     ObtainWriteLock(&tvc->lock,230);
2527     code = afs_HandleLink(tvc, areq);
2528     if (!code) {
2529         if (tvc->linkData) {
2530             if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2531                 code =  EINVAL;
2532         } else 
2533             code = EIO;
2534     }
2535     ReleaseWriteLock(&tvc->lock);
2536     osi_dnlc_purgedp(tvc);
2537     afs_PutVCache(tvc, WRITE_LOCK);
2538     if (code) {
2539         afs_PutDCache(tdc);
2540         goto out;
2541     }
2542     ObtainWriteLock(&avc->lock,231);
2543     osi_dnlc_remove(avc, bufp, tvc);
2544     do {
2545         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2546         if (tc) {
2547           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2548           RX_AFS_GUNLOCK();
2549           code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2550                                   bufp, &OutDirStatus, &tsync);
2551           RX_AFS_GLOCK();
2552           XSTATS_END_TIME;
2553         }
2554         else code = -1;
2555     } while
2556         (afs_Analyze(tc, code, &avc->fid, areq,
2557                      AFS_STATS_FS_RPCIDX_REMOVEFILE,
2558                      SHARED_LOCK, (struct cell *)0));
2559
2560     if (code) {
2561         if (tdc) afs_PutDCache(tdc);
2562         ReleaseWriteLock(&avc->lock);
2563         goto out;
2564     }
2565     if (tdc) {
2566         /* we have the thing in the cache */
2567         ObtainWriteLock(&tdc->lock, 661);
2568         if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2569             /* we can do it locally */
2570             code = afs_dir_Delete(&tdc->f.inode, bufp);
2571             if (code) {
2572                 ZapDCE(tdc);    /* surprise error -- invalid value */
2573                 DZap(&tdc->f.inode);
2574             }
2575         }
2576         ReleaseWriteLock(&tdc->lock);
2577         afs_PutDCache(tdc);     /* drop ref count */
2578     }
2579     avc->states &= ~CUnique;            /* For the dfs xlator */
2580     ReleaseWriteLock(&avc->lock);
2581     code = 0;
2582 out:
2583     if (sysState.allocked) osi_FreeLargeSpace(bufp);
2584     return code;    
2585 }
2586
2587 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2588     struct vcache *avc;
2589     int afun;
2590     struct vrequest *areq;
2591     register char *ain;
2592     char *aout;
2593     afs_int32 ainSize;
2594     struct AFS_UCRED *acred;
2595     afs_int32 *aoutSize;        /* set this */ {
2596     return EINVAL;              /* OBSOLETE */
2597 }
2598
2599 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2600     struct vcache *avc;
2601     int afun;
2602     struct vrequest *areq;
2603     char *ain, *aout;
2604     afs_int32 ainSize;
2605     afs_int32 *aoutSize;        /* set this */ {
2606     register struct cell *tcell;
2607     afs_int32 temp;
2608
2609     AFS_STATCNT(PGetCellStatus);
2610     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2611         return EIO;          /* Inappropriate ioctl for device */
2612
2613     tcell = afs_GetCellByName(ain, READ_LOCK);
2614     if (!tcell) return ENOENT;
2615     temp = tcell->states;
2616     afs_PutCell(tcell, READ_LOCK);
2617     memcpy(aout, (char *)&temp, sizeof(afs_int32));
2618     *aoutSize = sizeof(afs_int32);
2619     return 0;
2620 }
2621
2622 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2623     struct vcache *avc;
2624     int afun;
2625     struct vrequest *areq;
2626     char *ain, *aout;
2627     afs_int32 ainSize;
2628     struct AFS_UCRED *acred;
2629     afs_int32 *aoutSize;        /* set this */ {
2630     register struct cell *tcell;
2631     afs_int32 temp;
2632     
2633     if (!afs_osi_suser(acred))
2634         return EACCES;
2635     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2636         return EIO;          /* Inappropriate ioctl for device */
2637
2638     tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2639     if (!tcell) return ENOENT;
2640     memcpy((char *)&temp, ain, sizeof(afs_int32));
2641     if (temp & CNoSUID)
2642         tcell->states |= CNoSUID;
2643     else
2644         tcell->states &= ~CNoSUID;
2645     afs_PutCell(tcell, WRITE_LOCK);
2646     return 0;
2647 }
2648
2649 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2650 struct vcache *avc;
2651 int afun;
2652 struct vrequest *areq;
2653 char *ain, *aout;
2654 afs_int32 ainSize;
2655 afs_int32 *aoutSize;    /* set this */ 
2656 struct AFS_UCRED *acred;
2657 {
2658     extern struct volume *afs_volumes[NVOLS];
2659     register afs_int32 i;
2660     register struct dcache *tdc;
2661     register struct vcache *tvc;
2662     register struct volume *tv;
2663     afs_int32 cell, volume;
2664
2665     AFS_STATCNT(PFlushVolumeData);
2666     if (!avc)
2667         return EINVAL;
2668     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2669         return EIO;          /* Inappropriate ioctl for device */
2670
2671     volume = avc->fid.Fid.Volume;  /* who to zap */
2672     cell = avc->fid.Cell;
2673
2674     /* 
2675      * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2676      * the vcaches associated with the volume.
2677      */
2678     ObtainReadLock(&afs_xvcache);
2679     for(i = 0; i < VCSIZE; i++) {
2680         for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2681             if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2682 #if     defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV)  || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2683                 VN_HOLD(AFSTOV(tvc));
2684 #else
2685 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2686                 osi_vnhold(tvc, 0);
2687 #else
2688                 VREFCOUNT_INC(tvc);
2689 #endif
2690 #endif
2691                 ReleaseReadLock(&afs_xvcache);
2692 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2693                 afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
2694 #endif
2695                 ObtainWriteLock(&tvc->lock,232);
2696
2697                 ObtainWriteLock(&afs_xcbhash, 458);
2698                 afs_DequeueCallback(tvc);
2699                 tvc->states &= ~(CStatd | CDirty);
2700                 ReleaseWriteLock(&afs_xcbhash);
2701                 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2702                     osi_dnlc_purgedp(tvc);
2703                 afs_TryToSmush(tvc, acred, 1);
2704                 ReleaseWriteLock(&tvc->lock);
2705 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2706                 afs_BozonUnlock(&tvc->pvnLock, tvc);
2707 #endif
2708                 ObtainReadLock(&afs_xvcache);
2709                 /* our tvc ptr is still good until now */
2710                 AFS_FAST_RELE(tvc);
2711             }
2712         }
2713     }
2714     ReleaseReadLock(&afs_xvcache);
2715
2716
2717     MObtainWriteLock(&afs_xdcache,328);  /* needed if you're going to flush any stuff */
2718     for(i=0;i<afs_cacheFiles;i++) {
2719         if (!(afs_indexFlags[i] & IFEverUsed)) continue;        /* never had any data */
2720         tdc = afs_GetDSlot(i, (struct dcache *) 0);
2721         if (tdc->refCount <= 1) {    /* too high, in use by running sys call */
2722             ReleaseReadLock(&tdc->tlock);
2723             if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2724                 if (! (afs_indexFlags[i] & IFDataMod)) {
2725                     /* if the file is modified, but has a ref cnt of only 1, then
2726                        someone probably has the file open and is writing into it.
2727                        Better to skip flushing such a file, it will be brought back
2728                        immediately on the next write anyway.
2729
2730                        If we *must* flush, then this code has to be rearranged to call
2731                        afs_storeAllSegments() first */
2732                         afs_FlushDCache(tdc);
2733                 }
2734             }
2735         } else {
2736             ReleaseReadLock(&tdc->tlock);
2737         }
2738         afs_PutDCache(tdc);     /* bumped by getdslot */
2739     }
2740     MReleaseWriteLock(&afs_xdcache);
2741
2742     ObtainReadLock(&afs_xvolume);
2743     for (i=0;i<NVOLS;i++) {
2744         for (tv = afs_volumes[i]; tv; tv=tv->next) {
2745             if (tv->volume == volume) {
2746                 afs_ResetVolumeInfo(tv);
2747                 break;
2748             }
2749         }
2750     }
2751     ReleaseReadLock(&afs_xvolume);
2752
2753     /* probably, a user is doing this, probably, because things are screwed up. 
2754      * maybe it's the dnlc's fault? */
2755     osi_dnlc_purge();  
2756     return 0;
2757 }
2758
2759
2760
2761 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2762     struct vcache *avc;
2763     int afun;
2764     struct vrequest *areq;
2765     char *ain, *aout;
2766     afs_int32 ainSize;
2767     afs_int32 *aoutSize;        /* set this */ {
2768     register afs_int32 code;
2769     struct vcxstat stat;
2770     afs_int32 mode, i;
2771     
2772 /*  AFS_STATCNT(PGetVnodeXStatus); */
2773     if (!avc) return EINVAL;
2774     code = afs_VerifyVCache(avc, areq);
2775     if (code) return code;
2776     if (vType(avc) == VDIR)
2777         mode = PRSFS_LOOKUP;
2778     else
2779         mode = PRSFS_READ;
2780     if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2781         return EACCES;    
2782     stat.fid = avc->fid;
2783     hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2784     stat.lock = avc->lock;
2785     stat.parentVnode = avc->parentVnode;
2786     stat.parentUnique = avc->parentUnique;
2787     hset(stat.flushDV, avc->flushDV);
2788     hset(stat.mapDV, avc->mapDV);
2789     stat.truncPos = avc->truncPos;
2790     { /* just grab the first two - won't break anything... */
2791       struct axscache *ac;
2792
2793       for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2794         stat.randomUid[i] = ac->uid;
2795         stat.randomAccess[i] = ac->axess;
2796       }
2797     }
2798     stat.callback = afs_data_pointer_to_int32(avc->callback);
2799     stat.cbExpires = avc->cbExpires;
2800     stat.anyAccess = avc->anyAccess;
2801     stat.opens = avc->opens;
2802     stat.execsOrWriters = avc->execsOrWriters;
2803     stat.flockCount = avc->flockCount;
2804     stat.mvstat = avc->mvstat;
2805     stat.states = avc->states;
2806     memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
2807     *aoutSize = sizeof(struct vcxstat);
2808     return 0;
2809 }
2810
2811
2812 /* We require root for local sysname changes, but not for remote */
2813 /* (since we don't really believe remote uids anyway) */
2814  /* outname[] shouldn't really be needed- this is left as an excercise */
2815  /* for the reader.  */
2816 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2817 struct vcache *avc;
2818 int afun;
2819 struct vrequest *areq;
2820 char *ain, *aout;
2821 afs_int32 ainSize;
2822 afs_int32 *aoutSize;    /* set this */
2823 register struct AFS_UCRED *acred;
2824 {
2825     char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2826     int setsysname, foundname=0;
2827     register struct afs_exporter *exporter;
2828     extern struct unixuser *afs_FindUser();
2829     extern char *afs_sysname;
2830     extern char *afs_sysnamelist[];
2831     extern int afs_sysnamecount;
2832     register struct unixuser *au;
2833     register afs_int32 pag, error;
2834     int t, count;
2835
2836
2837     AFS_STATCNT(PSetSysName);
2838     if (!afs_globalVFS) {
2839       /* Afsd is NOT running; disable it */
2840 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2841         return (EINVAL);
2842 #else
2843         return (setuerror(EINVAL), EINVAL);
2844 #endif
2845     }
2846     memset(inname, 0, MAXSYSNAME);
2847     memcpy((char *)&setsysname, ain, sizeof(afs_int32));
2848     ain += sizeof(afs_int32);
2849     if (setsysname) {
2850
2851       /* Check my args */
2852       if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2853         return EINVAL;
2854       for(cp = ain,count = 0;count < setsysname;count++) {
2855         /* won't go past end of ain since maxsysname*num < ain length */
2856         t = strlen(cp);
2857         if (t >= MAXSYSNAME || t <= 0)
2858           return EINVAL;
2859         /* check for names that can shoot us in the foot */
2860         if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2861           return EINVAL;
2862         cp += t+1;
2863       }
2864       /* args ok */
2865
2866       /* inname gets first entry in case we're being a translater */
2867       t = strlen(ain);
2868       memcpy(inname, ain, t+1);  /* include terminating null */
2869       ain += t + 1;
2870     }
2871     if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2872         pag = PagInCred(acred);
2873         if (pag == NOPAG) {
2874             return EINVAL;  /* Better than panicing */
2875         }
2876         if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2877             return EINVAL;  /* Better than panicing */
2878         }
2879         if (!(exporter = au->exporter)) {
2880             afs_PutUser(au, READ_LOCK);
2881             return EINVAL;  /* Better than panicing */
2882         }
2883         error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2884         if (error) {
2885             if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2886             else {
2887                 afs_PutUser(au, READ_LOCK);
2888                 return error;
2889             }
2890         }
2891         else foundname = 1;
2892         afs_PutUser(au, READ_LOCK);
2893     } else {
2894
2895       /* Not xlating, so local case */
2896         if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2897         if (!setsysname) {      /* user just wants the info */
2898             strcpy(outname, afs_sysname);
2899             foundname = afs_sysnamecount;
2900         } else {     /* Local guy; only root can change sysname */
2901             if (!afs_osi_suser(acred))
2902                 return EACCES;
2903            
2904             /* clear @sys entries from the dnlc, once afs_lookup can
2905              do lookups of @sys entries and thinks it can trust them */
2906             /* privs ok, store the entry, ... */
2907             strcpy(afs_sysname, inname);
2908             if (setsysname > 1) { /* ... or list */
2909               cp = ain;
2910               for(count=1; count < setsysname;++count) {
2911                 if (!afs_sysnamelist[count])
2912                   osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2913                 t = strlen(cp);
2914                 memcpy(afs_sysnamelist[count], cp, t+1); /* include null */
2915                 cp += t+1;
2916               }
2917             }
2918             afs_sysnamecount = setsysname;
2919         }
2920     }
2921     if (!setsysname) {
2922         cp = aout;  /* not changing so report back the count and ... */
2923         memcpy(cp, (char *)&foundname, sizeof(afs_int32));
2924         cp += sizeof(afs_int32);
2925         if (foundname) {
2926             strcpy(cp, outname);                /* ... the entry, ... */
2927             cp += strlen(outname)+1;
2928             for(count=1; count < foundname; ++count) { /* ... or list. */
2929               /* Note: we don't support @sys lists for exporters */
2930               if (!afs_sysnamelist[count])
2931                 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2932               t = strlen(afs_sysnamelist[count]);
2933               if (t >= MAXSYSNAME)
2934                 osi_Panic("PSetSysName: sysname entry garbled\n");
2935               strcpy(cp, afs_sysnamelist[count]);
2936               cp += t + 1;
2937             }
2938         }
2939         *aoutSize = cp - aout;
2940     }
2941     return 0;
2942 }
2943
2944 /* sequential search through the list of touched cells is not a good
2945  * long-term solution here. For small n, though, it should be just
2946  * fine.  Should consider special-casing the local cell for large n.
2947  * Likewise for PSetSPrefs.
2948  */
2949 static void ReSortCells(s,l, vlonly)  
2950   int s;     /* number of ids in array l[] -- NOT index of last id */
2951   afs_int32 l[];  /* array of cell ids which have volumes that need to be sorted */
2952   int vlonly; /* sort vl servers or file servers?*/
2953 {
2954   extern struct volume *afs_volumes[NVOLS];   /* volume hash table */
2955
2956   int i;
2957   struct volume *j;
2958   register int  k;
2959
2960   if (vlonly) {
2961       struct cell *tcell;
2962       ObtainWriteLock(&afs_xcell,300);
2963       for(k=0;k<s;k++) {
2964           tcell = afs_GetCellNoLock(l[k], WRITE_LOCK);
2965           if (!tcell) continue;
2966           afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2967           afs_PutCell(tcell, WRITE_LOCK);
2968       }
2969       ReleaseWriteLock(&afs_xcell);
2970       return;
2971   }
2972
2973   ObtainReadLock(&afs_xvolume);
2974   for (i= 0; i< NVOLS; i++) {
2975       for (j=afs_volumes[i];j;j=j->next) {
2976           for (k=0;k<s;k++)
2977               if (j->cell == l[k]) {
2978                   ObtainWriteLock(&j->lock,233);
2979                   afs_SortServers(j->serverHost, MAXHOSTS);
2980                   ReleaseWriteLock(&j->lock);
2981                   break; 
2982               }
2983       }
2984   }
2985   ReleaseReadLock(&afs_xvolume);
2986 }
2987
2988 int debugsetsp = 0;
2989
2990 static int afs_setsprefs(sp, num, vlonly)
2991    struct spref *sp;
2992    unsigned int num;
2993    unsigned int vlonly;
2994 {
2995    struct srvAddr *sa;
2996    int i,j,k,matches,touchedSize;
2997    struct server *srvr = NULL;
2998    afs_int32 touched[34];
2999    int isfs;
3000    
3001    touchedSize=0;
3002    for (k=0; k < num; sp++, k++) { 
3003       if (debugsetsp) {
3004          printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
3005       }
3006       matches=0;
3007       ObtainReadLock(&afs_xserver);
3008       
3009       i = SHash(sp->host.s_addr);
3010       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3011          if (sa->sa_ip == sp->host.s_addr) {
3012             srvr = sa->server;
3013             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
3014                    || (sa->sa_portal == AFS_FSPORT); 
3015             if ((!vlonly && isfs) || (vlonly && !isfs)) {
3016                matches++;
3017                break;
3018             }
3019          }
3020       }
3021       
3022       if (sa && matches) {  /* found one! */
3023          if (debugsetsp) {
3024             printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
3025          }
3026          sa->sa_iprank = sp->rank + afs_randomMod15();
3027          afs_SortOneServer(sa->server);
3028          
3029          if (srvr->cell) {
3030            /* if we don't know yet what cell it's in, this is moot */
3031            for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
3032                  /* is it in our list of touched cells ?  */ ;
3033            if (j < 0) {                   /* no, it's not */
3034              touched[touchedSize++] = srvr->cell->cell;
3035              if (touchedSize >= 32) {                /* watch for ovrflow */
3036                ReleaseReadLock(&afs_xserver);
3037                ReSortCells(touchedSize, touched, vlonly);
3038                touchedSize=0;
3039                ObtainReadLock(&afs_xserver);
3040              }
3041            }
3042          }
3043       }
3044       
3045       ReleaseReadLock(&afs_xserver);
3046       /* if we didn't find one, start to create one. */
3047       /* Note that it doesn't have a cell yet...     */
3048       if (!matches) {
3049          afs_uint32 temp = sp->host.s_addr;
3050          srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT), 
3051                               WRITE_LOCK, (afsUUID *)0,0);
3052          srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3053          afs_PutServer(srvr, WRITE_LOCK);
3054       }
3055    } /* for all cited preferences */
3056    
3057    ReSortCells(touchedSize, touched, vlonly);
3058    return 0;
3059 }
3060
3061  /* Note that this may only be performed by the local root user.
3062  */
3063 static int 
3064 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3065      struct vcache *avc;
3066      int afun;
3067      struct vrequest *areq;
3068      char *ain, *aout;
3069      afs_int32 ainSize;
3070      struct AFS_UCRED *acred;
3071      afs_int32 *aoutSize;
3072 {
3073   struct setspref *ssp;
3074   AFS_STATCNT(PSetSPrefs);
3075
3076   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
3077         return EIO;          /* Inappropriate ioctl for device */
3078
3079   if (!afs_osi_suser(acred))
3080       return EACCES;
3081
3082   if (ainSize < sizeof(struct setspref)) 
3083     return EINVAL;
3084
3085   ssp = (struct setspref *)ain;
3086   if (ainSize < sizeof(struct spref)*ssp->num_servers) 
3087     return EINVAL;
3088
3089   afs_setsprefs(&(ssp->servers[0]), ssp->num_servers, 
3090                 (ssp->flags & DBservers));
3091   return 0;
3092 }
3093
3094 static int 
3095 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3096     struct vcache *avc;
3097     int afun;
3098     struct vrequest *areq;
3099     char *ain, *aout;
3100     afs_int32 ainSize;
3101     struct AFS_UCRED *acred;
3102     afs_int32 *aoutSize;
3103 {
3104   struct spref *sp;
3105   AFS_STATCNT(PSetSPrefs);
3106   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
3107         return EIO;          /* Inappropriate ioctl for device */
3108
3109
3110   if (!afs_osi_suser(acred))
3111     return EACCES;
3112
3113   sp = (struct spref *)ain;
3114   afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
3115   return 0;
3116 }
3117
3118 /* some notes on the following code...
3119  * in the hash table of server structs, all servers with the same IP address
3120  * will be on the same overflow chain.  
3121  * This could be sped slightly in some circumstances by having it cache the 
3122  * immediately previous slot in the hash table and some supporting information
3123  * Only reports file servers now.
3124  */
3125 static int 
3126      PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3127 struct vcache *avc;
3128 int afun;
3129 struct vrequest *areq;
3130 char *ain, *aout;
3131 afs_int32 ainSize;
3132 afs_int32 *aoutSize;
3133 {
3134    struct sprefrequest *spin; /* input */
3135    struct sprefinfo *spout;   /* output */
3136    struct spref *srvout;      /* one output component */
3137    int i,j;                   /* counters for hash table traversal */
3138    struct server *srvr;       /* one of CM's server structs */
3139    struct srvAddr *sa;
3140    afs_uint32 prevh;
3141    int vlonly;                /* just return vlservers ? */
3142    int isfs;
3143    
3144    AFS_STATCNT(PGetSPrefs);
3145    if ( !afs_resourceinit_flag )        /* afs deamons havn't started yet */
3146         return EIO;          /* Inappropriate ioctl for device */
3147
3148    
3149    if (ainSize < sizeof (struct sprefrequest_33)) {
3150       return ENOENT;
3151    }
3152    else {
3153       spin = ((struct sprefrequest *) ain);
3154    }
3155    
3156    if (ainSize > sizeof  (struct sprefrequest_33)) {
3157       vlonly = (spin->flags & DBservers);
3158    }
3159    else vlonly = 0;
3160    
3161    /* struct sprefinfo includes 1 server struct...  that size gets added
3162     * in during the loop that follows.
3163     */
3164    *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
3165    spout = (struct sprefinfo *) aout;
3166    spout->next_offset = spin->offset;
3167    spout->num_servers = 0;
3168    srvout = spout->servers;
3169    
3170    ObtainReadLock(&afs_xserver);
3171    for (i=0, j=0; j < NSERVERS; j++) {       /* sift through hash table */
3172       for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3173          if (spin->offset > (unsigned short)i) {
3174             continue;                /* catch up to where we left off */
3175          }
3176             spout->next_offset++;
3177          
3178             srvr = sa->server;
3179             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
3180                  || (sa->sa_portal == AFS_FSPORT); 
3181          
3182             if ((vlonly && isfs) || (!vlonly && !isfs)) {
3183                /* only report ranks for vl servers */
3184                continue;
3185             }
3186          
3187          srvout->host.s_addr = sa->sa_ip;
3188          srvout->rank = sa->sa_iprank;
3189          *aoutSize += sizeof(struct spref);
3190          spout->num_servers++;
3191          srvout++;
3192
3193          if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3194             ReleaseReadLock(&afs_xserver);                /* no more room! */
3195             return 0;
3196          }
3197       }
3198    }
3199    ReleaseReadLock(&afs_xserver);
3200    
3201    spout->next_offset = 0;  /* start over from the beginning next time */
3202    return 0;
3203 }
3204
3205 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3206 int  afs_NFSRootOnly = 1;
3207 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3208 struct vcache *avc;
3209 int afun;
3210 struct vrequest *areq;
3211 char *ain, *aout;
3212 afs_int32 ainSize;
3213 afs_int32 *aoutSize;    /* set this */
3214 struct AFS_UCRED *acred;
3215 {
3216     afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3217     extern struct afs_exporter *exporter_find();
3218     register struct afs_exporter *exporter;
3219
3220     AFS_STATCNT(PExportAfs);
3221     memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3222     type = handleValue >> 24;
3223     if (type == 0x71) {
3224         newint = 1;
3225         type = 1;       /* nfs */
3226     }
3227     exporter = exporter_find(type);
3228     if (newint) {
3229         export = handleValue & 3;
3230         changestate = handleValue & 0xff;
3231         smounts = (handleValue >> 2) & 3;
3232         pwsync = (handleValue >> 4) & 3;
3233         convmode = (handleValue >> 6) & 3;
3234     } else {
3235         changestate = (handleValue >> 16) & 0x1;
3236         convmode = (handleValue >> 16) & 0x2;
3237         pwsync = (handleValue >> 16) & 0x4;
3238         smounts = (handleValue >> 16) & 0x8;
3239         export = handleValue & 0xff;
3240     }
3241     if (!exporter) {
3242         /*  Failed finding desired exporter; */
3243         return ENODEV;
3244     }
3245     if (!changestate) {
3246         handleValue = exporter->exp_states;
3247         memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3248         *aoutSize = sizeof(afs_int32);
3249     } else {
3250         if (!afs_osi_suser(acred))
3251             return EACCES;    /* Only superuser can do this */
3252         if (newint) {
3253             if (export & 2) {
3254                 if (export & 1)
3255                     exporter->exp_states |= EXP_EXPORTED;
3256                 else
3257                     exporter->exp_states &= ~EXP_EXPORTED;
3258             }
3259             if (convmode & 2) {
3260                 if (convmode & 1)
3261                     exporter->exp_states |= EXP_UNIXMODE;
3262                 else
3263                     exporter->exp_states &= ~EXP_UNIXMODE;
3264             }
3265             if (pwsync & 2) {
3266                 if (pwsync & 1)
3267                     exporter->exp_states |= EXP_PWSYNC;
3268                 else
3269                     exporter->exp_states &= ~EXP_PWSYNC;
3270             }
3271             if (smounts & 2) {
3272                 if (smounts & 1) {
3273                     afs_NFSRootOnly = 0;
3274                     exporter->exp_states |= EXP_SUBMOUNTS;
3275                 } else {
3276                     afs_NFSRootOnly = 1;
3277                     exporter->exp_states &= ~EXP_SUBMOUNTS;
3278                 }
3279             }
3280             handleValue = exporter->exp_states;
3281             memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3282             *aoutSize = sizeof(afs_int32);
3283         } else {
3284             if (export)
3285                 exporter->exp_states |= EXP_EXPORTED;
3286             else
3287                 exporter->exp_states &= ~EXP_EXPORTED;
3288             if (convmode)
3289                 exporter->exp_states |= EXP_UNIXMODE;
3290             else
3291                 exporter->exp_states &= ~EXP_UNIXMODE;
3292             if (pwsync)
3293                 exporter->exp_states |= EXP_PWSYNC;
3294             else
3295                 exporter->exp_states &= ~EXP_PWSYNC;
3296             if (smounts) {
3297                 afs_NFSRootOnly = 0;
3298                 exporter->exp_states |= EXP_SUBMOUNTS;
3299             } else {
3300                 afs_NFSRootOnly = 1;
3301                 exporter->exp_states &= ~EXP_SUBMOUNTS;
3302             }
3303         }
3304     }
3305
3306     return 0;
3307 }
3308
3309 static int
3310 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3311 struct vcache *avc;
3312 int afun;
3313 struct vrequest *areq;
3314 char *ain, *aout;
3315 afs_int32 ainSize;
3316 struct AFS_UCRED *acred;
3317 afs_int32 *aoutSize;    /* set this */
3318 {
3319 struct gaginfo *gagflags;
3320
3321   if (!afs_osi_suser(acred))
3322     return EACCES;
3323
3324   gagflags = (struct gaginfo *) ain;
3325   afs_showflags = gagflags->showflags;
3326
3327   return 0;
3328 }
3329
3330
3331 static int
3332 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3333 struct vcache *avc;
3334 int afun;
3335 struct vrequest *areq;
3336 char *ain, *aout;
3337 afs_int32 ainSize;
3338 struct AFS_UCRED *acred;
3339 afs_int32 *aoutSize;    
3340 {
3341   struct rxparams *rxp;
3342
3343   if (!afs_osi_suser(acred))
3344     return EACCES;
3345
3346   rxp = (struct rxparams *) ain;
3347
3348   if (rxp->rx_initReceiveWindow)
3349     rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3350   if (rxp->rx_maxReceiveWindow)
3351     rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3352   if (rxp->rx_initSendWindow)
3353     rx_initSendWindow = rxp->rx_initSendWindow;
3354   if (rxp->rx_maxSendWindow)
3355     rx_maxSendWindow = rxp->rx_maxSendWindow;
3356   if (rxp->rxi_nSendFrags)
3357     rxi_nSendFrags = rxp->rxi_nSendFrags;
3358   if (rxp->rxi_nRecvFrags)
3359     rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3360   if (rxp->rxi_OrphanFragSize)
3361     rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3362   if (rxp->rx_maxReceiveSize)
3363   {
3364     rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3365     rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3366   }
3367   if (rxp->rx_MyMaxSendSize)
3368     rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3369  
3370   return 0;
3371 }
3372
3373 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3374      struct vcache *avc;
3375      int afun;
3376      struct vrequest *areq;
3377      register char *ain;
3378      char *aout;
3379      afs_int32 ainSize;
3380      afs_int32 *aoutSize;       /* set this */
3381 {
3382     if (sizeof(struct cm_initparams) > PIGGYSIZE)
3383         return E2BIG;
3384
3385     memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3386     *aoutSize = sizeof(struct cm_initparams);
3387     return 0;
3388 }
3389
3390 #ifdef AFS_SGI65_ENV
3391 /* They took crget() from us, so fake it. */
3392 static cred_t *crget(void)
3393 {
3394     cred_t *cr;
3395     cr = crdup(get_current_cred());
3396     memset((char*)cr, 0, sizeof(cred_t));
3397 #if CELL || CELL_PREPARE
3398     cr->cr_id = -1;
3399 #endif
3400     return cr;
3401 }
3402 #endif
3403
3404 static int
3405 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3406 struct vcache *avc;
3407 int afun;
3408 struct vrequest *areq;
3409 char *ain, *aout;
3410 afs_int32 ainSize;
3411 afs_int32 *aoutSize;
3412 struct AFS_UCRED *acred;
3413 {
3414     memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3415     *aoutSize=sizeof(afs_int32);
3416     return 0;
3417 }
3418
3419 static int
3420 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3421 struct vcache *avc;
3422 int afun;
3423 struct vrequest *areq;
3424 char *ain, *aout;
3425 afs_int32 ainSize;
3426 afs_int32 *aoutSize;
3427 struct AFS_UCRED *acred;
3428 {
3429     afs_int32 tmpval;
3430
3431     if (!afs_osi_suser(acred))
3432       return EPERM;
3433     if (ainSize != sizeof(afs_int32) || ain == NULL)
3434       return EINVAL;
3435     memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3436     /* if new mappings added later this will need to be changed */
3437     if (tmpval != 0 && tmpval != 1)
3438       return EINVAL;
3439     cryptall = tmpval;
3440     return 0;
3441 }
3442
3443 /*
3444  * Create new credentials to correspond to a remote user with given
3445  * <hostaddr, uid, g0, g1>.  This allows a server running as root to
3446  * provide pioctl (and other) services to foreign clients (i.e. nfs
3447  * clients) by using this call to `become' the client.
3448  */
3449 #define PSETPAG         110
3450 #define PIOCTL_HEADER   6
3451 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3452 {
3453     char *ain, *inData;
3454     afs_uint32 hostaddr;
3455     afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3456     extern struct afs_exporter *exporter_find();
3457     struct afs_exporter *exporter, *outexporter;
3458     struct AFS_UCRED *newcred;
3459     struct unixuser *au;
3460
3461 #if     defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3462     return EINVAL;                      /* NFS trans not supported for Ultrix */
3463 #else
3464 #if defined(AFS_SGIMP_ENV)
3465     osi_Assert(ISAFS_GLOCK());
3466 #endif
3467     AFS_STATCNT(HandleClientContext);
3468     if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) { 
3469         /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3470         return EINVAL; /* Too small to be good  */
3471     }
3472     ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3473     AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3474     if (code) {
3475         osi_FreeLargeSpace(inData);
3476         return code;
3477     }
3478
3479     /* Extract information for remote user */
3480     hostaddr = *((afs_uint32 *)ain);
3481     ain += sizeof(hostaddr);
3482     uid = *((afs_uint32 *)ain);
3483     ain += sizeof(uid);
3484     g0 = *((afs_uint32 *)ain);
3485     ain += sizeof(g0);
3486     g1 = *((afs_uint32 *)ain);
3487     ain += sizeof(g1);
3488     *com = *((afs_uint32 *)ain);
3489     ain += sizeof(afs_int32);
3490     exporter_type = *((afs_uint32 *)ain);       /* In case we support more than NFS */
3491
3492     /*
3493      * Of course, one must be root for most of these functions, but
3494      * we'll allow (for knfs) you to set things if the pag is 0 and
3495      * you're setting tokens or unlogging.
3496      */
3497     i = (*com) & 0xff;
3498     if (!afs_osi_suser(credp)) {
3499 #ifdef  AFS_SGI_ENV 
3500 #ifndef AFS_SGI64_ENV
3501         /* Since SGI's suser() returns explicit failure after the call.. */
3502         u.u_error = 0;          
3503 #endif 
3504 #endif
3505         /* check for acceptable opcodes for normal folks, which are, so far,
3506          * set tokens and unlog.
3507          */
3508         if (i != 9 && i != 3 && i != 38 && i != 8)      {
3509             osi_FreeLargeSpace(inData);
3510             return EACCES;
3511         }
3512     }
3513
3514     ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3515     ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3516     osi_FreeLargeSpace(inData);
3517     if (uid == 0) {
3518         /*
3519          * We map uid 0 to nobody to match the mapping that the nfs
3520          * server does and to ensure that the suser() calls in the afs
3521          * code fails for remote client roots.
3522          */
3523         uid = afs_nobody;       /* NFS_NOBODY == -2 */
3524     }
3525     newcred = crget();
3526 #ifdef  AFS_AIX41_ENV
3527     setuerror(0);       
3528 #endif
3529     newcred->cr_gid = RMTUSER_REQ;
3530     newcred->cr_groups[0] = g0;
3531     newcred->cr_groups[1] = g1;
3532 #ifdef AFS_AIX_ENV
3533     newcred->cr_ngrps = 2;
3534 #else
3535 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3536     newcred->cr_ngroups = 2;
3537 #else
3538     for (i=2; i<NGROUPS; i++)
3539         newcred->cr_groups[i] = NOGROUP;
3540 #endif
3541 #endif
3542 #if     !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3543     afs_nfsclient_init();       /* before looking for exporter, ensure one exists */
3544 #endif
3545     if (!(exporter = exporter_find(exporter_type))) {
3546         /* Exporter wasn't initialized or an invalid exporter type */
3547          crfree(newcred);
3548          return EINVAL;
3549     }
3550     if (exporter->exp_states & EXP_PWSYNC) {
3551         if (uid != credp->cr_uid) {
3552             crfree(newcred);
3553             return ENOEXEC;     /* XXX Find a better errno XXX */
3554         }
3555     }
3556     newcred->cr_uid = uid; /* Only temporary  */
3557     code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3558     /* The client's pag is the only unique identifier for it */
3559     newcred->cr_uid = pag;
3560     *acred = newcred;
3561     if (!code && *com == PSETPAG) {
3562       /* Special case for 'setpag' */
3563       afs_uint32 pagvalue = genpag();
3564
3565       au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3566       /*
3567        * Note that we leave the 'outexporter' struct held so it won't
3568        * dissappear on us
3569        */
3570       au->exporter = outexporter;
3571       if (ablob->out_size >= 4) {
3572         AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3573       }
3574       afs_PutUser(au, WRITE_LOCK);
3575       if (code) return code;
3576       return PSETPAG;           /*  Special return for setpag  */
3577     } else if (!code) {
3578         EXP_RELE(outexporter);
3579     }
3580     return code;
3581 #endif  /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3582 }
3583
3584 /* get all interface addresses of this client */
3585
3586 static int
3587 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3588 struct vcache *avc;
3589 int afun;
3590 struct vrequest *areq;
3591 char *ain, *aout;
3592 afs_int32 ainSize;
3593 afs_int32 *aoutSize;
3594 {
3595         struct sprefrequest *spin; /* input */
3596         struct sprefinfo *spout;   /* output */
3597         struct spref *srvout;      /* one output component */
3598         int maxNumber;
3599         int i,j;
3600
3601         AFS_STATCNT(PGetCPrefs);
3602         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3603             return EIO;          /* Inappropriate ioctl for device */
3604
3605         if ( ainSize < sizeof (struct sprefrequest ))
3606                 return EINVAL;
3607         
3608         spin = (struct sprefrequest *) ain;
3609         spout = (struct sprefinfo *) aout;
3610
3611         maxNumber = spin->num_servers; /* max addrs this time */
3612         srvout = spout->servers;
3613
3614         ObtainReadLock(&afs_xinterface);
3615
3616         /* copy out the client interface information from the
3617         ** kernel data structure "interface" to the output buffer
3618         */
3619         for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3620                                    && ( j< maxNumber) ; i++, j++, srvout++)
3621                 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3622         
3623         spout->num_servers = j;
3624         *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3625
3626         if ( i >= afs_cb_interface.numberOfInterfaces )
3627                 spout->next_offset = 0; /* start from beginning again */
3628         else
3629                 spout->next_offset = spin->offset + j;
3630         
3631         ReleaseReadLock(&afs_xinterface);
3632         return 0;
3633 }
3634
3635 static int
3636 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3637 struct vcache *avc;
3638 int afun;
3639 struct vrequest *areq;
3640 char *ain, *aout;
3641 afs_int32 ainSize;
3642 afs_int32 *aoutSize;
3643 {
3644         struct setspref *sin;
3645         int i;
3646
3647         AFS_STATCNT(PSetCPrefs);
3648         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3649             return EIO;          /* Inappropriate ioctl for device */
3650
3651         sin = (struct setspref *)ain;
3652
3653         if ( ainSize < sizeof(struct setspref) )
3654                 return EINVAL;
3655 #if 0   /* num_servers is unsigned */
3656         if ( sin->num_servers < 0 )
3657                 return EINVAL;
3658 #endif
3659         if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3660                 return ENOMEM;
3661
3662         ObtainWriteLock(&afs_xinterface, 412);
3663         afs_cb_interface.numberOfInterfaces = sin->num_servers;
3664         for ( i=0; (unsigned short)i < sin->num_servers; i++)
3665                 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3666
3667         ReleaseWriteLock(&afs_xinterface);
3668         return 0;
3669 }
3670
3671 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3672     struct vcache *avc;
3673     int afun;
3674     struct vrequest *areq;
3675     char *ain, *aout;
3676     afs_int32 ainSize;
3677     afs_int32 *aoutSize;
3678     struct AFS_UCRED *acred; {
3679     register afs_int32 code;
3680     register struct vcache *tvc;
3681     register struct dcache *tdc;
3682     struct VenusFid tfid;
3683     char *bufp;
3684     struct sysname_info sysState;
3685     afs_size_t offset, len;
3686
3687     AFS_STATCNT(PFlushMount);
3688     if (!avc) return EINVAL;
3689     code = afs_VerifyVCache(avc, areq);
3690     if (code) return code;
3691     if (vType(avc) != VDIR) {
3692         return ENOTDIR;
3693     }
3694     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3695     if (!tdc) return ENOENT;
3696     Check_AtSys(avc, ain, &sysState, areq);
3697     ObtainReadLock(&tdc->lock);
3698     do {
3699       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3700     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3701     ReleaseReadLock(&tdc->lock);
3702     afs_PutDCache(tdc);     /* we're done with the data */
3703     bufp = sysState.name;
3704     if (code) {
3705         goto out;
3706     }
3707     tfid.Cell = avc->fid.Cell;
3708     tfid.Fid.Volume = avc->fid.Fid.Volume;
3709     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3710         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3711     } else {
3712         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3713                             WRITE_LOCK);
3714     }
3715     if (!tvc) {
3716         code = ENOENT;
3717         goto out;
3718     }
3719     if (tvc->mvstat != 1) {
3720         afs_PutVCache(tvc, WRITE_LOCK);
3721         code = EINVAL;
3722         goto out;
3723     }
3724 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3725     afs_BozonLock(&tvc->pvnLock, tvc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
3726 #endif
3727     ObtainWriteLock(&tvc->lock,649);
3728     ObtainWriteLock(&afs_xcbhash, 650);
3729     afs_DequeueCallback(tvc);
3730     tvc->states &= ~(CStatd | CDirty);  /* next reference will re-stat cache entry */
3731     ReleaseWriteLock(&afs_xcbhash);
3732     /* now find the disk cache entries */
3733     afs_TryToSmush(tvc, acred, 1);
3734     osi_dnlc_purgedp(tvc);
3735     afs_symhint_inval(tvc);
3736     if (tvc->linkData && !(tvc->states & CCore)) {
3737         afs_osi_Free(tvc->link