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