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