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