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