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