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