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