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