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