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