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