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