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