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