62dae24f6c57c40cb8eb384d8663d5452269b2d6
[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 #ifdef UKERNEL
1849             /* set the expire times to 0, causes
1850              * afs_GCUserData to remove this entry
1851              */
1852             tu->ct.EndTimestamp = 0;
1853             tu->tokenTime = 0;
1854 #endif  /* UKERNEL */
1855         }
1856     }
1857     ReleaseWriteLock(&afs_xuser);
1858     return 0;
1859 }
1860
1861 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1862     struct vcache *avc;
1863     int afun;
1864     struct vrequest *areq;
1865     char *ain, *aout;
1866     afs_int32 ainSize;
1867     afs_int32 *aoutSize;        /* set this */ {
1868     afs_int32 newHostAddr;
1869     afs_int32 oldHostAddr;
1870     
1871     AFS_STATCNT(PMariner);
1872     if (afs_mariner)
1873         bcopy((char *)&afs_marinerHost, (char *)&oldHostAddr, sizeof(afs_int32));
1874     else
1875         oldHostAddr = 0xffffffff;   /* disabled */
1876     
1877     bcopy(ain, (char *)&newHostAddr, sizeof(afs_int32));
1878     if (newHostAddr == 0xffffffff) {
1879         /* disable mariner operations */
1880         afs_mariner = 0;
1881     }
1882     else if (newHostAddr) {
1883         afs_mariner = 1;
1884         afs_marinerHost = newHostAddr;
1885     }
1886     bcopy((char *)&oldHostAddr, aout, sizeof(afs_int32));
1887     *aoutSize = sizeof(afs_int32);
1888     return 0;
1889 }
1890
1891 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1892     struct vcache *avc;
1893     int afun;
1894     struct vrequest *areq;
1895     char *ain, *aout;
1896     afs_int32 ainSize;
1897     afs_int32 *aoutSize;        /* set this */ 
1898     struct AFS_UCRED *acred;
1899 {
1900     register char *cp = 0;
1901     register int i;
1902     register struct server *ts;
1903     afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1904     struct cell *cellp;
1905     struct chservinfo *pcheck;
1906
1907     AFS_STATCNT(PCheckServers);
1908
1909     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1910         return EIO;          /* Inappropriate ioctl for device */
1911
1912     if (*lp == 0x12345678) {    /* For afs3.3 version */
1913         pcheck=(struct chservinfo *)ain;
1914         if (pcheck->tinterval >= 0) {
1915             cp = aout;      
1916             bcopy((char *)&PROBE_INTERVAL, cp, sizeof(afs_int32));
1917             *aoutSize = sizeof(afs_int32);
1918             if (pcheck->tinterval > 0) {
1919                 if (!afs_osi_suser(acred))
1920                     return EACCES;
1921                 PROBE_INTERVAL=pcheck->tinterval;
1922             }
1923             return 0;
1924         }
1925         if (pcheck->tsize)
1926             havecell = 1;
1927         temp=pcheck->tflags;
1928         cp = pcheck->tbuffer;
1929     } else {    /* For pre afs3.3 versions */
1930         bcopy(ain, (char *)&temp, sizeof(afs_int32));
1931         cp = ain+sizeof(afs_int32);
1932         if (ainSize > sizeof(afs_int32)) 
1933             havecell = 1;
1934     }
1935
1936     /* 
1937      * 1: fast check, don't contact servers.
1938      * 2: local cell only.
1939      */
1940     if (havecell) {
1941         /* have cell name, too */
1942         cellp = afs_GetCellByName(cp, READ_LOCK);
1943         if (!cellp) return ENOENT;
1944     }
1945     else cellp = (struct cell *) 0;
1946     if (!cellp && (temp & 2)) {
1947         /* use local cell */
1948         cellp = afs_GetCell(1, READ_LOCK);
1949     }
1950     if (!(temp & 1)) {  /* if not fast, call server checker routine */
1951         afs_CheckServers(1, cellp);     /* check down servers */
1952         afs_CheckServers(0, cellp);     /* check up servers */
1953     }
1954     /* now return the current down server list */
1955     cp = aout;
1956     ObtainReadLock(&afs_xserver);
1957     for(i=0;i<NSERVERS;i++) {
1958         for(ts = afs_servers[i]; ts; ts=ts->next) {
1959             if (cellp && ts->cell != cellp) continue;   /* cell spec'd and wrong */
1960             if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1961                 bcopy((char *)&ts->addr->sa_ip, cp, sizeof(afs_int32));
1962                 cp += sizeof(afs_int32);
1963             }
1964         }
1965     }
1966     ReleaseReadLock(&afs_xserver);
1967     if (cellp) afs_PutCell(cellp, READ_LOCK);
1968     *aoutSize = cp - aout;
1969     return 0;
1970 }
1971
1972 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
1973     struct vcache *avc;
1974     int afun;
1975     struct vrequest *areq;
1976     char *ain, *aout;
1977     afs_int32 ainSize;
1978     afs_int32 *aoutSize;        /* set this */ {
1979     AFS_STATCNT(PCheckVolNames);
1980     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1981         return EIO;          /* Inappropriate ioctl for device */
1982
1983     afs_CheckRootVolume();
1984     afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
1985                          AFS_VOLCHECK_EXPIRED |
1986                          AFS_VOLCHECK_BUSY |
1987                          AFS_VOLCHECK_MTPTS);
1988     return 0;
1989 }
1990
1991 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
1992     struct vcache *avc;
1993     int afun;
1994     struct vrequest *areq;
1995     char *ain, *aout;
1996     afs_int32 ainSize;
1997     afs_int32 *aoutSize;        /* set this */ {
1998        int i;
1999        struct srvAddr *sa;
2000        struct conn *tc;
2001        struct unixuser *tu;
2002        afs_int32 retValue;
2003        extern afs_rwlock_t afs_xsrvAddr;        
2004
2005     AFS_STATCNT(PCheckAuth);
2006     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2007         return EIO;          /* Inappropriate ioctl for device */
2008
2009     retValue = 0;
2010     tu = afs_GetUser(areq->uid, 1, READ_LOCK);  /* check local cell authentication */
2011     if (!tu) retValue = EACCES;
2012     else {
2013         /* we have a user */
2014         ObtainReadLock(&afs_xsrvAddr);  
2015         ObtainReadLock(&afs_xconn);
2016
2017         /* any tokens set? */
2018         if ((tu->states & UHasTokens) == 0) retValue = EACCES;
2019         /* all connections in cell 1 working? */
2020         for(i=0;i<NSERVERS;i++) {
2021             for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
2022                for (tc = sa->conns; tc; tc=tc->next) {
2023                   if (tc->user == tu && (tu->states & UTokensBad))
2024                        retValue = EACCES;
2025                }
2026             }
2027         }
2028         ReleaseReadLock(&afs_xsrvAddr);
2029         ReleaseReadLock(&afs_xconn);
2030         afs_PutUser(tu, READ_LOCK);
2031     }
2032     bcopy((char *)&retValue, aout, sizeof(afs_int32));
2033     *aoutSize = sizeof(afs_int32);
2034     return 0;
2035 }
2036
2037 static Prefetch(apath, adata, afollow, acred)
2038 char *apath;
2039 struct afs_ioctl *adata;
2040 int afollow;
2041 struct AFS_UCRED *acred; 
2042 {
2043     register char *tp;
2044     register afs_int32 code;
2045 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV)
2046     size_t bufferSize;
2047 #else
2048     u_int bufferSize;
2049 #endif
2050
2051     AFS_STATCNT(Prefetch);
2052     if (!apath) return EINVAL;
2053     tp = osi_AllocLargeSpace(1024);
2054     AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2055     if (code) {
2056         osi_FreeLargeSpace(tp);
2057         return code;
2058     }
2059     if (afs_BBusy()) {  /* do this as late as possible */
2060         osi_FreeLargeSpace(tp);
2061         return EWOULDBLOCK;     /* pretty close */
2062     }
2063     afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred, (long)tp, 0L, 0L, 0L);
2064     return 0;
2065 }
2066
2067 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
2068     struct vcache *avc;
2069     int afun;
2070     struct vrequest *areq;
2071     char *ain, *aout;
2072     afs_int32 ainSize;
2073     afs_int32 *aoutSize;        /* set this */ {
2074     register struct volume *tvp;
2075     register struct server *ts;
2076     register afs_int32 i;
2077     register char *cp;
2078     
2079     AFS_STATCNT(PFindVolume);
2080     if (!avc) return EINVAL;
2081     tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2082     if (tvp) {
2083         cp = aout;
2084         for(i=0;i<MAXHOSTS;i++) {
2085             ts = tvp->serverHost[i];
2086             if (!ts) break;
2087             bcopy((char *)&ts->addr->sa_ip, cp, sizeof(afs_int32));
2088             cp += sizeof(afs_int32);
2089         }
2090         if (i<MAXHOSTS) {
2091             /* still room for terminating NULL, add it on */
2092             ainSize = 0;        /* reuse vbl */
2093             bcopy((char *)&ainSize, cp, sizeof(afs_int32));
2094             cp += sizeof(afs_int32);
2095         }
2096         *aoutSize = cp - aout;
2097         afs_PutVolume(tvp, READ_LOCK);
2098         return 0;
2099     }
2100     return ENODEV;
2101 }
2102
2103 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
2104     struct vcache *avc;
2105     int afun;
2106     struct vrequest *areq;
2107     char *ain, *aout;
2108     afs_int32 ainSize;
2109     afs_int32 *aoutSize;        /* set this */ {
2110     register afs_int32 code;
2111     afs_int32 temp;
2112     
2113     AFS_STATCNT(PViceAccess);
2114     if (!avc) return EINVAL;
2115     code = afs_VerifyVCache(avc, areq);
2116     if (code) return code;
2117     bcopy(ain, (char *)&temp, sizeof(afs_int32));
2118     code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2119     if (code) return 0;
2120     else return EACCES;
2121 }
2122
2123 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2124     struct vcache *avc;
2125     int afun;
2126     struct vrequest *areq;
2127     char *ain, *aout;
2128     afs_int32 ainSize;
2129     afs_int32 *aoutSize;        /* set this */ 
2130     struct AFS_UCRED *acred;
2131 {
2132     afs_int32 newValue;
2133     int waitcnt = 0;
2134     
2135     AFS_STATCNT(PSetCacheSize);
2136     if (!afs_osi_suser(acred))
2137         return EACCES;
2138     /* too many things are setup initially in mem cache version */
2139     if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2140     bcopy(ain, (char *)&newValue, sizeof(afs_int32));
2141     if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2142     else {
2143         extern u_int afs_min_cache;
2144         if (newValue < afs_min_cache)
2145             afs_cacheBlocks = afs_min_cache;
2146         else
2147             afs_cacheBlocks = newValue;
2148     }
2149     afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2150     afs_ComputeCacheParms();    /* recompute basic cache parameters */
2151     afs_MaybeWakeupTruncateDaemon();
2152     while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2153         afs_osi_Wait(1000, 0, 0);
2154         afs_MaybeWakeupTruncateDaemon();
2155     }
2156     return 0;
2157 }
2158
2159 #define MAXGCSTATS      16
2160 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2161 struct vcache *avc;
2162 int afun;
2163 struct vrequest *areq;
2164 char *ain, *aout;
2165 afs_int32 ainSize;
2166 afs_int32 *aoutSize;    /* set this */ {
2167     afs_int32 results[MAXGCSTATS];
2168
2169     AFS_STATCNT(PGetCacheSize);
2170     bzero((char *)results, sizeof(results));
2171     results[0] = afs_cacheBlocks;
2172     results[1] = afs_blocksUsed;
2173     bcopy((char *)results, aout, sizeof(results));
2174     *aoutSize = sizeof(results);
2175     return 0;
2176 }
2177
2178 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2179     struct vcache *avc;
2180     int afun;
2181     struct vrequest *areq;
2182     char *ain, *aout;
2183     afs_int32 ainSize;
2184     afs_int32 *aoutSize;        /* set this */ {
2185     register struct conn *tc;
2186     register afs_int32 code;
2187     struct AFSCallBack CallBacks_Array[1];
2188     struct AFSCBFids theFids;
2189     struct AFSCBs theCBs;
2190     XSTATS_DECLS;
2191
2192     AFS_STATCNT(PRemoveCallBack);
2193     if (!avc) return EINVAL;
2194     if (avc->states & CRO) return 0;    /* read-only-ness can't change */
2195     ObtainWriteLock(&avc->lock,229);
2196     theFids.AFSCBFids_len = 1;
2197     theCBs.AFSCBs_len = 1;
2198     theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2199     theCBs.AFSCBs_val = CallBacks_Array;
2200     CallBacks_Array[0].CallBackType = CB_DROPPED;
2201     if (avc->callback) {
2202         do {
2203             tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2204             if (tc) {
2205               XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2206 #ifdef RX_ENABLE_LOCKS
2207               AFS_GUNLOCK();
2208 #endif /* RX_ENABLE_LOCKS */
2209               code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2210 #ifdef RX_ENABLE_LOCKS
2211               AFS_GLOCK();
2212 #endif /* RX_ENABLE_LOCKS */
2213               XSTATS_END_TIME;
2214             }
2215             /* don't set code on failure since we wouldn't use it */
2216         } while
2217           (afs_Analyze(tc, code, &avc->fid, areq,
2218                        AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2219                        SHARED_LOCK, (struct cell *)0));
2220
2221         ObtainWriteLock(&afs_xcbhash, 457);
2222         afs_DequeueCallback(avc);
2223         avc->callback = 0;
2224         avc->states &= ~(CStatd | CUnique);
2225         ReleaseWriteLock(&afs_xcbhash);
2226         if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2227             osi_dnlc_purgedp(avc);
2228     }
2229     ReleaseWriteLock(&avc->lock);
2230     return 0;
2231 }
2232
2233 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2234     struct vcache *avc;
2235     int afun;
2236     struct vrequest *areq;
2237     register char *ain;
2238     char *aout;
2239     afs_int32 ainSize;
2240     struct AFS_UCRED *acred;
2241     afs_int32 *aoutSize;        /* set this */ {
2242     /* create a new cell */
2243     afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2244     register struct cell *tcell;
2245     char *newcell=0, *linkedcell=0, *tp= ain;
2246     register afs_int32 code, linkedstate=0, ls;
2247     u_short fsport = 0, vlport = 0;
2248     afs_int32 scount;
2249     
2250     AFS_STATCNT(PNewCell);
2251     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2252         return EIO;          /* Inappropriate ioctl for device */
2253
2254     if (!afs_osi_suser(acred))
2255         return EACCES;
2256
2257     bcopy(tp, (char *)&magic, sizeof(afs_int32));
2258     tp += sizeof(afs_int32);
2259     if (magic != 0x12345678)
2260         return EINVAL;
2261
2262     /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2263      * server addresses while the 3.5 fs newcell command passes
2264      * MAXHOSTS. To figure out which is which, check if the cellname
2265      * is good.
2266      */
2267     newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2268     scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2269
2270     /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2271     bcopy(tp, (char *)cellHosts, MAXCELLHOSTS * sizeof(afs_int32));
2272     tp += (scount * sizeof(afs_int32));
2273
2274     lp = (afs_int32 *)tp;
2275     fsport = *lp++;
2276     vlport = *lp++;
2277     if (fsport < 1024) fsport = 0;      /* Privileged ports not allowed */
2278     if (vlport < 1024) vlport = 0;      /* Privileged ports not allowed */
2279     tp += (3 * sizeof(afs_int32));
2280     newcell = tp;
2281     if ((ls = *lp) & 1) {
2282        linkedcell = tp + strlen(newcell)+1;
2283        linkedstate |= CLinkedCell;
2284     }
2285
2286     linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2287     code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0);
2288     return code;
2289 }
2290
2291 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2292     struct vcache *avc;
2293     int afun;
2294     struct vrequest *areq;
2295     char *ain, *aout;
2296     afs_int32 ainSize;
2297     afs_int32 *aoutSize;        /* set this */ {
2298     afs_int32 whichCell;
2299     register struct cell *tcell=0;
2300     register afs_int32 i;
2301     register char *cp, *tp = ain;
2302     register struct afs_q *cq, *tq;
2303
2304     AFS_STATCNT(PListCells);
2305     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2306         return EIO;          /* Inappropriate ioctl for device */
2307
2308     bcopy(tp, (char *)&whichCell, sizeof(afs_int32));
2309     tp += sizeof(afs_int32);
2310     ObtainReadLock(&afs_xcell);
2311     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2312         tcell = QTOC(cq); tq = QNext(cq);
2313         if (whichCell == 0) break;
2314         if (tq == &CellLRU) tcell = 0;
2315         whichCell--;
2316     }
2317     if (tcell) {
2318         cp = aout;
2319         bzero(cp, MAXCELLHOSTS * sizeof(afs_int32));
2320         for(i=0;i<MAXCELLHOSTS;i++) {
2321             if (tcell->cellHosts[i] == 0) break;
2322             bcopy((char *)&tcell->cellHosts[i]->addr->sa_ip, cp, sizeof(afs_int32));
2323             cp += sizeof(afs_int32);
2324         }
2325         cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2326         strcpy(cp, tcell->cellName);
2327         cp += strlen(tcell->cellName)+1;
2328         *aoutSize = cp - aout;
2329     }
2330     ReleaseReadLock(&afs_xcell);
2331     if (tcell) return 0;
2332     else return EDOM;
2333 }
2334
2335 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2336     struct vcache *avc;
2337     int afun;
2338     struct vrequest *areq;
2339     register char *ain;
2340     char *aout;
2341     afs_int32 ainSize;
2342     afs_int32 *aoutSize;        /* set this */ {
2343     register afs_int32 code;
2344     char *bufp = 0;
2345     afs_int32 offset, len, hasatsys = 0;
2346     register struct conn *tc;
2347     register struct dcache *tdc;
2348     register struct vcache *tvc;
2349     struct AFSFetchStatus OutDirStatus;
2350     struct VenusFid tfid;
2351     struct AFSVolSync tsync;
2352     XSTATS_DECLS;
2353
2354
2355     /* "ain" is the name of the file in this dir to remove */
2356
2357     AFS_STATCNT(PRemoveMount);
2358     if (!avc) return EINVAL;
2359     code = afs_VerifyVCache(avc, areq);
2360     if (code) return code;
2361     if (vType(avc) != VDIR) return ENOTDIR;
2362
2363     tdc = afs_GetDCache(avc, 0, areq, &offset,  &len, 1);       /* test for error below */
2364     if (!tdc) return ENOENT;
2365     hasatsys = Check_AtSys(avc, ain, &bufp, areq);
2366     code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
2367     if (code) {
2368         afs_PutDCache(tdc);
2369         goto out;
2370     }
2371     tfid.Cell = avc->fid.Cell;
2372     tfid.Fid.Volume = avc->fid.Fid.Volume;
2373     if (!tfid.Fid.Unique &&  (avc->states & CForeign)) {
2374         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2375     } else {
2376         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2377                             (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2378     }
2379     if (!tvc) {
2380         code = ENOENT;
2381         afs_PutDCache(tdc);
2382         goto out;
2383     }
2384     if (vType(tvc) != VLNK) {
2385         afs_PutDCache(tdc);
2386         afs_PutVCache(tvc, WRITE_LOCK);
2387         code = EINVAL;
2388         goto out;
2389     }
2390     ObtainWriteLock(&tvc->lock,230);
2391     code = afs_HandleLink(tvc, areq);
2392     if (!code) {
2393         if (tvc->linkData) {
2394             if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2395                 code =  EINVAL;
2396         } else 
2397             code = EIO;
2398     }
2399     ReleaseWriteLock(&tvc->lock);
2400     osi_dnlc_purgedp(tvc);
2401     afs_PutVCache(tvc, WRITE_LOCK);
2402     if (code) {
2403         afs_PutDCache(tdc);
2404         goto out;
2405     }
2406     ObtainWriteLock(&avc->lock,231);
2407     osi_dnlc_remove(avc, bufp, tvc);
2408     do {
2409         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2410         if (tc) {
2411           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2412 #ifdef RX_ENABLE_LOCKS
2413           AFS_GUNLOCK();
2414 #endif /* RX_ENABLE_LOCKS */
2415           code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2416                                   bufp, &OutDirStatus, &tsync);
2417 #ifdef RX_ENABLE_LOCKS
2418           AFS_GLOCK();
2419 #endif /* RX_ENABLE_LOCKS */
2420           XSTATS_END_TIME;
2421         }
2422         else code = -1;
2423     } while
2424         (afs_Analyze(tc, code, &avc->fid, areq,
2425                      AFS_STATS_FS_RPCIDX_REMOVEFILE,
2426                      SHARED_LOCK, (struct cell *)0));
2427
2428     if (code) {
2429         if (tdc) afs_PutDCache(tdc);
2430         ReleaseWriteLock(&avc->lock);
2431         goto out;
2432     }
2433     if (tdc) {
2434         /* we have the thing in the cache */
2435         if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2436             /* we can do it locally */
2437             code = afs_dir_Delete(&tdc->f.inode, bufp);
2438             if (code) {
2439                 ZapDCE(tdc);    /* surprise error -- invalid value */
2440                 DZap(&tdc->f.inode);
2441             }
2442         }
2443         afs_PutDCache(tdc);     /* drop ref count */
2444     }
2445     avc->states &= ~CUnique;            /* For the dfs xlator */
2446     ReleaseWriteLock(&avc->lock);
2447     code = 0;
2448 out:
2449     if (hasatsys) osi_FreeLargeSpace(bufp);
2450     return code;    
2451 }
2452
2453 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2454     struct vcache *avc;
2455     int afun;
2456     struct vrequest *areq;
2457     register char *ain;
2458     char *aout;
2459     afs_int32 ainSize;
2460     struct AFS_UCRED *acred;
2461     afs_int32 *aoutSize;        /* set this */ {
2462     return EINVAL;              /* OBSOLETE */
2463 }
2464
2465 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2466     struct vcache *avc;
2467     int afun;
2468     struct vrequest *areq;
2469     char *ain, *aout;
2470     afs_int32 ainSize;
2471     afs_int32 *aoutSize;        /* set this */ {
2472     register struct cell *tcell;
2473     afs_int32 temp;
2474
2475     AFS_STATCNT(PGetCellStatus);
2476     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2477         return EIO;          /* Inappropriate ioctl for device */
2478
2479     tcell = afs_GetCellByName(ain, READ_LOCK);
2480     if (!tcell) return ENOENT;
2481     temp = tcell->states;
2482     afs_PutCell(tcell, READ_LOCK);
2483     bcopy((char *)&temp, aout, sizeof(afs_int32));
2484     *aoutSize = sizeof(afs_int32);
2485     return 0;
2486 }
2487
2488 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2489     struct vcache *avc;
2490     int afun;
2491     struct vrequest *areq;
2492     char *ain, *aout;
2493     afs_int32 ainSize;
2494     struct AFS_UCRED *acred;
2495     afs_int32 *aoutSize;        /* set this */ {
2496     register struct cell *tcell;
2497     afs_int32 temp;
2498     
2499     if (!afs_osi_suser(acred))
2500         return EACCES;
2501     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2502         return EIO;          /* Inappropriate ioctl for device */
2503
2504     tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2505     if (!tcell) return ENOENT;
2506     bcopy(ain, (char *)&temp, sizeof(afs_int32));
2507     if (temp & CNoSUID)
2508         tcell->states |= CNoSUID;
2509     else
2510         tcell->states &= ~CNoSUID;
2511     afs_PutCell(tcell, WRITE_LOCK);
2512     return 0;
2513 }
2514
2515 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2516 struct vcache *avc;
2517 int afun;
2518 struct vrequest *areq;
2519 char *ain, *aout;
2520 afs_int32 ainSize;
2521 afs_int32 *aoutSize;    /* set this */ 
2522 struct AFS_UCRED *acred;
2523 {
2524     extern struct volume *afs_volumes[NVOLS];
2525     register afs_int32 i;
2526     register struct dcache *tdc;
2527     register struct vcache *tvc;
2528     register struct volume *tv;
2529     afs_int32 cell, volume;
2530
2531     AFS_STATCNT(PFlushVolumeData);
2532     if (!avc)
2533         return EINVAL;
2534     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2535         return EIO;          /* Inappropriate ioctl for device */
2536
2537     volume = avc->fid.Fid.Volume;  /* who to zap */
2538     cell = avc->fid.Cell;
2539
2540     /* 
2541      * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2542      * the vcaches associated with the volume.
2543      */
2544     ObtainReadLock(&afs_xvcache);
2545     for(i = 0; i < VCSIZE; i++) {
2546         for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2547             if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2548 #if     defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV)  || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV)
2549                 VN_HOLD((struct vnode *)tvc);
2550 #else
2551 #if defined(AFS_DARWIN_ENV)
2552                 osi_vnhold(tvc, 0);
2553 #else
2554                 tvc->vrefCount++;
2555 #endif
2556 #endif
2557                 ReleaseReadLock(&afs_xvcache);
2558 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2559                 afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
2560 #endif
2561                 ObtainWriteLock(&tvc->lock,232);
2562
2563                 ObtainWriteLock(&afs_xcbhash, 458);
2564                 afs_DequeueCallback(tvc);
2565                 tvc->states &= ~(CStatd | CDirty);
2566                 ReleaseWriteLock(&afs_xcbhash);
2567                 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2568                     osi_dnlc_purgedp(tvc);
2569                 afs_TryToSmush(tvc, acred, 1);
2570                 ReleaseWriteLock(&tvc->lock);
2571 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2572                 afs_BozonUnlock(&tvc->pvnLock, tvc);
2573 #endif
2574                 ObtainReadLock(&afs_xvcache);
2575                 /* our tvc ptr is still good until now */
2576                 AFS_FAST_RELE(tvc);
2577             }
2578         }
2579     }
2580     ReleaseReadLock(&afs_xvcache);
2581
2582
2583     MObtainWriteLock(&afs_xdcache,328);  /* needed if you're going to flush any stuff */
2584     for(i=0;i<afs_cacheFiles;i++) {
2585         if (!(afs_indexFlags[i] & IFEverUsed)) continue;        /* never had any data */
2586         tdc = afs_GetDSlot(i, (struct dcache *) 0);
2587         if (tdc->refCount <= 1) {    /* too high, in use by running sys call */
2588             if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2589                 if (! (afs_indexFlags[i] & IFDataMod)) {
2590                     /* if the file is modified, but has a ref cnt of only 1, then
2591                        someone probably has the file open and is writing into it.
2592                        Better to skip flushing such a file, it will be brought back
2593                        immediately on the next write anyway.
2594
2595                        If we *must* flush, then this code has to be rearranged to call
2596                        afs_storeAllSegments() first */
2597                         afs_FlushDCache(tdc);
2598                 }
2599             }
2600         }
2601         tdc->refCount--;        /* bumped by getdslot */
2602     }
2603     MReleaseWriteLock(&afs_xdcache);
2604
2605     ObtainReadLock(&afs_xvolume);
2606     for (i=0;i<NVOLS;i++) {
2607         for (tv = afs_volumes[i]; tv; tv=tv->next) {
2608             if (tv->volume == volume) {
2609                 afs_ResetVolumeInfo(tv);
2610                 break;
2611             }
2612         }
2613     }
2614     ReleaseReadLock(&afs_xvolume);
2615
2616     /* probably, a user is doing this, probably, because things are screwed up. 
2617      * maybe it's the dnlc's fault? */
2618     osi_dnlc_purge();  
2619     return 0;
2620 }
2621
2622
2623
2624 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2625     struct vcache *avc;
2626     int afun;
2627     struct vrequest *areq;
2628     char *ain, *aout;
2629     afs_int32 ainSize;
2630     afs_int32 *aoutSize;        /* set this */ {
2631     register afs_int32 code;
2632     struct vcxstat stat;
2633     afs_int32 mode, i;
2634     
2635 /*  AFS_STATCNT(PGetVnodeXStatus); */
2636     if (!avc) return EINVAL;
2637     code = afs_VerifyVCache(avc, areq);
2638     if (code) return code;
2639     if (vType(avc) == VDIR)
2640         mode = PRSFS_LOOKUP;
2641     else
2642         mode = PRSFS_READ;
2643     if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2644         return EACCES;    
2645     stat.fid = avc->fid;
2646     hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2647     stat.lock = avc->lock;
2648     stat.parentVnode = avc->parentVnode;
2649     stat.parentUnique = avc->parentUnique;
2650     hset(stat.flushDV, avc->flushDV);
2651     hset(stat.mapDV, avc->mapDV);
2652     stat.truncPos = avc->truncPos;
2653     { /* just grab the first two - won't break anything... */
2654       struct axscache *ac;
2655
2656       for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2657         stat.randomUid[i] = ac->uid;
2658         stat.randomAccess[i] = ac->axess;
2659       }
2660     }
2661     stat.callback = afs_data_pointer_to_int32(avc->callback);
2662     stat.cbExpires = avc->cbExpires;
2663     stat.anyAccess = avc->anyAccess;
2664     stat.opens = avc->opens;
2665     stat.execsOrWriters = avc->execsOrWriters;
2666     stat.flockCount = avc->flockCount;
2667     stat.mvstat = avc->mvstat;
2668     stat.states = avc->states;
2669     bcopy((char *)&stat, aout, sizeof(struct vcxstat));
2670     *aoutSize = sizeof(struct vcxstat);
2671     return 0;
2672 }
2673
2674
2675 /* We require root for local sysname changes, but not for remote */
2676 /* (since we don't really believe remote uids anyway) */
2677  /* outname[] shouldn't really be needed- this is left as an excercise */
2678  /* for the reader.  */
2679
2680 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2681 struct vcache *avc;
2682 int afun;
2683 struct vrequest *areq;
2684 char *ain, *aout;
2685 afs_int32 ainSize;
2686 afs_int32 *aoutSize;    /* set this */
2687 register struct AFS_UCRED *acred;
2688 {
2689     char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2690     int setsysname, foundname=0;
2691     register struct afs_exporter *exporter;
2692     extern struct unixuser *afs_FindUser();
2693     extern char *afs_sysname;
2694     register struct unixuser *au;
2695     register afs_int32 pag, error;
2696     int t;
2697
2698
2699     AFS_STATCNT(PSetSysName);
2700     if (!afs_globalVFS) {
2701       /* Afsd is NOT running; disable it */
2702 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV)
2703         return (EINVAL);
2704 #else
2705         return (setuerror(EINVAL), EINVAL);
2706 #endif
2707     }
2708     bzero(inname, MAXSYSNAME);
2709     bcopy(ain, (char *)&setsysname, sizeof(afs_int32));
2710     ain += sizeof(afs_int32);
2711     if (setsysname) {
2712       t = strlen(ain);
2713       if (t > MAXSYSNAME)
2714         return EINVAL;
2715       bcopy(ain, inname, t+1);  /* include terminating null */
2716       ain += t + 1;
2717     }
2718     if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2719         pag = PagInCred(acred);
2720         if (pag == NOPAG) {
2721             return EINVAL;  /* Better than panicing */
2722         }
2723         if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2724             return EINVAL;  /* Better than panicing */
2725         }
2726         if (!(exporter = au->exporter)) {
2727             afs_PutUser(au, READ_LOCK);
2728             return EINVAL;  /* Better than panicing */
2729         }
2730         error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2731         if (error) {
2732             if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2733             else {
2734                 afs_PutUser(au, READ_LOCK);
2735                 return error;
2736             }
2737         }
2738         else foundname = 1;
2739         afs_PutUser(au, READ_LOCK);
2740     } else {
2741         if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2742         if (!setsysname) {
2743             strcpy(outname, afs_sysname);
2744             foundname = 1;
2745         } else {
2746             if (!afs_osi_suser(acred))     /* Local guy; only root can change sysname */
2747                 return EACCES;
2748             strcpy(afs_sysname, inname);
2749         }
2750     }
2751     if (!setsysname) {
2752         cp = aout;
2753         bcopy((char *)&foundname, cp, sizeof(afs_int32));
2754         cp += sizeof(afs_int32);
2755         if (foundname) {
2756             strcpy(cp, outname);
2757             cp += strlen(outname)+1;
2758         }
2759         *aoutSize = cp - aout;
2760     }
2761     return 0;
2762 }
2763
2764 /* sequential search through the list of touched cells is not a good
2765  * long-term solution here. For small n, though, it should be just
2766  * fine.  Should consider special-casing the local cell for large n.
2767  * Likewise for PSetSPrefs.
2768  */
2769 static void ReSortCells(s,l, vlonly)  
2770   int s;     /* number of ids in array l[] -- NOT index of last id */
2771   afs_int32 l[];  /* array of cell ids which have volumes that need to be sorted */
2772   int vlonly; /* sort vl servers or file servers?*/
2773 {
2774   extern struct volume *afs_volumes[NVOLS];   /* volume hash table */
2775
2776   int i;
2777   struct volume *j;
2778   register int  k;
2779
2780   if (vlonly) {
2781      struct cell *tcell;
2782      for(k=0;k<s;k++) {
2783         tcell = afs_GetCell(l[k], WRITE_LOCK);
2784         if (!tcell) continue;
2785         afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2786         afs_PutCell(tcell, WRITE_LOCK);
2787      }
2788      return;
2789   }
2790
2791   ObtainReadLock(&afs_xvolume);
2792   for (i= 0; i< NVOLS; i++) {
2793      for (j=afs_volumes[i];j;j=j->next) {
2794         for (k=0;k<s;k++)
2795            if (j->cell == l[k]) {
2796               ObtainWriteLock(&j->lock,233);
2797               afs_SortServers(j->serverHost, MAXHOSTS);
2798               ReleaseWriteLock(&j->lock);
2799               break; 
2800            }
2801      }
2802   }
2803   ReleaseReadLock(&afs_xvolume);
2804 }
2805
2806 int debugsetsp = 0;
2807
2808 static int afs_setsprefs(sp, num, vlonly)
2809    struct spref *sp;
2810    unsigned int num;
2811    unsigned int vlonly;
2812 {
2813    struct srvAddr *sa;
2814    int i,j,k,matches,touchedSize;
2815    struct server *srvr = NULL;
2816    afs_int32 touched[34];
2817    int isfs;
2818    
2819    touchedSize=0;
2820    for (k=0; k < num; sp++, k++) { 
2821       if (debugsetsp) {
2822          printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2823       }
2824       matches=0;
2825       ObtainReadLock(&afs_xserver);
2826       
2827       i = SHash(sp->host.s_addr);
2828       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2829          if (sa->sa_ip == sp->host.s_addr) {
2830             srvr = sa->server;
2831             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
2832                    || (sa->sa_portal == AFS_FSPORT); 
2833             if ((!vlonly && isfs) || (vlonly && !isfs)) {
2834                matches++;
2835                break;
2836             }
2837          }
2838       }
2839       
2840       if (sa && matches) {  /* found one! */
2841          if (debugsetsp) {
2842             printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
2843          }
2844          sa->sa_iprank = sp->rank + afs_randomMod15();
2845          afs_SortOneServer(sa->server);
2846          
2847          if (srvr->cell) {
2848            /* if we don't know yet what cell it's in, this is moot */
2849            for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
2850                  /* is it in our list of touched cells ?  */ ;
2851            if (j < 0) {                   /* no, it's not */
2852              touched[touchedSize++] = srvr->cell->cell;
2853              if (touchedSize >= 32) {                /* watch for ovrflow */
2854                ReleaseReadLock(&afs_xserver);
2855                ReSortCells(touchedSize, touched, vlonly);
2856                touchedSize=0;
2857                ObtainReadLock(&afs_xserver);
2858              }
2859            }
2860          }
2861       }
2862       
2863       ReleaseReadLock(&afs_xserver);
2864       /* if we didn't find one, start to create one. */
2865       /* Note that it doesn't have a cell yet...     */
2866       if (!matches) {
2867          afs_uint32 temp = sp->host.s_addr;
2868          srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT), 
2869                               WRITE_LOCK, (afsUUID *)0,0);
2870          srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
2871          afs_PutServer(srvr, WRITE_LOCK);
2872       }
2873    } /* for all cited preferences */
2874    
2875    ReSortCells(touchedSize, touched, vlonly);
2876    return 0;
2877 }
2878
2879  /* Note that this may only be performed by the local root user.
2880  */
2881 static int 
2882 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2883      struct vcache *avc;
2884      int afun;
2885      struct vrequest *areq;
2886      char *ain, *aout;
2887      afs_int32 ainSize;
2888      struct AFS_UCRED *acred;
2889      afs_int32 *aoutSize;
2890 {
2891   struct setspref *ssp;
2892   AFS_STATCNT(PSetSPrefs);
2893
2894   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
2895         return EIO;          /* Inappropriate ioctl for device */
2896
2897   if (!afs_osi_suser(acred))
2898       return EACCES;
2899
2900   if (ainSize < sizeof(struct setspref)) 
2901     return EINVAL;
2902
2903   ssp = (struct setspref *)ain;
2904   if (ainSize < sizeof(struct spref)*ssp->num_servers) 
2905     return EINVAL;
2906
2907   afs_setsprefs(&(ssp->servers[0]), ssp->num_servers, 
2908                 (ssp->flags & DBservers));
2909   return 0;
2910 }
2911
2912 static int 
2913 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2914     struct vcache *avc;
2915     int afun;
2916     struct vrequest *areq;
2917     char *ain, *aout;
2918     afs_int32 ainSize;
2919     struct AFS_UCRED *acred;
2920     afs_int32 *aoutSize;
2921 {
2922   struct spref *sp;
2923   AFS_STATCNT(PSetSPrefs);
2924   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
2925         return EIO;          /* Inappropriate ioctl for device */
2926
2927
2928   if (!afs_osi_suser(acred))
2929     return EACCES;
2930
2931   sp = (struct spref *)ain;
2932   afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
2933   return 0;
2934 }
2935
2936 /* some notes on the following code...
2937  * in the hash table of server structs, all servers with the same IP address
2938  * will be on the same overflow chain.  
2939  * This could be sped slightly in some circumstances by having it cache the 
2940  * immediately previous slot in the hash table and some supporting information
2941  * Only reports file servers now.
2942  */
2943 static int 
2944      PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
2945 struct vcache *avc;
2946 int afun;
2947 struct vrequest *areq;
2948 char *ain, *aout;
2949 afs_int32 ainSize;
2950 afs_int32 *aoutSize;
2951 {
2952    struct sprefrequest *spin; /* input */
2953    struct sprefinfo *spout;   /* output */
2954    struct spref *srvout;      /* one output component */
2955    int i,j;                   /* counters for hash table traversal */
2956    struct server *srvr;       /* one of CM's server structs */
2957    struct srvAddr *sa;
2958    afs_uint32 prevh;
2959    int vlonly;                /* just return vlservers ? */
2960    int isfs;
2961    
2962    AFS_STATCNT(PGetSPrefs);
2963    if ( !afs_resourceinit_flag )        /* afs deamons havn't started yet */
2964         return EIO;          /* Inappropriate ioctl for device */
2965
2966    
2967    if (ainSize < sizeof (struct sprefrequest_33)) {
2968       return ENOENT;
2969    }
2970    else {
2971       spin = ((struct sprefrequest *) ain);
2972    }
2973    
2974    if (ainSize > sizeof  (struct sprefrequest_33)) {
2975       vlonly = (spin->flags & DBservers);
2976    }
2977    else vlonly = 0;
2978    
2979    /* struct sprefinfo includes 1 server struct...  that size gets added
2980     * in during the loop that follows.
2981     */
2982    *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
2983    spout = (struct sprefinfo *) aout;
2984    spout->next_offset = spin->offset;
2985    spout->num_servers = 0;
2986    srvout = spout->servers;
2987    
2988    ObtainReadLock(&afs_xserver);
2989    for (i=0, j=0; j < NSERVERS; j++) {       /* sift through hash table */
2990       for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
2991          if (spin->offset > (unsigned short)i) {
2992             continue;                /* catch up to where we left off */
2993          }
2994             spout->next_offset++;
2995          
2996             srvr = sa->server;
2997             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
2998                  || (sa->sa_portal == AFS_FSPORT); 
2999          
3000             if ((vlonly && isfs) || (!vlonly && !isfs)) {
3001                /* only report ranks for vl servers */
3002                continue;
3003             }
3004          
3005          srvout->host.s_addr = sa->sa_ip;
3006          srvout->rank = sa->sa_iprank;
3007          *aoutSize += sizeof(struct spref);
3008          spout->num_servers++;
3009          srvout++;
3010
3011          if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3012             ReleaseReadLock(&afs_xserver);                /* no more room! */
3013             return 0;
3014          }
3015       }
3016    }
3017    ReleaseReadLock(&afs_xserver);
3018    
3019    spout->next_offset = 0;  /* start over from the beginning next time */
3020    return 0;
3021 }
3022
3023 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3024 int  afs_NFSRootOnly = 1;
3025 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3026 struct vcache *avc;
3027 int afun;
3028 struct vrequest *areq;
3029 char *ain, *aout;
3030 afs_int32 ainSize;
3031 afs_int32 *aoutSize;    /* set this */
3032 struct AFS_UCRED *acred;
3033 {
3034     afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3035     extern struct afs_exporter *exporter_find();
3036     register struct afs_exporter *exporter;
3037
3038     AFS_STATCNT(PExportAfs);
3039     bcopy(ain, (char *)&handleValue, sizeof(afs_int32));
3040     type = handleValue >> 24;
3041     if (type == 0x71) {
3042         newint = 1;
3043         type = 1;       /* nfs */
3044     }
3045     exporter = exporter_find(type);
3046     if (newint) {
3047         export = handleValue & 3;
3048         changestate = handleValue & 0xff;
3049         smounts = (handleValue >> 2) & 3;
3050         pwsync = (handleValue >> 4) & 3;
3051         convmode = (handleValue >> 6) & 3;
3052     } else {
3053         changestate = (handleValue >> 16) & 0x1;
3054         convmode = (handleValue >> 16) & 0x2;
3055         pwsync = (handleValue >> 16) & 0x4;
3056         smounts = (handleValue >> 16) & 0x8;
3057         export = handleValue & 0xff;
3058     }
3059     if (!exporter) {
3060         /*  Failed finding desired exporter; */
3061         return ENODEV;
3062     }
3063     if (!changestate) {
3064         handleValue = exporter->exp_states;
3065         bcopy((char *)&handleValue, aout, sizeof(afs_int32));
3066         *aoutSize = sizeof(afs_int32);
3067     } else {
3068         if (!afs_osi_suser(acred))
3069             return EACCES;    /* Only superuser can do this */
3070         if (newint) {
3071             if (export & 2) {
3072                 if (export & 1)
3073                     exporter->exp_states |= EXP_EXPORTED;
3074                 else
3075                     exporter->exp_states &= ~EXP_EXPORTED;
3076             }
3077             if (convmode & 2) {
3078                 if (convmode & 1)
3079                     exporter->exp_states |= EXP_UNIXMODE;
3080                 else
3081                     exporter->exp_states &= ~EXP_UNIXMODE;
3082             }
3083             if (pwsync & 2) {
3084                 if (pwsync & 1)
3085                     exporter->exp_states |= EXP_PWSYNC;
3086                 else
3087                     exporter->exp_states &= ~EXP_PWSYNC;
3088             }
3089             if (smounts & 2) {
3090                 if (smounts & 1) {
3091                     afs_NFSRootOnly = 0;
3092                     exporter->exp_states |= EXP_SUBMOUNTS;
3093                 } else {
3094                     afs_NFSRootOnly = 1;
3095                     exporter->exp_states &= ~EXP_SUBMOUNTS;
3096                 }
3097             }
3098             handleValue = exporter->exp_states;
3099             bcopy((char *)&handleValue, aout, sizeof(afs_int32));
3100             *aoutSize = sizeof(afs_int32);
3101         } else {
3102             if (export)
3103                 exporter->exp_states |= EXP_EXPORTED;
3104             else
3105                 exporter->exp_states &= ~EXP_EXPORTED;
3106             if (convmode)
3107                 exporter->exp_states |= EXP_UNIXMODE;
3108             else
3109                 exporter->exp_states &= ~EXP_UNIXMODE;
3110             if (pwsync)
3111                 exporter->exp_states |= EXP_PWSYNC;
3112             else
3113                 exporter->exp_states &= ~EXP_PWSYNC;
3114             if (smounts) {
3115                 afs_NFSRootOnly = 0;
3116                 exporter->exp_states |= EXP_SUBMOUNTS;
3117             } else {
3118                 afs_NFSRootOnly = 1;
3119                 exporter->exp_states &= ~EXP_SUBMOUNTS;
3120             }
3121         }
3122     }
3123
3124     return 0;
3125 }
3126
3127 static int
3128 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3129 struct vcache *avc;
3130 int afun;
3131 struct vrequest *areq;
3132 char *ain, *aout;
3133 afs_int32 ainSize;
3134 struct AFS_UCRED *acred;
3135 afs_int32 *aoutSize;    /* set this */
3136 {
3137 struct gaginfo *gagflags;
3138
3139   if (!afs_osi_suser(acred))
3140     return EACCES;
3141
3142   gagflags = (struct gaginfo *) ain;
3143   afs_showflags = gagflags->showflags;
3144
3145   return 0;
3146 }
3147
3148
3149 static int
3150 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3151 struct vcache *avc;
3152 int afun;
3153 struct vrequest *areq;
3154 char *ain, *aout;
3155 afs_int32 ainSize;
3156 struct AFS_UCRED *acred;
3157 afs_int32 *aoutSize;    
3158 {
3159   struct rxparams *rxp;
3160
3161   if (!afs_osi_suser(acred))
3162     return EACCES;
3163
3164   rxp = (struct rxparams *) ain;
3165
3166   if (rxp->rx_initReceiveWindow)
3167     rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3168   if (rxp->rx_maxReceiveWindow)
3169     rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3170   if (rxp->rx_initSendWindow)
3171     rx_initSendWindow = rxp->rx_initSendWindow;
3172   if (rxp->rx_maxSendWindow)
3173     rx_maxSendWindow = rxp->rx_maxSendWindow;
3174   if (rxp->rxi_nSendFrags)
3175     rxi_nSendFrags = rxp->rxi_nSendFrags;
3176   if (rxp->rxi_nRecvFrags)
3177     rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3178   if (rxp->rxi_OrphanFragSize)
3179     rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3180   if (rxp->rx_maxReceiveSize)
3181   {
3182     rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3183     rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3184   }
3185   if (rxp->rx_MyMaxSendSize)
3186     rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3187  
3188   return 0;
3189 }
3190
3191 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3192      struct vcache *avc;
3193      int afun;
3194      struct vrequest *areq;
3195      register char *ain;
3196      char *aout;
3197      afs_int32 ainSize;
3198      afs_int32 *aoutSize;       /* set this */
3199 {
3200     if (sizeof(struct cm_initparams) > PIGGYSIZE)
3201         return E2BIG;
3202
3203     bcopy((char*)&cm_initParams, aout, sizeof(struct cm_initparams));
3204     *aoutSize = sizeof(struct cm_initparams);
3205     return 0;
3206 }
3207
3208 #ifdef AFS_SGI65_ENV
3209 /* They took crget() from us, so fake it. */
3210 static cred_t *crget(void)
3211 {
3212     cred_t *cr;
3213     cr = crdup(get_current_cred());
3214     bzero((char*)cr, sizeof(cred_t));
3215 #if CELL || CELL_PREPARE
3216     cr->cr_id = -1;
3217 #endif
3218     return cr;
3219 }
3220 #endif
3221
3222 static int
3223 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3224 struct vcache *avc;
3225 int afun;
3226 struct vrequest *areq;
3227 char *ain, *aout;
3228 afs_int32 ainSize;
3229 afs_int32 *aoutSize;
3230 struct AFS_UCRED *acred;
3231 {
3232     bcopy((char *)&cryptall, aout, sizeof(afs_int32));
3233     *aoutSize=sizeof(afs_int32);
3234     return 0;
3235 }
3236
3237 static int
3238 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3239 struct vcache *avc;
3240 int afun;
3241 struct vrequest *areq;
3242 char *ain, *aout;
3243 afs_int32 ainSize;
3244 afs_int32 *aoutSize;
3245 struct AFS_UCRED *acred;
3246 {
3247     afs_int32 tmpval;
3248
3249     if (!afs_osi_suser(acred))
3250       return EPERM;
3251     if (ainSize != sizeof(afs_int32) || ain == NULL)
3252       return EINVAL;
3253     bcopy(ain, (char *)&tmpval, sizeof(afs_int32));
3254     /* if new mappings added later this will need to be changed */
3255     if (tmpval != 0 && tmpval != 1)
3256       return EINVAL;
3257     cryptall = tmpval;
3258     return 0;
3259 }
3260
3261 /*
3262  * Create new credentials to correspond to a remote user with given
3263  * <hostaddr, uid, g0, g1>.  This allows a server running as root to
3264  * provide pioctl (and other) services to foreign clients (i.e. nfs
3265  * clients) by using this call to `become' the client.
3266  */
3267 #define PSETPAG         110
3268 #define PIOCTL_HEADER   6
3269 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3270 {
3271     char *ain, *inData;
3272     afs_uint32 hostaddr;
3273     afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3274     extern struct afs_exporter *exporter_find();
3275     struct afs_exporter *exporter, *outexporter;
3276     struct AFS_UCRED *newcred;
3277     struct unixuser *au;
3278
3279 #if     defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3280     return EINVAL;                      /* NFS trans not supported for Ultrix */
3281 #else
3282 #if defined(AFS_SGIMP_ENV)
3283     osi_Assert(ISAFS_GLOCK());
3284 #endif
3285     AFS_STATCNT(HandleClientContext);
3286     if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) { 
3287         /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3288         return EINVAL; /* Too small to be good  */
3289     }
3290     ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3291     AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3292     if (code) {
3293         osi_FreeLargeSpace(inData);
3294         return code;
3295     }
3296
3297     /* Extract information for remote user */
3298     hostaddr = *((afs_uint32 *)ain);
3299     ain += sizeof(hostaddr);
3300     uid = *((afs_uint32 *)ain);
3301     ain += sizeof(uid);
3302     g0 = *((afs_uint32 *)ain);
3303     ain += sizeof(g0);
3304     g1 = *((afs_uint32 *)ain);
3305     ain += sizeof(g1);
3306     *com = *((afs_uint32 *)ain);
3307     ain += sizeof(afs_int32);
3308     exporter_type = *((afs_uint32 *)ain);       /* In case we support more than NFS */
3309
3310     /*
3311      * Of course, one must be root for most of these functions, but
3312      * we'll allow (for knfs) you to set things if the pag is 0 and
3313      * you're setting tokens or unlogging.
3314      */
3315     i = (*com) & 0xff;
3316     if (!afs_osi_suser(credp)) {
3317 #ifdef  AFS_SGI_ENV 
3318 #ifndef AFS_SGI64_ENV
3319         /* Since SGI's suser() returns explicit failure after the call.. */
3320         u.u_error = 0;          
3321 #endif 
3322 #endif
3323         /* check for acceptable opcodes for normal folks, which are, so far,
3324          * set tokens and unlog.
3325          */
3326         if (i != 9 && i != 3 && i != 38 && i != 8)      {
3327             osi_FreeLargeSpace(inData);
3328             return EACCES;
3329         }
3330     }
3331
3332     ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3333     ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3334     osi_FreeLargeSpace(inData);
3335     if (uid == 0) {
3336         /*
3337          * We map uid 0 to nobody to match the mapping that the nfs
3338          * server does and to ensure that the suser() calls in the afs
3339          * code fails for remote client roots.
3340          */
3341         uid = afs_nobody;       /* NFS_NOBODY == -2 */
3342     }
3343     newcred = crget();
3344 #ifdef  AFS_AIX41_ENV
3345     setuerror(0);       
3346 #endif
3347     newcred->cr_gid = RMTUSER_REQ;
3348     newcred->cr_groups[0] = g0;
3349     newcred->cr_groups[1] = g1;
3350 #ifdef AFS_AIX_ENV
3351     newcred->cr_ngrps = 2;
3352 #else
3353 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3354     newcred->cr_ngroups = 2;
3355 #else
3356     for (i=2; i<NGROUPS; i++)
3357         newcred->cr_groups[i] = NOGROUP;
3358 #endif
3359 #endif
3360 #if     !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3361     afs_nfsclient_init();       /* before looking for exporter, ensure one exists */
3362 #endif
3363     if (!(exporter = exporter_find(exporter_type))) {
3364         /* Exporter wasn't initialized or an invalid exporter type */
3365          crfree(newcred);
3366          return EINVAL;
3367     }
3368     if (exporter->exp_states & EXP_PWSYNC) {
3369         if (uid != credp->cr_uid) {
3370             crfree(newcred);
3371             return ENOEXEC;     /* XXX Find a better errno XXX */
3372         }
3373     }
3374     newcred->cr_uid = uid; /* Only temporary  */
3375     code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3376     /* The client's pag is the only unique identifier for it */
3377     newcred->cr_uid = pag;
3378     *acred = newcred;
3379     if (!code && *com == PSETPAG) {
3380       /* Special case for 'setpag' */
3381       afs_uint32 pagvalue = genpag();
3382
3383       au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3384       /*
3385        * Note that we leave the 'outexporter' struct held so it won't
3386        * dissappear on us
3387        */
3388       au->exporter = outexporter;
3389       if (ablob->out_size >= 4) {
3390         AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3391       }
3392       afs_PutUser(au, WRITE_LOCK);
3393       if (code) return code;
3394       return PSETPAG;           /*  Special return for setpag  */
3395     } else if (!code) {
3396         EXP_RELE(outexporter);
3397     }
3398     return code;
3399 #endif  /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3400 }
3401
3402 /* get all interface addresses of this client */
3403
3404 static int
3405 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3406 struct vcache *avc;
3407 int afun;
3408 struct vrequest *areq;
3409 char *ain, *aout;
3410 afs_int32 ainSize;
3411 afs_int32 *aoutSize;
3412 {
3413         struct sprefrequest *spin; /* input */
3414         struct sprefinfo *spout;   /* output */
3415         struct spref *srvout;      /* one output component */
3416         int maxNumber;
3417         int i,j;
3418
3419         AFS_STATCNT(PGetCPrefs);
3420         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3421             return EIO;          /* Inappropriate ioctl for device */
3422
3423         if ( ainSize < sizeof (struct sprefrequest ))
3424                 return EINVAL;
3425         
3426         spin = (struct sprefrequest *) ain;
3427         spout = (struct sprefinfo *) aout;
3428
3429         maxNumber = spin->num_servers; /* max addrs this time */
3430         srvout = spout->servers;
3431
3432         ObtainReadLock(&afs_xinterface);
3433
3434         /* copy out the client interface information from the
3435         ** kernel data structure "interface" to the output buffer
3436         */
3437         for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3438                                    && ( j< maxNumber) ; i++, j++, srvout++)
3439                 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3440         
3441         spout->num_servers = j;
3442         *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3443
3444         if ( i >= afs_cb_interface.numberOfInterfaces )
3445                 spout->next_offset = 0; /* start from beginning again */
3446         else
3447                 spout->next_offset = spin->offset + j;
3448         
3449         ReleaseReadLock(&afs_xinterface);
3450         return 0;
3451 }
3452
3453 static int
3454 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3455 struct vcache *avc;
3456 int afun;
3457 struct vrequest *areq;
3458 char *ain, *aout;
3459 afs_int32 ainSize;
3460 afs_int32 *aoutSize;
3461 {
3462         struct setspref *sin;
3463         int i;
3464
3465         AFS_STATCNT(PSetCPrefs);
3466         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3467             return EIO;          /* Inappropriate ioctl for device */
3468
3469         sin = (struct setspref *)ain;
3470
3471         if ( ainSize < sizeof(struct setspref) )
3472                 return EINVAL;
3473 #if 0   /* num_servers is unsigned */
3474         if ( sin->num_servers < 0 )
3475                 return EINVAL;
3476 #endif
3477         if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3478                 return ENOMEM;
3479
3480         ObtainWriteLock(&afs_xinterface, 412);
3481         afs_cb_interface.numberOfInterfaces = sin->num_servers;
3482         for ( i=0; (unsigned short)i < sin->num_servers; i++)
3483                 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3484
3485         ReleaseWriteLock(&afs_xinterface);
3486         return 0;
3487 }
3488
3489 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3490     struct vcache *avc;
3491     int afun;
3492     struct vrequest *areq;
3493     char *ain, *aout;
3494     afs_int32 ainSize;
3495     afs_int32 *aoutSize;
3496     struct AFS_UCRED *acred; {
3497     register afs_int32 code;
3498     register struct vcache *tvc;
3499     register struct dcache *tdc;
3500     struct VenusFid tfid;
3501     char *bufp = 0;
3502     afs_int32 offset, len, hasatsys=0;
3503
3504     AFS_STATCNT(PFlushMount);
3505     if (!avc) return EINVAL;
3506     code = afs_VerifyVCache(avc, areq);
3507     if (code) return code;
3508     if (vType(avc) != VDIR) {
3509         return ENOTDIR;
3510     }
3511     tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
3512     if (!tdc) return ENOENT;
3513     hasatsys = Check_AtSys(avc, ain, &bufp, areq);
3514     code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
3515     if (code) {
3516         afs_PutDCache(tdc);
3517         goto out;
3518     }
3519     tfid.Cell = avc->fid.Cell;
3520     tfid.Fid.Volume = avc->fid.Fid.Volume;
3521     afs_PutDCache(tdc);     /* we're done with the data */
3522     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3523         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3524     } else {
3525         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3526                             WRITE_LOCK);
3527     }
3528     if (!tvc) {
3529         code = ENOENT;
3530         goto out;
3531     }
3532     if (vType(tvc) != VLNK) {
3533         afs_PutVCache(tvc, WRITE_LOCK);
3534         code = EINVAL;
3535         goto out;
3536     }
3537 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3538     afs_BozonLock(&tvc->pvnLock, tvc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
3539 #endif
3540     ObtainWriteLock(&tvc->lock,645);
3541     ObtainWriteLock(&afs_xcbhash, 646);
3542     afs_DequeueCallback(tvc);
3543     tvc->states &= ~(CStatd | CDirty);  /* next reference will re-stat cache entry */
3544     ReleaseWriteLock(&afs_xcbhash);
3545     /* now find the disk cache entries */
3546     afs_TryToSmush(tvc, acred, 1);
3547     osi_dnlc_purgedp(tvc);
3548     afs_symhint_inval(tvc);
3549     if (tvc->linkData && !(tvc->states & CCore)) {
3550         afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3551         tvc->linkData = (char *) 0;
3552     }
3553     ReleaseWriteLock(&tvc->lock);
3554 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3555     afs_BozonUnlock(&tvc->pvnLock, tvc);
3556 #endif
3557     afs_PutVCache(tvc, WRITE_LOCK);
3558 out:
3559     if (hasatsys) osi_FreeLargeSpace(bufp);
3560     return code;
3561 }
3562
3563 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3564     struct vcache *avc;
3565     int afun;
3566     struct vrequest *areq;
3567     char *ain, *aout;
3568     afs_int32 ainSize;
3569     afs_int32 *aoutSize;
3570     struct AFS_UCRED *acred;
3571 {
3572     int code = 0;
3573     afs_int32 flags;
3574
3575     if (!afs_osi_suser(acred)) {
3576         code = EACCES;
3577         goto out;
3578     }
3579     if (ainSize != sizeof(afs_int32)) {
3580         code = EINVAL;
3581         goto out;
3582     }
3583     bcopy(ain, (char *)&flags, sizeof(afs_int32));
3584     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3585         code = EINVAL;
3586         goto out;
3587     }
3588     if (flags & AFSCALL_RXSTATS_ENABLE) {
3589         rx_enableProcessRPCStats();
3590     }
3591     if (flags & AFSCALL_RXSTATS_DISABLE) {
3592         rx_disableProcessRPCStats();
3593     }
3594     if (flags & AFSCALL_RXSTATS_CLEAR) {
3595         rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3596     }
3597 out:
3598     *aoutSize = 0;
3599     return code;
3600 }
3601
3602
3603 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3604     struct vcache *avc;
3605     int afun;
3606     struct vrequest *areq;
3607     char *ain, *aout;
3608     afs_int32 ainSize;
3609     afs_int32 *aoutSize;
3610     struct AFS_UCRED *acred;
3611 {
3612     int code = 0;
3613     afs_int32 flags;
3614
3615     if (!afs_osi_suser(acred)) {
3616         code = EACCES;
3617         goto out;
3618     }
3619     if (ainSize != sizeof(afs_int32)) {
3620         code = EINVAL;
3621         goto out;
3622     }
3623     bcopy(ain, (char *)&flags, sizeof(afs_int32));
3624     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3625         code = EINVAL;
3626         goto out;
3627     }
3628     if (flags & AFSCALL_RXSTATS_ENABLE) {
3629         rx_enablePeerRPCStats();
3630     }
3631     if (flags & AFSCALL_RXSTATS_DISABLE) {
3632         rx_disablePeerRPCStats();
3633     }
3634     if (flags & AFSCALL_RXSTATS_CLEAR) {
3635         rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3636     }
3637 out:
3638     *aoutSize = 0;
3639     return code;
3640 }
3641
3642 static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
3643   struct vcache *avc;
3644   int afun;
3645   struct vrequest *areq;
3646   char *ain, *aout;
3647   afs_int32 ainSize;
3648   afs_int32 *aoutSize;  /* set this */
3649 {
3650     register afs_int32 code, code1;
3651     afs_int32 bytes;
3652     struct conn *tc;
3653     struct rx_call *tcall;
3654     struct AFSVolSync tsync;
3655     struct AFSFetchStatus OutStatus;
3656     struct AFSCallBack CallBack;
3657     struct VenusFid tfid;
3658     struct AFSFid *Fid;
3659     struct vcache *tvc;
3660     XSTATS_DECLS;
3661
3662     AFS_STATCNT(PSetAcl);
3663     if (!avc)
3664       return EINVAL;
3665
3666     if (ain && (ainSize == 3 * sizeof(afs_int32)))
3667         Fid = (struct AFSFid *) ain;
3668     else
3669         Fid = &avc->fid.Fid;
3670     tfid.Cell = avc->fid.Cell;
3671     tfid.Fid.Volume = Fid->Volume;
3672     tfid.Fid.Vnode = Fid->Vnode;
3673     tfid.Fid.Unique = Fid->Unique;
3674
3675     tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3676                                 WRITE_LOCK);
3677     if (!tvc) {
3678         afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3679                 ICL_TYPE_POINTER, tvc,
3680                 ICL_TYPE_FID, &tfid,
3681                 ICL_TYPE_FID, &avc->fid);
3682         return ENOENT;
3683     }
3684     afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3685                 ICL_TYPE_POINTER, tvc,
3686                 ICL_TYPE_FID, &tfid,
3687                 ICL_TYPE_FID, &tvc->fid);
3688
3689     do {
3690         tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3691         if (tc) {
3692
3693 #ifdef RX_ENABLE_LOCKS
3694             AFS_GUNLOCK();
3695 #endif /* RX_ENABLE_LOCKS */
3696             tcall = rx_NewCall(tc->id);
3697             code = StartRXAFS_FetchData(tcall,
3698                                 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3699             if (!code) {
3700                 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3701                 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3702             }
3703             code1 = rx_EndCall(tcall, code);
3704 #ifdef RX_ENABLE_LOCKS
3705             AFS_GLOCK();
3706 #endif /* RX_ENABLE_LOCKS */
3707         } else
3708             code = -1;
3709     } while
3710         (afs_Analyze(tc, code, &tvc->fid, areq, 
3711                 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, 
3712                 (struct cell *)0));
3713     /* This call is done only to have the callback things handled correctly */
3714     afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3715     afs_PutVCache(tvc, WRITE_LOCK);
3716
3717     if (!code) {
3718         *aoutSize = sizeof(afs_int32);
3719     }
3720     return code;
3721 }
3722
3723 static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
3724 struct vcache *avc;
3725 int afun;
3726 struct vrequest *areq;
3727 char *ain, *aout;
3728 afs_int32 ainSize;
3729 afs_int32 *aoutSize;        /* set this */
3730 {
3731     register afs_int32 code;
3732     struct conn *tc;
3733     struct vcache *tvc;
3734     struct ResidencyCmdInputs *Inputs;
3735     struct ResidencyCmdOutputs *Outputs;
3736     struct VenusFid tfid;
3737     struct AFSFid *Fid;
3738
3739     Inputs = (struct ResidencyCmdInputs *) ain;
3740     Outputs = (struct ResidencyCmdOutputs *) aout;
3741     if (!avc) return EINVAL;
3742     if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3743
3744     Fid = &Inputs->fid;
3745     if (!Fid->Volume)
3746         Fid = &avc->fid.Fid;
3747
3748     tfid.Cell = avc->fid.Cell;
3749     tfid.Fid.Volume = Fid->Volume;
3750     tfid.Fid.Vnode = Fid->Vnode;
3751     tfid.Fid.Unique = Fid->Unique;
3752
3753     tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3754                                 WRITE_LOCK);
3755     afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3756                 ICL_TYPE_POINTER, tvc,
3757                 ICL_TYPE_INT32, Inputs->command,
3758                 ICL_TYPE_FID, &tfid);
3759     if (!tvc)
3760         return ENOENT;
3761
3762     if (Inputs->command) {
3763         do {
3764             tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3765             if (tc) {
3766 #ifdef RX_ENABLE_LOCKS
3767                 AFS_GUNLOCK();
3768 #endif /* RX_ENABLE_LOCKS */
3769                 code = RXAFS_ResidencyCmd(tc->id, Fid,
3770                                  Inputs,
3771                                  (struct ResidencyCmdOutputs *) aout);
3772 #ifdef RX_ENABLE_LOCKS
3773                 AFS_GLOCK();
3774 #endif /* RX_ENABLE_LOCKS */
3775             } else
3776                 code = -1;
3777         } while
3778           (afs_Analyze(tc, code, &tvc->fid, areq, 
3779                 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3780                 (struct cell *)0));
3781        /* This call is done to have the callback things handled correctly */
3782        afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3783     } else { /* just a status request, return also link data */
3784         code = 0;
3785         Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3786         Outputs->chars[0] = 0;
3787         if (vType(tvc) == VLNK) {
3788             ObtainWriteLock(&tvc->lock,555);
3789             if (afs_HandleLink(tvc, areq) == 0)
3790                 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3791             ReleaseWriteLock(&tvc->lock);
3792         }
3793     }
3794
3795     afs_PutVCache(tvc, WRITE_LOCK);
3796
3797     if (!code) {
3798         *aoutSize = sizeof(struct ResidencyCmdOutputs);
3799     }
3800     return code;
3801 }