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