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