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