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