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