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