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