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