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