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