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