check-flushvol-args-20001202
[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_AllocLargeSpace(1024);
1946     AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
1947     if (code) {
1948         osi_FreeLargeSpace(tp);
1949         return code;
1950     }
1951     if (afs_BBusy()) {  /* do this as late as possible */
1952         osi_FreeLargeSpace(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 (!avc)
2425         return EINVAL;
2426     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2427         return EIO;          /* Inappropriate ioctl for device */
2428
2429     volume = avc->fid.Fid.Volume;  /* who to zap */
2430     cell = avc->fid.Cell;
2431
2432     /* 
2433      * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2434      * the vcaches associated with the volume.
2435      */
2436     ObtainReadLock(&afs_xvcache);
2437     for(i = 0; i < VCSIZE; i++) {
2438         for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2439             if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2440 #if     defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV)  || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV)
2441                 VN_HOLD((struct vnode *)tvc);
2442 #else
2443                 tvc->vrefCount++;
2444 #endif
2445                 ReleaseReadLock(&afs_xvcache);
2446 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2447                 afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
2448 #endif
2449                 ObtainWriteLock(&tvc->lock,232);
2450
2451                 ObtainWriteLock(&afs_xcbhash, 458);
2452                 afs_DequeueCallback(tvc);
2453                 tvc->states &= ~(CStatd | CDirty);
2454                 ReleaseWriteLock(&afs_xcbhash);
2455                 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2456                     osi_dnlc_purgedp(tvc);
2457                 afs_TryToSmush(tvc, acred, 1);
2458                 ReleaseWriteLock(&tvc->lock);
2459 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2460                 afs_BozonUnlock(&tvc->pvnLock, tvc);
2461 #endif
2462                 ObtainReadLock(&afs_xvcache);
2463                 /* our tvc ptr is still good until now */
2464                 AFS_FAST_RELE(tvc);
2465             }
2466         }
2467     }
2468     ReleaseReadLock(&afs_xvcache);
2469
2470
2471     MObtainWriteLock(&afs_xdcache,328);  /* needed if you're going to flush any stuff */
2472     for(i=0;i<afs_cacheFiles;i++) {
2473         if (!(afs_indexFlags[i] & IFEverUsed)) continue;        /* never had any data */
2474         tdc = afs_GetDSlot(i, (struct dcache *) 0);
2475         if (tdc->refCount <= 1) {    /* too high, in use by running sys call */
2476             if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2477                 if (! (afs_indexFlags[i] & IFDataMod)) {
2478                     /* if the file is modified, but has a ref cnt of only 1, then
2479                        someone probably has the file open and is writing into it.
2480                        Better to skip flushing such a file, it will be brought back
2481                        immediately on the next write anyway.
2482
2483                        If we *must* flush, then this code has to be rearranged to call
2484                        afs_storeAllSegments() first */
2485                         afs_FlushDCache(tdc);
2486                 }
2487             }
2488         }
2489         tdc->refCount--;        /* bumped by getdslot */
2490     }
2491     MReleaseWriteLock(&afs_xdcache);
2492
2493     ObtainReadLock(&afs_xvolume);
2494     for (i=0;i<NVOLS;i++) {
2495         for (tv = afs_volumes[i]; tv; tv=tv->next) {
2496             if (tv->volume == volume) {
2497                 afs_ResetVolumeInfo(tv);
2498                 break;
2499             }
2500         }
2501     }
2502     ReleaseReadLock(&afs_xvolume);
2503
2504     /* probably, a user is doing this, probably, because things are screwed up. 
2505      * maybe it's the dnlc's fault? */
2506     osi_dnlc_purge();  
2507     return 0;
2508 }
2509
2510
2511
2512 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2513     struct vcache *avc;
2514     int afun;
2515     struct vrequest *areq;
2516     char *ain, *aout;
2517     afs_int32 ainSize;
2518     afs_int32 *aoutSize;        /* set this */ {
2519     register afs_int32 code;
2520     struct vcxstat stat;
2521     afs_int32 mode, i;
2522     
2523 /*  AFS_STATCNT(PGetVnodeXStatus); */
2524     if (!avc) return EINVAL;
2525     code = afs_VerifyVCache(avc, areq);
2526     if (code) return code;
2527     if (vType(avc) == VDIR)
2528         mode = PRSFS_LOOKUP;
2529     else
2530         mode = PRSFS_READ;
2531     if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2532         return EACCES;    
2533     stat.fid = avc->fid;
2534     hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2535     stat.lock = avc->lock;
2536     stat.parentVnode = avc->parentVnode;
2537     stat.parentUnique = avc->parentUnique;
2538     hset(stat.flushDV, avc->flushDV);
2539     hset(stat.mapDV, avc->mapDV);
2540     stat.truncPos = avc->truncPos;
2541     { /* just grab the first two - won't break anything... */
2542       struct axscache *ac;
2543
2544       for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2545         stat.randomUid[i] = ac->uid;
2546         stat.randomAccess[i] = ac->axess;
2547       }
2548     }
2549     stat.callback = afs_data_pointer_to_int32(avc->callback);
2550     stat.cbExpires = avc->cbExpires;
2551     stat.anyAccess = avc->anyAccess;
2552     stat.opens = avc->opens;
2553     stat.execsOrWriters = avc->execsOrWriters;
2554     stat.flockCount = avc->flockCount;
2555     stat.mvstat = avc->mvstat;
2556     stat.states = avc->states;
2557     bcopy((char *)&stat, aout, sizeof(struct vcxstat));
2558     *aoutSize = sizeof(struct vcxstat);
2559     return 0;
2560 }
2561
2562
2563 /* We require root for local sysname changes, but not for remote */
2564 /* (since we don't really believe remote uids anyway) */
2565  /* outname[] shouldn't really be needed- this is left as an excercise */
2566  /* for the reader.  */
2567
2568 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2569 struct vcache *avc;
2570 int afun;
2571 struct vrequest *areq;
2572 char *ain, *aout;
2573 afs_int32 ainSize;
2574 afs_int32 *aoutSize;    /* set this */
2575 register struct AFS_UCRED *acred;
2576 {
2577     char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2578     int setsysname, foundname=0;
2579     register struct afs_exporter *exporter;
2580     extern struct unixuser *afs_FindUser();
2581     extern char *afs_sysname;
2582     register struct unixuser *au;
2583     register afs_int32 pag, error;
2584     int t;
2585
2586
2587     AFS_STATCNT(PSetSysName);
2588     if (!afs_globalVFS) {
2589       /* Afsd is NOT running; disable it */
2590 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
2591         return (EINVAL);
2592 #else
2593         return (setuerror(EINVAL), EINVAL);
2594 #endif
2595     }
2596     bzero(inname, MAXSYSNAME);
2597     bcopy(ain, (char *)&setsysname, sizeof(afs_int32));
2598     ain += sizeof(afs_int32);
2599     if (setsysname) {
2600       t = strlen(ain);
2601       if (t > MAXSYSNAME)
2602         return EINVAL;
2603       bcopy(ain, inname, t+1);  /* include terminating null */
2604       ain += t + 1;
2605     }
2606     if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2607         pag = PagInCred(acred);
2608         if (pag == NOPAG) {
2609             return EINVAL;  /* Better than panicing */
2610         }
2611         if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2612             return EINVAL;  /* Better than panicing */
2613         }
2614         if (!(exporter = au->exporter)) {
2615             afs_PutUser(au, READ_LOCK);
2616             return EINVAL;  /* Better than panicing */
2617         }
2618         error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2619         if (error) {
2620             if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2621             else {
2622                 afs_PutUser(au, READ_LOCK);
2623                 return error;
2624             }
2625         }
2626         else foundname = 1;
2627         afs_PutUser(au, READ_LOCK);
2628     } else {
2629         if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2630         if (!setsysname) {
2631             strcpy(outname, afs_sysname);
2632             foundname = 1;
2633         } else {
2634             if (!afs_osi_suser(acred))     /* Local guy; only root can change sysname */
2635                 return EACCES;
2636             strcpy(afs_sysname, inname);
2637         }
2638     }
2639     if (!setsysname) {
2640         cp = aout;
2641         bcopy((char *)&foundname, cp, sizeof(afs_int32));
2642         cp += sizeof(afs_int32);
2643         if (foundname) {
2644             strcpy(cp, outname);
2645             cp += strlen(outname)+1;
2646         }
2647         *aoutSize = cp - aout;
2648     }
2649     return 0;
2650 }
2651
2652 /* sequential search through the list of touched cells is not a good
2653  * long-term solution here. For small n, though, it should be just
2654  * fine.  Should consider special-casing the local cell for large n.
2655  * Likewise for PSetSPrefs.
2656  */
2657 static void ReSortCells(s,l, vlonly)  
2658   int s;     /* number of ids in array l[] -- NOT index of last id */
2659   afs_int32 l[];  /* array of cell ids which have volumes that need to be sorted */
2660   int vlonly; /* sort vl servers or file servers?*/
2661 {
2662   extern struct volume *afs_volumes[NVOLS];   /* volume hash table */
2663
2664   int i;
2665   struct volume *j;
2666   register int  k;
2667
2668   if (vlonly) {
2669      struct cell *tcell;
2670      for(k=0;k<s;k++) {
2671         tcell = afs_GetCell(l[k], WRITE_LOCK);
2672         if (!tcell) continue;
2673         afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2674         afs_PutCell(tcell, WRITE_LOCK);
2675      }
2676      return;
2677   }
2678
2679   ObtainReadLock(&afs_xvolume);
2680   for (i= 0; i< NVOLS; i++) {
2681      for (j=afs_volumes[i];j;j=j->next) {
2682         for (k=0;k<s;k++)
2683            if (j->cell == l[k]) {
2684               ObtainWriteLock(&j->lock,233);
2685               afs_SortServers(j->serverHost, MAXHOSTS);
2686               ReleaseWriteLock(&j->lock);
2687               break; 
2688            }
2689      }
2690   }
2691   ReleaseReadLock(&afs_xvolume);
2692 }
2693
2694 int debugsetsp = 0;
2695
2696 static int afs_setsprefs(sp, num, vlonly)
2697    struct spref *sp;
2698    unsigned int num;
2699    unsigned int vlonly;
2700 {
2701    struct srvAddr *sa;
2702    int i,j,k,matches,touchedSize;
2703    struct server *srvr = NULL;
2704    afs_int32 touched[34];
2705    int isfs;
2706    
2707    touchedSize=0;
2708    for (k=0; k < num; sp++, k++) { 
2709       if (debugsetsp) {
2710          printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2711       }
2712       matches=0;
2713       ObtainReadLock(&afs_xserver);
2714       
2715       i = SHash(sp->host.s_addr);
2716       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2717          if (sa->sa_ip == sp->host.s_addr) {
2718             srvr = sa->server;
2719             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
2720                    || (sa->sa_portal == AFS_FSPORT); 
2721             if ((!vlonly && isfs) || (vlonly && !isfs)) {
2722                matches++;
2723                break;
2724             }
2725          }
2726       }
2727       
2728       if (sa && matches) {  /* found one! */
2729          if (debugsetsp) {
2730             printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
2731          }
2732          sa->sa_iprank = sp->rank + afs_randomMod15();
2733          afs_SortOneServer(sa->server);
2734          
2735          if (srvr->cell) {
2736            /* if we don't know yet what cell it's in, this is moot */
2737            for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
2738                  /* is it in our list of touched cells ?  */ ;
2739            if (j < 0) {                   /* no, it's not */
2740              touched[touchedSize++] = srvr->cell->cell;
2741              if (touchedSize >= 32) {                /* watch for ovrflow */
2742                ReleaseReadLock(&afs_xserver);
2743                ReSortCells(touchedSize, touched, vlonly);
2744                touchedSize=0;
2745                ObtainReadLock(&afs_xserver);
2746              }
2747            }
2748          }
2749       }
2750       
2751       ReleaseReadLock(&afs_xserver);
2752       /* if we didn't find one, start to create one. */
2753       /* Note that it doesn't have a cell yet...     */
2754       if (!matches) {
2755          afs_uint32 temp = sp->host.s_addr;
2756          srvr = afs_GetServer(&temp, 1, NULL, (vlonly ? AFS_VLPORT : AFS_FSPORT), 
2757                               WRITE_LOCK, (afsUUID *)0,0);
2758          srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
2759          afs_PutServer(srvr, WRITE_LOCK);
2760       }
2761    } /* for all cited preferences */
2762    
2763    ReSortCells(touchedSize, touched, vlonly);
2764    return 0;
2765 }
2766
2767  /* Note that this may only be performed by the local root user.
2768  */
2769 static int 
2770 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2771      struct vcache *avc;
2772      int afun;
2773      struct vrequest *areq;
2774      char *ain, *aout;
2775      afs_int32 ainSize;
2776      struct AFS_UCRED *acred;
2777      afs_int32 *aoutSize;
2778 {
2779   struct setspref *ssp;
2780   AFS_STATCNT(PSetSPrefs);
2781
2782   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
2783         return EIO;          /* Inappropriate ioctl for device */
2784
2785   if (!afs_osi_suser(acred))
2786       return EACCES;
2787
2788   if (ainSize < sizeof(struct setspref)) 
2789     return EINVAL;
2790
2791   ssp = (struct setspref *)ain;
2792   if (ainSize < sizeof(struct spref)*ssp->num_servers) 
2793     return EINVAL;
2794
2795   afs_setsprefs(&(ssp->servers[0]), ssp->num_servers, 
2796                 (ssp->flags & DBservers));
2797   return 0;
2798 }
2799
2800 static int 
2801 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2802     struct vcache *avc;
2803     int afun;
2804     struct vrequest *areq;
2805     char *ain, *aout;
2806     afs_int32 ainSize;
2807     struct AFS_UCRED *acred;
2808     afs_int32 *aoutSize;
2809 {
2810   struct spref *sp;
2811   AFS_STATCNT(PSetSPrefs);
2812   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
2813         return EIO;          /* Inappropriate ioctl for device */
2814
2815
2816   if (!afs_osi_suser(acred))
2817     return EACCES;
2818
2819   sp = (struct spref *)ain;
2820   afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
2821   return 0;
2822 }
2823
2824 /* some notes on the following code...
2825  * in the hash table of server structs, all servers with the same IP address
2826  * will be on the same overflow chain.  
2827  * This could be sped slightly in some circumstances by having it cache the 
2828  * immediately previous slot in the hash table and some supporting information
2829  * Only reports file servers now.
2830  */
2831 static int 
2832      PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
2833 struct vcache *avc;
2834 int afun;
2835 struct vrequest *areq;
2836 char *ain, *aout;
2837 afs_int32 ainSize;
2838 afs_int32 *aoutSize;
2839 {
2840    struct sprefrequest *spin; /* input */
2841    struct sprefinfo *spout;   /* output */
2842    struct spref *srvout;      /* one output component */
2843    int i,j;                   /* counters for hash table traversal */
2844    struct server *srvr;       /* one of CM's server structs */
2845    struct srvAddr *sa;
2846    afs_uint32 prevh;
2847    int vlonly;                /* just return vlservers ? */
2848    int isfs;
2849    
2850    AFS_STATCNT(PGetSPrefs);
2851    if ( !afs_resourceinit_flag )        /* afs deamons havn't started yet */
2852         return EIO;          /* Inappropriate ioctl for device */
2853
2854    
2855    if (ainSize < sizeof (struct sprefrequest_33)) {
2856       return ENOENT;
2857    }
2858    else {
2859       spin = ((struct sprefrequest *) ain);
2860    }
2861    
2862    if (ainSize > sizeof  (struct sprefrequest_33)) {
2863       vlonly = (spin->flags & DBservers);
2864    }
2865    else vlonly = 0;
2866    
2867    /* struct sprefinfo includes 1 server struct...  that size gets added
2868     * in during the loop that follows.
2869     */
2870    *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
2871    spout = (struct sprefinfo *) aout;
2872    spout->next_offset = spin->offset;
2873    spout->num_servers = 0;
2874    srvout = spout->servers;
2875    
2876    ObtainReadLock(&afs_xserver);
2877    for (i=0, j=0; j < NSERVERS; j++) {       /* sift through hash table */
2878       for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
2879          if (spin->offset > (unsigned short)i) {
2880             continue;                /* catch up to where we left off */
2881          }
2882             spout->next_offset++;
2883          
2884             srvr = sa->server;
2885             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
2886                  || (sa->sa_portal == AFS_FSPORT); 
2887          
2888             if ((vlonly && isfs) || (!vlonly && !isfs)) {
2889                /* only report ranks for vl servers */
2890                continue;
2891             }
2892          
2893          srvout->host.s_addr = sa->sa_ip;
2894          srvout->rank = sa->sa_iprank;
2895          *aoutSize += sizeof(struct spref);
2896          spout->num_servers++;
2897          srvout++;
2898
2899          if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
2900             ReleaseReadLock(&afs_xserver);                /* no more room! */
2901             return 0;
2902          }
2903       }
2904    }
2905    ReleaseReadLock(&afs_xserver);
2906    
2907    spout->next_offset = 0;  /* start over from the beginning next time */
2908    return 0;
2909 }
2910
2911 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
2912 int  afs_NFSRootOnly = 1;
2913 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2914 struct vcache *avc;
2915 int afun;
2916 struct vrequest *areq;
2917 char *ain, *aout;
2918 afs_int32 ainSize;
2919 afs_int32 *aoutSize;    /* set this */
2920 struct AFS_UCRED *acred;
2921 {
2922     afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
2923     extern struct afs_exporter *exporter_find();
2924     register struct afs_exporter *exporter;
2925
2926     AFS_STATCNT(PExportAfs);
2927     bcopy(ain, (char *)&handleValue, sizeof(afs_int32));
2928     type = handleValue >> 24;
2929     if (type == 0x71) {
2930         newint = 1;
2931         type = 1;       /* nfs */
2932     }
2933     exporter = exporter_find(type);
2934     if (newint) {
2935         export = handleValue & 3;
2936         changestate = handleValue & 0xff;
2937         smounts = (handleValue >> 2) & 3;
2938         pwsync = (handleValue >> 4) & 3;
2939         convmode = (handleValue >> 6) & 3;
2940     } else {
2941         changestate = (handleValue >> 16) & 0x1;
2942         convmode = (handleValue >> 16) & 0x2;
2943         pwsync = (handleValue >> 16) & 0x4;
2944         smounts = (handleValue >> 16) & 0x8;
2945         export = handleValue & 0xff;
2946     }
2947     if (!exporter) {
2948         /*  Failed finding desired exporter; */
2949         return ENODEV;
2950     }
2951     if (!changestate) {
2952         handleValue = exporter->exp_states;
2953         bcopy((char *)&handleValue, aout, sizeof(afs_int32));
2954         *aoutSize = sizeof(afs_int32);
2955     } else {
2956         if (!afs_osi_suser(acred))
2957             return EACCES;    /* Only superuser can do this */
2958         if (newint) {
2959             if (export & 2) {
2960                 if (export & 1)
2961                     exporter->exp_states |= EXP_EXPORTED;
2962                 else
2963                     exporter->exp_states &= ~EXP_EXPORTED;
2964             }
2965             if (convmode & 2) {
2966                 if (convmode & 1)
2967                     exporter->exp_states |= EXP_UNIXMODE;
2968                 else
2969                     exporter->exp_states &= ~EXP_UNIXMODE;
2970             }
2971             if (pwsync & 2) {
2972                 if (pwsync & 1)
2973                     exporter->exp_states |= EXP_PWSYNC;
2974                 else
2975                     exporter->exp_states &= ~EXP_PWSYNC;
2976             }
2977             if (smounts & 2) {
2978                 if (smounts & 1) {
2979                     afs_NFSRootOnly = 0;
2980                     exporter->exp_states |= EXP_SUBMOUNTS;
2981                 } else {
2982                     afs_NFSRootOnly = 1;
2983                     exporter->exp_states &= ~EXP_SUBMOUNTS;
2984                 }
2985             }
2986             handleValue = exporter->exp_states;
2987             bcopy((char *)&handleValue, aout, sizeof(afs_int32));
2988             *aoutSize = sizeof(afs_int32);
2989         } else {
2990             if (export)
2991                 exporter->exp_states |= EXP_EXPORTED;
2992             else
2993                 exporter->exp_states &= ~EXP_EXPORTED;
2994             if (convmode)
2995                 exporter->exp_states |= EXP_UNIXMODE;
2996             else
2997                 exporter->exp_states &= ~EXP_UNIXMODE;
2998             if (pwsync)
2999                 exporter->exp_states |= EXP_PWSYNC;
3000             else
3001                 exporter->exp_states &= ~EXP_PWSYNC;
3002             if (smounts) {
3003                 afs_NFSRootOnly = 0;
3004                 exporter->exp_states |= EXP_SUBMOUNTS;
3005             } else {
3006                 afs_NFSRootOnly = 1;
3007                 exporter->exp_states &= ~EXP_SUBMOUNTS;
3008             }
3009         }
3010     }
3011
3012     return 0;
3013 }
3014
3015 static int
3016 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3017 struct vcache *avc;
3018 int afun;
3019 struct vrequest *areq;
3020 char *ain, *aout;
3021 afs_int32 ainSize;
3022 struct AFS_UCRED *acred;
3023 afs_int32 *aoutSize;    /* set this */
3024 {
3025 struct gaginfo *gagflags;
3026
3027   if (!afs_osi_suser(acred))
3028     return EACCES;
3029
3030   gagflags = (struct gaginfo *) ain;
3031   afs_showflags = gagflags->showflags;
3032
3033   return 0;
3034 }
3035
3036
3037 static int
3038 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3039 struct vcache *avc;
3040 int afun;
3041 struct vrequest *areq;
3042 char *ain, *aout;
3043 afs_int32 ainSize;
3044 struct AFS_UCRED *acred;
3045 afs_int32 *aoutSize;    
3046 {
3047   struct rxparams *rxp;
3048
3049   if (!afs_osi_suser(acred))
3050     return EACCES;
3051
3052   rxp = (struct rxparams *) ain;
3053
3054   if (rxp->rx_initReceiveWindow)
3055     rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3056   if (rxp->rx_maxReceiveWindow)
3057     rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3058   if (rxp->rx_initSendWindow)
3059     rx_initSendWindow = rxp->rx_initSendWindow;
3060   if (rxp->rx_maxSendWindow)
3061     rx_maxSendWindow = rxp->rx_maxSendWindow;
3062   if (rxp->rxi_nSendFrags)
3063     rxi_nSendFrags = rxp->rxi_nSendFrags;
3064   if (rxp->rxi_nRecvFrags)
3065     rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3066   if (rxp->rxi_OrphanFragSize)
3067     rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3068   if (rxp->rx_maxReceiveSize)
3069   {
3070     rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3071     rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3072   }
3073   if (rxp->rx_MyMaxSendSize)
3074     rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3075  
3076   return 0;
3077 }
3078
3079 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3080      struct vcache *avc;
3081      int afun;
3082      struct vrequest *areq;
3083      register char *ain;
3084      char *aout;
3085      afs_int32 ainSize;
3086      afs_int32 *aoutSize;       /* set this */
3087 {
3088     if (sizeof(struct cm_initparams) > PIGGYSIZE)
3089         return E2BIG;
3090
3091     bcopy((char*)&cm_initParams, aout, sizeof(struct cm_initparams));
3092     *aoutSize = sizeof(struct cm_initparams);
3093     return 0;
3094 }
3095
3096 #ifdef AFS_SGI65_ENV
3097 /* They took crget() from us, so fake it. */
3098 static cred_t *crget(void)
3099 {
3100     cred_t *cr;
3101     cr = crdup(get_current_cred());
3102     bzero((char*)cr, sizeof(cred_t));
3103 #if CELL || CELL_PREPARE
3104     cr->cr_id = -1;
3105 #endif
3106     return cr;
3107 }
3108 #endif
3109 /*
3110  * Create new credentials to correspond to a remote user with given
3111  * <hostaddr, uid, g0, g1>.  This allows a server running as root to
3112  * provide pioctl (and other) services to foreign clients (i.e. nfs
3113  * clients) by using this call to `become' the client.
3114  */
3115 #define PSETPAG         110
3116 #define PIOCTL_HEADER   6
3117 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3118 {
3119     char *ain, *inData;
3120     afs_uint32 hostaddr;
3121     afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3122     extern struct afs_exporter *exporter_find();
3123     struct afs_exporter *exporter, *outexporter;
3124     struct AFS_UCRED *newcred;
3125     struct unixuser *au;
3126
3127 #if     defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3128     return EINVAL;                      /* NFS trans not supported for Ultrix */
3129 #else
3130 #if defined(AFS_SGIMP_ENV)
3131     osi_Assert(ISAFS_GLOCK());
3132 #endif
3133     AFS_STATCNT(HandleClientContext);
3134     if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) { 
3135         /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3136         return EINVAL; /* Too small to be good  */
3137     }
3138     ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3139     AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3140     if (code) {
3141         osi_FreeLargeSpace(inData);
3142         return code;
3143     }
3144
3145     /* Extract information for remote user */
3146     hostaddr = *((afs_uint32 *)ain);
3147     ain += sizeof(hostaddr);
3148     uid = *((afs_uint32 *)ain);
3149     ain += sizeof(uid);
3150     g0 = *((afs_uint32 *)ain);
3151     ain += sizeof(g0);
3152     g1 = *((afs_uint32 *)ain);
3153     ain += sizeof(g1);
3154     *com = *((afs_uint32 *)ain);
3155     ain += sizeof(afs_int32);
3156     exporter_type = *((afs_uint32 *)ain);       /* In case we support more than NFS */
3157
3158     /*
3159      * Of course, one must be root for most of these functions, but
3160      * we'll allow (for knfs) you to set things if the pag is 0 and
3161      * you're setting tokens or unlogging.
3162      */
3163     i = (*com) & 0xff;
3164     if (!afs_osi_suser(credp)) {
3165 #ifdef  AFS_SGI_ENV 
3166 #ifndef AFS_SGI64_ENV
3167         /* Since SGI's suser() returns explicit failure after the call.. */
3168         u.u_error = 0;          
3169 #endif 
3170 #endif
3171         /* check for acceptable opcodes for normal folks, which are, so far,
3172          * set tokens and unlog.
3173          */
3174         if (i != 9 && i != 3 && i != 38 && i != 8)      {
3175             osi_FreeLargeSpace(inData);
3176             return EACCES;
3177         }
3178     }
3179
3180     ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3181     ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3182     osi_FreeLargeSpace(inData);
3183     if (uid == 0) {
3184         /*
3185          * We map uid 0 to nobody to match the mapping that the nfs
3186          * server does and to ensure that the suser() calls in the afs
3187          * code fails for remote client roots.
3188          */
3189         uid = afs_nobody;       /* NFS_NOBODY == -2 */
3190     }
3191     newcred = crget();
3192 #ifdef  AFS_AIX41_ENV
3193     setuerror(0);       
3194 #endif
3195     newcred->cr_gid = RMTUSER_REQ;
3196     newcred->cr_groups[0] = g0;
3197     newcred->cr_groups[1] = g1;
3198 #ifdef AFS_AIX_ENV
3199     newcred->cr_ngrps = 2;
3200 #else
3201 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3202     newcred->cr_ngroups = 2;
3203 #else
3204     for (i=2; i<NGROUPS; i++)
3205         newcred->cr_groups[i] = NOGROUP;
3206 #endif
3207 #endif
3208 #if     !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3209     afs_nfsclient_init();       /* before looking for exporter, ensure one exists */
3210 #endif
3211     if (!(exporter = exporter_find(exporter_type))) {
3212         /* Exporter wasn't initialized or an invalid exporter type */
3213          crfree(newcred);
3214          return EINVAL;
3215     }
3216     if (exporter->exp_states & EXP_PWSYNC) {
3217         if (uid != credp->cr_uid) {
3218             crfree(newcred);
3219             return ENOEXEC;     /* XXX Find a better errno XXX */
3220         }
3221     }
3222     newcred->cr_uid = uid; /* Only temporary  */
3223     code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3224     /* The client's pag is the only unique identifier for it */
3225     newcred->cr_uid = pag;
3226     *acred = newcred;
3227     if (!code && *com == PSETPAG) {
3228       /* Special case for 'setpag' */
3229       afs_uint32 pagvalue = genpag();
3230
3231       au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3232       /*
3233        * Note that we leave the 'outexporter' struct held so it won't
3234        * dissappear on us
3235        */
3236       au->exporter = outexporter;
3237       if (ablob->out_size >= 4) {
3238         AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3239       }
3240       afs_PutUser(au, WRITE_LOCK);
3241       if (code) return code;
3242       return PSETPAG;           /*  Special return for setpag  */
3243     } else if (!code) {
3244         EXP_RELE(outexporter);
3245     }
3246     return code;
3247 #endif  /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3248 }
3249
3250 /* get all interface addresses of this client */
3251
3252 static int
3253 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3254 struct vcache *avc;
3255 int afun;
3256 struct vrequest *areq;
3257 char *ain, *aout;
3258 afs_int32 ainSize;
3259 afs_int32 *aoutSize;
3260 {
3261         struct sprefrequest *spin; /* input */
3262         struct sprefinfo *spout;   /* output */
3263         struct spref *srvout;      /* one output component */
3264         int maxNumber;
3265         int i,j;
3266
3267         AFS_STATCNT(PGetCPrefs);
3268         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3269             return EIO;          /* Inappropriate ioctl for device */
3270
3271         if ( ainSize < sizeof (struct sprefrequest ))
3272                 return EINVAL;
3273         
3274         spin = (struct sprefrequest *) ain;
3275         spout = (struct sprefinfo *) aout;
3276
3277         maxNumber = spin->num_servers; /* max addrs this time */
3278         srvout = spout->servers;
3279
3280         ObtainReadLock(&afs_xinterface);
3281
3282         /* copy out the client interface information from the
3283         ** kernel data structure "interface" to the output buffer
3284         */
3285         for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3286                                    && ( j< maxNumber) ; i++, j++, srvout++)
3287                 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3288         
3289         spout->num_servers = j;
3290         *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3291
3292         if ( i >= afs_cb_interface.numberOfInterfaces )
3293                 spout->next_offset = 0; /* start from beginning again */
3294         else
3295                 spout->next_offset = spin->offset + j;
3296         
3297         ReleaseReadLock(&afs_xinterface);
3298         return 0;
3299 }
3300
3301 static int
3302 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3303 struct vcache *avc;
3304 int afun;
3305 struct vrequest *areq;
3306 char *ain, *aout;
3307 afs_int32 ainSize;
3308 afs_int32 *aoutSize;
3309 {
3310         struct setspref *sin;
3311         int i;
3312
3313         AFS_STATCNT(PSetCPrefs);
3314         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3315             return EIO;          /* Inappropriate ioctl for device */
3316
3317         sin = (struct setspref *)ain;
3318
3319         if ( ainSize < sizeof(struct setspref) )
3320                 return EINVAL;
3321         if ( sin->num_servers < 0 )
3322                 return EINVAL;
3323         if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3324                 return ENOMEM;
3325
3326         ObtainWriteLock(&afs_xinterface, 412);
3327         afs_cb_interface.numberOfInterfaces = sin->num_servers;
3328         for ( i=0; (unsigned short)i < sin->num_servers; i++)
3329                 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3330
3331         ReleaseWriteLock(&afs_xinterface);
3332         return 0;
3333 }
3334
3335 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3336     struct vcache *avc;
3337     int afun;
3338     struct vrequest *areq;
3339     char *ain, *aout;
3340     afs_int32 ainSize;
3341     afs_int32 *aoutSize;
3342     struct AFS_UCRED *acred; {
3343     register afs_int32 code;
3344     register struct vcache *tvc;
3345     register struct dcache *tdc;
3346     struct VenusFid tfid;
3347     char *bufp = 0;
3348     afs_int32 offset, len, hasatsys=0;
3349
3350     AFS_STATCNT(PFlushMount);
3351     if (!avc) return EINVAL;
3352     code = afs_VerifyVCache(avc, areq);
3353     if (code) return code;
3354     if (vType(avc) != VDIR) {
3355         return ENOTDIR;
3356     }
3357     tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
3358     if (!tdc) return ENOENT;
3359     hasatsys = Check_AtSys(avc, ain, &bufp, areq);
3360     code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
3361     if (code) {
3362         afs_PutDCache(tdc);
3363         goto out;
3364     }
3365     tfid.Cell = avc->fid.Cell;
3366     tfid.Fid.Volume = avc->fid.Fid.Volume;
3367     afs_PutDCache(tdc);     /* we're done with the data */
3368     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3369         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3370     } else {
3371         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3372                             WRITE_LOCK);
3373     }
3374     if (!tvc) {
3375         code = ENOENT;
3376         goto out;
3377     }
3378     if (vType(tvc) != VLNK) {
3379         afs_PutVCache(tvc, WRITE_LOCK);
3380         code = EINVAL;
3381         goto out;
3382     }
3383 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3384     afs_BozonLock(&tvc->pvnLock, tvc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
3385 #endif
3386     ObtainWriteLock(&tvc->lock,645);
3387     ObtainWriteLock(&afs_xcbhash, 646);
3388     afs_DequeueCallback(tvc);
3389     tvc->states &= ~(CStatd | CDirty);  /* next reference will re-stat cache entry */
3390     ReleaseWriteLock(&afs_xcbhash);
3391     /* now find the disk cache entries */
3392     afs_TryToSmush(tvc, acred, 1);
3393     osi_dnlc_purgedp(tvc);
3394     afs_symhint_inval(tvc);
3395     if (tvc->linkData && !(tvc->states & CCore)) {
3396         afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3397         tvc->linkData = (char *) 0;
3398     }
3399     ReleaseWriteLock(&tvc->lock);
3400 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3401     afs_BozonUnlock(&tvc->pvnLock, tvc);
3402 #endif
3403     afs_PutVCache(tvc, WRITE_LOCK);
3404 out:
3405     if (hasatsys) osi_FreeLargeSpace(bufp);
3406     return code;
3407 }
3408
3409 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3410     struct vcache *avc;
3411     int afun;
3412     struct vrequest *areq;
3413     char *ain, *aout;
3414     afs_int32 ainSize;
3415     afs_int32 *aoutSize;
3416     struct AFS_UCRED *acred;
3417 {
3418     int code = 0;
3419     afs_int32 flags;
3420
3421     if (!afs_osi_suser(acred)) {
3422         code = EACCES;
3423         goto out;
3424     }
3425     if (ainSize != sizeof(afs_int32)) {
3426         code = EINVAL;
3427         goto out;
3428     }
3429     bcopy(ain, (char *)&flags, sizeof(afs_int32));
3430     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3431         code = EINVAL;
3432         goto out;
3433     }
3434     if (flags & AFSCALL_RXSTATS_ENABLE) {
3435         rx_enableProcessRPCStats();
3436     }
3437     if (flags & AFSCALL_RXSTATS_DISABLE) {
3438         rx_disableProcessRPCStats();
3439     }
3440     if (flags & AFSCALL_RXSTATS_CLEAR) {
3441         rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3442     }
3443 out:
3444     *aoutSize = 0;
3445     return code;
3446 }
3447
3448
3449 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3450     struct vcache *avc;
3451     int afun;
3452     struct vrequest *areq;
3453     char *ain, *aout;
3454     afs_int32 ainSize;
3455     afs_int32 *aoutSize;
3456     struct AFS_UCRED *acred;
3457 {
3458     int code = 0;
3459     afs_int32 flags;
3460
3461     if (!afs_osi_suser(acred)) {
3462         code = EACCES;
3463         goto out;
3464     }
3465     if (ainSize != sizeof(afs_int32)) {
3466         code = EINVAL;
3467         goto out;
3468     }
3469     bcopy(ain, (char *)&flags, sizeof(afs_int32));
3470     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3471         code = EINVAL;
3472         goto out;
3473     }
3474     if (flags & AFSCALL_RXSTATS_ENABLE) {
3475         rx_enablePeerRPCStats();
3476     }
3477     if (flags & AFSCALL_RXSTATS_DISABLE) {
3478         rx_disablePeerRPCStats();
3479     }
3480     if (flags & AFSCALL_RXSTATS_CLEAR) {
3481         rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3482     }
3483 out:
3484     *aoutSize = 0;
3485     return code;
3486 }
3487