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