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