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