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