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