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