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