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