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