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