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