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