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