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