doxygen-comments-20081010
[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 "afs/afs_bypasscache.h"
27 #include "rx/rx_globals.h"
28
29 struct VenusFid afs_rootFid;
30 afs_int32 afs_waitForever = 0;
31 short afs_waitForeverCount = 0;
32 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
33
34 #ifdef AFS_DISCON_ENV
35 afs_int32 afs_is_disconnected;
36 afs_int32 afs_is_logging;
37 afs_int32 afs_is_discon_rw;
38 /* On reconnection, turn this knob on until it finishes,
39  * then turn it off.
40  */
41 afs_int32 afs_in_sync = 0;
42 #endif
43
44 /*!
45  * \defgroup pioctl Path IOCTL functions
46  *
47  * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
48  *
49  * \param[in] avc       the AFS vcache structure in use by pioctl
50  * \param[in] afun      not in use
51  * \param[in] areq      the AFS vrequest structure
52  * \param[in] ain       as defined by the function
53  * \param[in] aout      as defined by the function
54  * \param[in] ainSize   size of ain
55  * \param[in] aoutSize  size of aout
56  * \param[in] acred     UNIX credentials structure underlying the operation
57  */
58
59 #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
60         char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
61         struct AFS_UCRED **acred)
62
63 /* Prototypes for pioctl routines */
64 DECL_PIOCTL(PGetFID);
65 DECL_PIOCTL(PSetAcl);
66 DECL_PIOCTL(PStoreBehind);
67 DECL_PIOCTL(PGCPAGs);
68 DECL_PIOCTL(PGetAcl);
69 DECL_PIOCTL(PNoop);
70 DECL_PIOCTL(PBogus);
71 DECL_PIOCTL(PGetFileCell);
72 DECL_PIOCTL(PGetWSCell);
73 DECL_PIOCTL(PGetUserCell);
74 DECL_PIOCTL(PSetTokens);
75 DECL_PIOCTL(PGetVolumeStatus);
76 DECL_PIOCTL(PSetVolumeStatus);
77 DECL_PIOCTL(PFlush);
78 DECL_PIOCTL(PNewStatMount);
79 DECL_PIOCTL(PGetTokens);
80 DECL_PIOCTL(PUnlog);
81 DECL_PIOCTL(PMariner);
82 DECL_PIOCTL(PCheckServers);
83 DECL_PIOCTL(PCheckVolNames);
84 DECL_PIOCTL(PCheckAuth);
85 DECL_PIOCTL(PFindVolume);
86 DECL_PIOCTL(PViceAccess);
87 DECL_PIOCTL(PSetCacheSize);
88 DECL_PIOCTL(PGetCacheSize);
89 DECL_PIOCTL(PRemoveCallBack);
90 DECL_PIOCTL(PNewCell);
91 DECL_PIOCTL(PNewAlias);
92 DECL_PIOCTL(PListCells);
93 DECL_PIOCTL(PListAliases);
94 DECL_PIOCTL(PRemoveMount);
95 DECL_PIOCTL(PVenusLogging);
96 DECL_PIOCTL(PGetCellStatus);
97 DECL_PIOCTL(PSetCellStatus);
98 DECL_PIOCTL(PFlushVolumeData);
99 DECL_PIOCTL(PGetVnodeXStatus);
100 DECL_PIOCTL(PGetVnodeXStatus2);
101 DECL_PIOCTL(PSetSysName);
102 DECL_PIOCTL(PSetSPrefs);
103 DECL_PIOCTL(PSetSPrefs33);
104 DECL_PIOCTL(PGetSPrefs);
105 DECL_PIOCTL(PExportAfs);
106 DECL_PIOCTL(PGag);
107 DECL_PIOCTL(PTwiddleRx);
108 DECL_PIOCTL(PGetInitParams);
109 DECL_PIOCTL(PGetRxkcrypt);
110 DECL_PIOCTL(PSetRxkcrypt);
111 DECL_PIOCTL(PGetCPrefs);
112 DECL_PIOCTL(PSetCPrefs);
113 DECL_PIOCTL(PFlushMount);
114 DECL_PIOCTL(PRxStatProc);
115 DECL_PIOCTL(PRxStatPeer);
116 DECL_PIOCTL(PPrefetchFromTape);
117 DECL_PIOCTL(PResidencyCmd);
118 DECL_PIOCTL(PCallBackAddr);
119 DECL_PIOCTL(PDiscon);
120 DECL_PIOCTL(PNFSNukeCreds);
121 DECL_PIOCTL(PNewUuid);
122 DECL_PIOCTL(PPrecache); 
123 #if defined(AFS_CACHE_BYPASS)
124 DECL_PIOCTL(PSetCachingThreshold);
125 DECL_PIOCTL(PSetCachingBlkSize);
126 #endif
127
128 /*
129  * A macro that says whether we're going to need HandleClientContext().
130  * This is currently used only by the nfs translator.
131  */
132 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
133 #define AFS_NEED_CLIENTCONTEXT
134 #endif
135
136 /* Prototypes for private routines */
137 #ifdef AFS_NEED_CLIENTCONTEXT
138 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
139                                struct AFS_UCRED **acred,
140                                struct AFS_UCRED *credp);
141 #endif
142 int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
143                 struct afs_ioctl *adata);
144 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
145                      register struct afs_ioctl *ablob, int afollow,
146                      struct AFS_UCRED **acred);
147 static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
148                     struct AFS_UCRED *acred);
149
150
151 static int (*(VpioctlSw[])) () = {
152     PBogus,                     /* 0 */
153         PSetAcl,                /* 1 */
154         PGetAcl,                /* 2 */
155         PSetTokens,             /* 3 */
156         PGetVolumeStatus,       /* 4 */
157         PSetVolumeStatus,       /* 5 */
158         PFlush,                 /* 6 */
159         PBogus,                 /* 7 */
160         PGetTokens,             /* 8 */
161         PUnlog,                 /* 9 */
162         PCheckServers,          /* 10 */
163         PCheckVolNames,         /* 11 */
164         PCheckAuth,             /* 12 */
165         PBogus,                 /* 13 -- used to be quick check time */
166         PFindVolume,            /* 14 */
167         PBogus,                 /* 15 -- prefetch is now special-cased; see pioctl code! */
168         PBogus,                 /* 16 -- used to be testing code */
169         PNoop,                  /* 17 -- used to be enable group */
170         PNoop,                  /* 18 -- used to be disable group */
171         PBogus,                 /* 19 -- used to be list group */
172         PViceAccess,            /* 20 */
173         PUnlog,                 /* 21 -- unlog *is* unpag in this system */
174         PGetFID,                /* 22 -- get file ID */
175         PBogus,                 /* 23 -- used to be waitforever */
176         PSetCacheSize,          /* 24 */
177         PRemoveCallBack,        /* 25 -- flush only the callback */
178         PNewCell,               /* 26 */
179         PListCells,             /* 27 */
180         PRemoveMount,           /* 28 -- delete mount point */
181         PNewStatMount,          /* 29 -- new style mount point stat */
182         PGetFileCell,           /* 30 -- get cell name for input file */
183         PGetWSCell,             /* 31 -- get cell name for workstation */
184         PMariner,               /* 32 - set/get mariner host */
185         PGetUserCell,           /* 33 -- get cell name for user */
186         PVenusLogging,          /* 34 -- Enable/Disable logging */
187         PGetCellStatus,         /* 35 */
188         PSetCellStatus,         /* 36 */
189         PFlushVolumeData,       /* 37 -- flush all data from a volume */
190         PSetSysName,            /* 38 - Set system name */
191         PExportAfs,             /* 39 - Export Afs to remote nfs clients */
192         PGetCacheSize,          /* 40 - get cache size and usage */
193         PGetVnodeXStatus,       /* 41 - get vcache's special status */
194         PSetSPrefs33,           /* 42 - Set CM Server preferences... */
195         PGetSPrefs,             /* 43 - Get CM Server preferences... */
196         PGag,                   /* 44 - turn off/on all CM messages */
197         PTwiddleRx,             /* 45 - adjust some RX params       */
198         PSetSPrefs,             /* 46 - Set CM Server preferences... */
199         PStoreBehind,           /* 47 - set degree of store behind to be done */
200         PGCPAGs,                /* 48 - disable automatic pag gc-ing */
201         PGetInitParams,         /* 49 - get initial cm params */
202         PGetCPrefs,             /* 50 - get client interface addresses */
203         PSetCPrefs,             /* 51 - set client interface addresses */
204         PFlushMount,            /* 52 - flush mount symlink data */
205         PRxStatProc,            /* 53 - control process RX statistics */
206         PRxStatPeer,            /* 54 - control peer RX statistics */
207         PGetRxkcrypt,           /* 55 -- Get rxkad encryption flag */
208         PSetRxkcrypt,           /* 56 -- Set rxkad encryption flag */
209         PBogus,                 /* 57 -- arla: set file prio */
210         PBogus,                 /* 58 -- arla: fallback getfh */
211         PBogus,                 /* 59 -- arla: fallback fhopen */
212         PBogus,                 /* 60 -- arla: controls xfsdebug */
213         PBogus,                 /* 61 -- arla: controls arla debug */
214         PBogus,                 /* 62 -- arla: debug interface */
215         PBogus,                 /* 63 -- arla: print xfs status */
216         PBogus,                 /* 64 -- arla: force cache check */
217         PBogus,                 /* 65 -- arla: break callback */
218         PPrefetchFromTape,      /* 66 -- MR-AFS: prefetch file from tape */
219         PResidencyCmd,          /* 67 -- MR-AFS: generic commnd interface */
220         PBogus,                 /* 68 -- arla: fetch stats */
221         PGetVnodeXStatus2,      /* 69 - get caller access and some vcache status */
222 };
223
224 static int (*(CpioctlSw[])) () = {
225     PBogus,                     /* 0 */
226         PNewAlias,              /* 1 -- create new cell alias */
227         PListAliases,           /* 2 -- list cell aliases */
228         PCallBackAddr,          /* 3 -- request addr for callback rxcon */
229         PBogus,                 /* 4 */
230         PDiscon,                /* 5 -- get/set discon mode */
231         PBogus,                 /* 6 */
232         PBogus,                 /* 7 */
233         PBogus,                 /* 8 */
234         PNewUuid,               /* 9 */
235     PBogus,                     /* 0 */
236     PBogus,                     /* 0 */
237     PPrecache,                  /* 12 */
238 };
239
240 static int (*(OpioctlSw[])) () = {
241     PBogus,                     /* 0 */
242     PNFSNukeCreds,              /* 1 -- nuke all creds for NFS client */
243 #if defined(AFS_CACHE_BYPASS)
244     PSetCachingThreshold        /* 2 -- get/set cache-bypass size threshold */
245 #else
246     PNoop                       /* 2 -- get/set cache-bypass size threshold */
247 #endif
248 };
249
250 #define PSetClientContext 99    /*  Special pioctl to setup caller's creds  */
251 int afs_nobody = NFS_NOBODY;
252
253 int
254 HandleIoctl(register struct vcache *avc, register afs_int32 acom,
255             struct afs_ioctl *adata)
256 {
257     register afs_int32 code;
258
259     code = 0;
260     AFS_STATCNT(HandleIoctl);
261
262     switch (acom & 0xff) {
263     case 1:
264         avc->states |= CSafeStore;
265         avc->asynchrony = 0;
266         break;
267
268         /* case 2 used to be abort store, but this is no longer provided,
269          * since it is impossible to implement under normal Unix.
270          */
271
272     case 3:{
273             /* return the name of the cell this file is open on */
274             register struct cell *tcell;
275             register afs_int32 i;
276
277             tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
278             if (tcell) {
279                 i = strlen(tcell->cellName) + 1;        /* bytes to copy out */
280
281                 if (i > adata->out_size) {
282                     /* 0 means we're not interested in the output */
283                     if (adata->out_size != 0)
284                         code = EFAULT;
285                 } else {
286                     /* do the copy */
287                     AFS_COPYOUT(tcell->cellName, adata->out, i, code);
288                 }
289                 afs_PutCell(tcell, READ_LOCK);
290             } else
291                 code = ENOTTY;
292         }
293         break;
294
295     case 49:                    /* VIOC_GETINITPARAMS */
296         if (adata->out_size < sizeof(struct cm_initparams)) {
297             code = EFAULT;
298         } else {
299             AFS_COPYOUT(&cm_initParams, adata->out,
300                         sizeof(struct cm_initparams), code);
301         }
302         break;
303
304     default:
305
306         code = EINVAL;
307 #ifdef AFS_AIX51_ENV
308         code = ENOSYS;
309 #endif
310         break;
311     }
312     return code;                /* so far, none implemented */
313 }
314
315
316 #ifdef  AFS_AIX_ENV
317 /* For aix we don't temporarily bypass ioctl(2) but rather do our
318  * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
319  * is now called from afs_gn_ioctl.
320  */
321 int
322 afs_ioctl(struct vcache *tvc, int cmd, int arg)
323 {
324     struct afs_ioctl data;
325     int error = 0;
326
327     AFS_STATCNT(afs_ioctl);
328     if (((cmd >> 8) & 0xff) == 'V') {
329         /* This is a VICEIOCTL call */
330         AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
331         if (error)
332             return (error);
333         error = HandleIoctl(tvc, cmd, &data);
334         return (error);
335     } else {
336         /* No-op call; just return. */
337         return (ENOTTY);
338     }
339 }
340 #endif /* AFS_AIX_ENV */
341
342 #if defined(AFS_SGI_ENV)
343 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
344           rval_t * rvalp
345 #ifdef AFS_SGI65_ENV
346           , struct vopbd * vbds
347 #endif
348     )
349 {
350     struct afs_ioctl data;
351     int error = 0;
352     int locked;
353
354     OSI_VN_CONVERT(tvc);
355
356     AFS_STATCNT(afs_ioctl);
357     if (((cmd >> 8) & 0xff) == 'V') {
358         /* This is a VICEIOCTL call */
359         error = copyin_afs_ioctl(arg, &data);
360         if (error)
361             return (error);
362         locked = ISAFS_GLOCK();
363         if (!locked)
364             AFS_GLOCK();
365         error = HandleIoctl(tvc, cmd, &data);
366         if (!locked)
367             AFS_GUNLOCK();
368         return (error);
369     } else {
370         /* No-op call; just return. */
371         return (ENOTTY);
372     }
373 }
374 #endif /* AFS_SGI_ENV */
375
376 /* unlike most calls here, this one uses u.u_error to return error conditions,
377    since this is really an intercepted chapter 2 call, rather than a vnode
378    interface call.
379    */
380 /* AFS_HPUX102 and up uses VNODE ioctl instead */
381 #if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
382 #if !defined(AFS_SGI_ENV)
383 #ifdef  AFS_AIX32_ENV
384 #ifdef AFS_AIX51_ENV
385 #ifdef __64BIT__
386 kioctl(fdes, com, arg, ext, arg2, arg3)
387 #else /* __64BIT__ */
388 kioctl32(fdes, com, arg, ext, arg2, arg3)
389 #endif /* __64BIT__ */
390      caddr_t arg2, arg3;
391 #else
392 kioctl(fdes, com, arg, ext)
393 #endif
394      int fdes, com;
395      caddr_t arg, ext;
396 {
397     struct a {
398         int fd, com;
399         caddr_t arg, ext;
400 #ifdef AFS_AIX51_ENV
401         caddr_t arg2, arg3;
402 #endif
403     } u_uap, *uap = &u_uap;
404 #else
405 #if defined(AFS_SUN5_ENV)
406
407 struct afs_ioctl_sys {
408     int fd;
409     int com;
410     int arg;
411 };
412
413 afs_xioctl(uap, rvp)
414      struct afs_ioctl_sys *uap;
415      rval_t *rvp;
416 {
417 #elif defined(AFS_OSF_ENV)
418 afs_xioctl(p, args, retval)
419      struct proc *p;
420      void *args;
421      long *retval;
422 {
423     struct a {
424         long fd;
425         u_long com;
426         caddr_t arg;
427     } *uap = (struct a *)args;
428 #elif defined(AFS_FBSD50_ENV)
429 #define arg data
430 int
431 afs_xioctl(td, uap, retval)
432      struct thread *td;
433      register struct ioctl_args *uap;
434      register_t *retval;
435 {
436     struct proc *p = td->td_proc;
437 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
438 struct ioctl_args {
439     int fd;
440     u_long com;
441     caddr_t arg;
442 };
443
444 int
445 afs_xioctl(p, uap, retval)
446      struct proc *p;
447      register struct ioctl_args *uap;
448      register_t *retval;
449 {
450 #elif defined(AFS_LINUX22_ENV)
451 struct afs_ioctl_sys {
452     unsigned int com;
453     unsigned long arg;
454 };
455 int
456 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
457            unsigned long arg)
458 {
459     struct afs_ioctl_sys ua, *uap = &ua;
460 #else
461 int
462 afs_xioctl(void)
463 {
464     register struct a {
465         int fd;
466         int com;
467         caddr_t arg;
468     } *uap = (struct a *)u.u_ap;
469 #endif /* AFS_SUN5_ENV */
470 #endif
471 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
472     struct file *fd;
473 #elif !defined(AFS_LINUX22_ENV)
474     register struct file *fd;
475 #endif
476 #if defined(AFS_XBSD_ENV)
477     register struct filedesc *fdp;
478 #endif
479     register struct vcache *tvc;
480     register int ioctlDone = 0, code = 0;
481
482     AFS_STATCNT(afs_xioctl);
483 #if defined(AFS_DARWIN_ENV)
484     if ((code = fdgetf(p, uap->fd, &fd)))
485         return code;
486 #elif defined(AFS_XBSD_ENV)
487     fdp = p->p_fd;
488     if ((u_int) uap->fd >= fdp->fd_nfiles
489         || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
490         return EBADF;
491     if ((fd->f_flag & (FREAD | FWRITE)) == 0)
492         return EBADF;
493 #elif defined(AFS_LINUX22_ENV)
494     ua.com = com;
495     ua.arg = arg;
496 #elif defined(AFS_AIX32_ENV)
497     uap->fd = fdes;
498     uap->com = com;
499     uap->arg = arg;
500 #ifdef AFS_AIX51_ENV
501     uap->arg2 = arg2;
502     uap->arg3 = arg3;
503 #endif
504     if (setuerror(getf(uap->fd, &fd))) {
505         return -1;
506     }
507 #elif defined(AFS_OSF_ENV)
508     fd = NULL;
509     if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
510         return code;
511 #elif defined(AFS_SUN5_ENV)
512 # if defined(AFS_SUN57_ENV)
513     fd = getf(uap->fd);
514     if (!fd)
515         return (EBADF);
516 # elif defined(AFS_SUN54_ENV)
517     fd = GETF(uap->fd);
518     if (!fd)
519         return (EBADF);
520 # else
521     if (code = getf(uap->fd, &fd)) {
522         return (code);
523     }
524 # endif /* AFS_SUN57_ENV */
525 #else
526     fd = getf(uap->fd);
527     if (!fd)
528         return (EBADF);
529 #endif
530     /* first determine whether this is any sort of vnode */
531 #if defined(AFS_LINUX22_ENV)
532     tvc = VTOAFS(ip);
533     {
534 #else
535 #ifdef AFS_SUN5_ENV
536     if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
537 #else
538     if (fd->f_type == DTYPE_VNODE) {
539 #endif
540         /* good, this is a vnode; next see if it is an AFS vnode */
541 #if     defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
542         tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
543 #elif defined(AFS_OBSD_ENV)
544         tvc =
545             IsAfsVnode((struct vnode *)fd->
546                        f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
547 #else
548         tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
549 #endif
550 #endif /* AFS_LINUX22_ENV */
551         if (tvc && IsAfsVnode(AFSTOV(tvc))) {
552             /* This is an AFS vnode */
553             if (((uap->com >> 8) & 0xff) == 'V') {
554                 register struct afs_ioctl *datap;
555                 AFS_GLOCK();
556                 datap =
557                     (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
558                 code=copyin_afs_ioctl((char *)uap->arg, datap);
559                 if (code) {
560                     osi_FreeSmallSpace(datap);
561                     AFS_GUNLOCK();
562 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
563                     return code;
564 #else
565 #if     defined(AFS_SUN5_ENV)
566 #ifdef  AFS_SUN54_ENV
567                     releasef(uap->fd);
568 #else
569                     releasef(fd);
570 #endif
571                     return (EFAULT);
572 #else
573 #ifdef  AFS_OSF_ENV
574 #ifdef  AFS_OSF30_ENV
575                     FP_UNREF_ALWAYS(fd);
576 #else
577                     FP_UNREF(fd);
578 #endif
579                     return code;
580 #else /* AFS_OSF_ENV */
581 #ifdef  AFS_AIX41_ENV
582                     ufdrele(uap->fd);
583 #endif
584 #ifdef AFS_LINUX22_ENV
585                     return -code;
586 #else
587                     setuerror(code);
588                     return;
589 #endif
590 #endif
591 #endif
592 #endif
593                 }
594                 code = HandleIoctl(tvc, uap->com, datap);
595                 osi_FreeSmallSpace(datap);
596                 AFS_GUNLOCK();
597                 ioctlDone = 1;
598 #ifdef  AFS_AIX41_ENV
599                 ufdrele(uap->fd);
600 #endif
601 #ifdef  AFS_OSF_ENV
602 #ifdef  AFS_OSF30_ENV
603                 FP_UNREF_ALWAYS(fd);
604 #else
605                 FP_UNREF(fd);
606 #endif
607 #endif
608             }
609 #if defined(AFS_LINUX22_ENV)
610             else
611                 code = EINVAL;
612 #endif
613         }
614     }
615
616     if (!ioctlDone) {
617 #ifdef  AFS_AIX41_ENV
618         ufdrele(uap->fd);
619 #ifdef AFS_AIX51_ENV
620 #ifdef __64BIT__
621         code = okioctl(fdes, com, arg, ext, arg2, arg3);
622 #else /* __64BIT__ */
623         code = okioctl32(fdes, com, arg, ext, arg2, arg3);
624 #endif /* __64BIT__ */
625 #else /* !AFS_AIX51_ENV */
626         code = okioctl(fdes, com, arg, ext);
627 #endif /* AFS_AIX51_ENV */
628         return code;
629 #else /* !AFS_AIX41_ENV */
630 #ifdef  AFS_AIX32_ENV
631         okioctl(fdes, com, arg, ext);
632 #elif defined(AFS_SUN5_ENV)
633 #if defined(AFS_SUN57_ENV)
634         releasef(uap->fd);
635 #elif defined(AFS_SUN54_ENV)
636         RELEASEF(uap->fd);
637 #else
638         releasef(fd);
639 #endif
640         code = ioctl(uap, rvp);
641 #elif defined(AFS_FBSD50_ENV)
642         return ioctl(td, uap);
643 #elif defined(AFS_FBSD_ENV)
644         return ioctl(p, uap);
645 #elif defined(AFS_OBSD_ENV)
646         code = sys_ioctl(p, uap, retval);
647 #elif defined(AFS_DARWIN_ENV)
648         return ioctl(p, uap, retval);
649 #elif defined(AFS_OSF_ENV)
650         code = ioctl(p, args, retval);
651 #ifdef  AFS_OSF30_ENV
652         FP_UNREF_ALWAYS(fd);
653 #else
654         FP_UNREF(fd);
655 #endif
656         return code;
657 #elif !defined(AFS_LINUX22_ENV)
658         ioctl();
659 #endif
660 #endif
661     }
662 #ifdef  AFS_SUN5_ENV
663     if (ioctlDone)
664 #ifdef  AFS_SUN54_ENV
665         releasef(uap->fd);
666 #else
667         releasef(fd);
668 #endif
669     return (code);
670 #else
671 #ifdef AFS_LINUX22_ENV
672     return -code;
673 #else
674 #if defined(KERNEL_HAVE_UERROR)
675     if (!getuerror())
676         setuerror(code);
677 #if     defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
678     return (getuerror()? -1 : u.u_ioctlrv);
679 #else
680     return getuerror()? -1 : 0;
681 #endif
682 #endif
683 #endif /* AFS_LINUX22_ENV */
684 #endif /* AFS_SUN5_ENV */
685 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
686     return (code);
687 #endif
688 }
689 #endif /* AFS_SGI_ENV */
690 #endif /* AFS_HPUX102_ENV */
691
692 #if defined(AFS_SGI_ENV)
693   /* "pioctl" system call entry point; just pass argument to the parameterized
694    * call below */
695 struct pioctlargs {
696     char *path;
697     sysarg_t cmd;
698     caddr_t cmarg;
699     sysarg_t follow;
700 };
701 int
702 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
703 {
704     int code;
705
706     AFS_STATCNT(afs_pioctl);
707     AFS_GLOCK();
708     code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
709     AFS_GUNLOCK();
710 #ifdef AFS_SGI64_ENV
711     return code;
712 #else
713     return u.u_error;
714 #endif
715 }
716
717 #elif defined(AFS_OSF_ENV)
718 afs_pioctl(p, args, retval)
719      struct proc *p;
720      void *args;
721      int *retval;
722 {
723     struct a {
724         char *path;
725         int cmd;
726         caddr_t cmarg;
727         int follow;
728     } *uap = (struct a *)args;
729
730     AFS_STATCNT(afs_pioctl);
731     return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
732 }
733
734 #elif defined(AFS_FBSD50_ENV)
735 int
736 afs_pioctl(td, args, retval)
737      struct thread *td;
738      void *args;
739      int *retval;
740 {
741     struct a {
742         char *path;
743         int cmd;
744         caddr_t cmarg;
745         int follow;
746     } *uap = (struct a *)args;
747
748     AFS_STATCNT(afs_pioctl);
749     return (afs_syscall_pioctl
750             (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
751 }
752
753 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
754 int
755 afs_pioctl(p, args, retval)
756      struct proc *p;
757      void *args;
758      int *retval;
759 {
760     struct a {
761         char *path;
762         int cmd;
763         caddr_t cmarg;
764         int follow;
765     } *uap = (struct a *)args;
766
767     AFS_STATCNT(afs_pioctl);
768 #ifdef AFS_DARWIN80_ENV
769     return (afs_syscall_pioctl
770             (uap->path, uap->cmd, uap->cmarg, uap->follow,
771              kauth_cred_get()));
772 #else
773     return (afs_syscall_pioctl
774             (uap->path, uap->cmd, uap->cmarg, uap->follow,
775              p->p_cred->pc_ucred));
776 #endif
777 }
778
779 #endif
780
781 /* macro to avoid adding any more #ifdef's to pioctl code. */
782 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
783 #define PIOCTL_FREE_CRED() crfree(credp)
784 #else
785 #define PIOCTL_FREE_CRED()
786 #endif
787
788 int
789 #ifdef  AFS_SUN5_ENV
790 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
791      rval_t *rvp;
792      struct AFS_UCRED *credp;
793 #else
794 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
795 afs_syscall_pioctl(path, com, cmarg, follow, credp)
796      struct AFS_UCRED *credp;
797 #else
798 afs_syscall_pioctl(path, com, cmarg, follow)
799 #endif
800 #endif
801      char *path;
802      unsigned int com;
803      caddr_t cmarg;
804      int follow;
805 {
806     struct afs_ioctl data;
807 #ifdef AFS_NEED_CLIENTCONTEXT
808     struct AFS_UCRED *tmpcred = NULL;
809 #endif
810     struct AFS_UCRED *foreigncreds = NULL;
811     register afs_int32 code = 0;
812     struct vnode *vp = NULL;
813 #ifdef  AFS_AIX41_ENV
814     struct ucred *credp = crref();      /* don't free until done! */
815 #endif
816 #ifdef AFS_LINUX22_ENV
817     cred_t *credp = crref();    /* don't free until done! */
818     struct dentry *dp;
819 #endif
820
821     AFS_STATCNT(afs_syscall_pioctl);
822     if (follow)
823         follow = 1;             /* compat. with old venus */
824     code = copyin_afs_ioctl(cmarg, &data);
825     if (code) {
826         PIOCTL_FREE_CRED();
827 #if defined(KERNEL_HAVE_UERROR)
828         setuerror(code);
829 #endif
830         return (code);
831     }
832     if ((com & 0xff) == PSetClientContext) {
833 #ifdef AFS_NEED_CLIENTCONTEXT
834 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
835         code = HandleClientContext(&data, &com, &foreigncreds, credp);
836 #else
837         code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
838 #endif
839         if (code) {
840             if (foreigncreds) {
841                 crfree(foreigncreds);
842             }
843             PIOCTL_FREE_CRED();
844 #if defined(KERNEL_HAVE_UERROR)
845             return (setuerror(code), code);
846 #else
847             return (code);
848 #endif
849         }
850 #else /* AFS_NEED_CLIENTCONTEXT */
851         return EINVAL;
852 #endif /* AFS_NEED_CLIENTCONTEXT */
853     }
854 #ifdef AFS_NEED_CLIENTCONTEXT
855     if (foreigncreds) {
856         /*
857          * We could have done without temporary setting the u.u_cred below
858          * (foreigncreds could be passed as param the pioctl modules)
859          * but calls such as afs_osi_suser() doesn't allow that since it
860          * references u.u_cred directly.  We could, of course, do something
861          * like afs_osi_suser(cred) which, I think, is better since it
862          * generalizes and supports multi cred environments...
863          */
864 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
865         tmpcred = credp;
866         credp = foreigncreds;
867 #elif defined(AFS_AIX41_ENV)
868         tmpcred = crref();      /* XXX */
869         crset(foreigncreds);
870 #elif defined(AFS_HPUX101_ENV)
871         tmpcred = p_cred(u.u_procp);
872         set_p_cred(u.u_procp, foreigncreds);
873 #elif defined(AFS_SGI_ENV)
874         tmpcred = OSI_GET_CURRENT_CRED();
875         OSI_SET_CURRENT_CRED(foreigncreds);
876 #else
877         tmpcred = u.u_cred;
878         u.u_cred = foreigncreds;
879 #endif
880     }
881 #endif /* AFS_NEED_CLIENTCONTEXT */
882     if ((com & 0xff) == 15) {
883         /* special case prefetch so entire pathname eval occurs in helper process.
884          * otherwise, the pioctl call is essentially useless */
885 #if     defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
886         code =
887             Prefetch(path, &data, follow,
888                      foreigncreds ? foreigncreds : credp);
889 #else
890         code = Prefetch(path, &data, follow, osi_curcred());
891 #endif
892         vp = NULL;
893 #if defined(KERNEL_HAVE_UERROR)
894         setuerror(code);
895 #endif
896         goto rescred;
897     }
898     if (path) {
899         AFS_GUNLOCK();
900 #ifdef  AFS_AIX41_ENV
901         code =
902             lookupname(path, USR, follow, NULL, &vp,
903                        foreigncreds ? foreigncreds : credp);
904 #else
905 #ifdef AFS_LINUX22_ENV
906         code = gop_lookupname(path, AFS_UIOUSER, follow, &dp);
907         if (!code)
908             vp = (struct vnode *)dp->d_inode;
909 #else
910         code = gop_lookupname(path, AFS_UIOUSER, follow, &vp);
911 #endif /* AFS_LINUX22_ENV */
912 #endif /* AFS_AIX41_ENV */
913         AFS_GLOCK();
914         if (code) {
915             vp = NULL;
916 #if defined(KERNEL_HAVE_UERROR)
917             setuerror(code);
918 #endif
919             goto rescred;
920         }
921     } else
922         vp = NULL;
923
924 #if defined(AFS_SUN510_ENV)
925     if (vp && !IsAfsVnode(vp)) {
926         struct vnode *realvp;
927         if
928 #ifdef AFS_SUN511_ENV
929           (VOP_REALVP(vp, &realvp, NULL) == 0) 
930 #else
931           (VOP_REALVP(vp, &realvp) == 0) 
932 #endif
933 {
934             struct vnode *oldvp = vp;
935             
936             VN_HOLD(realvp);
937             vp = realvp;
938             AFS_RELE(oldvp);
939         }
940     }
941 #endif
942     /* now make the call if we were passed no file, or were passed an AFS file */
943     if (!vp || IsAfsVnode(vp)) {
944 #if defined(AFS_SUN5_ENV)
945         code = afs_HandlePioctl(vp, com, &data, follow, &credp);
946 #elif defined(AFS_AIX41_ENV)
947         {
948             struct ucred *cred1, *cred2;
949
950             if (foreigncreds) {
951                 cred1 = cred2 = foreigncreds;
952             } else {
953                 cred1 = cred2 = credp;
954             }
955             code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
956             if (cred1 != cred2) {
957                 /* something changed the creds */
958                 crset(cred1);
959             }
960         }
961 #elif defined(AFS_HPUX101_ENV)
962         {
963             struct ucred *cred = p_cred(u.u_procp);
964             code = afs_HandlePioctl(vp, com, &data, follow, &cred);
965         }
966 #elif defined(AFS_SGI_ENV)
967         {
968             struct cred *credp;
969             credp = OSI_GET_CURRENT_CRED();
970             code = afs_HandlePioctl(vp, com, &data, follow, &credp);
971         }
972 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
973         code = afs_HandlePioctl(vp, com, &data, follow, &credp);
974 #else
975         code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
976 #endif
977     } else {
978 #if defined(KERNEL_HAVE_UERROR)
979         setuerror(EINVAL);
980 #else
981         code = EINVAL;          /* not in /afs */
982 #endif
983     }
984
985   rescred:
986 #if defined(AFS_NEED_CLIENTCONTEXT)
987     if (foreigncreds) {
988 #ifdef  AFS_AIX41_ENV
989         crset(tmpcred);         /* restore original credentials */
990 #else
991 #if     defined(AFS_HPUX101_ENV)
992         set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
993 #elif   defined(AFS_SGI_ENV)
994         OSI_SET_CURRENT_CRED(tmpcred);  /* restore original credentials */
995 #elif   defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
996         credp = tmpcred;                /* restore original credentials */
997 #else
998         osi_curcred() = tmpcred;        /* restore original credentials */
999 #endif /* AFS_HPUX101_ENV */
1000         crfree(foreigncreds);
1001 #endif /* AIX41 */
1002     }
1003 #endif /* AFS_NEED_CLIENTCONTEXT */
1004     if (vp) {
1005 #ifdef AFS_LINUX22_ENV
1006         dput(dp);
1007 #else
1008         AFS_RELE(vp);           /* put vnode back */
1009 #endif
1010     }
1011     PIOCTL_FREE_CRED();
1012 #if defined(KERNEL_HAVE_UERROR)
1013     if (!getuerror())
1014         setuerror(code);
1015     return (getuerror());
1016 #else
1017     return (code);
1018 #endif
1019 }
1020
1021 #define MAXPIOCTLTOKENLEN \
1022 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1023
1024 int
1025 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1026                  register struct afs_ioctl *ablob, int afollow,
1027                  struct AFS_UCRED **acred)
1028 {
1029     struct vcache *avc;
1030     struct vrequest treq;
1031     register afs_int32 code;
1032     register afs_int32 function, device;
1033     afs_int32 inSize, outSize, outSizeMax;
1034     char *inData, *outData;
1035     int (*(*pioctlSw)) ();
1036     int pioctlSwSize;
1037     struct afs_fakestat_state fakestate;
1038
1039     avc = avp ? VTOAFS(avp) : NULL;
1040     afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1041                ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1042     AFS_STATCNT(HandlePioctl);
1043     if ((code = afs_InitReq(&treq, *acred)))
1044         return code;
1045     afs_InitFakeStat(&fakestate);
1046     if (avc) {
1047         code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1048         if (code) {
1049             afs_PutFakeStat(&fakestate);
1050             return code;
1051         }
1052     }
1053     device = (acom & 0xff00) >> 8;
1054     switch (device) {
1055     case 'V':                   /* Original pioctls */
1056         pioctlSw = VpioctlSw;
1057         pioctlSwSize = sizeof(VpioctlSw);
1058         break;
1059     case 'C':                   /* Coordinated/common pioctls */
1060         pioctlSw = CpioctlSw;
1061         pioctlSwSize = sizeof(CpioctlSw);
1062         break;
1063     case 'O':                   /* Coordinated/common pioctls */
1064         pioctlSw = OpioctlSw;
1065         pioctlSwSize = sizeof(OpioctlSw);
1066         break;
1067     default:
1068         afs_PutFakeStat(&fakestate);
1069         return EINVAL;
1070     }
1071     function = acom & 0xff;
1072     if (function >= (pioctlSwSize / sizeof(char *))) {
1073         afs_PutFakeStat(&fakestate);
1074         return EINVAL;          /* out of range */
1075     }
1076     inSize = ablob->in_size;
1077
1078     /* Do all range checking before continuing */
1079     if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1080         return E2BIG;
1081
1082     /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1083     if (inSize > AFS_LRALLOCSIZ) {
1084         inData = osi_Alloc(inSize + 1);
1085     } else {
1086         inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1087     }
1088     if (!inData)
1089         return ENOMEM;
1090     if (inSize > 0) {
1091         AFS_COPYIN(ablob->in, inData, inSize, code);
1092         inData[inSize] = '\0';
1093     } else
1094         code = 0;
1095     if (code) {
1096         if (inSize > AFS_LRALLOCSIZ) {
1097             osi_Free(inData, inSize + 1);
1098         } else {
1099             osi_FreeLargeSpace(inData);
1100         }
1101         afs_PutFakeStat(&fakestate);
1102         return code;
1103     }
1104     if (function == 8 && device == 'V') {       /* PGetTokens */
1105         outSizeMax = MAXPIOCTLTOKENLEN;
1106         outData = osi_Alloc(outSizeMax);
1107     } else {
1108         outSizeMax = AFS_LRALLOCSIZ;
1109         outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1110     }
1111     if (!outData) {
1112         if (inSize > AFS_LRALLOCSIZ) {
1113             osi_Free(inData, inSize + 1);
1114         } else {
1115             osi_FreeLargeSpace(inData);
1116         }
1117         afs_PutFakeStat(&fakestate);
1118         return ENOMEM;
1119     }
1120     outSize = 0;
1121     code =
1122         (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1123                                &outSize, acred);
1124     if (inSize > AFS_LRALLOCSIZ) {
1125         osi_Free(inData, inSize + 1);
1126     } else {
1127         osi_FreeLargeSpace(inData);
1128     }
1129     if (code == 0 && ablob->out_size > 0) {
1130         if (outSize > ablob->out_size) {
1131             code = E2BIG;       /* data wont fit in user buffer */
1132         } else if (outSize) {
1133             AFS_COPYOUT(outData, ablob->out, outSize, code);
1134         }
1135     }
1136     if (outSizeMax > AFS_LRALLOCSIZ) {
1137         osi_Free(outData, outSizeMax);
1138     } else {
1139         osi_FreeLargeSpace(outData);
1140     }
1141     afs_PutFakeStat(&fakestate);
1142     return afs_CheckCode(code, &treq, 41);
1143 }
1144
1145 /*!
1146  * VIOCETFID (22) - Get file ID quickly
1147  *
1148  * \ingroup pioctl
1149  *
1150  * \param[in] ain       not in use
1151  * \param[out] aout     not in use
1152  *
1153  * \retval EINVAL       Error if some of the initial arguments aren't set
1154  *
1155  * \post get the file id of some file
1156  */
1157 DECL_PIOCTL(PGetFID)
1158 {
1159     AFS_STATCNT(PGetFID);
1160     if (!avc)
1161         return EINVAL;
1162     memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1163     *aoutSize = sizeof(struct VenusFid);
1164     return 0;
1165 }
1166
1167 /*!
1168  * VIOCSETAL (1) - Set access control list
1169  *
1170  * \ingroup pioctl
1171  *
1172  * \param[in] ain       the ACL being set
1173  * \param[out] aout     the ACL being set returned
1174  *
1175  * \retval EINVAL       Error if some of the standard args aren't set
1176  *
1177  * \post Changed ACL, via direct writing to the wire
1178  */
1179 int dummy_PSetAcl(char *ain, char *aout)
1180 {
1181     return 0;
1182 }
1183
1184 DECL_PIOCTL(PSetAcl)
1185 {
1186     register afs_int32 code;
1187     struct conn *tconn;
1188     struct AFSOpaque acl;
1189     struct AFSVolSync tsync;
1190     struct AFSFetchStatus OutStatus;
1191     XSTATS_DECLS;
1192
1193     AFS_STATCNT(PSetAcl);
1194     if (!avc)
1195         return EINVAL;
1196     if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1197         return EINVAL;
1198
1199     acl.AFSOpaque_val = ain;
1200     do {
1201         tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1202         if (tconn) {
1203             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1204             RX_AFS_GUNLOCK();
1205             code =
1206                 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->fid.Fid,
1207                                &acl, &OutStatus, &tsync);
1208             RX_AFS_GLOCK();
1209             XSTATS_END_TIME;
1210         } else
1211             code = -1;
1212     } while (afs_Analyze
1213              (tconn, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1214               SHARED_LOCK, NULL));
1215
1216     /* now we've forgotten all of the access info */
1217     ObtainWriteLock(&afs_xcbhash, 455);
1218     avc->callback = 0;
1219     afs_DequeueCallback(avc);
1220     avc->states &= ~(CStatd | CUnique);
1221     ReleaseWriteLock(&afs_xcbhash);
1222     if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1223         osi_dnlc_purgedp(avc);
1224     return code;
1225 }
1226
1227 int afs_defaultAsynchrony = 0;
1228
1229 /*!
1230  * VIOC_STOREBEHIND (47) Adjust store asynchrony
1231  *
1232  * \ingroup pioctl
1233  *
1234  * \param[in] ain       sbstruct (store behind structure) input
1235  * \param[out] aout     resulting sbstruct
1236  *
1237  * \retval EPERM        Error if the user doesn't have super-user credentials
1238  * \retval EACCES       Error if there isn't enough access to not check the mode bits
1239  *
1240  * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1241  */
1242 DECL_PIOCTL(PStoreBehind)
1243 {
1244     afs_int32 code = 0;
1245     struct sbstruct *sbr;
1246
1247     sbr = (struct sbstruct *)ain;
1248     if (sbr->sb_default != -1) {
1249         if (afs_osi_suser(*acred))
1250             afs_defaultAsynchrony = sbr->sb_default;
1251         else
1252             code = EPERM;
1253     }
1254
1255     if (avc && (sbr->sb_thisfile != -1)) {
1256         if (afs_AccessOK
1257             (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1258             avc->asynchrony = sbr->sb_thisfile;
1259         else
1260             code = EACCES;
1261     }
1262
1263     *aoutSize = sizeof(struct sbstruct);
1264     sbr = (struct sbstruct *)aout;
1265     sbr->sb_default = afs_defaultAsynchrony;
1266     if (avc) {
1267         sbr->sb_thisfile = avc->asynchrony;
1268     }
1269
1270     return code;
1271 }
1272
1273 /*!
1274  * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1275  *
1276  * \ingroup pioctl
1277  *
1278  * \param[in] ain       not in use
1279  * \param[out] aout     not in use
1280  *
1281  * \retval EACCES       Error if the user doesn't have super-user credentials
1282  *
1283  * \post set the gcpags to GCPAGS_USERDISABLED
1284  */
1285 DECL_PIOCTL(PGCPAGs)
1286 {
1287     if (!afs_osi_suser(*acred)) {
1288         return EACCES;
1289     }
1290     afs_gcpags = AFS_GCPAGS_USERDISABLED;
1291     return 0;
1292 }
1293
1294 /*!
1295  * VIOCGETAL (2) - Get access control list
1296  *
1297  * \ingroup pioctl
1298  *
1299  * \param[in] ain       not in use
1300  * \param[out] aout     the ACL
1301  *
1302  * \retval EINVAL       Error if some of the standard args aren't set
1303  * \retval ERANGE       Error if the vnode of the file id is too large
1304  * \retval -1           Error if getting the ACL failed
1305  *
1306  * \post Obtain the ACL, based on file ID
1307  *
1308  * \notes there is a hack to tell which type of ACL is being returned, checks the top 2-bytes to judge what type of ACL it is, only for dfs xlat or ACLs
1309  */
1310 DECL_PIOCTL(PGetAcl)
1311 {
1312     struct AFSOpaque acl;
1313     struct AFSVolSync tsync;
1314     struct AFSFetchStatus OutStatus;
1315     afs_int32 code;
1316     struct conn *tconn;
1317     struct AFSFid Fid;
1318     XSTATS_DECLS;
1319
1320     AFS_STATCNT(PGetAcl);
1321     if (!avc)
1322         return EINVAL;
1323     Fid.Volume = avc->fid.Fid.Volume;
1324     Fid.Vnode = avc->fid.Fid.Vnode;
1325     Fid.Unique = avc->fid.Fid.Unique;
1326     if (avc->states & CForeign) {
1327         /*
1328          * For a dfs xlator acl we have a special hack so that the
1329          * xlator will distinguish which type of acl will return. So
1330          * we currently use the top 2-bytes (vals 0-4) to tell which
1331          * type of acl to bring back. Horrible hack but this will
1332          * cause the least number of changes to code size and interfaces.
1333          */
1334         if (Fid.Vnode & 0xc0000000)
1335             return ERANGE;
1336         Fid.Vnode |= (ainSize << 30);
1337     }
1338     acl.AFSOpaque_val = aout;
1339     do {
1340         tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1341         if (tconn) {
1342             *aout = 0;
1343             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1344             RX_AFS_GUNLOCK();
1345             code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1346             RX_AFS_GLOCK();
1347             XSTATS_END_TIME;
1348         } else
1349             code = -1;
1350     } while (afs_Analyze
1351              (tconn, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1352               SHARED_LOCK, NULL));
1353
1354     if (code == 0) {
1355         *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1356     }
1357     return code;
1358 }
1359
1360 /*!
1361  * PNoop returns success.  Used for functions which are not implemented or are no longer in use.
1362  *
1363  * \ingroup pioctl
1364  *
1365  * \notes Functions involved in this: 17 (VIOCENGROUP) -- used to be enable group; 18 (VIOCDISGROUP) -- used to be disable group; 2 (?) -- get/set cache-bypass size threshold
1366  */
1367 DECL_PIOCTL(PNoop)
1368 {
1369     AFS_STATCNT(PNoop);
1370     return 0;
1371 }
1372
1373 /*!
1374  * PBogus returns fail.  Used for functions which are not implemented or are no longer in use.
1375  *
1376  * \ingroup pioctl
1377  *
1378  * \retval EINVAL       Error if some of the standard args aren't set
1379  *
1380  * \notes Functions involved in this: 0 (?); 4 (?); 6 (?); 7 (VIOCSTAT); 8 (?); 13 (VIOCGETTIME) -- used to be quick check time; 15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!; 16 (VIOCNOP) -- used to be testing code; 19 (VIOCLISTGROUPS) -- used to be list group; 23 (VIOCWAITFOREVER) -- used to be waitforever; 57 (VIOC_FPRIOSTATUS) -- arla: set file prio; 58 (VIOC_FHGET) -- arla: fallback getfh; 59 (VIOC_FHOPEN) -- arla: fallback fhopen; 60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug; 61 (VIOC_ARLADEBUG) -- arla: controls arla debug; 62 (VIOC_AVIATOR) -- arla: debug interface; 63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status; 64 (VIOC_CALCULATE_CACHE) -- arla: force cache check; 65 (VIOC_BREAKCELLBACK) -- arla: break callback; 68 (?) -- arla: fetch stats;
1381  */
1382 DECL_PIOCTL(PBogus)
1383 {
1384     AFS_STATCNT(PBogus);
1385     return EINVAL;
1386 }
1387
1388 /*!
1389  * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1390  *
1391  * \ingroup pioctl
1392  *
1393  * \param[in] ain       not in use (avc used to pass in file id)
1394  * \param[out] aout     cell name
1395  *
1396  * \retval EINVAL       Error if some of the standard args aren't set
1397  * \retval ESRCH        Error if the file isn't part of a cell
1398  *
1399  * \post Get a cell based on a passed in file id
1400  */
1401 DECL_PIOCTL(PGetFileCell)
1402 {
1403     register struct cell *tcell;
1404
1405     AFS_STATCNT(PGetFileCell);
1406     if (!avc)
1407         return EINVAL;
1408     tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1409     if (!tcell)
1410         return ESRCH;
1411     strcpy(aout, tcell->cellName);
1412     afs_PutCell(tcell, READ_LOCK);
1413     *aoutSize = strlen(aout) + 1;
1414     return 0;
1415 }
1416
1417 /*!
1418  * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1419  *
1420  * \ingroup pioctl
1421  *
1422  * \param[in] ain       not in use
1423  * \param[out] aout     cell name
1424  *
1425  * \retval EIO          Error if the afs daemon hasn't started yet
1426  * \retval ESRCH        Error if the machine isn't part of a cell, for whatever reason
1427  *
1428  * \post Get the primary cell that the machine is a part of.
1429  */
1430 DECL_PIOCTL(PGetWSCell)
1431 {
1432     struct cell *tcell = NULL;
1433
1434     AFS_STATCNT(PGetWSCell);
1435     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1436         return EIO;             /* Inappropriate ioctl for device */
1437
1438     tcell = afs_GetPrimaryCell(READ_LOCK);
1439     if (!tcell)                 /* no primary cell? */
1440         return ESRCH;
1441     strcpy(aout, tcell->cellName);
1442     *aoutSize = strlen(aout) + 1;
1443     afs_PutCell(tcell, READ_LOCK);
1444     return 0;
1445 }
1446
1447 /*!
1448  * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1449  *
1450  * \ingroup pioctl
1451  *
1452  * \param[in] ain       not in use (user id found via areq)
1453  * \param[out] aout     cell name
1454  *
1455  * \retval ESRCH        Error if the user id doesn't have a primary cell specified
1456  *
1457  * \post Get the primary cell for a certain user, based on the user's uid
1458  */
1459 DECL_PIOCTL(PGetUserCell)
1460 {
1461     register afs_int32 i;
1462     register struct unixuser *tu;
1463     register struct cell *tcell;
1464
1465     AFS_STATCNT(PGetUserCell);
1466     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1467         return EIO;             /* Inappropriate ioctl for device */
1468
1469     /* return the cell name of the primary cell for this user */
1470     i = UHash(areq->uid);
1471     ObtainWriteLock(&afs_xuser, 224);
1472     for (tu = afs_users[i]; tu; tu = tu->next) {
1473         if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1474             tu->refCount++;
1475             ReleaseWriteLock(&afs_xuser);
1476             break;
1477         }
1478     }
1479     if (tu) {
1480         tcell = afs_GetCell(tu->cell, READ_LOCK);
1481         afs_PutUser(tu, WRITE_LOCK);
1482         if (!tcell)
1483             return ESRCH;
1484         else {
1485             strcpy(aout, tcell->cellName);
1486             afs_PutCell(tcell, READ_LOCK);
1487             *aoutSize = strlen(aout) + 1;       /* 1 for the null */
1488         }
1489     } else {
1490         ReleaseWriteLock(&afs_xuser);
1491         *aout = 0;
1492         *aoutSize = 1;
1493     }
1494     return 0;
1495 }
1496
1497 /*!
1498  * VIOCSETTOK (3) - Set authentication tokens
1499  *
1500  * \ingroup pioctl
1501  *
1502  * \param[in] ain       the krb tickets from which to set the afs tokens
1503  * \param[out] aout     not in use
1504  *
1505  * \retval EINVAL       Error if the ticket is either too long or too short
1506  * \retval EIO          Error if the AFS initState is below 101
1507  * \retval ESRCH        Error if the cell for which the Token is being set can't be found
1508  *
1509  * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1510  *
1511  */
1512 DECL_PIOCTL(PSetTokens)
1513 {
1514     afs_int32 i;
1515     register struct unixuser *tu;
1516     struct ClearToken clear;
1517     register struct cell *tcell;
1518     char *stp;
1519     int stLen;
1520     struct vrequest treq;
1521     afs_int32 flag, set_parent_pag = 0;
1522
1523     AFS_STATCNT(PSetTokens);
1524     if (!afs_resourceinit_flag) {
1525         return EIO;
1526     }
1527     memcpy((char *)&i, ain, sizeof(afs_int32));
1528     ain += sizeof(afs_int32);
1529     stp = ain;                  /* remember where the ticket is */
1530     if (i < 0 || i > MAXKTCTICKETLEN)
1531         return EINVAL;          /* malloc may fail */
1532     stLen = i;
1533     ain += i;                   /* skip over ticket */
1534     memcpy((char *)&i, ain, sizeof(afs_int32));
1535     ain += sizeof(afs_int32);
1536     if (i != sizeof(struct ClearToken)) {
1537         return EINVAL;
1538     }
1539     memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1540     if (clear.AuthHandle == -1)
1541         clear.AuthHandle = 999; /* more rxvab compat stuff */
1542     ain += sizeof(struct ClearToken);
1543     if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1544         /* still stuff left?  we've got primary flag and cell name.  Set these */
1545         memcpy((char *)&flag, ain, sizeof(afs_int32));  /* primary id flag */
1546         ain += sizeof(afs_int32);       /* skip id field */
1547         /* rest is cell name, look it up */
1548         /* some versions of gcc appear to need != 0 in order to get this right */
1549         if ((flag & 0x8000) != 0) {     /* XXX Use Constant XXX */
1550             flag &= ~0x8000;
1551             set_parent_pag = 1;
1552         }
1553         tcell = afs_GetCellByName(ain, READ_LOCK);
1554         if (!tcell)
1555             goto nocell;
1556     } else {
1557         /* default to primary cell, primary id */
1558         flag = 1;               /* primary id */
1559         tcell = afs_GetPrimaryCell(READ_LOCK);
1560         if (!tcell)
1561             goto nocell;
1562     }
1563     i = tcell->cellNum;
1564     afs_PutCell(tcell, READ_LOCK);
1565     if (set_parent_pag) {
1566         afs_int32 pag;
1567 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1568 #if defined(AFS_DARWIN_ENV)
1569         struct proc *p = current_proc();        /* XXX */
1570 #else
1571         struct proc *p = curproc;       /* XXX */
1572 #endif
1573 #ifndef AFS_DARWIN80_ENV
1574         uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1575                 p->p_pid, p->p_comm);
1576 #endif
1577         if (!setpag(p, acred, -1, &pag, 1)) {
1578 #else
1579 #ifdef  AFS_OSF_ENV
1580         if (!setpag(u.u_procp, acred, -1, &pag, 1)) {   /* XXX u.u_procp is a no-op XXX */
1581 #else
1582         if (!setpag(acred, -1, &pag, 1)) {
1583 #endif
1584 #endif
1585             afs_InitReq(&treq, *acred);
1586             areq = &treq;
1587         }
1588     }
1589     /* now we just set the tokens */
1590     tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1591     tu->vid = clear.ViceId;
1592     if (tu->stp != NULL) {
1593         afs_osi_Free(tu->stp, tu->stLen);
1594     }
1595     tu->stp = (char *)afs_osi_Alloc(stLen);
1596     if (tu->stp == NULL) {
1597         return ENOMEM;
1598     }
1599     tu->stLen = stLen;
1600     memcpy(tu->stp, stp, stLen);
1601     tu->ct = clear;
1602 #ifndef AFS_NOSTATS
1603     afs_stats_cmfullperf.authent.TicketUpdates++;
1604     afs_ComputePAGStats();
1605 #endif /* AFS_NOSTATS */
1606     tu->states |= UHasTokens;
1607     tu->states &= ~UTokensBad;
1608     afs_SetPrimary(tu, flag);
1609     tu->tokenTime = osi_Time();
1610     afs_ResetUserConns(tu);
1611     afs_PutUser(tu, WRITE_LOCK);
1612
1613     return 0;
1614
1615   nocell:
1616     {
1617         int t1;
1618         t1 = afs_initState;
1619         if (t1 < 101)
1620             return EIO;
1621         else
1622             return ESRCH;
1623     }
1624 }
1625
1626 /*!
1627  * VIOCGETVOLSTAT (4) - Get volume status
1628  *
1629  * \ingroup pioctl
1630  *
1631  * \param[in] ain       not in use
1632  * \param[out] aout     status of the volume
1633  *
1634  * \retval EINVAL       Error if some of the standard args aren't set
1635  *
1636  * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1637  */
1638 DECL_PIOCTL(PGetVolumeStatus)
1639 {
1640     char volName[32];
1641     char *offLineMsg = afs_osi_Alloc(256);
1642     char *motd = afs_osi_Alloc(256);
1643     register struct conn *tc;
1644     register afs_int32 code = 0;
1645     struct AFSFetchVolumeStatus volstat;
1646     register char *cp;
1647     char *Name, *OfflineMsg, *MOTD;
1648     XSTATS_DECLS;
1649
1650     AFS_STATCNT(PGetVolumeStatus);
1651     if (!avc) {
1652         code = EINVAL;
1653         goto out;
1654     }
1655     Name = volName;
1656     OfflineMsg = offLineMsg;
1657     MOTD = motd;
1658     do {
1659         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1660         if (tc) {
1661             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1662             RX_AFS_GUNLOCK();
1663             code =
1664                 RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1665                                       &Name, &OfflineMsg, &MOTD);
1666             RX_AFS_GLOCK();
1667             XSTATS_END_TIME;
1668         } else
1669             code = -1;
1670     } while (afs_Analyze
1671              (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1672               SHARED_LOCK, NULL));
1673
1674     if (code)
1675         goto out;
1676     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1677     cp = aout;
1678     memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1679     cp += sizeof(VolumeStatus);
1680     strcpy(cp, volName);
1681     cp += strlen(volName) + 1;
1682     strcpy(cp, offLineMsg);
1683     cp += strlen(offLineMsg) + 1;
1684     strcpy(cp, motd);
1685     cp += strlen(motd) + 1;
1686     *aoutSize = (cp - aout);
1687   out:
1688     afs_osi_Free(offLineMsg, 256);
1689     afs_osi_Free(motd, 256);
1690     return code;
1691 }
1692
1693 /*!
1694  * VIOCSETVOLSTAT (5) - Set volume status
1695  *
1696  * \ingroup pioctl
1697  *
1698  * \param[in] ain       values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1699  * \param[out] aout     status of a volume, offlines messages, minimum quota, maximumm quota
1700  *
1701  * \retval EINVAL       Error if some of the standard args aren't set
1702  * \retval EROFS        Error if the volume is read only, or a backup volume
1703  * \retval ENODEV       Error if the volume can't be accessed
1704  * \retval E2BIG        Error if the volume name, offline message, and motd are too big
1705  *
1706  * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1707  */
1708 DECL_PIOCTL(PSetVolumeStatus)
1709 {
1710     char volName[32];
1711     char *offLineMsg = afs_osi_Alloc(256);
1712     char *motd = afs_osi_Alloc(256);
1713     register struct conn *tc;
1714     register afs_int32 code = 0;
1715     struct AFSFetchVolumeStatus volstat;
1716     struct AFSStoreVolumeStatus storeStat;
1717     register struct volume *tvp;
1718     register char *cp;
1719     XSTATS_DECLS;
1720
1721     AFS_STATCNT(PSetVolumeStatus);
1722     if (!avc) {
1723         code = EINVAL;
1724         goto out;
1725     }
1726
1727     tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1728     if (tvp) {
1729         if (tvp->states & (VRO | VBackup)) {
1730             afs_PutVolume(tvp, READ_LOCK);
1731             code = EROFS;
1732             goto out;
1733         }
1734         afs_PutVolume(tvp, READ_LOCK);
1735     } else {
1736         code = ENODEV;
1737         goto out;
1738     }
1739     /* Copy the junk out, using cp as a roving pointer. */
1740     cp = ain;
1741     memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1742     cp += sizeof(AFSFetchVolumeStatus);
1743     if (strlen(cp) >= sizeof(volName)) {
1744         code = E2BIG;
1745         goto out;
1746     }
1747     strcpy(volName, cp);
1748     cp += strlen(volName) + 1;
1749     if (strlen(cp) >= sizeof(offLineMsg)) {
1750         code = E2BIG;
1751         goto out;
1752     }
1753     strcpy(offLineMsg, cp);
1754     cp += strlen(offLineMsg) + 1;
1755     if (strlen(cp) >= sizeof(motd)) {
1756         code = E2BIG;
1757         goto out;
1758     }
1759     strcpy(motd, cp);
1760     storeStat.Mask = 0;
1761     if (volstat.MinQuota != -1) {
1762         storeStat.MinQuota = volstat.MinQuota;
1763         storeStat.Mask |= AFS_SETMINQUOTA;
1764     }
1765     if (volstat.MaxQuota != -1) {
1766         storeStat.MaxQuota = volstat.MaxQuota;
1767         storeStat.Mask |= AFS_SETMAXQUOTA;
1768     }
1769     do {
1770         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1771         if (tc) {
1772             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1773             RX_AFS_GUNLOCK();
1774             code =
1775                 RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume, &storeStat,
1776                                       volName, offLineMsg, motd);
1777             RX_AFS_GLOCK();
1778             XSTATS_END_TIME;
1779         } else
1780             code = -1;
1781     } while (afs_Analyze
1782              (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1783               SHARED_LOCK, NULL));
1784
1785     if (code)
1786         goto out;
1787     /* we are sending parms back to make compat. with prev system.  should
1788      * change interface later to not ask for current status, just set new status */
1789     cp = aout;
1790     memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1791     cp += sizeof(VolumeStatus);
1792     strcpy(cp, volName);
1793     cp += strlen(volName) + 1;
1794     strcpy(cp, offLineMsg);
1795     cp += strlen(offLineMsg) + 1;
1796     strcpy(cp, motd);
1797     cp += strlen(motd) + 1;
1798     *aoutSize = cp - aout;
1799   out:
1800     afs_osi_Free(offLineMsg, 256);
1801     afs_osi_Free(motd, 256);
1802     return code;
1803 }
1804
1805 /*!
1806  * VIOCFLUSH (6) - Invalidate cache entry
1807  *
1808  * \ingroup pioctl
1809  *
1810  * \param[in] ain       not in use
1811  * \param[out] aout     not in use
1812  *
1813  * \retval EINVAL       Error if some of the standard args aren't set
1814  *
1815  * \post Flush any information the cache manager has on an entry
1816  */
1817 DECL_PIOCTL(PFlush)
1818 {
1819     AFS_STATCNT(PFlush);
1820     if (!avc)
1821         return EINVAL;
1822 #ifdef AFS_BOZONLOCK_ENV
1823     afs_BozonLock(&avc->pvnLock, avc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
1824 #endif
1825     ObtainWriteLock(&avc->lock, 225);
1826     ObtainWriteLock(&afs_xcbhash, 456);
1827     afs_DequeueCallback(avc);
1828     avc->states &= ~(CStatd | CDirty);  /* next reference will re-stat cache entry */
1829     ReleaseWriteLock(&afs_xcbhash);
1830     /* now find the disk cache entries */
1831     afs_TryToSmush(avc, *acred, 1);
1832     osi_dnlc_purgedp(avc);
1833     if (avc->linkData && !(avc->states & CCore)) {
1834         afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
1835         avc->linkData = NULL;
1836     }
1837     ReleaseWriteLock(&avc->lock);
1838 #ifdef AFS_BOZONLOCK_ENV
1839     afs_BozonUnlock(&avc->pvnLock, avc);
1840 #endif
1841     return 0;
1842 }
1843
1844 /*!
1845  * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1846  *
1847  * \ingroup pioctl
1848  *
1849  * \param[in] ain       the last component in a path, related to mountpoint that we're looking for information about
1850  * \param[out] aout     volume, cell, link data 
1851  *
1852  * \retval EINVAL       Error if some of the standard args aren't set
1853  * \retval ENOTDIR      Error if the 'mount point' argument isn't a directory
1854  * \retval EIO          Error if the link data can't be accessed
1855  *
1856  * \post Get the volume, and cell, as well as the link data for a mount point
1857  */
1858 DECL_PIOCTL(PNewStatMount)
1859 {
1860     register afs_int32 code;
1861     register struct vcache *tvc;
1862     register struct dcache *tdc;
1863     struct VenusFid tfid;
1864     char *bufp;
1865     struct sysname_info sysState;
1866     afs_size_t offset, len;
1867
1868     AFS_STATCNT(PNewStatMount);
1869     if (!avc)
1870         return EINVAL;
1871     code = afs_VerifyVCache(avc, areq);
1872     if (code)
1873         return code;
1874     if (vType(avc) != VDIR) {
1875         return ENOTDIR;
1876     }
1877     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1878     if (!tdc)
1879         return ENOENT;
1880     Check_AtSys(avc, ain, &sysState, areq);
1881     ObtainReadLock(&tdc->lock);
1882     do {
1883         code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1884     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1885     ReleaseReadLock(&tdc->lock);
1886     afs_PutDCache(tdc);         /* we're done with the data */
1887     bufp = sysState.name;
1888     if (code) {
1889         goto out;
1890     }
1891     tfid.Cell = avc->fid.Cell;
1892     tfid.Fid.Volume = avc->fid.Fid.Volume;
1893     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1894         tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1895     } else {
1896         tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1897     }
1898     if (!tvc) {
1899         code = ENOENT;
1900         goto out;
1901     }
1902     if (tvc->mvstat != 1) {
1903         afs_PutVCache(tvc);
1904         code = EINVAL;
1905         goto out;
1906     }
1907     ObtainWriteLock(&tvc->lock, 226);
1908     code = afs_HandleLink(tvc, areq);
1909     if (code == 0) {
1910         if (tvc->linkData) {
1911             if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1912                 code = EINVAL;
1913             else {
1914                 /* we have the data */
1915                 strcpy(aout, tvc->linkData);
1916                 *aoutSize = strlen(tvc->linkData) + 1;
1917             }
1918         } else
1919             code = EIO;
1920     }
1921     ReleaseWriteLock(&tvc->lock);
1922     afs_PutVCache(tvc);
1923   out:
1924     if (sysState.allocked)
1925         osi_FreeLargeSpace(bufp);
1926     return code;
1927 }
1928
1929 /*!
1930  * VIOCGETTOK (8) - Get authentication tokens
1931  *  
1932  * \ingroup pioctl
1933  *      
1934  * \param[in] ain       userid
1935  * \param[out] aout     token
1936  * 
1937  * \retval EIO          Error if the afs daemon hasn't started yet
1938  * \retval EDOM         Error if the input parameter is out of the bounds of the available tokens
1939  * \retval ENOTCONN     Error if there aren't tokens for this cell
1940  *  
1941  * \post If the input paramater exists, get the token that corresponds to the parameter value, if there is no token at this value, get the token for the first cell
1942  *
1943  * \notes "it's a weird interface (from comments in the code)"
1944  */
1945
1946 DECL_PIOCTL(PGetTokens)
1947 {
1948     register struct cell *tcell;
1949     register afs_int32 i;
1950     register struct unixuser *tu;
1951     register char *cp;
1952     afs_int32 iterator;
1953     int newStyle;
1954
1955     AFS_STATCNT(PGetTokens);
1956     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1957         return EIO;             /* Inappropriate ioctl for device */
1958
1959     /* weird interface.  If input parameter is present, it is an integer and
1960      * we're supposed to return the parm'th tokens for this unix uid.
1961      * If not present, we just return tokens for cell 1.
1962      * If counter out of bounds, return EDOM.
1963      * If no tokens for the particular cell, return ENOTCONN.
1964      * Also, if this mysterious parm is present, we return, along with the
1965      * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1966      * at the end, in that order.
1967      */
1968     if ((newStyle = (ainSize > 0))) {
1969         memcpy((char *)&iterator, ain, sizeof(afs_int32));
1970     }
1971     i = UHash(areq->uid);
1972     ObtainReadLock(&afs_xuser);
1973     for (tu = afs_users[i]; tu; tu = tu->next) {
1974         if (newStyle) {
1975             if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1976                 if (iterator-- == 0)
1977                     break;      /* are we done yet? */
1978             }
1979         } else {
1980             if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1981                 break;
1982         }
1983     }
1984     if (tu) {
1985         /*
1986          * No need to hold a read lock on each user entry
1987          */
1988         tu->refCount++;
1989     }
1990     ReleaseReadLock(&afs_xuser);
1991
1992     if (!tu) {
1993         return EDOM;
1994     }
1995     if (((tu->states & UHasTokens) == 0)
1996         || (tu->ct.EndTimestamp < osi_Time())) {
1997         tu->states |= (UTokensBad | UNeedsReset);
1998         afs_PutUser(tu, READ_LOCK);
1999         return ENOTCONN;
2000     }
2001     /* use iterator for temp */
2002     cp = aout;
2003     iterator = tu->stLen;       /* for compat, we try to return 56 byte tix if they fit */
2004     if (iterator < 56)
2005         iterator = 56;          /* # of bytes we're returning */
2006     memcpy(cp, (char *)&iterator, sizeof(afs_int32));
2007     cp += sizeof(afs_int32);
2008     memcpy(cp, tu->stp, tu->stLen);     /* copy out st */
2009     cp += iterator;
2010     iterator = sizeof(struct ClearToken);
2011     memcpy(cp, (char *)&iterator, sizeof(afs_int32));
2012     cp += sizeof(afs_int32);
2013     memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
2014     cp += sizeof(struct ClearToken);
2015     if (newStyle) {
2016         /* put out primary id and cell name, too */
2017         iterator = (tu->states & UPrimary ? 1 : 0);
2018         memcpy(cp, (char *)&iterator, sizeof(afs_int32));
2019         cp += sizeof(afs_int32);
2020         tcell = afs_GetCell(tu->cell, READ_LOCK);
2021         if (tcell) {
2022             strcpy(cp, tcell->cellName);
2023             cp += strlen(tcell->cellName) + 1;
2024             afs_PutCell(tcell, READ_LOCK);
2025         } else
2026             *cp++ = 0;
2027     }
2028     *aoutSize = cp - aout;
2029     afs_PutUser(tu, READ_LOCK);
2030     return 0;
2031 }
2032
2033 /*!
2034  * VIOCUNLOG (9) - Invalidate tokens
2035  *
2036  * \ingroup pioctl
2037  *
2038  * \param[in] ain       not in use
2039  * \param[out] aout     not in use
2040  *
2041  * \retval EIO  Error if the afs daemon hasn't been started yet
2042  *
2043  * \post remove tokens from a user, specified by the user id
2044  *
2045  * \notes sets the token's time to 0, which then causes it to be removed
2046  * \notes Unlog is the same as un-pag in OpenAFS
2047  */
2048 DECL_PIOCTL(PUnlog)
2049 {
2050     register afs_int32 i;
2051     register struct unixuser *tu;
2052
2053     AFS_STATCNT(PUnlog);
2054     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2055         return EIO;             /* Inappropriate ioctl for device */
2056
2057     i = UHash(areq->uid);
2058     ObtainWriteLock(&afs_xuser, 227);
2059     for (tu = afs_users[i]; tu; tu = tu->next) {
2060         if (tu->uid == areq->uid) {
2061             tu->vid = UNDEFVID;
2062             tu->states &= ~UHasTokens;
2063             /* security is not having to say you're sorry */
2064             memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
2065             tu->refCount++;
2066             ReleaseWriteLock(&afs_xuser);
2067             /* We have to drop the lock over the call to afs_ResetUserConns, since
2068              * it obtains the afs_xvcache lock.  We could also keep the lock, and
2069              * modify ResetUserConns to take parm saying we obtained the lock
2070              * already, but that is overkill.  By keeping the "tu" pointer
2071              * held over the released lock, we guarantee that we won't lose our
2072              * place, and that we'll pass over every user conn that existed when
2073              * we began this call.
2074              */
2075             afs_ResetUserConns(tu);
2076             tu->refCount--;
2077             ObtainWriteLock(&afs_xuser, 228);
2078 #ifdef UKERNEL
2079             /* set the expire times to 0, causes
2080              * afs_GCUserData to remove this entry
2081              */
2082             tu->ct.EndTimestamp = 0;
2083             tu->tokenTime = 0;
2084 #endif /* UKERNEL */
2085         }
2086     }
2087     ReleaseWriteLock(&afs_xuser);
2088     return 0;
2089 }
2090
2091 /*!
2092  * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2093  *
2094  * \ingroup pioctl
2095  *
2096  * \param[in] ain       host address to be set
2097  * \param[out] aout     old host address
2098  *
2099  * \post depending on whether or not a variable is set, either get the host for the cache manager monitor, or set the old address and give it a new address
2100  *
2101  * \notes Errors turn off mariner
2102  */
2103 DECL_PIOCTL(PMariner)
2104 {
2105     afs_int32 newHostAddr;
2106     afs_int32 oldHostAddr;
2107
2108     AFS_STATCNT(PMariner);
2109     if (afs_mariner)
2110         memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2111                sizeof(afs_int32));
2112     else
2113         oldHostAddr = 0xffffffff;       /* disabled */
2114
2115     memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2116     if (newHostAddr == 0xffffffff) {
2117         /* disable mariner operations */
2118         afs_mariner = 0;
2119     } else if (newHostAddr) {
2120         afs_mariner = 1;
2121         afs_marinerHost = newHostAddr;
2122     }
2123     memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2124     *aoutSize = sizeof(afs_int32);
2125     return 0;
2126 }
2127
2128 /*!
2129  * VIOCCKSERV (10) - Check that servers are up
2130  *
2131  * \ingroup pioctl
2132  *
2133  * \param[in] ain       name of the cell
2134  * \param[out] aout     current down server list
2135  *
2136  * \retval EIO          Error if the afs daemon hasn't started yet
2137  * \retval EACCES       Error if the user doesn't have super-user credentials
2138  * \retval ENOENT       Error if we are unable to obtain the cell
2139  *
2140  * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2141  */
2142 DECL_PIOCTL(PCheckServers)
2143 {
2144     register char *cp = 0;
2145     register int i;
2146     register struct server *ts;
2147     afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2148     struct cell *cellp;
2149     struct chservinfo *pcheck;
2150
2151     AFS_STATCNT(PCheckServers);
2152
2153     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2154         return EIO;             /* Inappropriate ioctl for device */
2155
2156     if (*lp == 0x12345678) {    /* For afs3.3 version */
2157         pcheck = (struct chservinfo *)ain;
2158         if (pcheck->tinterval >= 0) {
2159             cp = aout;
2160             memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2161             *aoutSize = sizeof(afs_int32);
2162             if (pcheck->tinterval > 0) {
2163                 if (!afs_osi_suser(*acred))
2164                     return EACCES;
2165                 afs_probe_interval = pcheck->tinterval;
2166             }
2167             return 0;
2168         }
2169         if (pcheck->tsize)
2170             havecell = 1;
2171         temp = pcheck->tflags;
2172         cp = pcheck->tbuffer;
2173     } else {                    /* For pre afs3.3 versions */
2174         memcpy((char *)&temp, ain, sizeof(afs_int32));
2175         cp = ain + sizeof(afs_int32);
2176         if (ainSize > sizeof(afs_int32))
2177             havecell = 1;
2178     }
2179
2180     /*
2181      * 1: fast check, don't contact servers.
2182      * 2: local cell only.
2183      */
2184     if (havecell) {
2185         /* have cell name, too */
2186         cellp = afs_GetCellByName(cp, READ_LOCK);
2187         if (!cellp)
2188             return ENOENT;
2189     } else
2190         cellp = NULL;
2191     if (!cellp && (temp & 2)) {
2192         /* use local cell */
2193         cellp = afs_GetPrimaryCell(READ_LOCK);
2194     }
2195     if (!(temp & 1)) {          /* if not fast, call server checker routine */
2196         afs_CheckServers(1, cellp);     /* check down servers */
2197         afs_CheckServers(0, cellp);     /* check up servers */
2198     }
2199     /* now return the current down server list */
2200     cp = aout;
2201     ObtainReadLock(&afs_xserver);
2202     for (i = 0; i < NSERVERS; i++) {
2203         for (ts = afs_servers[i]; ts; ts = ts->next) {
2204             if (cellp && ts->cell != cellp)
2205                 continue;       /* cell spec'd and wrong */
2206             if ((ts->flags & SRVR_ISDOWN)
2207                 && ts->addr->sa_portal != ts->cell->vlport) {
2208                 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2209                 cp += sizeof(afs_int32);
2210             }
2211         }
2212     }
2213     ReleaseReadLock(&afs_xserver);
2214     if (cellp)
2215         afs_PutCell(cellp, READ_LOCK);
2216     *aoutSize = cp - aout;
2217     return 0;
2218 }
2219
2220 /*!
2221  * VIOCCKBACK (11) - Check backup volume mappings
2222  *
2223  * \ingroup pioctl
2224  *
2225  * \param[in] ain       not in use
2226  * \param[out] aout     not in use
2227  *
2228  * \retval EIO          Error if the afs daemon hasn't started yet
2229  *
2230  * \post Check the root volume, and then check the names if the volume check variable is set to force, has expired, is busy, or if the mount points variable is set
2231  */
2232 DECL_PIOCTL(PCheckVolNames)
2233 {
2234     AFS_STATCNT(PCheckVolNames);
2235     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2236         return EIO;             /* Inappropriate ioctl for device */
2237
2238     afs_CheckRootVolume();
2239     afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2240                          AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2241     return 0;
2242 }
2243
2244 /*!
2245  * VIOCCKCONN (12) - Check connections for a user
2246  *
2247  * \ingroup pioctl
2248  *
2249  * \param[in] ain       not in use
2250  * \param[out] aout     not in use
2251  *
2252  * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2253  *
2254  * \post check to see if a user has the correct authentication.  If so, allow access.
2255  *
2256  * \notes Check the connections to all the servers specified
2257  */
2258 DECL_PIOCTL(PCheckAuth)
2259 {
2260     int i;
2261     struct srvAddr *sa;
2262     struct conn *tc;
2263     struct unixuser *tu;
2264     afs_int32 retValue;
2265
2266     AFS_STATCNT(PCheckAuth);
2267     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2268         return EIO;             /* Inappropriate ioctl for device */
2269
2270     retValue = 0;
2271     tu = afs_GetUser(areq->uid, 1, READ_LOCK);  /* check local cell authentication */
2272     if (!tu)
2273         retValue = EACCES;
2274     else {
2275         /* we have a user */
2276         ObtainReadLock(&afs_xsrvAddr);
2277         ObtainReadLock(&afs_xconn);
2278
2279         /* any tokens set? */
2280         if ((tu->states & UHasTokens) == 0)
2281             retValue = EACCES;
2282         /* all connections in cell 1 working? */
2283         for (i = 0; i < NSERVERS; i++) {
2284             for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2285                 for (tc = sa->conns; tc; tc = tc->next) {
2286                     if (tc->user == tu && (tu->states & UTokensBad))
2287                         retValue = EACCES;
2288                 }
2289             }
2290         }
2291         ReleaseReadLock(&afs_xsrvAddr);
2292         ReleaseReadLock(&afs_xconn);
2293         afs_PutUser(tu, READ_LOCK);
2294     }
2295     memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2296     *aoutSize = sizeof(afs_int32);
2297     return 0;
2298 }
2299
2300 static int
2301 Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
2302          struct AFS_UCRED *acred)
2303 {
2304     register char *tp;
2305     register afs_int32 code;
2306 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2307     size_t bufferSize;
2308 #else
2309     u_int bufferSize;
2310 #endif
2311
2312     AFS_STATCNT(Prefetch);
2313     if (!apath)
2314         return EINVAL;
2315     tp = osi_AllocLargeSpace(1024);
2316     AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2317     if (code) {
2318         osi_FreeLargeSpace(tp);
2319         return code;
2320     }
2321     if (afs_BBusy()) {          /* do this as late as possible */
2322         osi_FreeLargeSpace(tp);
2323         return EWOULDBLOCK;     /* pretty close */
2324     }
2325     afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2326                (afs_size_t) 0, tp);
2327     return 0;
2328 }
2329
2330 /*!
2331  * VIOCWHEREIS (14) - Find out where a volume is located
2332  *
2333  * \ingroup pioctl
2334  *
2335  * \param[in] ain       not in use
2336  * \param[out] aout     volume location
2337  *
2338  * \retval EINVAL       Error if some of the default arguments don't exist
2339  * \retval ENODEV       Error if there is no such volume
2340  *
2341  * \post fine a volume, based on a volume file id
2342  *
2343  * \notes check each of the servers specified
2344  */
2345 DECL_PIOCTL(PFindVolume)
2346 {
2347     register struct volume *tvp;
2348     register struct server *ts;
2349     register afs_int32 i;
2350     register char *cp;
2351
2352     AFS_STATCNT(PFindVolume);
2353     if (!avc)
2354         return EINVAL;
2355     tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2356     if (tvp) {
2357         cp = aout;
2358         for (i = 0; i < MAXHOSTS; i++) {
2359             ts = tvp->serverHost[i];
2360             if (!ts)
2361                 break;
2362             memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2363             cp += sizeof(afs_int32);
2364         }
2365         if (i < MAXHOSTS) {
2366             /* still room for terminating NULL, add it on */
2367             ainSize = 0;        /* reuse vbl */
2368             memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2369             cp += sizeof(afs_int32);
2370         }
2371         *aoutSize = cp - aout;
2372         afs_PutVolume(tvp, READ_LOCK);
2373         return 0;
2374     }
2375     return ENODEV;
2376 }
2377
2378 /*!
2379  * VIOCACCESS (20) - Access using PRS_FS bits
2380  *
2381  * \ingroup pioctl
2382  *
2383  * \param[in] ain       PRS_FS bits
2384  * \param[out] aout     not in use
2385  *
2386  * \retval EINVAL       Error if some of the initial arguments aren't set
2387  * \retval EACCES       Error if access is denied
2388  *
2389  * \post check to make sure access is allowed
2390  */
2391 DECL_PIOCTL(PViceAccess)
2392 {
2393     register afs_int32 code;
2394     afs_int32 temp;
2395
2396     AFS_STATCNT(PViceAccess);
2397     if (!avc)
2398         return EINVAL;
2399     code = afs_VerifyVCache(avc, areq);
2400     if (code)
2401         return code;
2402     memcpy((char *)&temp, ain, sizeof(afs_int32));
2403     code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2404     if (code)
2405         return 0;
2406     else
2407         return EACCES;
2408 }
2409
2410 DECL_PIOCTL(PPrecache)
2411 {
2412     afs_int32 newValue;
2413
2414     /*AFS_STATCNT(PPrecache);*/
2415     if (!afs_osi_suser(*acred))
2416         return EACCES;
2417     memcpy((char *)&newValue, ain, sizeof(afs_int32));
2418     afs_preCache = newValue*1024;
2419     return 0;
2420 }
2421
2422 /*!
2423  * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2424  *
2425  * \ingroup pioctl
2426  *
2427  * \param[in] ain       the size the venus cache should be set to
2428  * \param[out] aout     not in use
2429  *
2430  * \retval EACCES       Error if the user doesn't have super-user credentials
2431  * \retval EROFS        Error if the cache is set to be in memory
2432  *
2433  * \post Set the cache size based on user input.  If no size is given, set it to the default OpenAFS cache size.
2434  *
2435  * \notes recompute the general cache parameters for every single block allocated
2436  */
2437 DECL_PIOCTL(PSetCacheSize)
2438 {
2439     afs_int32 newValue;
2440     int waitcnt = 0;
2441
2442     AFS_STATCNT(PSetCacheSize);
2443     if (!afs_osi_suser(*acred))
2444         return EACCES;
2445     /* too many things are setup initially in mem cache version */
2446     if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2447         return EROFS;
2448     memcpy((char *)&newValue, ain, sizeof(afs_int32));
2449     if (newValue == 0)
2450         afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2451     else {
2452         if (newValue < afs_min_cache)
2453             afs_cacheBlocks = afs_min_cache;
2454         else
2455             afs_cacheBlocks = newValue;
2456     }
2457     afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2458     afs_ComputeCacheParms();    /* recompute basic cache parameters */
2459     afs_MaybeWakeupTruncateDaemon();
2460     while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2461         afs_osi_Wait(1000, 0, 0);
2462         afs_MaybeWakeupTruncateDaemon();
2463     }
2464     return 0;
2465 }
2466
2467 #define MAXGCSTATS      16
2468 /*!
2469  * VIOCGETCACHEPARMS (40) - Get cache stats
2470  *
2471  * \ingroup pioctl
2472  *
2473  * \param[in] ain       afs index flags
2474  * \param[out] aout     cache blocks, blocks used, blocks files (in an array)
2475  *
2476  * \post Get the cache blocks, and how many of the cache blocks there are
2477  */
2478 DECL_PIOCTL(PGetCacheSize)
2479 {
2480     afs_int32 results[MAXGCSTATS];
2481     afs_int32 flags;
2482     register struct dcache * tdc;
2483     int i, size;
2484     
2485     AFS_STATCNT(PGetCacheSize);
2486
2487     if (sizeof(afs_int32) == ainSize){
2488         memcpy((char *)&flags, ain, sizeof(afs_int32));
2489     } else if (0 == ainSize){ 
2490         flags = 0;
2491     } else {
2492         return EINVAL;
2493     }
2494     
2495     memset((char *)results, 0, sizeof(results));
2496     results[0] = afs_cacheBlocks;
2497     results[1] = afs_blocksUsed;
2498     results[2] = afs_cacheFiles;
2499     
2500     if (1 == flags){
2501         for (i = 0; i < afs_cacheFiles; i++) {
2502             if (afs_indexFlags[i] & IFFree) results[3]++;
2503         }
2504     } else if (2 == flags){
2505         for (i = 0; i < afs_cacheFiles; i++) {
2506             if (afs_indexFlags[i] & IFFree) results[3]++;
2507             if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2508             if (afs_indexFlags[i] & IFDataMod) results[5]++;
2509             if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2510             if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2511             if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2512
2513             tdc = afs_indexTable[i];
2514             if (tdc){
2515                 results[9]++;
2516                 size = tdc->validPos;
2517                 if ( 0 < size && size < (1<<12) ) results[10]++;
2518                 else if (size < (1<<14) ) results[11]++;
2519                 else if (size < (1<<16) ) results[12]++;
2520                 else if (size < (1<<18) ) results[13]++;
2521                 else if (size < (1<<20) ) results[14]++;
2522                 else if (size >= (1<<20) ) results[15]++;
2523             }
2524         }
2525     }
2526     memcpy(aout, (char *)results, sizeof(results));
2527     *aoutSize = sizeof(results);
2528     return 0;
2529 }
2530
2531 /*!
2532  * VIOCFLUSHCB (25) - Flush callback only
2533  *
2534  * \ingroup pioctl
2535  *
2536  * \param[in] ain       not in use
2537  * \param[out] aout     not in use
2538  *
2539  * \retval EINVAL       Error if some of the standard args aren't set
2540  * \retval 0            0 returned if the volume is set to read-only
2541  *
2542  * \post Flushes callbacks, by setting the length of callbacks to one, setting the next callback to be sent to the CB_DROPPED value, and then dequeues everything else.
2543  */
2544 DECL_PIOCTL(PRemoveCallBack)
2545 {
2546     register struct conn *tc;
2547     register afs_int32 code = 0;
2548     struct AFSCallBack CallBacks_Array[1];
2549     struct AFSCBFids theFids;
2550     struct AFSCBs theCBs;
2551     XSTATS_DECLS;
2552
2553     AFS_STATCNT(PRemoveCallBack);
2554     if (!avc)
2555         return EINVAL;
2556     if (avc->states & CRO)
2557         return 0;               /* read-only-ness can't change */
2558     ObtainWriteLock(&avc->lock, 229);
2559     theFids.AFSCBFids_len = 1;
2560     theCBs.AFSCBs_len = 1;
2561     theFids.AFSCBFids_val = (struct AFSFid *)&avc->fid.Fid;
2562     theCBs.AFSCBs_val = CallBacks_Array;
2563     CallBacks_Array[0].CallBackType = CB_DROPPED;
2564     if (avc->callback) {
2565         do {
2566             tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2567             if (tc) {
2568                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2569                 RX_AFS_GUNLOCK();
2570                 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2571                 RX_AFS_GLOCK();
2572                 XSTATS_END_TIME;
2573             }
2574             /* don't set code on failure since we wouldn't use it */
2575         } while (afs_Analyze
2576                  (tc, code, &avc->fid, areq,
2577                   AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2578
2579         ObtainWriteLock(&afs_xcbhash, 457);
2580         afs_DequeueCallback(avc);
2581         avc->callback = 0;
2582         avc->states &= ~(CStatd | CUnique);
2583         ReleaseWriteLock(&afs_xcbhash);
2584         if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2585             osi_dnlc_purgedp(avc);
2586     }
2587     ReleaseWriteLock(&avc->lock);
2588     return 0;
2589 }
2590
2591 /*!
2592  * VIOCNEWCELL (26) - Configure new cell
2593  *
2594  * \ingroup pioctl
2595  *
2596  * \param[in] ain       the name of the cell, the hosts that will be a part of the cell, whether or not it's linked with another cell, the other cell it's linked with, the file server port, and the volume server port
2597  * \param[out] aout     not in use
2598  *
2599  * \retval EIO          Error if the afs daemon hasn't started yet
2600  * \retval EACCES       Error if the user doesn't have super-user cedentials
2601  * \retval EINVAL       Error if some 'magic' var doesn't have a certain bit set
2602  *
2603  * \post creates a new cell
2604  */
2605 DECL_PIOCTL(PNewCell)
2606 {
2607     /* create a new cell */
2608     afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2609     char *newcell = 0, *linkedcell = 0, *tp = ain;
2610     register afs_int32 code, linkedstate = 0, ls;
2611     u_short fsport = 0, vlport = 0;
2612     afs_int32 scount;
2613
2614     AFS_STATCNT(PNewCell);
2615     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2616         return EIO;             /* Inappropriate ioctl for device */
2617
2618     if (!afs_osi_suser(*acred))
2619         return EACCES;
2620
2621     memcpy((char *)&magic, tp, sizeof(afs_int32));
2622     tp += sizeof(afs_int32);
2623     if (magic != 0x12345678)
2624         return EINVAL;
2625
2626     /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2627      * server addresses while the 3.5 fs newcell command passes
2628      * MAXHOSTS. To figure out which is which, check if the cellname
2629      * is good.
2630      */
2631     newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2632     scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2633
2634     /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2635     memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2636     tp += (scount * sizeof(afs_int32));
2637
2638     lp = (afs_int32 *) tp;
2639     fsport = *lp++;
2640     vlport = *lp++;
2641     if (fsport < 1024)
2642         fsport = 0;             /* Privileged ports not allowed */
2643     if (vlport < 1024)
2644         vlport = 0;             /* Privileged ports not allowed */
2645     tp += (3 * sizeof(afs_int32));
2646     newcell = tp;
2647     if ((ls = *lp) & 1) {
2648         linkedcell = tp + strlen(newcell) + 1;
2649         linkedstate |= CLinkedCell;
2650     }
2651
2652     linkedstate |= CNoSUID;     /* setuid is disabled by default for fs newcell */
2653     code =
2654         afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2655                     vlport, (int)0);
2656     return code;
2657 }
2658
2659 DECL_PIOCTL(PNewAlias)
2660 {
2661     /* create a new cell alias */
2662     char *tp = ain;
2663     register afs_int32 code;
2664     char *realName, *aliasName;
2665
2666     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2667         return EIO;             /* Inappropriate ioctl for device */
2668
2669     if (!afs_osi_suser(*acred))
2670         return EACCES;
2671
2672     aliasName = tp;
2673     tp += strlen(aliasName) + 1;
2674     realName = tp;
2675
2676     code = afs_NewCellAlias(aliasName, realName);
2677     *aoutSize = 0;
2678     return code;
2679 }
2680
2681 /*!
2682  * VIOCGETCELL (27) - Get cell info
2683  *
2684  * \ingroup pioctl
2685  *
2686  * \param[in] ain       The cell index of a specific cell
2687  * \param[out] aout     list of servers in the cell
2688  *
2689  * \retval EIO          Error if the afs daemon hasn't started yet
2690  * \retval EDOM         Error if there is no cell asked about
2691  *
2692  * \post Lists the cell's server names and and addresses
2693  */
2694 DECL_PIOCTL(PListCells)
2695 {
2696     afs_int32 whichCell;
2697     register struct cell *tcell = 0;
2698     register afs_int32 i;
2699     register char *cp, *tp = ain;
2700
2701     AFS_STATCNT(PListCells);
2702     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2703         return EIO;             /* Inappropriate ioctl for device */
2704
2705     memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2706     tp += sizeof(afs_int32);
2707     tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2708     if (tcell) {
2709         cp = aout;
2710         memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2711         for (i = 0; i < MAXCELLHOSTS; i++) {
2712             if (tcell->cellHosts[i] == 0)
2713                 break;
2714             memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2715                    sizeof(afs_int32));
2716             cp += sizeof(afs_int32);
2717         }
2718         cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2719         strcpy(cp, tcell->cellName);
2720         cp += strlen(tcell->cellName) + 1;
2721         *aoutSize = cp - aout;
2722         afs_PutCell(tcell, READ_LOCK);
2723     }
2724     if (tcell)
2725         return 0;
2726     else
2727         return EDOM;
2728 }
2729
2730 DECL_PIOCTL(PListAliases)
2731 {
2732     afs_int32 whichAlias;
2733     register struct cell_alias *tcalias = 0;
2734     register char *cp, *tp = ain;
2735
2736     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2737         return EIO;             /* Inappropriate ioctl for device */
2738     if (ainSize < sizeof(afs_int32))
2739         return EINVAL;
2740
2741     memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2742     tp += sizeof(afs_int32);
2743
2744     tcalias = afs_GetCellAlias(whichAlias);
2745     if (tcalias) {
2746         cp = aout;
2747         strcpy(cp, tcalias->alias);
2748         cp += strlen(tcalias->alias) + 1;
2749         strcpy(cp, tcalias->cell);
2750         cp += strlen(tcalias->cell) + 1;
2751         *aoutSize = cp - aout;
2752         afs_PutCellAlias(tcalias);
2753     }
2754     if (tcalias)
2755         return 0;
2756     else
2757         return EDOM;
2758 }
2759
2760 /*!
2761  * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2762  *
2763  * \ingroup pioctl
2764  *
2765  * \param[in] ain       the name of the file in this dir to remove
2766  * \param[out] aout     not in use
2767  *
2768  * \retval EINVAL       Error if some of the standard args aren't set
2769  * \retval ENOTDIR      Error if the argument to remove is not a directory
2770  * \retval ENOENT       Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2771  *
2772  * \post Ensure that everything is OK before deleting the mountpoint.  If not, don't delete.  Delete a mount point based on a file id.
2773  */
2774 DECL_PIOCTL(PRemoveMount)
2775 {
2776     register afs_int32 code;
2777     char *bufp;
2778     struct sysname_info sysState;
2779     afs_size_t offset, len;
2780     register struct conn *tc;
2781     register struct dcache *tdc;
2782     register struct vcache *tvc;
2783     struct AFSFetchStatus OutDirStatus;
2784     struct VenusFid tfid;
2785     struct AFSVolSync tsync;
2786     XSTATS_DECLS;
2787
2788
2789     /* "ain" is the name of the file in this dir to remove */
2790
2791     AFS_STATCNT(PRemoveMount);
2792     if (!avc)
2793         return EINVAL;
2794     code = afs_VerifyVCache(avc, areq);
2795     if (code)
2796         return code;
2797     if (vType(avc) != VDIR)
2798         return ENOTDIR;
2799
2800     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);   /* test for error below */
2801     if (!tdc)
2802         return ENOENT;
2803     Check_AtSys(avc, ain, &sysState, areq);
2804     ObtainReadLock(&tdc->lock);
2805     do {
2806         code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2807     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2808     ReleaseReadLock(&tdc->lock);
2809     bufp = sysState.name;
2810     if (code) {
2811         afs_PutDCache(tdc);
2812         goto out;
2813     }
2814     tfid.Cell = avc->fid.Cell;
2815     tfid.Fid.Volume = avc->fid.Fid.Volume;
2816     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2817         tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2818     } else {
2819         tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2820     }
2821     if (!tvc) {
2822         code = ENOENT;
2823         afs_PutDCache(tdc);
2824         goto out;
2825     }
2826     if (tvc->mvstat != 1) {
2827         afs_PutDCache(tdc);
2828         afs_PutVCache(tvc);
2829         code = EINVAL;
2830         goto out;
2831     }
2832     ObtainWriteLock(&tvc->lock, 230);
2833     code = afs_HandleLink(tvc, areq);
2834     if (!code) {
2835         if (tvc->linkData) {
2836             if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2837                 code = EINVAL;
2838         } else
2839             code = EIO;
2840     }
2841     ReleaseWriteLock(&tvc->lock);
2842     osi_dnlc_purgedp(tvc);
2843     afs_PutVCache(tvc);
2844     if (code) {
2845         afs_PutDCache(tdc);
2846         goto out;
2847     }
2848     ObtainWriteLock(&avc->lock, 231);
2849     osi_dnlc_remove(avc, bufp, tvc);
2850     do {
2851         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2852         if (tc) {
2853             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2854             RX_AFS_GUNLOCK();
2855             code =
2856                 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->fid.Fid, bufp,
2857                                  &OutDirStatus, &tsync);
2858             RX_AFS_GLOCK();
2859             XSTATS_END_TIME;
2860         } else
2861             code = -1;
2862     } while (afs_Analyze
2863              (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2864               SHARED_LOCK, NULL));
2865
2866     if (code) {
2867         if (tdc)
2868             afs_PutDCache(tdc);
2869         ReleaseWriteLock(&avc->lock);
2870         goto out;
2871     }
2872     if (tdc) {
2873         /* we have the thing in the cache */
2874         ObtainWriteLock(&tdc->lock, 661);
2875         if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2876             /* we can do it locally */
2877             code = afs_dir_Delete(tdc, bufp);
2878             if (code) {
2879                 ZapDCE(tdc);    /* surprise error -- invalid value */
2880                 DZap(tdc);
2881             }
2882         }
2883         ReleaseWriteLock(&tdc->lock);
2884         afs_PutDCache(tdc);     /* drop ref count */
2885     }
2886     avc->states &= ~CUnique;    /* For the dfs xlator */
2887     ReleaseWriteLock(&avc->lock);
2888     code = 0;
2889   out:
2890     if (sysState.allocked)
2891         osi_FreeLargeSpace(bufp);
2892     return code;
2893 }
2894
2895 /*!
2896  * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2897  *
2898  * \ingroup pioctl
2899  *
2900  * \retval EINVAL       Error if some of the standard args aren't set
2901  *
2902  * \notes Obsoleted, perhaps should be PBogus
2903  */
2904 DECL_PIOCTL(PVenusLogging)
2905 {
2906     return EINVAL;              /* OBSOLETE */
2907 }
2908
2909 /*!
2910  * VIOC_GETCELLSTATUS (35) - Get cell status info
2911  *
2912  * \ingroup pioctl
2913  *
2914  * \param[in] ain       The cell you want status information on
2915  * \param[out] aout     cell state (as a struct)
2916  *
2917  * \retval EIO          Error if the afs daemon hasn't started yet
2918  * \retval ENOENT       Error if the cell doesn't exist
2919  *
2920  * \post Returns the state of the cell as defined in a struct cell
2921  */
2922 DECL_PIOCTL(PGetCellStatus)
2923 {
2924     register struct cell *tcell;
2925     afs_int32 temp;
2926
2927     AFS_STATCNT(PGetCellStatus);
2928     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2929         return EIO;             /* Inappropriate ioctl for device */
2930
2931     tcell = afs_GetCellByName(ain, READ_LOCK);
2932     if (!tcell)
2933         return ENOENT;
2934     temp = tcell->states;
2935     afs_PutCell(tcell, READ_LOCK);
2936     memcpy(aout, (char *)&temp, sizeof(afs_int32));
2937     *aoutSize = sizeof(afs_int32);
2938     return 0;
2939 }
2940
2941 /*!
2942  * VIOC_SETCELLSTATUS (36) - Set corresponding info
2943  *
2944  * \ingroup pioctl
2945  *
2946  * \param[in] ain       The cell you want to set information about, and the values you want to set
2947  * \param[out] aout     not in use
2948  *
2949  * \retval EIO          Error if the afs daemon hasn't started yet
2950  * \retval EACCES       Error if the user doesn't have super-user credentials
2951  *
2952  * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2953  */
2954 DECL_PIOCTL(PSetCellStatus)
2955 {
2956     register struct cell *tcell;
2957     afs_int32 temp;
2958
2959     if (!afs_osi_suser(*acred))
2960         return EACCES;
2961     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2962         return EIO;             /* Inappropriate ioctl for device */
2963
2964     tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2965     if (!tcell)
2966         return ENOENT;
2967     memcpy((char *)&temp, ain, sizeof(afs_int32));
2968     if (temp & CNoSUID)
2969         tcell->states |= CNoSUID;
2970     else
2971         tcell->states &= ~CNoSUID;
2972     afs_PutCell(tcell, WRITE_LOCK);
2973     return 0;
2974 }
2975
2976 /*!
2977  * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2978  *
2979  * \ingroup pioctl
2980  *
2981  * \param[in] ain       not in use (args in avc)
2982  * \param[out] aout     not in use
2983  *
2984  * \retval EINVAL       Error if some of the standard args aren't set
2985  * \retval EIO          Error if the afs daemon hasn't started yet
2986  *
2987  * \post Wipe everything on the volume.  This is done dependent on which platform this is for.
2988  *
2989  * \notes Does not flush a file that a user has open and is using, because it will be re-created on next write.  Also purges the dnlc, because things are screwed up.
2990  */
2991 DECL_PIOCTL(PFlushVolumeData)
2992 {
2993     register afs_int32 i;
2994     register struct dcache *tdc;
2995     register struct vcache *tvc;
2996     register struct volume *tv;
2997     afs_int32 cell, volume;
2998     struct afs_q *tq, *uq;
2999 #ifdef AFS_DARWIN80_ENV
3000     vnode_t vp;
3001 #endif
3002
3003     AFS_STATCNT(PFlushVolumeData);
3004     if (!avc)
3005         return EINVAL;
3006     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3007         return EIO;             /* Inappropriate ioctl for device */
3008
3009     volume = avc->fid.Fid.Volume;       /* who to zap */
3010     cell = avc->fid.Cell;
3011
3012     /*
3013      * Clear stat'd flag from all vnodes from this volume; this will invalidate all
3014      * the vcaches associated with the volume.
3015      */
3016  loop:
3017     ObtainReadLock(&afs_xvcache);
3018     i = VCHashV(&avc->fid);
3019     for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
3020             uq = QPrev(tq);
3021             tvc = QTOVH(tq);
3022             if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
3023                 if (tvc->states & CVInit) {
3024                     ReleaseReadLock(&afs_xvcache);
3025                     afs_osi_Sleep(&tvc->states);
3026                     goto loop;
3027                 }
3028 #ifdef AFS_DARWIN80_ENV
3029                 if (tvc->states & CDeadVnode) {
3030                     ReleaseReadLock(&afs_xvcache);
3031                     afs_osi_Sleep(&tvc->states);
3032                     goto loop;
3033                 }
3034 #endif
3035 #if     defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)  || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
3036                 VN_HOLD(AFSTOV(tvc));
3037 #else
3038 #ifdef AFS_DARWIN80_ENV
3039                 vp = AFSTOV(tvc);
3040                 if (vnode_get(vp))
3041                     continue;
3042                 if (vnode_ref(vp)) {
3043                     AFS_GUNLOCK();
3044                     vnode_put(vp);
3045                     AFS_GLOCK();
3046                     continue;
3047                 }
3048 #else
3049 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3050                 osi_vnhold(tvc, 0);
3051 #else
3052                 VREFCOUNT_INC(tvc); /* AIX, apparently */
3053 #endif
3054 #endif
3055 #endif
3056                 ReleaseReadLock(&afs_xvcache);
3057 #ifdef AFS_BOZONLOCK_ENV
3058                 afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
3059 #endif
3060                 ObtainWriteLock(&tvc->lock, 232);
3061
3062                 ObtainWriteLock(&afs_xcbhash, 458);
3063                 afs_DequeueCallback(tvc);
3064                 tvc->states &= ~(CStatd | CDirty);
3065                 ReleaseWriteLock(&afs_xcbhash);
3066                 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3067                     osi_dnlc_purgedp(tvc);
3068                 afs_TryToSmush(tvc, *acred, 1);
3069                 ReleaseWriteLock(&tvc->lock);
3070 #ifdef AFS_BOZONLOCK_ENV
3071                 afs_BozonUnlock(&tvc->pvnLock, tvc);
3072 #endif
3073 #ifdef AFS_DARWIN80_ENV
3074                 vnode_put(AFSTOV(tvc));
3075 #endif
3076                 ObtainReadLock(&afs_xvcache);
3077                 uq = QPrev(tq);
3078                 /* our tvc ptr is still good until now */
3079                 AFS_FAST_RELE(tvc);
3080             }
3081         }
3082     ReleaseReadLock(&afs_xvcache);
3083
3084
3085     MObtainWriteLock(&afs_xdcache, 328);        /* needed if you're going to flush any stuff */
3086     for (i = 0; i < afs_cacheFiles; i++) {
3087         if (!(afs_indexFlags[i] & IFEverUsed))
3088             continue;           /* never had any data */
3089         tdc = afs_GetDSlot(i, NULL);
3090         if (tdc->refCount <= 1) {       /* too high, in use by running sys call */
3091             ReleaseReadLock(&tdc->tlock);
3092             if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3093                 if (!(afs_indexFlags[i] & IFDataMod)) {
3094                     /* if the file is modified, but has a ref cnt of only 1, then
3095                      * someone probably has the file open and is writing into it.
3096                      * Better to skip flushing such a file, it will be brought back
3097                      * immediately on the next write anyway.
3098                      * 
3099                      * If we *must* flush, then this code has to be rearranged to call
3100                      * afs_storeAllSegments() first */
3101                     afs_FlushDCache(tdc);
3102                 }
3103             }
3104         } else {
3105             ReleaseReadLock(&tdc->tlock);
3106         }
3107         afs_PutDCache(tdc);     /* bumped by getdslot */
3108     }
3109     MReleaseWriteLock(&afs_xdcache);
3110
3111     ObtainReadLock(&afs_xvolume);
3112     for (i = 0; i < NVOLS; i++) {
3113         for (tv = afs_volumes[i]; tv; tv = tv->next) {
3114             if (tv->volume == volume) {
3115                 afs_ResetVolumeInfo(tv);
3116                 break;
3117             }
3118         }
3119     }
3120     ReleaseReadLock(&afs_xvolume);
3121
3122     /* probably, a user is doing this, probably, because things are screwed up.
3123      * maybe it's the dnlc's fault? */
3124     osi_dnlc_purge();
3125     return 0;
3126 }
3127
3128
3129 /*!
3130  * VIOCGETVCXSTATUS (41) - gets vnode x status
3131  *
3132  * \ingroup pioctl
3133  *
3134  * \param[in] ain       not in use (avc used)
3135  * \param[out] aout     vcxstat: the file id, the data version, any lock, the parent vnode, the parent unique id, the trunc position, the callback, cbExpires, what access is being made, what files are open, any users executing/writing, the flock ount, the states, the move stat
3136  *
3137  * \retval EINVAL       Error if some of the initial default arguments aren't set
3138  * \retval EACCES       Error if access to check the mode bits is denied
3139  *
3140  * \post gets stats for the vnode, a struct listed in vcxstat
3141  */
3142 DECL_PIOCTL(PGetVnodeXStatus)
3143 {
3144     register afs_int32 code;
3145     struct vcxstat stat;
3146     afs_int32 mode, i;
3147
3148 /*  AFS_STATCNT(PGetVnodeXStatus); */
3149     if (!avc)
3150         return EINVAL;
3151     code = afs_VerifyVCache(avc, areq);
3152     if (code)
3153         return code;
3154     if (vType(avc) == VDIR)
3155         mode = PRSFS_LOOKUP;
3156     else
3157         mode = PRSFS_READ;
3158     if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3159         return EACCES;
3160
3161     memset(&stat, 0, sizeof(struct vcxstat));
3162     stat.fid = avc->fid;
3163     hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
3164     stat.lock = avc->lock;
3165     stat.parentVnode = avc->parentVnode;
3166     stat.parentUnique = avc->parentUnique;
3167     hset(stat.flushDV, avc->flushDV);
3168     hset(stat.mapDV, avc->mapDV);
3169     stat.truncPos = avc->truncPos;
3170     {                           /* just grab the first two - won't break anything... */
3171         struct axscache *ac;
3172
3173         for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3174             stat.randomUid[i] = ac->uid;
3175             stat.randomAccess[i] = ac->axess;
3176         }
3177     }
3178     stat.callback = afs_data_pointer_to_int32(avc->callback);
3179     stat.cbExpires = avc->cbExpires;
3180     stat.anyAccess = avc->anyAccess;
3181     stat.opens = avc->opens;
3182     stat.execsOrWriters = avc->execsOrWriters;
3183     stat.flockCount = avc->flockCount;
3184     stat.mvstat = avc->mvstat;
3185     stat.states = avc->states;
3186     memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3187     *aoutSize = sizeof(struct vcxstat);
3188     return 0;
3189 }
3190
3191
3192 DECL_PIOCTL(PGetVnodeXStatus2)
3193 {
3194     register afs_int32 code;
3195     struct vcxstat2 stat;
3196     afs_int32 mode;
3197
3198     if (!avc)
3199         return EINVAL;
3200     code = afs_VerifyVCache(avc, areq);
3201     if (code)
3202         return code;
3203     if (vType(avc) == VDIR)
3204         mode = PRSFS_LOOKUP;
3205     else
3206         mode = PRSFS_READ;
3207     if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3208         return EACCES;
3209
3210     memset(&stat, 0, sizeof(struct vcxstat2));
3211
3212     stat.cbExpires = avc->cbExpires;
3213     stat.anyAccess = avc->anyAccess;
3214     stat.mvstat = avc->mvstat;
3215     stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3216
3217     memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3218     *aoutSize = sizeof(struct vcxstat2);
3219     return 0;
3220 }
3221
3222
3223 /*!
3224  * VIOC_AFS_SYSNAME (38) - Change @sys value
3225  *
3226  * \ingroup pioctl
3227  *
3228  * \param[in] ain       new value for @sys
3229  * \param[out] aout     count, entry, list (debug values?)
3230  *
3231  * \retval EINVAL       Error if afsd isn't running, the new sysname is too large, the new sysname causes issues (starts with a .0 or ..0), there is no PAG set in the credentials, the user of a PAG can't be found, (!(exporter = au->exporter)) "NOT SURE ON THIS"
3232  * \retval ENODEV       Error if there isn't already a system named that ("I THINK")
3233  * \retval EACCES       Error if the user doesn't have super-user credentials
3234  *
3235  * \post Set the value of @sys if these things work: if the input isn't too long or if input doesn't start with .0 or ..0
3236  *
3237  * \notes We require root for local sysname changes, but not for remote (since we don't really believe remote uids anyway) outname[] shouldn't really be needed- this is left as an exercise for the reader.
3238  */
3239 DECL_PIOCTL(PSetSysName)
3240 {
3241     char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3242     afs_int32 setsysname;
3243     int foundname = 0;
3244     register struct afs_exporter *exporter;
3245     register struct unixuser *au;
3246     register afs_int32 pag, error;
3247     int t, count, num = 0, allpags = 0;
3248     char **sysnamelist;
3249
3250     AFS_STATCNT(PSetSysName);
3251     if (!afs_globalVFS) {
3252         /* Afsd is NOT running; disable it */
3253 #if defined(KERNEL_HAVE_UERROR)
3254         return (setuerror(EINVAL), EINVAL);
3255 #else
3256         return (EINVAL);
3257 #endif
3258     }
3259     memset(inname, 0, MAXSYSNAME);
3260     memcpy(&setsysname, ain, sizeof(afs_int32));
3261     ain += sizeof(afs_int32);
3262     if (setsysname & 0x8000) {
3263         allpags = 1;
3264         setsysname &= ~0x8000;
3265     }
3266     if (setsysname) {
3267
3268         /* Check my args */
3269         if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3270             return EINVAL;
3271         cp2 = ain;
3272         for (cp = ain, count = 0; count < setsysname; count++) {
3273             /* won't go past end of ain since maxsysname*num < ain length */
3274             t = strlen(cp);
3275             if (t >= MAXSYSNAME || t <= 0)
3276                 return EINVAL;
3277             /* check for names that can shoot us in the foot */
3278             if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3279                 return EINVAL;
3280             cp += t + 1;
3281         }
3282         /* args ok */
3283
3284         /* inname gets first entry in case we're being a translator */
3285         t = strlen(ain);
3286         memcpy(inname, ain, t + 1);     /* include terminating null */
3287         ain += t + 1;
3288         num = count;
3289     }
3290     if ((*acred)->cr_gid == RMTUSER_REQ ||
3291         (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3292         if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) {
3293             return EPERM;
3294         }
3295         pag = PagInCred(*acred);
3296         if (pag == NOPAG) {
3297             return EINVAL;      /* Better than panicing */
3298         }
3299         if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3300             return EINVAL;      /* Better than panicing */
3301         }
3302         if (!(exporter = au->exporter)) {
3303             afs_PutUser(au, READ_LOCK);
3304             return EINVAL;      /* Better than panicing */
3305         }
3306         error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3307                             &num, allpags);
3308         if (error) {
3309             if (error == ENODEV)
3310                 foundname = 0;  /* sysname not set yet! */
3311             else {
3312                 afs_PutUser(au, READ_LOCK);
3313                 return error;
3314             }
3315         } else {
3316             foundname = num;
3317             strcpy(outname, sysnamelist[0]);
3318         }
3319         afs_PutUser(au, READ_LOCK);
3320         if (setsysname)
3321             afs_sysnamegen++;
3322     } else {
3323         /* Not xlating, so local case */
3324         if (!afs_sysname)
3325             osi_Panic("PSetSysName: !afs_sysname\n");
3326         if (!setsysname) {      /* user just wants the info */
3327             strcpy(outname, afs_sysname);
3328             foundname = afs_sysnamecount;
3329             sysnamelist = afs_sysnamelist;
3330         } else {                /* Local guy; only root can change sysname */
3331             if (!afs_osi_suser(*acred))
3332                 return EACCES;
3333
3334             /* allpags makes no sense for local use */
3335             if (allpags)
3336                 return EINVAL;
3337
3338             /* clear @sys entries from the dnlc, once afs_lookup can
3339              * do lookups of @sys entries and thinks it can trust them */
3340             /* privs ok, store the entry, ... */
3341             strcpy(afs_sysname, inname);
3342             if (setsysname > 1) {       /* ... or list */
3343                 cp = ain;
3344                 for (count = 1; count < setsysname; ++count) {
3345                     if (!afs_sysnamelist[count])
3346                         osi_Panic
3347                             ("PSetSysName: no afs_sysnamelist entry to write\n");
3348                     t = strlen(cp);
3349                     memcpy(afs_sysnamelist[count], cp, t + 1);  /* include null */
3350                     cp += t + 1;
3351                 }
3352             }
3353             afs_sysnamecount = setsysname;
3354             afs_sysnamegen++;
3355         }
3356     }
3357     if (!setsysname) {
3358         cp = aout;              /* not changing so report back the count and ... */
3359         memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3360         cp += sizeof(afs_int32);
3361         if (foundname) {
3362             strcpy(cp, outname);        /* ... the entry, ... */
3363             cp += strlen(outname) + 1;
3364             for (count = 1; count < foundname; ++count) {       /* ... or list. */
3365                 if (!sysnamelist[count])
3366                     osi_Panic
3367                         ("PSetSysName: no afs_sysnamelist entry to read\n");
3368                 t = strlen(sysnamelist[count]);
3369                 if (t >= MAXSYSNAME)
3370                     osi_Panic("PSetSysName: sysname entry garbled\n");
3371                 strcpy(cp, sysnamelist[count]);
3372                 cp += t + 1;
3373             }
3374         }
3375         *aoutSize = cp - aout;
3376     }
3377     return 0;
3378 }
3379
3380 /* sequential search through the list of touched cells is not a good
3381  * long-term solution here. For small n, though, it should be just
3382  * fine.  Should consider special-casing the local cell for large n.
3383  * Likewise for PSetSPrefs.
3384  *
3385  * s - number of ids in array l[] -- NOT index of last id
3386  * l - array of cell ids which have volumes that need to be sorted
3387  * vlonly - sort vl servers or file servers?
3388  */
3389 static void *
3390 ReSortCells_cb(struct cell *cell, void *arg)
3391 {
3392     afs_int32 *p = (afs_int32 *) arg;
3393     afs_int32 *l = p + 1;
3394     int i, s = p[0];
3395
3396     for (i = 0; i < s; i++) {
3397         if (l[i] == cell->cellNum) {
3398             ObtainWriteLock(&cell->lock, 690);
3399             afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3400             ReleaseWriteLock(&cell->lock);
3401         }
3402     }
3403
3404     return NULL;
3405 }
3406
3407 static void
3408 ReSortCells(int s, afs_int32 * l, int vlonly)
3409 {
3410     int i;
3411     struct volume *j;
3412     register int k;
3413
3414     if (vlonly) {
3415         afs_int32 *p;
3416         p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3417         p[0] = s;
3418         memcpy(p + 1, l, s * sizeof(afs_int32));
3419         afs_TraverseCells(&ReSortCells_cb, p);
3420         afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3421         return;
3422     }
3423
3424     ObtainReadLock(&afs_xvolume);
3425     for (i = 0; i < NVOLS; i++) {
3426         for (j = afs_volumes[i]; j; j = j->next) {
3427             for (k = 0; k < s; k++)
3428                 if (j->cell == l[k]) {
3429                     ObtainWriteLock(&j->lock, 233);
3430                     afs_SortServers(j->serverHost, MAXHOSTS);
3431                     ReleaseWriteLock(&j->lock);
3432                     break;
3433                 }
3434         }
3435     }
3436     ReleaseReadLock(&afs_xvolume);
3437 }
3438
3439
3440 static int debugsetsp = 0;
3441 static int
3442 afs_setsprefs(sp, num, vlonly)
3443      struct spref *sp;
3444      unsigned int num;
3445      unsigned int vlonly;
3446 {
3447     struct srvAddr *sa;
3448     int i, j, k, matches, touchedSize;
3449     struct server *srvr = NULL;
3450     afs_int32 touched[34];
3451     int isfs;
3452
3453     touchedSize = 0;
3454     for (k = 0; k < num; sp++, k++) {
3455         if (debugsetsp) {
3456             printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3457         }
3458         matches = 0;
3459         ObtainReadLock(&afs_xserver);
3460
3461         i = SHash(sp->host.s_addr);
3462         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3463             if (sa->sa_ip == sp->host.s_addr) {
3464                 srvr = sa->server;
3465                 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3466                     || (sa->sa_portal == AFS_FSPORT);
3467                 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3468                     matches++;
3469                     break;
3470                 }
3471             }
3472         }
3473
3474         if (sa && matches) {    /* found one! */
3475             if (debugsetsp) {
3476                 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3477             }
3478             sa->sa_iprank = sp->rank + afs_randomMod15();
3479             afs_SortOneServer(sa->server);
3480
3481             if (srvr->cell) {
3482                 /* if we don't know yet what cell it's in, this is moot */
3483                 for (j = touchedSize - 1;
3484                      j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3485                     /* is it in our list of touched cells ?  */ ;
3486                 if (j < 0) {    /* no, it's not */
3487                     touched[touchedSize++] = srvr->cell->cellNum;
3488                     if (touchedSize >= 32) {    /* watch for ovrflow */
3489                         ReleaseReadLock(&afs_xserver);
3490                         ReSortCells(touchedSize, touched, vlonly);
3491                         touchedSize = 0;
3492                         ObtainReadLock(&afs_xserver);
3493                     }
3494                 }
3495             }
3496         }
3497
3498         ReleaseReadLock(&afs_xserver);
3499         /* if we didn't find one, start to create one. */
3500         /* Note that it doesn't have a cell yet...     */
3501         if (!matches) {
3502             afs_uint32 temp = sp->host.s_addr;
3503             srvr =
3504                 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3505                               WRITE_LOCK, (afsUUID *) 0, 0);
3506             srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3507             afs_PutServer(srvr, WRITE_LOCK);
3508         }
3509     }                           /* for all cited preferences */
3510
3511     ReSortCells(touchedSize, touched, vlonly);
3512     return 0;
3513 }
3514
3515 /*!
3516  * VIOC_SETPREFS (46) - Set server ranks
3517  *
3518  * \param[in] ain       the sprefs value you want the sprefs to be set to
3519  * \param[out] aout     not in use
3520  *
3521  * \retval EIO          Error if the afs daemon hasn't started yet
3522  * \retval EACCES       Error if the user doesn't have super-user credentials
3523  * \retval EINVAL       Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3524  *
3525  * \post set the sprefs using the afs_setsprefs() function
3526  */
3527 DECL_PIOCTL(PSetSPrefs)
3528 {
3529     struct setspref *ssp;
3530     AFS_STATCNT(PSetSPrefs);
3531
3532     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3533         return EIO;             /* Inappropriate ioctl for device */
3534
3535     if (!afs_osi_suser(*acred))
3536         return EACCES;
3537
3538     if (ainSize < sizeof(struct setspref))
3539         return EINVAL;
3540
3541     ssp = (struct setspref *)ain;
3542     if (ainSize < sizeof(struct spref) * ssp->num_servers)
3543         return EINVAL;
3544
3545     afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3546                   (ssp->flags & DBservers));
3547     return 0;
3548 }
3549
3550 /* 
3551  * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3552  *
3553  * \param[in] ain       the server preferences to be set
3554  * \param[out] aout     not in use
3555  *
3556  * \retval EIO          Error if the afs daemon hasn't started yet
3557  * \retval EACCES       Error if the user doesn't have super-user credentials
3558  *
3559  * \post set the server preferences, calling a function
3560  *
3561  * \notes this may only be performed by the local root user.
3562  */
3563 DECL_PIOCTL(PSetSPrefs33)
3564 {
3565     struct spref *sp;
3566     AFS_STATCNT(PSetSPrefs);
3567     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3568         return EIO;             /* Inappropriate ioctl for device */
3569
3570
3571     if (!afs_osi_suser(*acred))
3572         return EACCES;
3573
3574     sp = (struct spref *)ain;
3575     afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3576     return 0;
3577 }
3578
3579 /* 
3580  * VIOC_GETSPREFS (43) - Get server ranks
3581  *
3582  * \ingroup pioctl
3583  *
3584  * \param[in] ain       the server preferences to get
3585  * \param[out] aout     the server preferences information
3586  *
3587  * \retval EIO          Error if the afs daemon hasn't started yet
3588  * \retval ENOENT       Error if the sprefrequest is too large
3589  *
3590  * \post Get the sprefs
3591  *
3592  * \notes in the hash table of server structs, all servers with the same IP address; will be on the same overflow chain; This could be sped slightly in some circumstances by having it cache the immediately previous slot in the hash table and some supporting information; Only reports file servers now.
3593  */
3594 DECL_PIOCTL(PGetSPrefs)
3595 {
3596     struct sprefrequest *spin;  /* input */
3597     struct sprefinfo *spout;    /* output */
3598     struct spref *srvout;       /* one output component */
3599     int i, j;                   /* counters for hash table traversal */
3600     struct server *srvr;        /* one of CM's server structs */
3601     struct srvAddr *sa;
3602     int vlonly;                 /* just return vlservers ? */
3603     int isfs;
3604
3605     AFS_STATCNT(PGetSPrefs);
3606     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3607         return EIO;             /* Inappropriate ioctl for device */
3608
3609
3610     if (ainSize < sizeof(struct sprefrequest_33)) {
3611         return ENOENT;
3612     } else {
3613         spin = ((struct sprefrequest *)ain);
3614     }
3615
3616     if (ainSize > sizeof(struct sprefrequest_33)) {
3617         vlonly = (spin->flags & DBservers);
3618     } else
3619         vlonly = 0;
3620
3621     /* struct sprefinfo includes 1 server struct...  that size gets added
3622      * in during the loop that follows.
3623      */
3624     *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3625     spout = (struct sprefinfo *)aout;
3626     spout->next_offset = spin->offset;
3627     spout->num_servers = 0;
3628     srvout = spout->servers;
3629
3630     ObtainReadLock(&afs_xserver);
3631     for (i = 0, j = 0; j < NSERVERS; j++) {     /* sift through hash table */
3632         for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3633             if (spin->offset > (unsigned short)i) {
3634                 continue;       /* catch up to where we left off */
3635             }
3636             spout->next_offset++;
3637
3638             srvr = sa->server;
3639             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3640                 || (sa->sa_portal == AFS_FSPORT);
3641
3642             if ((vlonly && isfs) || (!vlonly && !isfs)) {
3643                 /* only report ranks for vl servers */
3644                 continue;
3645             }
3646
3647             srvout->host.s_addr = sa->sa_ip;
3648             srvout->rank = sa->sa_iprank;
3649             *aoutSize += sizeof(struct spref);
3650             spout->num_servers++;
3651             srvout++;
3652
3653             if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3654                 ReleaseReadLock(&afs_xserver);  /* no more room! */
3655                 return 0;
3656             }
3657         }
3658     }
3659     ReleaseReadLock(&afs_xserver);
3660
3661     spout->next_offset = 0;     /* start over from the beginning next time */
3662     return 0;
3663 }
3664
3665 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3666 int afs_NFSRootOnly = 1;
3667 /*!
3668  * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3669  *
3670  * \ingroup pioctl
3671  *
3672  * \param[in] ain       a struct Vic * EIOctl containing export values needed to change between nfs and afs
3673  * \param[out] aout     a struct of the exporter states (exporter->exp_states)
3674  *
3675  * \retval ENODEV       Error if the exporter doesn't exist
3676  * \retval EACCES       Error if the user doesn't have super-user credentials
3677  *
3678  * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3679  *
3680  * \notes Legacy code obtained from IBM.
3681  */
3682 DECL_PIOCTL(PExportAfs)
3683 {
3684     afs_int32 export, newint =
3685         0, type, changestate, handleValue, convmode, pwsync, smounts;
3686     afs_int32 rempags = 0, pagcb = 0;
3687     register struct afs_exporter *exporter;
3688
3689     AFS_STATCNT(PExportAfs);
3690     memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3691     type = handleValue >> 24;
3692     if (type == 0x71) {
3693         newint = 1;
3694         type = 1;               /* nfs */
3695     }
3696     exporter = exporter_find(type);
3697     if (newint) {
3698         export = handleValue & 3;
3699         changestate = handleValue & 0xfff;
3700         smounts = (handleValue >> 2) & 3;
3701         pwsync = (handleValue >> 4) & 3;
3702         convmode = (handleValue >> 6) & 3;
3703         rempags = (handleValue >> 8) & 3;
3704         pagcb = (handleValue >> 10) & 3;
3705     } else {
3706         changestate = (handleValue >> 16) & 0x1;
3707         convmode = (handleValue >> 16) & 0x2;
3708         pwsync = (handleValue >> 16) & 0x4;
3709         smounts = (handleValue >> 16) & 0x8;
3710         export = handleValue & 0xff;
3711     }
3712     if (!exporter) {
3713         /*  Failed finding desired exporter; */
3714         return ENODEV;
3715     }
3716     if (!changestate) {
3717         handleValue = exporter->exp_states;
3718         memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3719         *aoutSize = sizeof(afs_int32);
3720     } else {
3721         if (!afs_osi_suser(*acred))
3722             return EACCES;      /* Only superuser can do this */
3723         if (newint) {
3724             if (export & 2) {
3725                 if (export & 1)
3726                     exporter->exp_states |= EXP_EXPORTED;
3727                 else
3728                     exporter->exp_states &= ~EXP_EXPORTED;
3729             }
3730             if (convmode & 2) {
3731                 if (convmode & 1)
3732                     exporter->exp_states |= EXP_UNIXMODE;
3733                 else
3734                     exporter->exp_states &= ~EXP_UNIXMODE;
3735             }
3736             if (pwsync & 2) {
3737                 if (pwsync & 1)
3738                     exporter->exp_states |= EXP_PWSYNC;
3739                 else
3740                     exporter->exp_states &= ~EXP_PWSYNC;
3741             }
3742             if (smounts & 2) {
3743                 if (smounts & 1) {
3744                     afs_NFSRootOnly = 0;
3745                     exporter->exp_states |= EXP_SUBMOUNTS;
3746                 } else {
3747                     afs_NFSRootOnly = 1;
3748                     exporter->exp_states &= ~EXP_SUBMOUNTS;
3749                 }
3750             }
3751             if (rempags & 2) {
3752                 if (rempags & 1)
3753                     exporter->exp_states |= EXP_CLIPAGS;
3754                 else
3755                     exporter->exp_states &= ~EXP_CLIPAGS;
3756             }
3757             if (pagcb & 2) {
3758                 if (pagcb & 1)
3759                     exporter->exp_states |= EXP_CALLBACK;
3760                 else
3761                     exporter->exp_states &= ~EXP_CALLBACK;
3762             }
3763             handleValue = exporter->exp_states;
3764             memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3765             *aoutSize = sizeof(afs_int32);
3766         } else {
3767             if (export)
3768                 exporter->exp_states |= EXP_EXPORTED;
3769             else
3770                 exporter->exp_states &= ~EXP_EXPORTED;
3771             if (convmode)
3772                 exporter->exp_states |= EXP_UNIXMODE;
3773             else
3774                 exporter->exp_states &= ~EXP_UNIXMODE;
3775             if (pwsync)
3776                 exporter->exp_states |= EXP_PWSYNC;
3777             else
3778                 exporter->exp_states &= ~EXP_PWSYNC;
3779             if (smounts) {
3780                 afs_NFSRootOnly = 0;
3781                 exporter->exp_states |= EXP_SUBMOUNTS;
3782             } else {
3783                 afs_NFSRootOnly = 1;
3784                 exporter->exp_states &= ~EXP_SUBMOUNTS;
3785             }
3786         }
3787     }
3788
3789     return 0;
3790 }
3791
3792 /*!
3793  * VIOC_GAG (44) - Silence Cache Manager
3794  *
3795  * \ingroup pioctl
3796  *
3797  * \param[in] ain       the flags to either gag or de-gag the cache manager
3798  * \param[out] aout     not in use
3799  *
3800  * \retval EACCES       Error if the user doesn't have super-user credentials
3801  *
3802  * \post set the gag flags, then show these flags
3803  */
3804 DECL_PIOCTL(PGag)
3805 {
3806     struct gaginfo *gagflags;
3807
3808     if (!afs_osi_suser(*acred))
3809         return EACCES;
3810
3811     gagflags = (struct gaginfo *)ain;
3812     afs_showflags = gagflags->showflags;
3813
3814     return 0;
3815 }
3816
3817 /*!
3818  * VIOC_TWIDDLE (45) - Adjust RX knobs
3819  *
3820  * \ingroup pioctl
3821  *
3822  * \param[in] ain       the previous settings of the 'knobs'
3823  * \param[out] aout     not in use
3824  *
3825  * \retval EACCES       Error if the user doesn't have super-user credentials
3826  *
3827  * \post build out the struct rxp, from a struct rx
3828  */
3829 DECL_PIOCTL(PTwiddleRx)
3830 {
3831     struct rxparams *rxp;
3832
3833     if (!afs_osi_suser(*acred))
3834         return EACCES;
3835
3836     rxp = (struct rxparams *)ain;
3837
3838     if (rxp->rx_initReceiveWindow)
3839         rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3840     if (rxp->rx_maxReceiveWindow)
3841         rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3842     if (rxp->rx_initSendWindow)
3843         rx_initSendWindow = rxp->rx_initSendWindow;
3844     if (rxp->rx_maxSendWindow)
3845         rx_maxSendWindow = rxp->rx_maxSendWindow;
3846     if (rxp->rxi_nSendFrags)
3847         rxi_nSendFrags = rxp->rxi_nSendFrags;
3848     if (rxp->rxi_nRecvFrags)
3849         rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3850     if (rxp->rxi_OrphanFragSize)
3851         rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3852     if (rxp->rx_maxReceiveSize) {
3853         rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3854         rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3855     }
3856     if (rxp->rx_MyMaxSendSize)
3857         rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3858
3859     return 0;
3860 }
3861
3862 /*!
3863  * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3864  *
3865  * \ingroup pioctl
3866  *
3867  * \param[in] ain       not in use
3868  * \param[out] aout     initial cache manager params
3869  *
3870  * \retval E2BIG        Error if the initial parameters are bigger than some PIGGYSIZE
3871  *
3872  * \post return the initial cache manager parameters
3873  */
3874 DECL_PIOCTL(PGetInitParams)
3875 {
3876     if (sizeof(struct cm_initparams) > PIGGYSIZE)
3877         return E2BIG;
3878
3879     memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3880     *aoutSize = sizeof(struct cm_initparams);
3881     return 0;
3882 }
3883
3884 #ifdef AFS_SGI65_ENV
3885 /* They took crget() from us, so fake it. */
3886 static cred_t *
3887 crget(void)
3888 {
3889     cred_t *cr;
3890     cr = crdup(get_current_cred());
3891     memset((char *)cr, 0, sizeof(cred_t));
3892 #if CELL || CELL_PREPARE
3893     cr->cr_id = -1;
3894 #endif
3895     return cr;
3896 }
3897 #endif
3898
3899 /*!
3900  * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3901  *
3902  * \ingroup pioctl
3903  *
3904  * \param[in] ain       not in use
3905  * \param[out] aout     value of cryptall
3906  *
3907  * \post get the value of cryptall (presumably whether or not things should be encrypted)
3908  */
3909 DECL_PIOCTL(PGetRxkcrypt)
3910 {
3911     memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3912     *aoutSize = sizeof(afs_int32);
3913     return 0;
3914 }
3915
3916 /*!
3917  * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3918  *
3919  * \ingroup pioctl
3920  *
3921  * \param[in] ain       the argument whether or not things should be encrypted
3922  * \param[out] aout     not in use
3923  *
3924  * \retval EPERM        Error if the user doesn't have super-user credentials
3925  * \retval EINVAL       Error if the input is too big, or if the input is outside the bounds of what it can be set to
3926  *
3927  * \post set whether or not things should be encrypted
3928  *
3929  * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3930  */
3931 DECL_PIOCTL(PSetRxkcrypt)
3932 {
3933     afs_int32 tmpval;
3934
3935     if (!afs_osi_suser(*acred))
3936         return EPERM;
3937     if (ainSize != sizeof(afs_int32) || ain == NULL)
3938         return EINVAL;
3939     memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3940     /* if new mappings added later this will need to be changed */
3941     if (tmpval != 0 && tmpval != 1)
3942         return EINVAL;
3943     cryptall = tmpval;
3944     return 0;
3945 }
3946
3947 #ifdef AFS_NEED_CLIENTCONTEXT
3948 /*
3949  * Create new credentials to correspond to a remote user with given
3950  * <hostaddr, uid, g0, g1>.  This allows a server running as root to
3951  * provide pioctl (and other) services to foreign clients (i.e. nfs
3952  * clients) by using this call to `become' the client.
3953  */
3954 #define PSETPAG         110
3955 #define PIOCTL_HEADER   6
3956 static int
3957 HandleClientContext(struct afs_ioctl *ablob, int *com,
3958                     struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3959 {
3960     char *ain, *inData;
3961     afs_uint32 hostaddr;
3962     afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3963     struct afs_exporter *exporter, *outexporter;
3964     struct AFS_UCRED *newcred;
3965     struct unixuser *au;
3966     afs_uint32 comp = *com & 0xff00;
3967     afs_uint32 h, l;
3968
3969 #if defined(AFS_SGIMP_ENV)
3970     osi_Assert(ISAFS_GLOCK());
3971 #endif
3972     AFS_STATCNT(HandleClientContext);
3973     if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3974         /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3975         return EINVAL;          /* Too small to be good  */
3976     }
3977     ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3978     AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3979     if (code) {
3980         osi_FreeLargeSpace(inData);
3981         return code;
3982     }
3983
3984     /* Extract information for remote user */
3985     hostaddr = *((afs_uint32 *) ain);
3986     ain += sizeof(hostaddr);
3987     uid = *((afs_uint32 *) ain);
3988     ain += sizeof(uid);
3989     g0 = *((afs_uint32 *) ain);
3990     ain += sizeof(g0);
3991     g1 = *((afs_uint32 *) ain);
3992     ain += sizeof(g1);
3993     *com = *((afs_uint32 *) ain);
3994     ain += sizeof(afs_int32);
3995     exporter_type = *((afs_uint32 *) ain);      /* In case we support more than NFS */
3996
3997     /*
3998      * Of course, one must be root for most of these functions, but
3999      * we'll allow (for knfs) you to set things if the pag is 0 and
4000      * you're setting tokens or unlogging.
4001      */
4002     i = (*com) & 0xff;
4003     if (!afs_osi_suser(credp)) {
4004 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4005         /* Since SGI's suser() returns explicit failure after the call.. */
4006         u.u_error = 0;
4007 #endif
4008         /* check for acceptable opcodes for normal folks, which are, so far,
4009          * get/set tokens, sysname, and unlog.
4010          */
4011         if (i != 9 && i != 3 && i != 38 && i != 8) {
4012             osi_FreeLargeSpace(inData);
4013             return EACCES;
4014         }
4015     }
4016
4017     ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
4018     ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
4019     osi_FreeLargeSpace(inData);
4020     if (uid == 0) {
4021         /*
4022          * We map uid 0 to nobody to match the mapping that the nfs
4023          * server does and to ensure that the suser() calls in the afs
4024          * code fails for remote client roots.
4025          */
4026         uid = afs_nobody;       /* NFS_NOBODY == -2 */
4027         isroot = 1;
4028     }
4029     newcred = crget();
4030 #ifdef  AFS_AIX41_ENV
4031     setuerror(0);
4032 #endif
4033     newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ;
4034 #ifdef AFS_AIX51_ENV
4035     newcred->cr_groupset.gs_union.un_groups[0] = g0;
4036     newcred->cr_groupset.gs_union.un_groups[1] = g1;
4037 #elif defined(AFS_LINUX26_ENV)
4038 #ifdef AFS_LINUX26_ONEGROUP_ENV
4039     newcred->cr_group_info = groups_alloc(1); /* not that anything sets this */
4040     l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
4041     h = ((g0-0x3f00) >> 14);
4042     h = ((g1-0x3f00) >> 14) + h + h + h;
4043     GROUP_AT(newcred->cr_group_info, 0) = ((h << 28) | l);
4044 #else
4045     newcred->cr_group_info = groups_alloc(2);
4046     GROUP_AT(newcred->cr_group_info, 0) = g0;
4047     GROUP_AT(newcred->cr_group_info, 1) = g1;
4048 #endif
4049 #else
4050     newcred->cr_groups[0] = g0;
4051     newcred->cr_groups[1] = g1;
4052 #endif
4053 #ifdef AFS_AIX_ENV
4054     newcred->cr_ngrps = 2;
4055 #elif !defined(AFS_LINUX26_ENV)
4056 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4057     newcred->cr_ngroups = 2;
4058 #else
4059     for (i = 2; i < NGROUPS; i++)
4060         newcred->cr_groups[i] = NOGROUP;
4061 #endif
4062 #endif
4063 #if     !defined(AFS_OSF_ENV) 
4064     afs_nfsclient_init();       /* before looking for exporter, ensure one exists */
4065 #endif
4066     if (!(exporter = exporter_find(exporter_type))) {
4067         /* Exporter wasn't initialized or an invalid exporter type */
4068         crfree(newcred);
4069         return EINVAL;
4070     }
4071     if (exporter->exp_states & EXP_PWSYNC) {
4072         if (uid != credp->cr_uid) {
4073             crfree(newcred);
4074             return ENOEXEC;     /* XXX Find a better errno XXX */
4075         }
4076     }
4077     newcred->cr_uid = uid;      /* Only temporary  */
4078     code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4079     /* The client's pag is the only unique identifier for it */
4080     newcred->cr_uid = pag;
4081     *acred = newcred;
4082     if (!code && *com == PSETPAG) {
4083         /* Special case for 'setpag' */
4084         afs_uint32 pagvalue = genpag();
4085
4086         au = afs_GetUser(pagvalue, -1, WRITE_LOCK);     /* a new unixuser struct */
4087         /*
4088          * Note that we leave the 'outexporter' struct held so it won't
4089          * dissappear on us
4090          */
4091         au->exporter = outexporter;
4092         if (ablob->out_size >= 4) {
4093             AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4094                         code);
4095         }
4096         afs_PutUser(au, WRITE_LOCK);
4097         if (code)
4098             return code;
4099         return PSETPAG;         /*  Special return for setpag  */
4100     } else if (!code) {
4101         EXP_RELE(outexporter);
4102     }
4103     if (!code) 
4104         *com = (*com) | comp;
4105     return code;
4106 }
4107 #endif /* AFS_NEED_CLIENTCONTEXT */
4108
4109
4110 /*! 
4111  * VIOC_GETCPREFS (50) - Get client interface
4112  *
4113  * \ingroup pioctl
4114  *
4115  * \param[in] ain       sprefrequest input
4116  * \param[out] aout     spref information
4117  *
4118  * \retval EIO          Error if the afs daemon hasn't started yet
4119  * \retval EINVAL       Error if some of the standard args aren't set
4120  *
4121  * \post get all interface addresses and other information of the client interface
4122  */
4123 DECL_PIOCTL(PGetCPrefs)
4124 {
4125     struct sprefrequest *spin;  /* input */
4126     struct sprefinfo *spout;    /* output */
4127     struct spref *srvout;       /* one output component */
4128     int maxNumber;
4129     int i, j;
4130
4131     AFS_STATCNT(PGetCPrefs);
4132     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4133         return EIO;             /* Inappropriate ioctl for device */
4134
4135     if (ainSize < sizeof(struct sprefrequest))
4136         return EINVAL;
4137
4138     spin = (struct sprefrequest *)ain;
4139     spout = (struct sprefinfo *)aout;
4140
4141     maxNumber = spin->num_servers;      /* max addrs this time */
4142     srvout = spout->servers;
4143
4144     ObtainReadLock(&afs_xinterface);
4145
4146     /* copy out the client interface information from the
4147      ** kernel data structure "interface" to the output buffer
4148      */
4149     for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4150          && (j < maxNumber); i++, j++, srvout++)
4151         srvout->host.s_addr = afs_cb_interface.addr_in[i];
4152
4153     spout->num_servers = j;
4154     *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4155
4156     if (i >= afs_cb_interface.numberOfInterfaces)
4157         spout->next_offset = 0; /* start from beginning again */
4158     else
4159         spout->next_offset = spin->offset + j;
4160
4161     ReleaseReadLock(&afs_xinterface);
4162     return 0;
4163 }
4164
4165 /*!
4166  * VIOC_SETCPREFS (51) - Set client interface
4167  *
4168  * \ingroup pioctl
4169  *
4170  * \param[in] ain       the interfaces you want set
4171  * \param[out] aout     not in use
4172  *
4173  * \retval EIO          Error if the afs daemon hasn't started yet
4174  * \retval EINVAL       Error if the input is too large for the struct
4175  * \retval ENOMEM       Error if there are too many servers
4176  *
4177  * \post set the callbak interfaces addresses to those of the hosts
4178  */
4179 DECL_PIOCTL(PSetCPrefs)
4180 {
4181     struct setspref *sin;
4182     int i;
4183
4184     AFS_STATCNT(PSetCPrefs);
4185     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4186         return EIO;             /* Inappropriate ioctl for device */
4187
4188     sin = (struct setspref *)ain;
4189
4190     if (ainSize < sizeof(struct setspref))
4191         return EINVAL;
4192 #if 0                           /* num_servers is unsigned */
4193     if (sin->num_servers < 0)
4194         return EINVAL;
4195 #endif
4196     if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4197         return ENOMEM;
4198
4199     ObtainWriteLock(&afs_xinterface, 412);
4200     afs_cb_interface.numberOfInterfaces = sin->num_servers;
4201     for (i = 0; (unsigned short)i < sin->num_servers; i++)
4202         afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4203
4204     ReleaseWriteLock(&afs_xinterface);
4205     return 0;
4206 }
4207
4208 /*!
4209  * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4210  *
4211  * \ingroup pioctl
4212  *
4213  * \param[in] ain       the last part of a path to a mount point, which tells us what to flush
4214  * \param[out] aout     not in use
4215  *
4216  * \retval EINVAL       Error if some of the initial arguments aren't set
4217  * \retval ENOTDIR      Error if the initial argument for the mount point isn't a directory
4218  * \retval ENOENT       Error if the dcache entry isn't set
4219  *
4220  * \post remove all of the mount data from the dcache regarding a certain mount point
4221  */
4222 DECL_PIOCTL(PFlushMount)
4223 {
4224     register afs_int32 code;
4225     register struct vcache *tvc;
4226     register struct dcache *tdc;
4227     struct VenusFid tfid;
4228     char *bufp;
4229     struct sysname_info sysState;
4230     afs_size_t offset, len;
4231
4232     AFS_STATCNT(PFlushMount);
4233     if (!avc)
4234         return EINVAL;
4235     code = afs_VerifyVCache(avc, areq);
4236     if (code)
4237         return code;
4238     if (vType(avc) != VDIR) {
4239         return ENOTDIR;
4240     }
4241     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4242     if (!tdc)
4243         return ENOENT;
4244     Check_AtSys(avc, ain, &sysState, areq);
4245     ObtainReadLock(&tdc->lock);
4246     do {
4247         code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4248     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4249     ReleaseReadLock(&tdc->lock);
4250     afs_PutDCache(tdc);         /* we're done with the data */
4251     bufp = sysState.name;
4252     if (code) {
4253         goto out;
4254     }
4255     tfid.Cell = avc->fid.Cell;
4256     tfid.Fid.Volume = avc->fid.Fid.Volume;
4257     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
4258         tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4259     } else {
4260         tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4261     }
4262     if (!tvc) {
4263         code = ENOENT;
4264         goto out;
4265     }
4266     if (tvc->mvstat != 1) {
4267         afs_PutVCache(tvc);
4268         code = EINVAL;
4269         goto out;
4270     }
4271 #ifdef AFS_BOZONLOCK_ENV
4272     afs_BozonLock(&tvc->pvnLock, tvc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
4273 #endif
4274     ObtainWriteLock(&tvc->lock, 649);
4275     ObtainWriteLock(&afs_xcbhash, 650);
4276     afs_DequeueCallback(tvc);
4277     tvc->states &= ~(CStatd | CDirty);  /* next reference will re-stat cache entry */
4278     ReleaseWriteLock(&afs_xcbhash);
4279     /* now find the disk cache entries */
4280     afs_TryToSmush(tvc, *acred, 1);
4281     osi_dnlc_purgedp(tvc);
4282     if (tvc->linkData && !(tvc->states & CCore)) {
4283         afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4284         tvc->linkData = NULL;
4285     }
4286     ReleaseWriteLock(&tvc->lock);
4287 #ifdef AFS_BOZONLOCK_ENV
4288     afs_BozonUnlock(&tvc->pvnLock, tvc);
4289 #endif
4290     afs_PutVCache(tvc);
4291   out:
4292     if (sysState.allocked)
4293         osi_FreeLargeSpace(bufp);
4294     return code;
4295 }
4296
4297 /*!
4298  * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4299  *
4300  * \ingroup pioctl
4301  *
4302  * \param[in] ain       the flags that control which stats to use
4303  * \param[out] aout     not in use
4304  *
4305  * \retval EACCES       Error if the user doesn't have super-user credentials
4306  * \retval EINVAL       Error if the flag input is too long
4307  *
4308  * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4309  */
4310 DECL_PIOCTL(PRxStatProc)
4311 {
4312     int code = 0;
4313     afs_int32 flags;
4314
4315     if (!afs_osi_suser(*acred)) {
4316         code = EACCES;
4317         goto out;
4318     }
4319     if (ainSize != sizeof(afs_int32)) {
4320         code = EINVAL;
4321         goto out;
4322     }
4323     memcpy((char *)&flags, ain, sizeof(afs_int32));
4324     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4325         code = EINVAL;
4326         goto out;
4327     }
4328     if (flags & AFSCALL_RXSTATS_ENABLE) {
4329         rx_enableProcessRPCStats();
4330     }
4331     if (flags & AFSCALL_RXSTATS_DISABLE) {
4332         rx_disableProcessRPCStats();
4333     }
4334     if (flags & AFSCALL_RXSTATS_CLEAR) {
4335         rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4336     }
4337   out:
4338     *aoutSize = 0;
4339     return code;
4340 }
4341
4342
4343 /*!
4344  * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4345  *
4346  * \ingroup pioctl
4347  *
4348  * \param[in] ain       the flags that control which statistics to use
4349  * \param[out] aout     not in use
4350  *
4351  * \retval EACCES       Error if the user doesn't have super-user credentials
4352  * \retval EINVAL       Error if the flag input is too long
4353  *
4354  * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4355  */
4356 DECL_PIOCTL(PRxStatPeer)
4357 {
4358     int code = 0;
4359     afs_int32 flags;
4360
4361     if (!afs_osi_suser(*acred)) {
4362         code = EACCES;
4363         goto out;
4364     }
4365     if (ainSize != sizeof(afs_int32)) {
4366         code = EINVAL;
4367         goto out;
4368     }
4369     memcpy((char *)&flags, ain, sizeof(afs_int32));
4370     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4371         code = EINVAL;
4372         goto out;
4373     }
4374     if (flags & AFSCALL_RXSTATS_ENABLE) {
4375         rx_enablePeerRPCStats();
4376     }
4377     if (flags & AFSCALL_RXSTATS_DISABLE) {
4378         rx_disablePeerRPCStats();
4379     }
4380     if (flags & AFSCALL_RXSTATS_CLEAR) {
4381         rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4382     }
4383   out:
4384     *aoutSize = 0;
4385     return code;
4386 }
4387
4388 DECL_PIOCTL(PPrefetchFromTape)
4389 {
4390     register afs_int32 code, code1;
4391     afs_int32 bytes;
4392     struct conn *tc;
4393     struct rx_call *tcall;
4394     struct AFSVolSync tsync;
4395     struct AFSFetchStatus OutStatus;
4396     struct AFSCallBack CallBack;
4397     struct VenusFid tfid;
4398     struct AFSFid *Fid;
4399     struct vcache *tvc;
4400
4401     AFS_STATCNT(PSetAcl);
4402     if (!avc)
4403         return EINVAL;
4404
4405     if (ain && (ainSize == 3 * sizeof(afs_int32)))
4406         Fid = (struct AFSFid *)ain;
4407     else
4408         Fid = &avc->fid.Fid;
4409     tfid.Cell = avc->fid.Cell;
4410     tfid.Fid.Volume = Fid->Volume;
4411     tfid.Fid.Vnode = Fid->Vnode;
4412     tfid.Fid.Unique = Fid->Unique;
4413
4414     tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4415     if (!tvc) {
4416         afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4417                    ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->fid);
4418         return ENOENT;
4419     }
4420     afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4421                ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->fid);
4422
4423     do {
4424         tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
4425         if (tc) {
4426
4427             RX_AFS_GUNLOCK();
4428             tcall = rx_NewCall(tc->id);
4429             code =
4430                 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->fid.Fid, 0,
4431                                      0);
4432             if (!code) {
4433                 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4434                 code =
4435                     EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4436             }
4437             code1 = rx_EndCall(tcall, code);
4438             RX_AFS_GLOCK();
4439         } else
4440             code = -1;
4441     } while (afs_Analyze
4442              (tc, code, &tvc->fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4443               SHARED_LOCK, NULL));
4444     /* This call is done only to have the callback things handled correctly */
4445     afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4446     afs_PutVCache(tvc);
4447
4448     if (!code) {
4449         *aoutSize = sizeof(afs_int32);
4450     }
4451     return code;
4452 }
4453
4454 DECL_PIOCTL(PResidencyCmd)
4455 {
4456     register afs_int32 code;
4457     struct conn *tc;
4458     struct vcache *tvc;
4459     struct ResidencyCmdInputs *Inputs;
4460     struct ResidencyCmdOutputs *Outputs;
4461     struct VenusFid tfid;
4462     struct AFSFid *Fid;
4463
4464     Inputs = (struct ResidencyCmdInputs *)ain;
4465     Outputs = (struct ResidencyCmdOutputs *)aout;
4466     if (!avc)
4467         return EINVAL;
4468     if (!ain || ainSize != sizeof(struct ResidencyCmdInputs))
4469         return EINVAL;
4470
4471     Fid = &Inputs->fid;
4472     if (!Fid->Volume)
4473         Fid = &avc->fid.Fid;
4474
4475     tfid.Cell = avc->fid.Cell;
4476     tfid.Fid.Volume = Fid->Volume;
4477     tfid.Fid.Vnode = Fid->Vnode;
4478     tfid.Fid.Unique = Fid->Unique;
4479
4480     tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4481     afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4482                ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4483     if (!tvc)
4484         return ENOENT;
4485
4486     if (Inputs->command) {
4487         do {
4488             tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
4489             if (tc) {
4490                 RX_AFS_GUNLOCK();
4491                 code =
4492                     RXAFS_ResidencyCmd(tc->id, Fid, Inputs,
4493                                        (struct ResidencyCmdOutputs *)aout);
4494                 RX_AFS_GLOCK();
4495             } else
4496                 code = -1;
4497         } while (afs_Analyze
4498                  (tc, code, &tvc->fid, areq,
4499                   AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4500         /* This call is done to have the callback things handled correctly */
4501         afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4502     } else {                    /* just a status request, return also link data */
4503         code = 0;
4504         Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4505         Outputs->chars[0] = 0;
4506         if (vType(tvc) == VLNK) {
4507             ObtainWriteLock(&tvc->lock, 555);
4508             if (afs_HandleLink(tvc, areq) == 0)
4509                 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4510             ReleaseWriteLock(&tvc->lock);
4511         }
4512     }
4513
4514     afs_PutVCache(tvc);
4515
4516     if (!code) {
4517         *aoutSize = sizeof(struct ResidencyCmdOutputs);
4518     }
4519     return code;
4520 }
4521
4522 DECL_PIOCTL(PNewUuid)
4523 {
4524     /*AFS_STATCNT(PNewUuid); */
4525     if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4526         return EIO;             /* Inappropriate ioctl for device */
4527
4528     if (!afs_osi_suser(acred))
4529         return EACCES;
4530
4531     ObtainWriteLock(&afs_xinterface, 555);
4532     afs_uuid_create(&afs_cb_interface.uuid);
4533     ReleaseWriteLock(&afs_xinterface);
4534     ForceAllNewConnections();
4535     return 0;
4536 }
4537
4538 #if defined(AFS_CACHE_BYPASS)
4539
4540 DECL_PIOCTL(PSetCachingThreshold)
4541 {
4542     afs_int32 getting;
4543     afs_int32 setting;
4544
4545     setting = getting = 1;
4546
4547     if (ain == NULL || ainSize < sizeof(afs_int32))
4548         setting = 0;
4549
4550     if (aout == NULL)
4551         getting = 0;
4552
4553     if (setting == 0 && getting == 0)
4554         return EINVAL;
4555         
4556     /* 
4557      * If setting, set first, and return the value now in effect
4558      */
4559     if (setting) {
4560         afs_int32 threshold;
4561
4562         if (!afs_osi_suser(*acred))
4563             return EPERM;
4564         memcpy((char *)&threshold, ain, sizeof(afs_int32));
4565         cache_bypass_threshold = threshold;
4566         afs_warn("Cache Bypass Threshold set to: %d\n", threshold);             
4567         /* TODO:  move to separate pioctl, or enhance pioctl */
4568         cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4569     }
4570         
4571     if (getting) {
4572         /* Return the current size threshold */
4573         afs_int32 oldThreshold = cache_bypass_threshold;
4574         memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4575         *aoutSize = sizeof(afs_int32);
4576     }
4577
4578     return(0);
4579 }
4580
4581 #endif /* defined(AFS_CACHE_BYPASS) */
4582
4583 DECL_PIOCTL(PCallBackAddr)
4584 {
4585 #ifndef UKERNEL
4586     afs_uint32 addr, code;
4587     int srvAddrCount;
4588     struct server *ts;
4589     struct srvAddr *sa;
4590     struct conn *tc;
4591     afs_int32 i, j;
4592     struct unixuser *tu;
4593     struct srvAddr **addrs;
4594
4595     /*AFS_STATCNT(PCallBackAddr); */
4596     if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4597         return EIO;             /* Inappropriate ioctl for device */
4598
4599     if (!afs_osi_suser(acred))
4600         return EACCES;
4601
4602     if (ainSize < sizeof(afs_int32))
4603         return EINVAL;
4604
4605     memcpy(&addr, ain, sizeof(afs_int32));
4606
4607     ObtainReadLock(&afs_xinterface);
4608     for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4609         if (afs_cb_interface.addr_in[i] == addr)
4610             break;
4611     }
4612
4613     ReleaseWriteLock(&afs_xinterface);
4614
4615     if (afs_cb_interface.addr_in[i] != addr)
4616         return EINVAL;
4617
4618     ObtainReadLock(&afs_xserver);       /* Necessary? */
4619     ObtainReadLock(&afs_xsrvAddr);
4620
4621     srvAddrCount = 0;
4622     for (i = 0; i < NSERVERS; i++) {
4623         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4624             srvAddrCount++;
4625         }
4626     }
4627
4628     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4629     j = 0;
4630     for (i = 0; i < NSERVERS; i++) {
4631         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4632             if (j >= srvAddrCount)
4633                 break;
4634             addrs[j++] = sa;
4635         }
4636     }
4637
4638     ReleaseReadLock(&afs_xsrvAddr);
4639     ReleaseReadLock(&afs_xserver);
4640
4641     for (i = 0; i < j; i++) {
4642         sa = addrs[i];
4643         ts = sa->server;
4644         if (!ts)
4645             continue;
4646
4647         /* vlserver has no callback conn */
4648         if (sa->sa_portal == AFS_VLPORT) {
4649             continue;
4650         }
4651
4652         if (!ts->cell)          /* not really an active server, anyway, it must */
4653             continue;           /* have just been added by setsprefs */
4654
4655         /* get a connection, even if host is down; bumps conn ref count */
4656         tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4657         tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4658                           1 /*force */ , 1 /*create */ , SHARED_LOCK);
4659         afs_PutUser(tu, SHARED_LOCK);
4660         if (!tc)
4661             continue;
4662
4663         if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4664             if (sa->sa_flags & SRVADDR_ISDOWN) {
4665                 rx_SetConnDeadTime(tc->id, 3);
4666             }
4667 #ifdef RX_ENABLE_LOCKS
4668             AFS_GUNLOCK();
4669 #endif /* RX_ENABLE_LOCKS */
4670             code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4671 #ifdef RX_ENABLE_LOCKS
4672             AFS_GLOCK();
4673 #endif /* RX_ENABLE_LOCKS */
4674         }
4675         afs_PutConn(tc, SHARED_LOCK);   /* done with it now */
4676     }                           /* Outer loop over addrs */
4677 #endif /* UKERNEL */
4678     return 0;
4679 }
4680
4681 DECL_PIOCTL(PDiscon)
4682 {
4683 #ifdef AFS_DISCON_ENV
4684     static afs_int32 mode = 1; /* Start up in 'off' */
4685     afs_int32 force = 0;
4686     int code = 0;
4687
4688     if (ainSize) {
4689
4690         if (!afs_osi_suser(*acred))
4691             return EPERM;
4692
4693         if (ain[0])
4694             mode = ain[0] - 1;
4695         if (ain[1])
4696             afs_ConflictPolicy = ain[1] - 1;
4697         if (ain[2])
4698             force = 1;
4699
4700         /*
4701          * All of these numbers are hard coded in fs.c. If they
4702          * change here, they should change there and vice versa
4703          */
4704         switch (mode) {
4705         case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4706             if (!AFS_IS_DISCONNECTED) {
4707                 ObtainWriteLock(&afs_discon_lock, 999);
4708                 afs_DisconGiveUpCallbacks();
4709                 afs_RemoveAllConns();
4710                 afs_is_disconnected = 1;
4711                 afs_is_discon_rw = 1;
4712                 ReleaseWriteLock(&afs_discon_lock);
4713             }
4714             break;
4715         case 1: /* Fully connected, ("online" mode). */
4716             ObtainWriteLock(&afs_discon_lock, 998);
4717
4718             afs_in_sync = 1;
4719             code = afs_ResyncDisconFiles(areq, *acred);
4720             afs_in_sync = 0;
4721
4722             if (code && !force) {
4723                 printf("Files not synchronized properly, still in discon state. \
4724                                                 Please retry or use \"force\".\n");
4725             } else {
4726                 afs_is_disconnected = 0;
4727                 afs_is_discon_rw = 0;
4728                 printf("\nSync succeeded. You are back online.\n");
4729             }
4730
4731             ReleaseWriteLock(&afs_discon_lock);
4732             break;
4733         default:
4734             return EINVAL;
4735         }
4736     } else {
4737         return EINVAL;
4738     }
4739
4740     memcpy(aout, &mode, sizeof(afs_int32));
4741     *aoutSize = sizeof(afs_int32);
4742     return 0;
4743 #else
4744     return EINVAL;
4745 #endif
4746 }
4747
4748 DECL_PIOCTL(PNFSNukeCreds)
4749 {
4750     afs_uint32 addr, code;
4751     register afs_int32 i;
4752     register struct unixuser *tu;
4753
4754     AFS_STATCNT(PUnlog);
4755     if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4756         return EIO;             /* Inappropriate ioctl for device */
4757
4758     if (ainSize < sizeof(afs_int32))
4759         return EINVAL;
4760     memcpy(&addr, ain, sizeof(afs_int32));
4761
4762     if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) {
4763         tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4764         if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4765             afs_PutUser(tu, SHARED_LOCK);
4766             return EACCES;
4767         }
4768         afs_PutUser(tu, SHARED_LOCK);
4769     } else if (!afs_osi_suser(acred)) {
4770         return EACCES;
4771     }
4772
4773     ObtainWriteLock(&afs_xuser, 227);
4774     for (i = 0; i < NUSERS; i++) {
4775         for (tu = afs_users[i]; tu; tu = tu->next) {
4776             if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4777                 tu->vid = UNDEFVID;
4778                 tu->states &= ~UHasTokens;
4779                 /* security is not having to say you're sorry */
4780                 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
4781                 tu->refCount++;
4782                 ReleaseWriteLock(&afs_xuser);
4783                 afs_ResetUserConns(tu);
4784                 tu->refCount--;
4785                 ObtainWriteLock(&afs_xuser, 228);
4786 #ifdef UKERNEL
4787                 /* set the expire times to 0, causes
4788                  * afs_GCUserData to remove this entry
4789                  */
4790                 tu->ct.EndTimestamp = 0;
4791                 tu->tokenTime = 0;
4792 #endif /* UKERNEL */
4793             }
4794         }
4795     }
4796     ReleaseWriteLock(&afs_xuser);
4797     return 0;
4798 }