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