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