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