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