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