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