ae55c75b86edffd79290691b80f60bb9d57adfd7
[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      for(k=0;k<s;k++) {
2946         tcell = afs_GetCell(l[k], WRITE_LOCK);
2947         if (!tcell) continue;
2948         afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2949         afs_PutCell(tcell, WRITE_LOCK);
2950      }
2951      return;
2952   }
2953
2954   ObtainReadLock(&afs_xvolume);
2955   for (i= 0; i< NVOLS; i++) {
2956      for (j=afs_volumes[i];j;j=j->next) {
2957         for (k=0;k<s;k++)
2958            if (j->cell == l[k]) {
2959               ObtainWriteLock(&j->lock,233);
2960               afs_SortServers(j->serverHost, MAXHOSTS);
2961               ReleaseWriteLock(&j->lock);
2962               break; 
2963            }
2964      }
2965   }
2966   ReleaseReadLock(&afs_xvolume);
2967 }
2968
2969 int debugsetsp = 0;
2970
2971 static int afs_setsprefs(sp, num, vlonly)
2972    struct spref *sp;
2973    unsigned int num;
2974    unsigned int vlonly;
2975 {
2976    struct srvAddr *sa;
2977    int i,j,k,matches,touchedSize;
2978    struct server *srvr = NULL;
2979    afs_int32 touched[34];
2980    int isfs;
2981    
2982    touchedSize=0;
2983    for (k=0; k < num; sp++, k++) { 
2984       if (debugsetsp) {
2985          printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2986       }
2987       matches=0;
2988       ObtainReadLock(&afs_xserver);
2989       
2990       i = SHash(sp->host.s_addr);
2991       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2992          if (sa->sa_ip == sp->host.s_addr) {
2993             srvr = sa->server;
2994             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
2995                    || (sa->sa_portal == AFS_FSPORT); 
2996             if ((!vlonly && isfs) || (vlonly && !isfs)) {
2997                matches++;
2998                break;
2999             }
3000          }
3001       }
3002       
3003       if (sa && matches) {  /* found one! */
3004          if (debugsetsp) {
3005             printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
3006          }
3007          sa->sa_iprank = sp->rank + afs_randomMod15();
3008          afs_SortOneServer(sa->server);
3009          
3010          if (srvr->cell) {
3011            /* if we don't know yet what cell it's in, this is moot */
3012            for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
3013                  /* is it in our list of touched cells ?  */ ;
3014            if (j < 0) {                   /* no, it's not */
3015              touched[touchedSize++] = srvr->cell->cell;
3016              if (touchedSize >= 32) {                /* watch for ovrflow */
3017                ReleaseReadLock(&afs_xserver);
3018                ReSortCells(touchedSize, touched, vlonly);
3019                touchedSize=0;
3020                ObtainReadLock(&afs_xserver);
3021              }
3022            }
3023          }
3024       }
3025       
3026       ReleaseReadLock(&afs_xserver);
3027       /* if we didn't find one, start to create one. */
3028       /* Note that it doesn't have a cell yet...     */
3029       if (!matches) {
3030          afs_uint32 temp = sp->host.s_addr;
3031          srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT), 
3032                               WRITE_LOCK, (afsUUID *)0,0);
3033          srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3034          afs_PutServer(srvr, WRITE_LOCK);
3035       }
3036    } /* for all cited preferences */
3037    
3038    ReSortCells(touchedSize, touched, vlonly);
3039    return 0;
3040 }
3041
3042  /* Note that this may only be performed by the local root user.
3043  */
3044 static int 
3045 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3046      struct vcache *avc;
3047      int afun;
3048      struct vrequest *areq;
3049      char *ain, *aout;
3050      afs_int32 ainSize;
3051      struct AFS_UCRED *acred;
3052      afs_int32 *aoutSize;
3053 {
3054   struct setspref *ssp;
3055   AFS_STATCNT(PSetSPrefs);
3056
3057   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
3058         return EIO;          /* Inappropriate ioctl for device */
3059
3060   if (!afs_osi_suser(acred))
3061       return EACCES;
3062
3063   if (ainSize < sizeof(struct setspref)) 
3064     return EINVAL;
3065
3066   ssp = (struct setspref *)ain;
3067   if (ainSize < sizeof(struct spref)*ssp->num_servers) 
3068     return EINVAL;
3069
3070   afs_setsprefs(&(ssp->servers[0]), ssp->num_servers, 
3071                 (ssp->flags & DBservers));
3072   return 0;
3073 }
3074
3075 static int 
3076 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3077     struct vcache *avc;
3078     int afun;
3079     struct vrequest *areq;
3080     char *ain, *aout;
3081     afs_int32 ainSize;
3082     struct AFS_UCRED *acred;
3083     afs_int32 *aoutSize;
3084 {
3085   struct spref *sp;
3086   AFS_STATCNT(PSetSPrefs);
3087   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
3088         return EIO;          /* Inappropriate ioctl for device */
3089
3090
3091   if (!afs_osi_suser(acred))
3092     return EACCES;
3093
3094   sp = (struct spref *)ain;
3095   afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
3096   return 0;
3097 }
3098
3099 /* some notes on the following code...
3100  * in the hash table of server structs, all servers with the same IP address
3101  * will be on the same overflow chain.  
3102  * This could be sped slightly in some circumstances by having it cache the 
3103  * immediately previous slot in the hash table and some supporting information
3104  * Only reports file servers now.
3105  */
3106 static int 
3107      PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3108 struct vcache *avc;
3109 int afun;
3110 struct vrequest *areq;
3111 char *ain, *aout;
3112 afs_int32 ainSize;
3113 afs_int32 *aoutSize;
3114 {
3115    struct sprefrequest *spin; /* input */
3116    struct sprefinfo *spout;   /* output */
3117    struct spref *srvout;      /* one output component */
3118    int i,j;                   /* counters for hash table traversal */
3119    struct server *srvr;       /* one of CM's server structs */
3120    struct srvAddr *sa;
3121    afs_uint32 prevh;
3122    int vlonly;                /* just return vlservers ? */
3123    int isfs;
3124    
3125    AFS_STATCNT(PGetSPrefs);
3126    if ( !afs_resourceinit_flag )        /* afs deamons havn't started yet */
3127         return EIO;          /* Inappropriate ioctl for device */
3128
3129    
3130    if (ainSize < sizeof (struct sprefrequest_33)) {
3131       return ENOENT;
3132    }
3133    else {
3134       spin = ((struct sprefrequest *) ain);
3135    }
3136    
3137    if (ainSize > sizeof  (struct sprefrequest_33)) {
3138       vlonly = (spin->flags & DBservers);
3139    }
3140    else vlonly = 0;
3141    
3142    /* struct sprefinfo includes 1 server struct...  that size gets added
3143     * in during the loop that follows.
3144     */
3145    *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
3146    spout = (struct sprefinfo *) aout;
3147    spout->next_offset = spin->offset;
3148    spout->num_servers = 0;
3149    srvout = spout->servers;
3150    
3151    ObtainReadLock(&afs_xserver);
3152    for (i=0, j=0; j < NSERVERS; j++) {       /* sift through hash table */
3153       for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3154          if (spin->offset > (unsigned short)i) {
3155             continue;                /* catch up to where we left off */
3156          }
3157             spout->next_offset++;
3158          
3159             srvr = sa->server;
3160             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
3161                  || (sa->sa_portal == AFS_FSPORT); 
3162          
3163             if ((vlonly && isfs) || (!vlonly && !isfs)) {
3164                /* only report ranks for vl servers */
3165                continue;
3166             }
3167          
3168          srvout->host.s_addr = sa->sa_ip;
3169          srvout->rank = sa->sa_iprank;
3170          *aoutSize += sizeof(struct spref);
3171          spout->num_servers++;
3172          srvout++;
3173
3174          if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3175             ReleaseReadLock(&afs_xserver);                /* no more room! */
3176             return 0;
3177          }
3178       }
3179    }
3180    ReleaseReadLock(&afs_xserver);
3181    
3182    spout->next_offset = 0;  /* start over from the beginning next time */
3183    return 0;
3184 }
3185
3186 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3187 int  afs_NFSRootOnly = 1;
3188 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3189 struct vcache *avc;
3190 int afun;
3191 struct vrequest *areq;
3192 char *ain, *aout;
3193 afs_int32 ainSize;
3194 afs_int32 *aoutSize;    /* set this */
3195 struct AFS_UCRED *acred;
3196 {
3197     afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3198     extern struct afs_exporter *exporter_find();
3199     register struct afs_exporter *exporter;
3200
3201     AFS_STATCNT(PExportAfs);
3202     memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3203     type = handleValue >> 24;
3204     if (type == 0x71) {
3205         newint = 1;
3206         type = 1;       /* nfs */
3207     }
3208     exporter = exporter_find(type);
3209     if (newint) {
3210         export = handleValue & 3;
3211         changestate = handleValue & 0xff;
3212         smounts = (handleValue >> 2) & 3;
3213         pwsync = (handleValue >> 4) & 3;
3214         convmode = (handleValue >> 6) & 3;
3215     } else {
3216         changestate = (handleValue >> 16) & 0x1;
3217         convmode = (handleValue >> 16) & 0x2;
3218         pwsync = (handleValue >> 16) & 0x4;
3219         smounts = (handleValue >> 16) & 0x8;
3220         export = handleValue & 0xff;
3221     }
3222     if (!exporter) {
3223         /*  Failed finding desired exporter; */
3224         return ENODEV;
3225     }
3226     if (!changestate) {
3227         handleValue = exporter->exp_states;
3228         memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3229         *aoutSize = sizeof(afs_int32);
3230     } else {
3231         if (!afs_osi_suser(acred))
3232             return EACCES;    /* Only superuser can do this */
3233         if (newint) {
3234             if (export & 2) {
3235                 if (export & 1)
3236                     exporter->exp_states |= EXP_EXPORTED;
3237                 else
3238                     exporter->exp_states &= ~EXP_EXPORTED;
3239             }
3240             if (convmode & 2) {
3241                 if (convmode & 1)
3242                     exporter->exp_states |= EXP_UNIXMODE;
3243                 else
3244                     exporter->exp_states &= ~EXP_UNIXMODE;
3245             }
3246             if (pwsync & 2) {
3247                 if (pwsync & 1)
3248                     exporter->exp_states |= EXP_PWSYNC;
3249                 else
3250                     exporter->exp_states &= ~EXP_PWSYNC;
3251             }
3252             if (smounts & 2) {
3253                 if (smounts & 1) {
3254                     afs_NFSRootOnly = 0;
3255                     exporter->exp_states |= EXP_SUBMOUNTS;
3256                 } else {
3257                     afs_NFSRootOnly = 1;
3258                     exporter->exp_states &= ~EXP_SUBMOUNTS;
3259                 }
3260             }
3261             handleValue = exporter->exp_states;
3262             memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3263             *aoutSize = sizeof(afs_int32);
3264         } else {
3265             if (export)
3266                 exporter->exp_states |= EXP_EXPORTED;
3267             else
3268                 exporter->exp_states &= ~EXP_EXPORTED;
3269             if (convmode)
3270                 exporter->exp_states |= EXP_UNIXMODE;
3271             else
3272                 exporter->exp_states &= ~EXP_UNIXMODE;
3273             if (pwsync)
3274                 exporter->exp_states |= EXP_PWSYNC;
3275             else
3276                 exporter->exp_states &= ~EXP_PWSYNC;
3277             if (smounts) {
3278                 afs_NFSRootOnly = 0;
3279                 exporter->exp_states |= EXP_SUBMOUNTS;
3280             } else {
3281                 afs_NFSRootOnly = 1;
3282                 exporter->exp_states &= ~EXP_SUBMOUNTS;
3283             }
3284         }
3285     }
3286
3287     return 0;
3288 }
3289
3290 static int
3291 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3292 struct vcache *avc;
3293 int afun;
3294 struct vrequest *areq;
3295 char *ain, *aout;
3296 afs_int32 ainSize;
3297 struct AFS_UCRED *acred;
3298 afs_int32 *aoutSize;    /* set this */
3299 {
3300 struct gaginfo *gagflags;
3301
3302   if (!afs_osi_suser(acred))
3303     return EACCES;
3304
3305   gagflags = (struct gaginfo *) ain;
3306   afs_showflags = gagflags->showflags;
3307
3308   return 0;
3309 }
3310
3311
3312 static int
3313 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3314 struct vcache *avc;
3315 int afun;
3316 struct vrequest *areq;
3317 char *ain, *aout;
3318 afs_int32 ainSize;
3319 struct AFS_UCRED *acred;
3320 afs_int32 *aoutSize;    
3321 {
3322   struct rxparams *rxp;
3323
3324   if (!afs_osi_suser(acred))
3325     return EACCES;
3326
3327   rxp = (struct rxparams *) ain;
3328
3329   if (rxp->rx_initReceiveWindow)
3330     rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3331   if (rxp->rx_maxReceiveWindow)
3332     rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3333   if (rxp->rx_initSendWindow)
3334     rx_initSendWindow = rxp->rx_initSendWindow;
3335   if (rxp->rx_maxSendWindow)
3336     rx_maxSendWindow = rxp->rx_maxSendWindow;
3337   if (rxp->rxi_nSendFrags)
3338     rxi_nSendFrags = rxp->rxi_nSendFrags;
3339   if (rxp->rxi_nRecvFrags)
3340     rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3341   if (rxp->rxi_OrphanFragSize)
3342     rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3343   if (rxp->rx_maxReceiveSize)
3344   {
3345     rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3346     rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3347   }
3348   if (rxp->rx_MyMaxSendSize)
3349     rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3350  
3351   return 0;
3352 }
3353
3354 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3355      struct vcache *avc;
3356      int afun;
3357      struct vrequest *areq;
3358      register char *ain;
3359      char *aout;
3360      afs_int32 ainSize;
3361      afs_int32 *aoutSize;       /* set this */
3362 {
3363     if (sizeof(struct cm_initparams) > PIGGYSIZE)
3364         return E2BIG;
3365
3366     memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3367     *aoutSize = sizeof(struct cm_initparams);
3368     return 0;
3369 }
3370
3371 #ifdef AFS_SGI65_ENV
3372 /* They took crget() from us, so fake it. */
3373 static cred_t *crget(void)
3374 {
3375     cred_t *cr;
3376     cr = crdup(get_current_cred());
3377     memset((char*)cr, 0, sizeof(cred_t));
3378 #if CELL || CELL_PREPARE
3379     cr->cr_id = -1;
3380 #endif
3381     return cr;
3382 }
3383 #endif
3384
3385 static int
3386 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3387 struct vcache *avc;
3388 int afun;
3389 struct vrequest *areq;
3390 char *ain, *aout;
3391 afs_int32 ainSize;
3392 afs_int32 *aoutSize;
3393 struct AFS_UCRED *acred;
3394 {
3395     memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3396     *aoutSize=sizeof(afs_int32);
3397     return 0;
3398 }
3399
3400 static int
3401 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3402 struct vcache *avc;
3403 int afun;
3404 struct vrequest *areq;
3405 char *ain, *aout;
3406 afs_int32 ainSize;
3407 afs_int32 *aoutSize;
3408 struct AFS_UCRED *acred;
3409 {
3410     afs_int32 tmpval;
3411
3412     if (!afs_osi_suser(acred))
3413       return EPERM;
3414     if (ainSize != sizeof(afs_int32) || ain == NULL)
3415       return EINVAL;
3416     memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3417     /* if new mappings added later this will need to be changed */
3418     if (tmpval != 0 && tmpval != 1)
3419       return EINVAL;
3420     cryptall = tmpval;
3421     return 0;
3422 }
3423
3424 /*
3425  * Create new credentials to correspond to a remote user with given
3426  * <hostaddr, uid, g0, g1>.  This allows a server running as root to
3427  * provide pioctl (and other) services to foreign clients (i.e. nfs
3428  * clients) by using this call to `become' the client.
3429  */
3430 #define PSETPAG         110
3431 #define PIOCTL_HEADER   6
3432 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3433 {
3434     char *ain, *inData;
3435     afs_uint32 hostaddr;
3436     afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3437     extern struct afs_exporter *exporter_find();
3438     struct afs_exporter *exporter, *outexporter;
3439     struct AFS_UCRED *newcred;
3440     struct unixuser *au;
3441
3442 #if     defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3443     return EINVAL;                      /* NFS trans not supported for Ultrix */
3444 #else
3445 #if defined(AFS_SGIMP_ENV)
3446     osi_Assert(ISAFS_GLOCK());
3447 #endif
3448     AFS_STATCNT(HandleClientContext);
3449     if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) { 
3450         /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3451         return EINVAL; /* Too small to be good  */
3452     }
3453     ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3454     AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3455     if (code) {
3456         osi_FreeLargeSpace(inData);
3457         return code;
3458     }
3459
3460     /* Extract information for remote user */
3461     hostaddr = *((afs_uint32 *)ain);
3462     ain += sizeof(hostaddr);
3463     uid = *((afs_uint32 *)ain);
3464     ain += sizeof(uid);
3465     g0 = *((afs_uint32 *)ain);
3466     ain += sizeof(g0);
3467     g1 = *((afs_uint32 *)ain);
3468     ain += sizeof(g1);
3469     *com = *((afs_uint32 *)ain);
3470     ain += sizeof(afs_int32);
3471     exporter_type = *((afs_uint32 *)ain);       /* In case we support more than NFS */
3472
3473     /*
3474      * Of course, one must be root for most of these functions, but
3475      * we'll allow (for knfs) you to set things if the pag is 0 and
3476      * you're setting tokens or unlogging.
3477      */
3478     i = (*com) & 0xff;
3479     if (!afs_osi_suser(credp)) {
3480 #ifdef  AFS_SGI_ENV 
3481 #ifndef AFS_SGI64_ENV
3482         /* Since SGI's suser() returns explicit failure after the call.. */
3483         u.u_error = 0;          
3484 #endif 
3485 #endif
3486         /* check for acceptable opcodes for normal folks, which are, so far,
3487          * set tokens and unlog.
3488          */
3489         if (i != 9 && i != 3 && i != 38 && i != 8)      {
3490             osi_FreeLargeSpace(inData);
3491             return EACCES;
3492         }
3493     }
3494
3495     ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3496     ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3497     osi_FreeLargeSpace(inData);
3498     if (uid == 0) {
3499         /*
3500          * We map uid 0 to nobody to match the mapping that the nfs
3501          * server does and to ensure that the suser() calls in the afs
3502          * code fails for remote client roots.
3503          */
3504         uid = afs_nobody;       /* NFS_NOBODY == -2 */
3505     }
3506     newcred = crget();
3507 #ifdef  AFS_AIX41_ENV
3508     setuerror(0);       
3509 #endif
3510     newcred->cr_gid = RMTUSER_REQ;
3511     newcred->cr_groups[0] = g0;
3512     newcred->cr_groups[1] = g1;
3513 #ifdef AFS_AIX_ENV
3514     newcred->cr_ngrps = 2;
3515 #else
3516 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3517     newcred->cr_ngroups = 2;
3518 #else
3519     for (i=2; i<NGROUPS; i++)
3520         newcred->cr_groups[i] = NOGROUP;
3521 #endif
3522 #endif
3523 #if     !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3524     afs_nfsclient_init();       /* before looking for exporter, ensure one exists */
3525 #endif
3526     if (!(exporter = exporter_find(exporter_type))) {
3527         /* Exporter wasn't initialized or an invalid exporter type */
3528          crfree(newcred);
3529          return EINVAL;
3530     }
3531     if (exporter->exp_states & EXP_PWSYNC) {
3532         if (uid != credp->cr_uid) {
3533             crfree(newcred);
3534             return ENOEXEC;     /* XXX Find a better errno XXX */
3535         }
3536     }
3537     newcred->cr_uid = uid; /* Only temporary  */
3538     code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3539     /* The client's pag is the only unique identifier for it */
3540     newcred->cr_uid = pag;
3541     *acred = newcred;
3542     if (!code && *com == PSETPAG) {
3543       /* Special case for 'setpag' */
3544       afs_uint32 pagvalue = genpag();
3545
3546       au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3547       /*
3548        * Note that we leave the 'outexporter' struct held so it won't
3549        * dissappear on us
3550        */
3551       au->exporter = outexporter;
3552       if (ablob->out_size >= 4) {
3553         AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3554       }
3555       afs_PutUser(au, WRITE_LOCK);
3556       if (code) return code;
3557       return PSETPAG;           /*  Special return for setpag  */
3558     } else if (!code) {
3559         EXP_RELE(outexporter);
3560     }
3561     return code;
3562 #endif  /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3563 }
3564
3565 /* get all interface addresses of this client */
3566
3567 static int
3568 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3569 struct vcache *avc;
3570 int afun;
3571 struct vrequest *areq;
3572 char *ain, *aout;
3573 afs_int32 ainSize;
3574 afs_int32 *aoutSize;
3575 {
3576         struct sprefrequest *spin; /* input */
3577         struct sprefinfo *spout;   /* output */
3578         struct spref *srvout;      /* one output component */
3579         int maxNumber;
3580         int i,j;
3581
3582         AFS_STATCNT(PGetCPrefs);
3583         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3584             return EIO;          /* Inappropriate ioctl for device */
3585
3586         if ( ainSize < sizeof (struct sprefrequest ))
3587                 return EINVAL;
3588         
3589         spin = (struct sprefrequest *) ain;
3590         spout = (struct sprefinfo *) aout;
3591
3592         maxNumber = spin->num_servers; /* max addrs this time */
3593         srvout = spout->servers;
3594
3595         ObtainReadLock(&afs_xinterface);
3596
3597         /* copy out the client interface information from the
3598         ** kernel data structure "interface" to the output buffer
3599         */
3600         for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3601                                    && ( j< maxNumber) ; i++, j++, srvout++)
3602                 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3603         
3604         spout->num_servers = j;
3605         *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3606
3607         if ( i >= afs_cb_interface.numberOfInterfaces )
3608                 spout->next_offset = 0; /* start from beginning again */
3609         else
3610                 spout->next_offset = spin->offset + j;
3611         
3612         ReleaseReadLock(&afs_xinterface);
3613         return 0;
3614 }
3615
3616 static int
3617 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3618 struct vcache *avc;
3619 int afun;
3620 struct vrequest *areq;
3621 char *ain, *aout;
3622 afs_int32 ainSize;
3623 afs_int32 *aoutSize;
3624 {
3625         struct setspref *sin;
3626         int i;
3627
3628         AFS_STATCNT(PSetCPrefs);
3629         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3630             return EIO;          /* Inappropriate ioctl for device */
3631
3632         sin = (struct setspref *)ain;
3633
3634         if ( ainSize < sizeof(struct setspref) )
3635                 return EINVAL;
3636 #if 0   /* num_servers is unsigned */
3637         if ( sin->num_servers < 0 )
3638                 return EINVAL;
3639 #endif
3640         if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3641                 return ENOMEM;
3642
3643         ObtainWriteLock(&afs_xinterface, 412);
3644         afs_cb_interface.numberOfInterfaces = sin->num_servers;
3645         for ( i=0; (unsigned short)i < sin->num_servers; i++)
3646                 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3647
3648         ReleaseWriteLock(&afs_xinterface);
3649         return 0;
3650 }
3651
3652 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3653     struct vcache *avc;
3654     int afun;
3655     struct vrequest *areq;
3656     char *ain, *aout;
3657     afs_int32 ainSize;
3658     afs_int32 *aoutSize;
3659     struct AFS_UCRED *acred; {
3660     register afs_int32 code;
3661     register struct vcache *tvc;
3662     register struct dcache *tdc;
3663     struct VenusFid tfid;
3664     char *bufp;
3665     struct sysname_info sysState;
3666     afs_size_t offset, len;
3667
3668     AFS_STATCNT(PFlushMount);
3669     if (!avc) return EINVAL;
3670     code = afs_VerifyVCache(avc, areq);
3671     if (code) return code;
3672     if (vType(avc) != VDIR) {
3673         return ENOTDIR;
3674     }
3675     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3676     if (!tdc) return ENOENT;
3677     Check_AtSys(avc, ain, &sysState, areq);
3678     do {
3679       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3680     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3681     bufp = sysState.name;
3682     if (code) {
3683         afs_PutDCache(tdc);
3684         goto out;
3685     }
3686     tfid.Cell = avc->fid.Cell;
3687     tfid.Fid.Volume = avc->fid.Fid.Volume;
3688     afs_PutDCache(tdc);     /* we're done with the data */
3689     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3690         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3691     } else {
3692         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3693                             WRITE_LOCK);
3694     }
3695     if (!tvc) {
3696         code = ENOENT;
3697         goto out;
3698     }
3699     if (vType(tvc) != VLNK) {
3700         afs_PutVCache(tvc, WRITE_LOCK);
3701         code = EINVAL;
3702         goto out;
3703     }
3704 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3705     afs_BozonLock(&tvc->pvnLock, tvc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
3706 #endif
3707     ObtainWriteLock(&tvc->lock,645);
3708     ObtainWriteLock(&afs_xcbhash, 646);
3709     afs_DequeueCallback(tvc);
3710     tvc->states &= ~(CStatd | CDirty);  /* next reference will re-stat cache entry */
3711     ReleaseWriteLock(&afs_xcbhash);
3712     /* now find the disk cache entries */
3713     afs_TryToSmush(tvc, acred, 1);
3714     osi_dnlc_purgedp(tvc);
3715     afs_symhint_inval(tvc);
3716     if (tvc->linkData && !(tvc->states & CCore)) {
3717         afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3718         tvc->linkData = (char *) 0;
3719     }
3720     ReleaseWriteLock(&tvc->lock);
3721 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3722     afs_BozonUnlock(&tvc->pvnLock, tvc);
3723 #endif
3724     afs_PutVCache(tvc, WRITE_LOCK);
3725 out:
3726     if (sysState.allocked) osi_FreeLargeSpace(bufp);
3727     return code;
3728 }
3729
3730 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3731     struct vcache *avc;
3732     int afun;
3733     struct vrequest *areq;
3734     char *ain, *aout;
3735     afs_int32 ainSize;
3736     afs_int32 *aoutSize;
3737     struct AFS_UCRED *acred;
3738 {
3739     int code = 0;
3740     afs_int32 flags;
3741
3742     if (!afs_osi_suser(acred)) {
3743         code = EACCES;
3744         goto out;
3745     }