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