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