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