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