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