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