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