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