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