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