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