ee43ba676f06a428683ac457f8955a105a4194c1
[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   PNoop,                        /* 57 -- arla: set file prio */
135   PNoop,                        /* 58 -- arla: fallback getfh */
136   PNoop,                        /* 59 -- arla: fallback fhopen */
137   PNoop,                        /* 60 -- arla: controls xfsdebug */
138   PNoop,                        /* 61 -- arla: controls arla debug */
139   PNoop,                        /* 62 -- arla: debug interface */
140   PNoop,                        /* 63 -- arla: print xfs status */
141   PNoop,                        /* 64 -- arla: force cache check */
142   PNoop,                        /* 65 -- arla: break callback */
143   PPrefetchFromTape,            /* 66 -- MR-AFS: prefetch file from tape */
144   PResidencyCmd,                /* 67 -- MR-AFS: generic commnd interface */
145   PNoop,                        /* 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      register 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
1053     afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1054                ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1055     AFS_STATCNT(HandlePioctl);
1056     if (code = afs_InitReq(&treq, *acred)) return code;
1057     device = (acom & 0xff00) >> 8;
1058     switch (device) {
1059         case 'V':       /* Original pioctl's */
1060                 pioctlSw = VpioctlSw;
1061                 pioctlSwSize = sizeof(VpioctlSw);
1062                 break;
1063         case 'C':       /* Coordinated/common pioctl's */
1064                 pioctlSw = CpioctlSw;
1065                 pioctlSwSize = sizeof(CpioctlSw);
1066                 break;
1067         default:
1068                 return EINVAL;
1069     }
1070     function = acom & 0xff;
1071     if (function >= (pioctlSwSize / sizeof(char *))) {
1072       return EINVAL;    /* out of range */
1073     }
1074     inSize = ablob->in_size;
1075     if (inSize >= PIGGYSIZE) return E2BIG;
1076     inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1077     if (inSize > 0) {
1078       AFS_COPYIN(ablob->in, inData, inSize, code);
1079     }
1080     else code = 0;
1081     if (code) {
1082       osi_FreeLargeSpace(inData);
1083       return code;
1084     }
1085     outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1086     outSize = 0;
1087     if (function == 3 && device == 'V') /* PSetTokens */
1088         code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
1089     else
1090         code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, *acred);
1091     osi_FreeLargeSpace(inData);
1092     if (code == 0 && ablob->out_size > 0) {
1093       if (outSize > ablob->out_size) outSize = ablob->out_size;
1094       if (outSize >= PIGGYSIZE) code = E2BIG;
1095       else if   (outSize) 
1096         AFS_COPYOUT(outData, ablob->out, outSize, code);
1097     }
1098     osi_FreeLargeSpace(outData);
1099     return afs_CheckCode(code, &treq, 41);
1100   }
1101   
1102 static PGetFID(avc, afun, areq, ain, aout, ainSize, aoutSize)
1103     struct vcache *avc;
1104   int afun;
1105   struct vrequest *areq;
1106   char *ain, *aout;
1107   afs_int32 ainSize;
1108   afs_int32 *aoutSize;  /* set this */ {
1109     register afs_int32 code;
1110     
1111     AFS_STATCNT(PGetFID);
1112     if (!avc) return EINVAL;
1113     memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1114     *aoutSize = sizeof(struct VenusFid);
1115     return 0;
1116   }
1117   
1118 static PSetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1119   struct vcache *avc;
1120   int afun;
1121   struct vrequest *areq;
1122   char *ain, *aout;
1123   afs_int32 ainSize;
1124   afs_int32 *aoutSize;  /* set this */ {
1125     register afs_int32 code;
1126     struct conn *tconn;
1127     struct AFSOpaque acl;
1128     struct AFSVolSync tsync;
1129     struct AFSFetchStatus OutStatus;
1130     XSTATS_DECLS;
1131     
1132     AFS_STATCNT(PSetAcl);
1133     if (!avc)
1134       return EINVAL;
1135     if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1136       return EINVAL;
1137
1138     acl.AFSOpaque_val = ain;
1139     do {
1140       tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1141       if (tconn) {
1142         XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1143         RX_AFS_GUNLOCK();
1144         code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1145                               &acl, &OutStatus, &tsync);
1146         RX_AFS_GLOCK();
1147         XSTATS_END_TIME;
1148       }
1149       else code = -1;
1150     } while
1151         (afs_Analyze(tconn, code, &avc->fid, areq,
1152                      AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, (struct cell *)0));
1153
1154     /* now we've forgotten all of the access info */
1155     ObtainWriteLock(&afs_xcbhash, 455);
1156     avc->callback = 0;
1157     afs_DequeueCallback(avc);
1158     avc->states &= ~(CStatd | CUnique);
1159     ReleaseWriteLock(&afs_xcbhash);
1160     if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1161         osi_dnlc_purgedp(avc);
1162     return code;
1163   }
1164
1165 int afs_defaultAsynchrony = 0;
1166
1167 static PStoreBehind(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1168      struct vcache *avc;
1169      int afun;
1170      struct vrequest *areq;
1171      char *ain, *aout;
1172      afs_int32 ainSize;
1173      afs_int32 *aoutSize;       /* set this */
1174      struct AFS_UCRED *acred;
1175 {
1176   afs_int32 code = 0;
1177   struct sbstruct *sbr;
1178
1179   sbr = (struct sbstruct *)ain;
1180   if (sbr->sb_default != -1) {
1181     if (afs_osi_suser(acred))
1182       afs_defaultAsynchrony = sbr->sb_default;
1183     else code = EPERM;
1184   }
1185
1186   if (avc && (sbr->sb_thisfile != -1)) {
1187     if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER, 
1188                       areq, DONT_CHECK_MODE_BITS))
1189       avc->asynchrony = sbr->sb_thisfile;
1190     else code = EACCES;
1191   }
1192
1193   *aoutSize = sizeof(struct sbstruct);
1194   sbr = (struct sbstruct *)aout;
1195   sbr->sb_default = afs_defaultAsynchrony;
1196   if (avc) {
1197     sbr->sb_thisfile = avc->asynchrony;
1198   }
1199
1200   return code;
1201 }
1202
1203 static PGCPAGs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1204      struct vcache *avc;
1205      int afun;
1206      struct vrequest *areq;
1207      char *ain, *aout;
1208      afs_int32 ainSize;
1209      afs_int32 *aoutSize;       /* set this */
1210      struct AFS_UCRED *acred;
1211 {
1212   if (!afs_osi_suser(acred)) {
1213     return EACCES;
1214   }
1215   afs_gcpags = AFS_GCPAGS_USERDISABLED;
1216   return 0;
1217 }
1218   
1219   static PGetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1220     struct vcache *avc;
1221   int afun;
1222   struct vrequest *areq;
1223   char *ain, *aout;
1224   afs_int32 ainSize;
1225   afs_int32 *aoutSize;  /* set this */ {
1226     struct AFSOpaque acl;
1227     struct AFSVolSync tsync;
1228     struct AFSFetchStatus OutStatus;
1229     afs_int32 code;
1230     struct conn *tconn;
1231     struct AFSFid Fid;
1232     XSTATS_DECLS;
1233
1234     AFS_STATCNT(PGetAcl);
1235     if (!avc) return EINVAL;
1236     Fid.Volume = avc->fid.Fid.Volume;
1237     Fid.Vnode = avc->fid.Fid.Vnode;
1238     Fid.Unique = avc->fid.Fid.Unique;
1239     if (avc->states & CForeign) {
1240         /*
1241          * For a dfs xlator acl we have a special hack so that the
1242          * xlator will distinguish which type of acl will return. So
1243          * we currently use the top 2-bytes (vals 0-4) to tell which
1244          * type of acl to bring back. Horrible hack but this will
1245          * cause the least number of changes to code size and interfaces.
1246          */
1247         if (Fid.Vnode & 0xc0000000)
1248             return ERANGE;
1249         Fid.Vnode |= (ainSize << 30);
1250     }
1251     acl.AFSOpaque_val = aout;
1252     do {
1253       tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1254       if (tconn) {
1255         *aout = 0;
1256         XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1257         RX_AFS_GUNLOCK();
1258         code = RXAFS_FetchACL(tconn->id, &Fid,
1259                               &acl, &OutStatus, &tsync);
1260         RX_AFS_GLOCK();
1261         XSTATS_END_TIME;
1262       }
1263       else code = -1;
1264     } while
1265         (afs_Analyze(tconn, code, &avc->fid, areq,
1266                      AFS_STATS_FS_RPCIDX_FETCHACL,
1267                      SHARED_LOCK, (struct cell *)0));
1268
1269     if (code == 0) {
1270       *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1271     }
1272     return code;
1273   }
1274   
1275   static PNoop() {
1276     AFS_STATCNT(PNoop);
1277     return 0;
1278   }
1279   
1280   static PBogus() {
1281     AFS_STATCNT(PBogus);
1282     return EINVAL;
1283   }
1284   
1285   static PGetFileCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1286     struct vcache *avc;
1287   int afun;
1288   struct vrequest *areq;
1289   register char *ain;
1290   char *aout;
1291   afs_int32 ainSize;
1292   afs_int32 *aoutSize;  /* set this */ {
1293     register struct cell *tcell;
1294     
1295     AFS_STATCNT(PGetFileCell);
1296     if (!avc) return EINVAL;
1297     tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1298     if (!tcell) return ESRCH;
1299     strcpy(aout, tcell->cellName);
1300     afs_PutCell(tcell, READ_LOCK);
1301     *aoutSize = strlen(aout) + 1;
1302     return 0;
1303   }
1304   
1305   static PGetWSCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1306     struct vcache *avc;
1307   int afun;
1308   struct vrequest *areq;
1309   register char *ain;
1310   char *aout;
1311   afs_int32 ainSize;
1312   afs_int32 *aoutSize;  /* set this */ {
1313     register struct cell *tcell=0, *cellOne=0;
1314     register struct afs_q *cq, *tq;
1315     
1316     AFS_STATCNT(PGetWSCell);
1317     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1318         return EIO;          /* Inappropriate ioctl for device */
1319
1320     ObtainReadLock(&afs_xcell);
1321     cellOne = (struct cell *) 0;
1322
1323     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
1324         tcell = QTOC(cq); tq = QNext(cq);
1325         if (tcell->states & CPrimary) break;
1326         if (tcell->cell == 1) cellOne = tcell;
1327         tcell = 0;
1328     }
1329     ReleaseReadLock(&afs_xcell);
1330     if (!tcell) {           /* no primary cell, use cell #1 */
1331       if (!cellOne) return ESRCH;
1332       tcell = cellOne;
1333     }
1334     strcpy(aout, tcell->cellName);
1335     *aoutSize = strlen(aout) + 1;
1336     return 0;
1337   }
1338   
1339   static PGetUserCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1340     struct vcache *avc;
1341   int afun;
1342   struct vrequest *areq;
1343   register char *ain;
1344   char *aout;
1345   afs_int32 ainSize;
1346   afs_int32 *aoutSize;  /* set this */ {
1347     register afs_int32 i;
1348     register struct unixuser *tu;
1349     register struct cell *tcell;
1350     
1351     AFS_STATCNT(PGetUserCell);
1352     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1353         return EIO;          /* Inappropriate ioctl for device */
1354
1355     /* return the cell name of the primary cell for this user */
1356     i = UHash(areq->uid);
1357     ObtainWriteLock(&afs_xuser,224);
1358     for(tu = afs_users[i]; tu; tu = tu->next) {
1359       if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1360         tu->refCount++;
1361         ReleaseWriteLock(&afs_xuser);
1362         break;
1363       }
1364     }
1365     if (tu) {
1366       tcell = afs_GetCell(tu->cell, READ_LOCK);
1367       afs_PutUser(tu, WRITE_LOCK);
1368       if (!tcell) return ESRCH;
1369       else {
1370         strcpy(aout, tcell->cellName);
1371         afs_PutCell(tcell, READ_LOCK);
1372         *aoutSize =     strlen(aout)+1;     /* 1 for the null */
1373       }
1374     }
1375     else {
1376       ReleaseWriteLock(&afs_xuser);
1377       *aout = 0;
1378       *aoutSize = 1;
1379     }
1380     return 0;
1381   }
1382   
1383   static PSetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1384     struct vcache *avc;
1385   int afun;
1386   struct vrequest *areq;
1387   register char *ain;
1388   char *aout;
1389   afs_int32 ainSize;
1390   afs_int32 *aoutSize;  /* set this */ 
1391   struct AFS_UCRED **acred;
1392 {
1393     afs_int32 i;
1394     register struct unixuser *tu;
1395     struct ClearToken clear;
1396     register struct cell *tcell;
1397     char *stp;
1398     int stLen;
1399     struct vrequest treq;
1400     afs_int32 flag, set_parent_pag = 0;
1401     
1402     AFS_STATCNT(PSetTokens);
1403     if (!afs_resourceinit_flag) {
1404       return EIO;
1405     }
1406     memcpy((char *)&i, ain, sizeof(afs_int32));
1407     ain += sizeof(afs_int32);
1408     stp = ain;  /* remember where the ticket is */
1409     if (i < 0 || i > 2000) return EINVAL;       /* malloc may fail */
1410     stLen = i;
1411     ain += i;   /* skip over ticket */
1412     memcpy((char *)&i, ain, sizeof(afs_int32));
1413     ain += sizeof(afs_int32);
1414     if (i != sizeof(struct ClearToken)) {
1415       return EINVAL;
1416     }
1417     memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1418     if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1419     ain += sizeof(struct ClearToken);
1420     if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1421       /* still stuff left?  we've got primary flag and cell name.  Set these */
1422       memcpy((char *)&flag, ain, sizeof(afs_int32));            /* primary id flag */
1423       ain += sizeof(afs_int32);                 /* skip id field */
1424       /* rest is cell name, look it up */
1425       if (flag & 0x8000) {                      /* XXX Use Constant XXX */
1426           flag &= ~0x8000;
1427           set_parent_pag = 1;
1428       }
1429       tcell = afs_GetCellByName(ain, READ_LOCK);
1430       if (tcell) {
1431         i = tcell->cell;
1432       }
1433       else {
1434         goto nocell;
1435       }
1436     }
1437     else {
1438       /* default to cell 1, primary id */
1439       flag = 1;         /* primary id */
1440       i = 1;            /* cell number */
1441       tcell = afs_GetCell(1, READ_LOCK);
1442       if (!tcell) goto nocell;
1443     }
1444     afs_PutCell(tcell, READ_LOCK);
1445     if (set_parent_pag) {
1446         int pag;
1447 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1448 #if defined(AFS_DARWIN_ENV)
1449         struct proc *p=current_proc(); /* XXX */
1450 #else
1451         struct proc *p=curproc; /* XXX */
1452 #endif
1453         uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1454                 p->p_pid, p->p_comm);
1455         if (!setpag(p, acred, -1, &pag, 1)) {
1456 #else   
1457 #ifdef  AFS_OSF_ENV
1458         if (!setpag(u.u_procp, acred, -1, &pag, 1)) {   /* XXX u.u_procp is a no-op XXX */
1459 #else
1460         if (!setpag(acred, -1, &pag, 1)) {
1461 #endif
1462 #endif
1463             afs_InitReq(&treq, *acred);
1464             areq = &treq;
1465         }
1466     }
1467     /* now we just set the tokens */
1468     tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1469     tu->vid = clear.ViceId;
1470     if (tu->stp != (char *) 0) {
1471       afs_osi_Free(tu->stp, tu->stLen);
1472     }
1473     tu->stp = (char *) afs_osi_Alloc(stLen);
1474     tu->stLen = stLen;
1475     memcpy(tu->stp, stp, stLen);
1476     tu->ct = clear;
1477 #ifndef AFS_NOSTATS
1478     afs_stats_cmfullperf.authent.TicketUpdates++;
1479     afs_ComputePAGStats();
1480 #endif /* AFS_NOSTATS */
1481     tu->states |= UHasTokens;
1482     tu->states &= ~UTokensBad;
1483     afs_SetPrimary(tu, flag);
1484     tu->tokenTime =osi_Time();
1485     afs_ResetUserConns(tu);
1486     afs_PutUser(tu, WRITE_LOCK);
1487
1488     return 0;
1489
1490   nocell:
1491     {
1492     int t1;
1493     t1 = afs_initState;
1494     if (t1 < 101)
1495       return EIO;
1496     else
1497       return ESRCH;
1498   }
1499 }  
1500
1501 static PGetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1502     struct vcache *avc;
1503   int afun;
1504   struct vrequest *areq;
1505   char *ain, *aout;
1506   afs_int32 ainSize;
1507   afs_int32 *aoutSize;  /* set this */ {
1508     char volName[32];
1509     char offLineMsg[256];
1510     char motd[256];
1511     register struct conn *tc;
1512     register afs_int32 code;
1513     struct VolumeStatus volstat;
1514     register char *cp;
1515     char *Name, *OfflineMsg, *MOTD;
1516     XSTATS_DECLS;
1517
1518     AFS_STATCNT(PGetVolumeStatus);
1519     if (!avc) return EINVAL;
1520     Name = volName;
1521     OfflineMsg = offLineMsg;
1522     MOTD = motd;
1523     do {
1524       tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1525       if (tc) {
1526         XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1527         RX_AFS_GUNLOCK();
1528         code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1529                                      &Name, &OfflineMsg, &MOTD);
1530         RX_AFS_GLOCK();
1531         XSTATS_END_TIME;
1532       }
1533       else code = -1;
1534     } while
1535       (afs_Analyze(tc, code, &avc->fid, areq,
1536                    AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1537                    SHARED_LOCK, (struct cell *)0));
1538
1539     if (code) return code;
1540     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1541     cp = aout;
1542     memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1543     cp += sizeof(VolumeStatus);
1544     strcpy(cp, volName);
1545     cp += strlen(volName)+1;
1546     strcpy(cp, offLineMsg);
1547     cp += strlen(offLineMsg)+1;
1548     strcpy(cp, motd);
1549     cp += strlen(motd)+1;
1550     *aoutSize = (cp - aout);
1551     return 0;
1552 }
1553
1554 static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1555     struct vcache *avc;
1556     int afun;
1557     struct vrequest *areq;
1558     char *ain, *aout;
1559     afs_int32 ainSize;
1560     afs_int32 *aoutSize;        /* set this */ {
1561     char volName[32];
1562     char offLineMsg[256];
1563     char motd[256];
1564     register struct conn *tc;
1565     register afs_int32 code;
1566     struct AFSFetchVolumeStatus volstat;
1567     struct AFSStoreVolumeStatus storeStat;
1568     register struct volume *tvp;
1569     register char *cp;
1570     XSTATS_DECLS;
1571
1572     AFS_STATCNT(PSetVolumeStatus);
1573     if (!avc) return EINVAL;
1574
1575     tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);       
1576     if (tvp) {
1577         if (tvp->states & (VRO | VBackup)) {
1578             afs_PutVolume(tvp, READ_LOCK);
1579             return EROFS;
1580         }
1581         afs_PutVolume(tvp, READ_LOCK);
1582     } else
1583         return ENODEV;
1584     /* Copy the junk out, using cp as a roving pointer. */
1585     cp = ain;
1586     memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1587     cp += sizeof(AFSFetchVolumeStatus);
1588     if (strlen(cp) >= sizeof(volName))
1589         return E2BIG;
1590     strcpy(volName, cp);
1591     cp += strlen(volName)+1;
1592     if (strlen(cp) >= sizeof(offLineMsg))
1593         return E2BIG;
1594     strcpy(offLineMsg, cp);
1595     cp +=  strlen(offLineMsg)+1;
1596     if (strlen(cp) >= sizeof(motd))
1597         return E2BIG;
1598     strcpy(motd, cp);
1599     storeStat.Mask = 0;
1600     if (volstat.MinQuota != -1) {
1601         storeStat.MinQuota = volstat.MinQuota;
1602         storeStat.Mask |= AFS_SETMINQUOTA;
1603     }
1604     if (volstat.MaxQuota != -1) {
1605         storeStat.MaxQuota = volstat.MaxQuota;
1606         storeStat.Mask |= AFS_SETMAXQUOTA;
1607     }
1608     do {
1609         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1610         if (tc) {
1611           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1612             RX_AFS_GUNLOCK();
1613             code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1614                                         &storeStat, volName, offLineMsg, motd);
1615             RX_AFS_GLOCK();
1616           XSTATS_END_TIME;
1617         }
1618         else code = -1;
1619     } while
1620       (afs_Analyze(tc, code, &avc->fid, areq,
1621                    AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1622                    SHARED_LOCK, (struct cell *)0));
1623
1624     if (code) return code;
1625     /* we are sending parms back to make compat. with prev system.  should
1626       change interface later to not ask for current status, just set new status */
1627     cp = aout;
1628     memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1629     cp += sizeof(VolumeStatus);
1630     strcpy(cp, volName);
1631     cp += strlen(volName)+1;
1632     strcpy(cp, offLineMsg);
1633     cp += strlen(offLineMsg)+1;
1634     strcpy(cp, motd);
1635     cp += strlen(motd)+1;
1636     *aoutSize = cp - aout;
1637     return 0;
1638 }
1639
1640 static PFlush(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1641     register struct vcache *avc;
1642     int afun;
1643     struct vrequest *areq;
1644     char *ain, *aout;
1645     afs_int32 ainSize;
1646     afs_int32 *aoutSize;        /* set this */ 
1647     struct AFS_UCRED *acred;
1648 {
1649
1650     AFS_STATCNT(PFlush);
1651     if (!avc) return EINVAL;
1652 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1653     afs_BozonLock(&avc->pvnLock, avc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
1654 #endif
1655     ObtainWriteLock(&avc->lock,225);
1656     ObtainWriteLock(&afs_xcbhash, 456);
1657     afs_DequeueCallback(avc);
1658     avc->states &= ~(CStatd | CDirty);  /* next reference will re-stat cache entry */
1659     ReleaseWriteLock(&afs_xcbhash);
1660     /* now find the disk cache entries */
1661     afs_TryToSmush(avc, acred, 1);
1662     osi_dnlc_purgedp(avc);
1663     afs_symhint_inval(avc);
1664     if (avc->linkData && !(avc->states & CCore)) {
1665         afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1666         avc->linkData = (char *) 0;
1667     }
1668     ReleaseWriteLock(&avc->lock);
1669 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1670     afs_BozonUnlock(&avc->pvnLock, avc);
1671 #endif
1672     return 0;
1673 }
1674
1675 static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
1676     struct vcache *avc;
1677     int afun;
1678     struct vrequest *areq;
1679     char *ain, *aout;
1680     afs_int32 ainSize;
1681     afs_int32 *aoutSize;        /* set this */ {
1682     register afs_int32 code;
1683     register struct vcache *tvc;
1684     register struct dcache *tdc;
1685     struct VenusFid tfid;
1686     char *bufp;
1687     struct sysname_info sysState;
1688     afs_size_t offset, len;
1689
1690     AFS_STATCNT(PNewStatMount);
1691     if (!avc) return EINVAL;
1692     code = afs_VerifyVCache(avc, areq);
1693     if (code) return code;
1694     if (vType(avc) != VDIR) {
1695         return ENOTDIR;
1696     }
1697     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1698     if (!tdc) return ENOENT;
1699     Check_AtSys(avc, ain, &sysState, areq);
1700     ObtainReadLock(&tdc->lock);
1701     do {
1702       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1703     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1704     ReleaseReadLock(&tdc->lock);
1705     afs_PutDCache(tdc);     /* we're done with the data */
1706     bufp = sysState.name;
1707     if (code) {
1708         goto out;
1709     }
1710     tfid.Cell = avc->fid.Cell;
1711     tfid.Fid.Volume = avc->fid.Fid.Volume;
1712     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1713         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
1714     } else {
1715         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
1716                             WRITE_LOCK);
1717     }
1718     if (!tvc) {
1719         code = ENOENT;
1720         goto out;
1721     }
1722     if (vType(tvc) != VLNK) {
1723         afs_PutVCache(tvc, WRITE_LOCK);
1724         code = EINVAL;
1725         goto out;
1726     }
1727     ObtainWriteLock(&tvc->lock,226);
1728     code = afs_HandleLink(tvc, areq);
1729     if (code == 0) {
1730         if (tvc->linkData) {
1731             if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1732                 code =  EINVAL;
1733             else {
1734                 /* we have the data */
1735                 strcpy(aout, tvc->linkData);
1736                 *aoutSize = strlen(tvc->linkData)+1;
1737             }
1738         } else 
1739             code = EIO;
1740     }
1741     ReleaseWriteLock(&tvc->lock);
1742     afs_PutVCache(tvc, WRITE_LOCK);
1743 out:
1744     if (sysState.allocked) osi_FreeLargeSpace(bufp);
1745     return code;
1746 }
1747
1748 static PGetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize)
1749     struct vcache *avc;
1750     int afun;
1751     struct vrequest *areq;
1752     char *ain, *aout;
1753     afs_int32 ainSize;
1754     afs_int32 *aoutSize;        /* set this */ {
1755     register struct cell *tcell;
1756     register afs_int32 i;
1757     register struct unixuser *tu;
1758     register char *cp;
1759     afs_int32 iterator;
1760     int newStyle;
1761
1762     AFS_STATCNT(PGetTokens);
1763     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1764         return EIO;          /* Inappropriate ioctl for device */
1765
1766     /* weird interface.  If input parameter is present, it is an integer and
1767         we're supposed to return the parm'th tokens for this unix uid.
1768         If not present, we just return tokens for cell 1.
1769         If counter out of bounds, return EDOM.
1770         If no tokens for the particular cell, return ENOTCONN.
1771         Also, if this mysterious parm is present, we return, along with the
1772         tokens, the primary cell indicator (an afs_int32 0) and the cell name
1773         at the end, in that order.
1774     */
1775     if (newStyle = (ainSize > 0)) {
1776         memcpy((char *)&iterator, ain, sizeof(afs_int32));
1777     }
1778     i = UHash(areq->uid);
1779     ObtainReadLock(&afs_xuser);
1780     for(tu = afs_users[i]; tu; tu=tu->next) {
1781         if (newStyle) {
1782             if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1783                 if (iterator-- == 0) break;     /* are we done yet? */
1784             }
1785         }
1786         else {
1787             if (tu->uid == areq->uid && tu->cell == 1) break;
1788         }
1789     }
1790     if (tu) {
1791         /*
1792          * No need to hold a read lock on each user entry 
1793          */
1794         tu->refCount++;
1795     }
1796     ReleaseReadLock(&afs_xuser);
1797
1798     if (!tu) {
1799         return EDOM;
1800     }
1801     if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1802         tu->states |= (UTokensBad | UNeedsReset);
1803         afs_PutUser(tu, READ_LOCK);
1804         return ENOTCONN;
1805     }
1806     /* use iterator for temp */
1807     cp = aout;
1808     iterator = tu->stLen;       /* for compat, we try to return 56 byte tix if they fit */
1809     if (iterator < 56) iterator = 56;   /* # of bytes we're returning */
1810     memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1811     cp += sizeof(afs_int32);
1812     memcpy(cp, tu->stp, tu->stLen);     /* copy out st */
1813     cp += iterator;
1814     iterator = sizeof(struct ClearToken);
1815     memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1816     cp += sizeof(afs_int32);
1817     memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1818     cp += sizeof(struct ClearToken);
1819     if (newStyle) {
1820         /* put out primary id and cell name, too */
1821         iterator = (tu->states & UPrimary ? 1 : 0);
1822         memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1823         cp += sizeof(afs_int32);
1824         tcell = afs_GetCell(tu->cell, READ_LOCK);
1825         if (tcell) {
1826             strcpy(cp, tcell->cellName);
1827             cp += strlen(tcell->cellName)+1;
1828             afs_PutCell(tcell, READ_LOCK);
1829         }
1830         else *cp++ = 0;
1831     }
1832     *aoutSize = cp - aout;
1833     afs_PutUser(tu, READ_LOCK);
1834     return 0;
1835 }
1836
1837 static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
1838     struct vcache *avc;
1839     int afun;
1840     struct vrequest *areq;
1841     char *ain, *aout;
1842     afs_int32 ainSize;
1843     afs_int32 *aoutSize;        /* set this */ {
1844     register afs_int32 i;
1845     register struct unixuser *tu;
1846
1847     AFS_STATCNT(PUnlog);
1848     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1849         return EIO;          /* Inappropriate ioctl for device */
1850
1851     i = UHash(areq->uid);
1852     ObtainWriteLock(&afs_xuser,227);
1853     for(tu=afs_users[i]; tu; tu=tu->next) {
1854         if (tu->uid == areq->uid) {
1855             tu->vid = UNDEFVID;
1856             tu->states &= ~UHasTokens;
1857             /* security is not having to say you're sorry */
1858             memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
1859             tu->refCount++;
1860             ReleaseWriteLock(&afs_xuser);
1861             /* We have to drop the lock over the call to afs_ResetUserConns, since
1862              * it obtains the afs_xvcache lock.  We could also keep the lock, and
1863              * modify ResetUserConns to take parm saying we obtained the lock
1864              * already, but that is overkill.  By keeping the "tu" pointer
1865              * held over the released lock, we guarantee that we won't lose our
1866              * place, and that we'll pass over every user conn that existed when
1867              * we began this call.
1868              */
1869             afs_ResetUserConns(tu);
1870             tu->refCount--;
1871             ObtainWriteLock(&afs_xuser,228);
1872 #ifdef UKERNEL
1873             /* set the expire times to 0, causes
1874              * afs_GCUserData to remove this entry
1875              */
1876             tu->ct.EndTimestamp = 0;
1877             tu->tokenTime = 0;
1878 #endif  /* UKERNEL */
1879         }
1880     }
1881     ReleaseWriteLock(&afs_xuser);
1882     return 0;
1883 }
1884
1885 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1886     struct vcache *avc;
1887     int afun;
1888     struct vrequest *areq;
1889     char *ain, *aout;
1890     afs_int32 ainSize;
1891     afs_int32 *aoutSize;        /* set this */ {
1892     afs_int32 newHostAddr;
1893     afs_int32 oldHostAddr;
1894     
1895     AFS_STATCNT(PMariner);
1896     if (afs_mariner)
1897         memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost, sizeof(afs_int32));
1898     else
1899         oldHostAddr = 0xffffffff;   /* disabled */
1900     
1901     memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
1902     if (newHostAddr == 0xffffffff) {
1903         /* disable mariner operations */
1904         afs_mariner = 0;
1905     }
1906     else if (newHostAddr) {
1907         afs_mariner = 1;
1908         afs_marinerHost = newHostAddr;
1909     }
1910     memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
1911     *aoutSize = sizeof(afs_int32);
1912     return 0;
1913 }
1914
1915 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1916     struct vcache *avc;
1917     int afun;
1918     struct vrequest *areq;
1919     char *ain, *aout;
1920     afs_int32 ainSize;
1921     afs_int32 *aoutSize;        /* set this */ 
1922     struct AFS_UCRED *acred;
1923 {
1924     register char *cp = 0;
1925     register int i;
1926     register struct server *ts;
1927     afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1928     struct cell *cellp;
1929     struct chservinfo *pcheck;
1930
1931     AFS_STATCNT(PCheckServers);
1932
1933     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
1934         return EIO;          /* Inappropriate ioctl for device */
1935
1936     if (*lp == 0x12345678) {    /* For afs3.3 version */
1937         pcheck=(struct chservinfo *)ain;
1938         if (pcheck->tinterval >= 0) {
1939             cp = aout;      
1940             memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
1941             *aoutSize = sizeof(afs_int32);
1942             if (pcheck->tinterval > 0) {
1943                 if (!afs_osi_suser(acred))
1944                     return EACCES;
1945                 PROBE_INTERVAL=pcheck->tinterval;
1946             }
1947             return 0;
1948         }
1949         if (pcheck->tsize)
1950             havecell = 1;
1951         temp=pcheck->tflags;
1952         cp = pcheck->tbuffer;
1953     } else {    /* For pre afs3.3 versions */
1954         memcpy((char *)&temp, ain, sizeof(afs_int32));
1955         cp = ain+sizeof(afs_int32);
1956         if (ainSize > sizeof(afs_int32)) 
1957             havecell = 1;
1958     }
1959
1960     /* 
1961      * 1: fast check, don't contact servers.
1962      * 2: local cell only.
1963      */
1964     if (havecell) {
1965         /* have cell name, too */
1966         cellp = afs_GetCellByName(cp, READ_LOCK);
1967         if (!cellp) return ENOENT;
1968     }
1969     else cellp = (struct cell *) 0;
1970     if (!cellp && (temp & 2)) {
1971         /* use local cell */
1972         cellp = afs_GetCell(1, READ_LOCK);
1973     }
1974     if (!(temp & 1)) {  /* if not fast, call server checker routine */
1975         afs_CheckServers(1, cellp);     /* check down servers */
1976         afs_CheckServers(0, cellp);     /* check up servers */
1977     }
1978     /* now return the current down server list */
1979     cp = aout;
1980     ObtainReadLock(&afs_xserver);
1981     for(i=0;i<NSERVERS;i++) {
1982         for(ts = afs_servers[i]; ts; ts=ts->next) {
1983             if (cellp && ts->cell != cellp) continue;   /* cell spec'd and wrong */
1984             if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1985                 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
1986                 cp += sizeof(afs_int32);
1987             }
1988         }
1989     }
1990     ReleaseReadLock(&afs_xserver);
1991     if (cellp) afs_PutCell(cellp, READ_LOCK);
1992     *aoutSize = cp - aout;
1993     return 0;
1994 }
1995
1996 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
1997     struct vcache *avc;
1998     int afun;
1999     struct vrequest *areq;
2000     char *ain, *aout;
2001     afs_int32 ainSize;
2002     afs_int32 *aoutSize;        /* set this */ {
2003     AFS_STATCNT(PCheckVolNames);
2004     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2005         return EIO;          /* Inappropriate ioctl for device */
2006
2007     afs_CheckRootVolume();
2008     afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
2009                          AFS_VOLCHECK_EXPIRED |
2010                          AFS_VOLCHECK_BUSY |
2011                          AFS_VOLCHECK_MTPTS);
2012     return 0;
2013 }
2014
2015 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
2016     struct vcache *avc;
2017     int afun;
2018     struct vrequest *areq;
2019     char *ain, *aout;
2020     afs_int32 ainSize;
2021     afs_int32 *aoutSize;        /* set this */ {
2022        int i;
2023        struct srvAddr *sa;
2024        struct conn *tc;
2025        struct unixuser *tu;
2026        afs_int32 retValue;
2027        extern afs_rwlock_t afs_xsrvAddr;        
2028
2029     AFS_STATCNT(PCheckAuth);
2030     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2031         return EIO;          /* Inappropriate ioctl for device */
2032
2033     retValue = 0;
2034     tu = afs_GetUser(areq->uid, 1, READ_LOCK);  /* check local cell authentication */
2035     if (!tu) retValue = EACCES;
2036     else {
2037         /* we have a user */
2038         ObtainReadLock(&afs_xsrvAddr);  
2039         ObtainReadLock(&afs_xconn);
2040
2041         /* any tokens set? */
2042         if ((tu->states & UHasTokens) == 0) retValue = EACCES;
2043         /* all connections in cell 1 working? */
2044         for(i=0;i<NSERVERS;i++) {
2045             for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
2046                for (tc = sa->conns; tc; tc=tc->next) {
2047                   if (tc->user == tu && (tu->states & UTokensBad))
2048                        retValue = EACCES;
2049                }
2050             }
2051         }
2052         ReleaseReadLock(&afs_xsrvAddr);
2053         ReleaseReadLock(&afs_xconn);
2054         afs_PutUser(tu, READ_LOCK);
2055     }
2056     memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2057     *aoutSize = sizeof(afs_int32);
2058     return 0;
2059 }
2060
2061 static Prefetch(apath, adata, afollow, acred)
2062 char *apath;
2063 struct afs_ioctl *adata;
2064 int afollow;
2065 struct AFS_UCRED *acred; 
2066 {
2067     register char *tp;
2068     register afs_int32 code;
2069 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2070     size_t bufferSize;
2071 #else
2072     u_int bufferSize;
2073 #endif
2074
2075     AFS_STATCNT(Prefetch);
2076     if (!apath) return EINVAL;
2077     tp = osi_AllocLargeSpace(1024);
2078     AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2079     if (code) {
2080         osi_FreeLargeSpace(tp);
2081         return code;
2082     }
2083     if (afs_BBusy()) {  /* do this as late as possible */
2084         osi_FreeLargeSpace(tp);
2085         return EWOULDBLOCK;     /* pretty close */
2086     }
2087     afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred,
2088                (afs_size_t) 0, (afs_size_t) 0, tp);
2089     return 0;
2090 }
2091
2092 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
2093     struct vcache *avc;
2094     int afun;
2095     struct vrequest *areq;
2096     char *ain, *aout;
2097     afs_int32 ainSize;
2098     afs_int32 *aoutSize;        /* set this */ {
2099     register struct volume *tvp;
2100     register struct server *ts;
2101     register afs_int32 i;
2102     register char *cp;
2103     
2104     AFS_STATCNT(PFindVolume);
2105     if (!avc) return EINVAL;
2106     tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2107     if (tvp) {
2108         cp = aout;
2109         for(i=0;i<MAXHOSTS;i++) {
2110             ts = tvp->serverHost[i];
2111             if (!ts) break;
2112             memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2113             cp += sizeof(afs_int32);
2114         }
2115         if (i<MAXHOSTS) {
2116             /* still room for terminating NULL, add it on */
2117             ainSize = 0;        /* reuse vbl */
2118             memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2119             cp += sizeof(afs_int32);
2120         }
2121         *aoutSize = cp - aout;
2122         afs_PutVolume(tvp, READ_LOCK);
2123         return 0;
2124     }
2125     return ENODEV;
2126 }
2127
2128 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
2129     struct vcache *avc;
2130     int afun;
2131     struct vrequest *areq;
2132     char *ain, *aout;
2133     afs_int32 ainSize;
2134     afs_int32 *aoutSize;        /* set this */ {
2135     register afs_int32 code;
2136     afs_int32 temp;
2137     
2138     AFS_STATCNT(PViceAccess);
2139     if (!avc) return EINVAL;
2140     code = afs_VerifyVCache(avc, areq);
2141     if (code) return code;
2142     memcpy((char *)&temp, ain, sizeof(afs_int32));
2143     code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2144     if (code) return 0;
2145     else return EACCES;
2146 }
2147
2148 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2149     struct vcache *avc;
2150     int afun;
2151     struct vrequest *areq;
2152     char *ain, *aout;
2153     afs_int32 ainSize;
2154     afs_int32 *aoutSize;        /* set this */ 
2155     struct AFS_UCRED *acred;
2156 {
2157     afs_int32 newValue;
2158     int waitcnt = 0;
2159     
2160     AFS_STATCNT(PSetCacheSize);
2161     if (!afs_osi_suser(acred))
2162         return EACCES;
2163     /* too many things are setup initially in mem cache version */
2164     if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2165     memcpy((char *)&newValue, ain, sizeof(afs_int32));
2166     if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2167     else {
2168         extern u_int afs_min_cache;
2169         if (newValue < afs_min_cache)
2170             afs_cacheBlocks = afs_min_cache;
2171         else
2172             afs_cacheBlocks = newValue;
2173     }
2174     afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2175     afs_ComputeCacheParms();    /* recompute basic cache parameters */
2176     afs_MaybeWakeupTruncateDaemon();
2177     while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2178         afs_osi_Wait(1000, 0, 0);
2179         afs_MaybeWakeupTruncateDaemon();
2180     }
2181     return 0;
2182 }
2183
2184 #define MAXGCSTATS      16
2185 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2186 struct vcache *avc;
2187 int afun;
2188 struct vrequest *areq;
2189 char *ain, *aout;
2190 afs_int32 ainSize;
2191 afs_int32 *aoutSize;    /* set this */ {
2192     afs_int32 results[MAXGCSTATS];
2193
2194     AFS_STATCNT(PGetCacheSize);
2195     memset((char *)results, 0, sizeof(results));
2196     results[0] = afs_cacheBlocks;
2197     results[1] = afs_blocksUsed;
2198     memcpy(aout, (char *)results, sizeof(results));
2199     *aoutSize = sizeof(results);
2200     return 0;
2201 }
2202
2203 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2204     struct vcache *avc;
2205     int afun;
2206     struct vrequest *areq;
2207     char *ain, *aout;
2208     afs_int32 ainSize;
2209     afs_int32 *aoutSize;        /* set this */ {
2210     register struct conn *tc;
2211     register afs_int32 code;
2212     struct AFSCallBack CallBacks_Array[1];
2213     struct AFSCBFids theFids;
2214     struct AFSCBs theCBs;
2215     XSTATS_DECLS;
2216
2217     AFS_STATCNT(PRemoveCallBack);
2218     if (!avc) return EINVAL;
2219     if (avc->states & CRO) return 0;    /* read-only-ness can't change */
2220     ObtainWriteLock(&avc->lock,229);
2221     theFids.AFSCBFids_len = 1;
2222     theCBs.AFSCBs_len = 1;
2223     theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2224     theCBs.AFSCBs_val = CallBacks_Array;
2225     CallBacks_Array[0].CallBackType = CB_DROPPED;
2226     if (avc->callback) {
2227         do {
2228             tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2229             if (tc) {
2230               XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2231               RX_AFS_GUNLOCK();
2232               code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2233               RX_AFS_GLOCK();
2234               XSTATS_END_TIME;
2235             }
2236             /* don't set code on failure since we wouldn't use it */
2237         } while
2238           (afs_Analyze(tc, code, &avc->fid, areq,
2239                        AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2240                        SHARED_LOCK, (struct cell *)0));
2241
2242         ObtainWriteLock(&afs_xcbhash, 457);
2243         afs_DequeueCallback(avc);
2244         avc->callback = 0;
2245         avc->states &= ~(CStatd | CUnique);
2246         ReleaseWriteLock(&afs_xcbhash);
2247         if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2248             osi_dnlc_purgedp(avc);
2249     }
2250     ReleaseWriteLock(&avc->lock);
2251     return 0;
2252 }
2253
2254 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2255     struct vcache *avc;
2256     int afun;
2257     struct vrequest *areq;
2258     register char *ain;
2259     char *aout;
2260     afs_int32 ainSize;
2261     struct AFS_UCRED *acred;
2262     afs_int32 *aoutSize;        /* set this */ {
2263     /* create a new cell */
2264     afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2265     register struct cell *tcell;
2266     char *newcell=0, *linkedcell=0, *tp= ain;
2267     register afs_int32 code, linkedstate=0, ls;
2268     u_short fsport = 0, vlport = 0;
2269     afs_int32 scount;
2270     
2271     AFS_STATCNT(PNewCell);
2272     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2273         return EIO;          /* Inappropriate ioctl for device */
2274
2275     if (!afs_osi_suser(acred))
2276         return EACCES;
2277
2278     memcpy((char *)&magic, tp, sizeof(afs_int32));
2279     tp += sizeof(afs_int32);
2280     if (magic != 0x12345678)
2281         return EINVAL;
2282
2283     /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2284      * server addresses while the 3.5 fs newcell command passes
2285      * MAXHOSTS. To figure out which is which, check if the cellname
2286      * is good.
2287      */
2288     newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2289     scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2290
2291     /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2292     memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2293     tp += (scount * sizeof(afs_int32));
2294
2295     lp = (afs_int32 *)tp;
2296     fsport = *lp++;
2297     vlport = *lp++;
2298     if (fsport < 1024) fsport = 0;      /* Privileged ports not allowed */
2299     if (vlport < 1024) vlport = 0;      /* Privileged ports not allowed */
2300     tp += (3 * sizeof(afs_int32));
2301     newcell = tp;
2302     if ((ls = *lp) & 1) {
2303        linkedcell = tp + strlen(newcell)+1;
2304        linkedstate |= CLinkedCell;
2305     }
2306
2307     linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2308     code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0, (char *) 0);
2309     return code;
2310 }
2311
2312 static PNewAlias(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2313     struct vcache *avc;
2314     int afun;
2315     struct vrequest *areq;
2316     register char *ain;
2317     char *aout;
2318     afs_int32 ainSize;
2319     struct AFS_UCRED *acred;
2320     afs_int32 *aoutSize;        /* set this */
2321 {
2322     /* create a new cell alias */
2323     register struct cell *tcell;
2324     char *tp = ain;
2325     register afs_int32 code;
2326     char *realName, *aliasName;
2327     register struct afs_q *cq, *tq;
2328     
2329     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2330         return EIO;          /* Inappropriate ioctl for device */
2331
2332     if (!afs_osi_suser(acred))
2333         return EACCES;
2334
2335     aliasName = tp;
2336     tp += strlen(aliasName) + 1;
2337     realName = tp;
2338
2339     /*
2340      * Prevent user from shooting themselves in the foot -- don't allow
2341      * creation of aliases when a real cell already exists with that name.
2342      */
2343     ObtainReadLock(&afs_xcell);
2344     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2345         tcell = QTOC(cq); tq = QNext(cq);
2346         if ((afs_strcasecmp(tcell->cellName, aliasName) == 0) &&
2347             !(tcell->states & CAlias)) {
2348             ReleaseReadLock(&afs_xcell);
2349             return EEXIST;
2350         }
2351     }
2352     ReleaseReadLock(&afs_xcell);
2353
2354     code = afs_NewCell(aliasName, 0, CAlias, 0, 0, 0, 0, realName);
2355     *aoutSize = 0;
2356     return code;
2357 }
2358
2359 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2360     struct vcache *avc;
2361     int afun;
2362     struct vrequest *areq;
2363     char *ain, *aout;
2364     afs_int32 ainSize;
2365     afs_int32 *aoutSize;        /* set this */ {
2366     afs_int32 whichCell;
2367     register struct cell *tcell=0;
2368     register afs_int32 i;
2369     register char *cp, *tp = ain;
2370     register struct afs_q *cq, *tq;
2371
2372     AFS_STATCNT(PListCells);
2373     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2374         return EIO;          /* Inappropriate ioctl for device */
2375
2376     memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2377     tp += sizeof(afs_int32);
2378     ObtainReadLock(&afs_xcell);
2379     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2380         tcell = QTOC(cq); tq = QNext(cq);
2381         if (tcell->states & CAlias) {
2382             tcell = 0;
2383             continue;
2384         }
2385         if (whichCell == 0) break;
2386         tcell = 0;
2387         whichCell--;
2388     }
2389     if (tcell) {
2390         cp = aout;
2391         memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2392         for(i=0;i<MAXCELLHOSTS;i++) {
2393             if (tcell->cellHosts[i] == 0) break;
2394             memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip, sizeof(afs_int32));
2395             cp += sizeof(afs_int32);
2396         }
2397         cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2398         strcpy(cp, tcell->cellName);
2399         cp += strlen(tcell->cellName)+1;
2400         *aoutSize = cp - aout;
2401     }
2402     ReleaseReadLock(&afs_xcell);
2403     if (tcell) return 0;
2404     else return EDOM;
2405 }
2406
2407 static PListAliases(avc, afun, areq, ain, aout, ainSize, aoutSize)
2408     struct vcache *avc;
2409     int afun;
2410     struct vrequest *areq;
2411     char *ain, *aout;
2412     afs_int32 ainSize;
2413     afs_int32 *aoutSize;        /* set this */
2414 {
2415     afs_int32 whichAlias;
2416     register struct cell *tcell=0;
2417     register char *cp, *tp = ain;
2418     register struct afs_q *cq, *tq;
2419
2420     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2421         return EIO;          /* Inappropriate ioctl for device */
2422     if (ainSize < sizeof(afs_int32))
2423         return EINVAL;
2424
2425     memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2426     tp += sizeof(afs_int32);
2427
2428     ObtainReadLock(&afs_xcell);
2429     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2430         tcell = QTOC(cq); tq = QNext(cq);
2431         if (!(tcell->states & CAlias)) {
2432             tcell = 0;
2433             continue;
2434         }
2435         if (whichAlias == 0) break;
2436         tcell = 0;
2437         whichAlias--;
2438     }
2439     if (tcell) {        
2440         cp = aout;
2441         strcpy(cp, tcell->cellName);
2442         cp += strlen(tcell->cellName)+1;
2443         strcpy(cp, tcell->realName);
2444         cp += strlen(tcell->realName)+1;
2445         *aoutSize = cp - aout;
2446     }
2447     ReleaseReadLock(&afs_xcell);
2448     if (tcell) return 0;
2449     else return EDOM;
2450 }
2451
2452 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2453     struct vcache *avc;
2454     int afun;
2455     struct vrequest *areq;
2456     register char *ain;
2457     char *aout;
2458     afs_int32 ainSize;
2459     afs_int32 *aoutSize;        /* set this */ {
2460     register afs_int32 code;
2461     char *bufp;
2462     struct sysname_info sysState;
2463     afs_size_t offset, len;
2464     register struct conn *tc;
2465     register struct dcache *tdc;
2466     register struct vcache *tvc;
2467     struct AFSFetchStatus OutDirStatus;
2468     struct VenusFid tfid;
2469     struct AFSVolSync tsync;
2470     XSTATS_DECLS;
2471
2472
2473     /* "ain" is the name of the file in this dir to remove */
2474
2475     AFS_STATCNT(PRemoveMount);
2476     if (!avc) return EINVAL;
2477     code = afs_VerifyVCache(avc, areq);
2478     if (code) return code;
2479     if (vType(avc) != VDIR) return ENOTDIR;
2480
2481     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);   /* test for error below */
2482     if (!tdc) return ENOENT;
2483     Check_AtSys(avc, ain, &sysState, areq);
2484     ObtainReadLock(&tdc->lock);
2485     do {
2486       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2487     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2488     ReleaseReadLock(&tdc->lock);
2489     bufp = sysState.name;
2490     if (code) {
2491         afs_PutDCache(tdc);
2492         goto out;
2493     }
2494     tfid.Cell = avc->fid.Cell;
2495     tfid.Fid.Volume = avc->fid.Fid.Volume;
2496     if (!tfid.Fid.Unique &&  (avc->states & CForeign)) {
2497         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2498     } else {
2499         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2500                             (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2501     }
2502     if (!tvc) {
2503         code = ENOENT;
2504         afs_PutDCache(tdc);
2505         goto out;
2506     }
2507     if (vType(tvc) != VLNK) {
2508         afs_PutDCache(tdc);
2509         afs_PutVCache(tvc, WRITE_LOCK);
2510         code = EINVAL;
2511         goto out;
2512     }
2513     ObtainWriteLock(&tvc->lock,230);
2514     code = afs_HandleLink(tvc, areq);
2515     if (!code) {
2516         if (tvc->linkData) {
2517             if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2518                 code =  EINVAL;
2519         } else 
2520             code = EIO;
2521     }
2522     ReleaseWriteLock(&tvc->lock);
2523     osi_dnlc_purgedp(tvc);
2524     afs_PutVCache(tvc, WRITE_LOCK);
2525     if (code) {
2526         afs_PutDCache(tdc);
2527         goto out;
2528     }
2529     ObtainWriteLock(&avc->lock,231);
2530     osi_dnlc_remove(avc, bufp, tvc);
2531     do {
2532         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2533         if (tc) {
2534           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2535           RX_AFS_GUNLOCK();
2536           code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2537                                   bufp, &OutDirStatus, &tsync);
2538           RX_AFS_GLOCK();
2539           XSTATS_END_TIME;
2540         }
2541         else code = -1;
2542     } while
2543         (afs_Analyze(tc, code, &avc->fid, areq,
2544                      AFS_STATS_FS_RPCIDX_REMOVEFILE,
2545                      SHARED_LOCK, (struct cell *)0));
2546
2547     if (code) {
2548         if (tdc) afs_PutDCache(tdc);
2549         ReleaseWriteLock(&avc->lock);
2550         goto out;
2551     }
2552     if (tdc) {
2553         /* we have the thing in the cache */
2554         ObtainWriteLock(&tdc->lock, 661);
2555         if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2556             /* we can do it locally */
2557             code = afs_dir_Delete(&tdc->f.inode, bufp);
2558             if (code) {
2559                 ZapDCE(tdc);    /* surprise error -- invalid value */
2560                 DZap(&tdc->f.inode);
2561             }
2562         }
2563         ReleaseWriteLock(&tdc->lock);
2564         afs_PutDCache(tdc);     /* drop ref count */
2565     }
2566     avc->states &= ~CUnique;            /* For the dfs xlator */
2567     ReleaseWriteLock(&avc->lock);
2568     code = 0;
2569 out:
2570     if (sysState.allocked) osi_FreeLargeSpace(bufp);
2571     return code;    
2572 }
2573
2574 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2575     struct vcache *avc;
2576     int afun;
2577     struct vrequest *areq;
2578     register char *ain;
2579     char *aout;
2580     afs_int32 ainSize;
2581     struct AFS_UCRED *acred;
2582     afs_int32 *aoutSize;        /* set this */ {
2583     return EINVAL;              /* OBSOLETE */
2584 }
2585
2586 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2587     struct vcache *avc;
2588     int afun;
2589     struct vrequest *areq;
2590     char *ain, *aout;
2591     afs_int32 ainSize;
2592     afs_int32 *aoutSize;        /* set this */ {
2593     register struct cell *tcell;
2594     afs_int32 temp;
2595
2596     AFS_STATCNT(PGetCellStatus);
2597     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2598         return EIO;          /* Inappropriate ioctl for device */
2599
2600     tcell = afs_GetCellByName(ain, READ_LOCK);
2601     if (!tcell) return ENOENT;
2602     temp = tcell->states;
2603     afs_PutCell(tcell, READ_LOCK);
2604     memcpy(aout, (char *)&temp, sizeof(afs_int32));
2605     *aoutSize = sizeof(afs_int32);
2606     return 0;
2607 }
2608
2609 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2610     struct vcache *avc;
2611     int afun;
2612     struct vrequest *areq;
2613     char *ain, *aout;
2614     afs_int32 ainSize;
2615     struct AFS_UCRED *acred;
2616     afs_int32 *aoutSize;        /* set this */ {
2617     register struct cell *tcell;
2618     afs_int32 temp;
2619     
2620     if (!afs_osi_suser(acred))
2621         return EACCES;
2622     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2623         return EIO;          /* Inappropriate ioctl for device */
2624
2625     tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2626     if (!tcell) return ENOENT;
2627     memcpy((char *)&temp, ain, sizeof(afs_int32));
2628     if (temp & CNoSUID)
2629         tcell->states |= CNoSUID;
2630     else
2631         tcell->states &= ~CNoSUID;
2632     afs_PutCell(tcell, WRITE_LOCK);
2633     return 0;
2634 }
2635
2636 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2637 struct vcache *avc;
2638 int afun;
2639 struct vrequest *areq;
2640 char *ain, *aout;
2641 afs_int32 ainSize;
2642 afs_int32 *aoutSize;    /* set this */ 
2643 struct AFS_UCRED *acred;
2644 {
2645     extern struct volume *afs_volumes[NVOLS];
2646     register afs_int32 i;
2647     register struct dcache *tdc;
2648     register struct vcache *tvc;
2649     register struct volume *tv;
2650     afs_int32 cell, volume;
2651
2652     AFS_STATCNT(PFlushVolumeData);
2653     if (!avc)
2654         return EINVAL;
2655     if ( !afs_resourceinit_flag )       /* afs deamons havn't started yet */
2656         return EIO;          /* Inappropriate ioctl for device */
2657
2658     volume = avc->fid.Fid.Volume;  /* who to zap */
2659     cell = avc->fid.Cell;
2660
2661     /* 
2662      * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2663      * the vcaches associated with the volume.
2664      */
2665     ObtainReadLock(&afs_xvcache);
2666     for(i = 0; i < VCSIZE; i++) {
2667         for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2668             if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2669 #if     defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV)  || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2670                 VN_HOLD(AFSTOV(tvc));
2671 #else
2672 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2673                 osi_vnhold(tvc, 0);
2674 #else
2675                 VREFCOUNT_INC(tvc);
2676 #endif
2677 #endif
2678                 ReleaseReadLock(&afs_xvcache);
2679 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2680                 afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
2681 #endif
2682                 ObtainWriteLock(&tvc->lock,232);
2683
2684                 ObtainWriteLock(&afs_xcbhash, 458);
2685                 afs_DequeueCallback(tvc);
2686                 tvc->states &= ~(CStatd | CDirty);
2687                 ReleaseWriteLock(&afs_xcbhash);
2688                 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2689                     osi_dnlc_purgedp(tvc);
2690                 afs_TryToSmush(tvc, acred, 1);
2691                 ReleaseWriteLock(&tvc->lock);
2692 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2693                 afs_BozonUnlock(&tvc->pvnLock, tvc);
2694 #endif
2695                 ObtainReadLock(&afs_xvcache);
2696                 /* our tvc ptr is still good until now */
2697                 AFS_FAST_RELE(tvc);
2698             }
2699         }
2700     }
2701     ReleaseReadLock(&afs_xvcache);
2702
2703
2704     MObtainWriteLock(&afs_xdcache,328);  /* needed if you're going to flush any stuff */
2705     for(i=0;i<afs_cacheFiles;i++) {
2706         if (!(afs_indexFlags[i] & IFEverUsed)) continue;        /* never had any data */
2707         tdc = afs_GetDSlot(i, (struct dcache *) 0);
2708         if (tdc->refCount <= 1) {    /* too high, in use by running sys call */
2709             ReleaseReadLock(&tdc->tlock);
2710             if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2711                 if (! (afs_indexFlags[i] & IFDataMod)) {
2712                     /* if the file is modified, but has a ref cnt of only 1, then
2713                        someone probably has the file open and is writing into it.
2714                        Better to skip flushing such a file, it will be brought back
2715                        immediately on the next write anyway.
2716
2717                        If we *must* flush, then this code has to be rearranged to call
2718                        afs_storeAllSegments() first */
2719                         afs_FlushDCache(tdc);
2720                 }
2721             }
2722         } else {
2723             ReleaseReadLock(&tdc->tlock);
2724         }
2725         afs_PutDCache(tdc);     /* bumped by getdslot */
2726     }
2727     MReleaseWriteLock(&afs_xdcache);
2728
2729     ObtainReadLock(&afs_xvolume);
2730     for (i=0;i<NVOLS;i++) {
2731         for (tv = afs_volumes[i]; tv; tv=tv->next) {
2732             if (tv->volume == volume) {
2733                 afs_ResetVolumeInfo(tv);
2734                 break;
2735             }
2736         }
2737     }
2738     ReleaseReadLock(&afs_xvolume);
2739
2740     /* probably, a user is doing this, probably, because things are screwed up. 
2741      * maybe it's the dnlc's fault? */
2742     osi_dnlc_purge();  
2743     return 0;
2744 }
2745
2746
2747
2748 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2749     struct vcache *avc;
2750     int afun;
2751     struct vrequest *areq;
2752     char *ain, *aout;
2753     afs_int32 ainSize;
2754     afs_int32 *aoutSize;        /* set this */ {
2755     register afs_int32 code;
2756     struct vcxstat stat;
2757     afs_int32 mode, i;
2758     
2759 /*  AFS_STATCNT(PGetVnodeXStatus); */
2760     if (!avc) return EINVAL;
2761     code = afs_VerifyVCache(avc, areq);
2762     if (code) return code;
2763     if (vType(avc) == VDIR)
2764         mode = PRSFS_LOOKUP;
2765     else
2766         mode = PRSFS_READ;
2767     if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2768         return EACCES;    
2769     stat.fid = avc->fid;
2770     hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2771     stat.lock = avc->lock;
2772     stat.parentVnode = avc->parentVnode;
2773     stat.parentUnique = avc->parentUnique;
2774     hset(stat.flushDV, avc->flushDV);
2775     hset(stat.mapDV, avc->mapDV);
2776     stat.truncPos = avc->truncPos;
2777     { /* just grab the first two - won't break anything... */
2778       struct axscache *ac;
2779
2780       for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2781         stat.randomUid[i] = ac->uid;
2782         stat.randomAccess[i] = ac->axess;
2783       }
2784     }
2785     stat.callback = afs_data_pointer_to_int32(avc->callback);
2786     stat.cbExpires = avc->cbExpires;
2787     stat.anyAccess = avc->anyAccess;
2788     stat.opens = avc->opens;
2789     stat.execsOrWriters = avc->execsOrWriters;
2790     stat.flockCount = avc->flockCount;
2791     stat.mvstat = avc->mvstat;
2792     stat.states = avc->states;
2793     memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
2794     *aoutSize = sizeof(struct vcxstat);
2795     return 0;
2796 }
2797
2798
2799 /* We require root for local sysname changes, but not for remote */
2800 /* (since we don't really believe remote uids anyway) */
2801  /* outname[] shouldn't really be needed- this is left as an excercise */
2802  /* for the reader.  */
2803 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2804 struct vcache *avc;
2805 int afun;
2806 struct vrequest *areq;
2807 char *ain, *aout;
2808 afs_int32 ainSize;
2809 afs_int32 *aoutSize;    /* set this */
2810 register struct AFS_UCRED *acred;
2811 {
2812     char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2813     int setsysname, foundname=0;
2814     register struct afs_exporter *exporter;
2815     extern struct unixuser *afs_FindUser();
2816     extern char *afs_sysname;
2817     extern char *afs_sysnamelist[];
2818     extern int afs_sysnamecount;
2819     register struct unixuser *au;
2820     register afs_int32 pag, error;
2821     int t, count;
2822
2823
2824     AFS_STATCNT(PSetSysName);
2825     if (!afs_globalVFS) {
2826       /* Afsd is NOT running; disable it */
2827 #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)
2828         return (EINVAL);
2829 #else
2830         return (setuerror(EINVAL), EINVAL);
2831 #endif
2832     }
2833     memset(inname, 0, MAXSYSNAME);
2834     memcpy((char *)&setsysname, ain, sizeof(afs_int32));
2835     ain += sizeof(afs_int32);
2836     if (setsysname) {
2837
2838       /* Check my args */
2839       if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2840         return EINVAL;
2841       for(cp = ain,count = 0;count < setsysname;count++) {
2842         /* won't go past end of ain since maxsysname*num < ain length */
2843         t = strlen(cp);
2844         if (t >= MAXSYSNAME || t <= 0)
2845           return EINVAL;
2846         /* check for names that can shoot us in the foot */
2847         if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2848           return EINVAL;
2849         cp += t+1;
2850       }
2851       /* args ok */
2852
2853       /* inname gets first entry in case we're being a translater */
2854       t = strlen(ain);
2855       memcpy(inname, ain, t+1);  /* include terminating null */
2856       ain += t + 1;
2857     }
2858     if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2859         pag = PagInCred(acred);
2860         if (pag == NOPAG) {
2861             return EINVAL;  /* Better than panicing */
2862         }
2863         if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2864             return EINVAL;  /* Better than panicing */
2865         }
2866         if (!(exporter = au->exporter)) {
2867             afs_PutUser(au, READ_LOCK);
2868             return EINVAL;  /* Better than panicing */
2869         }
2870         error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2871         if (error) {
2872             if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2873             else {
2874                 afs_PutUser(au, READ_LOCK);
2875                 return error;
2876             }
2877         }
2878         else foundname = 1;
2879         afs_PutUser(au, READ_LOCK);
2880     } else {
2881
2882       /* Not xlating, so local case */
2883         if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2884         if (!setsysname) {      /* user just wants the info */
2885             strcpy(outname, afs_sysname);
2886             foundname = afs_sysnamecount;
2887         } else {     /* Local guy; only root can change sysname */
2888             if (!afs_osi_suser(acred))
2889                 return EACCES;
2890            
2891             /* clear @sys entries from the dnlc, once afs_lookup can
2892              do lookups of @sys entries and thinks it can trust them */
2893             /* privs ok, store the entry, ... */
2894             strcpy(afs_sysname, inname);
2895             if (setsysname > 1) { /* ... or list */
2896               cp = ain;
2897               for(count=1; count < setsysname;++count) {
2898                 if (!afs_sysnamelist[count])
2899                   osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2900                 t = strlen(cp);
2901                 memcpy(afs_sysnamelist[count], cp, t+1); /* include null */
2902                 cp += t+1;
2903               }
2904             }
2905             afs_sysnamecount = setsysname;
2906         }
2907     }
2908     if (!setsysname) {
2909         cp = aout;  /* not changing so report back the count and ... */
2910         memcpy(cp, (char *)&foundname, sizeof(afs_int32));
2911         cp += sizeof(afs_int32);
2912         if (foundname) {
2913             strcpy(cp, outname);                /* ... the entry, ... */
2914             cp += strlen(outname)+1;
2915             for(count=1; count < foundname; ++count) { /* ... or list. */
2916               /* Note: we don't support @sys lists for exporters */
2917               if (!afs_sysnamelist[count])
2918                 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2919               t = strlen(afs_sysnamelist[count]);
2920               if (t >= MAXSYSNAME)
2921                 osi_Panic("PSetSysName: sysname entry garbled\n");
2922               strcpy(cp, afs_sysnamelist[count]);
2923               cp += t + 1;
2924             }
2925         }
2926         *aoutSize = cp - aout;
2927     }
2928     return 0;
2929 }
2930
2931 /* sequential search through the list of touched cells is not a good
2932  * long-term solution here. For small n, though, it should be just
2933  * fine.  Should consider special-casing the local cell for large n.
2934  * Likewise for PSetSPrefs.
2935  */
2936 static void ReSortCells(s,l, vlonly)  
2937   int s;     /* number of ids in array l[] -- NOT index of last id */
2938   afs_int32 l[];  /* array of cell ids which have volumes that need to be sorted */
2939   int vlonly; /* sort vl servers or file servers?*/
2940 {
2941   extern struct volume *afs_volumes[NVOLS];   /* volume hash table */
2942
2943   int i;
2944   struct volume *j;
2945   register int  k;
2946
2947   if (vlonly) {
2948       struct cell *tcell;
2949       ObtainWriteLock(&afs_xcell,300);
2950       for(k=0;k<s;k++) {
2951           tcell = afs_GetCellNoLock(l[k], WRITE_LOCK);
2952           if (!tcell) continue;
2953           afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2954           afs_PutCell(tcell, WRITE_LOCK);
2955       }
2956       ReleaseWriteLock(&afs_xcell);
2957       return;
2958   }
2959
2960   ObtainReadLock(&afs_xvolume);
2961   for (i= 0; i< NVOLS; i++) {
2962       for (j=afs_volumes[i];j;j=j->next) {
2963           for (k=0;k<s;k++)
2964               if (j->cell == l[k]) {
2965                   ObtainWriteLock(&j->lock,233);
2966                   afs_SortServers(j->serverHost, MAXHOSTS);
2967                   ReleaseWriteLock(&j->lock);
2968                   break; 
2969               }
2970       }
2971   }
2972   ReleaseReadLock(&afs_xvolume);
2973 }
2974
2975 int debugsetsp = 0;
2976
2977 static int afs_setsprefs(sp, num, vlonly)
2978    struct spref *sp;
2979    unsigned int num;
2980    unsigned int vlonly;
2981 {
2982    struct srvAddr *sa;
2983    int i,j,k,matches,touchedSize;
2984    struct server *srvr = NULL;
2985    afs_int32 touched[34];
2986    int isfs;
2987    
2988    touchedSize=0;
2989    for (k=0; k < num; sp++, k++) { 
2990       if (debugsetsp) {
2991          printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2992       }
2993       matches=0;
2994       ObtainReadLock(&afs_xserver);
2995       
2996       i = SHash(sp->host.s_addr);
2997       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2998          if (sa->sa_ip == sp->host.s_addr) {
2999             srvr = sa->server;
3000             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
3001                    || (sa->sa_portal == AFS_FSPORT); 
3002             if ((!vlonly && isfs) || (vlonly && !isfs)) {
3003                matches++;
3004                break;
3005             }
3006          }
3007       }
3008       
3009       if (sa && matches) {  /* found one! */
3010          if (debugsetsp) {
3011             printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
3012          }
3013          sa->sa_iprank = sp->rank + afs_randomMod15();
3014          afs_SortOneServer(sa->server);
3015          
3016          if (srvr->cell) {
3017            /* if we don't know yet what cell it's in, this is moot */
3018            for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
3019                  /* is it in our list of touched cells ?  */ ;
3020            if (j < 0) {                   /* no, it's not */
3021              touched[touchedSize++] = srvr->cell->cell;
3022              if (touchedSize >= 32) {                /* watch for ovrflow */
3023                ReleaseReadLock(&afs_xserver);
3024                ReSortCells(touchedSize, touched, vlonly);
3025                touchedSize=0;
3026                ObtainReadLock(&afs_xserver);
3027              }
3028            }
3029          }
3030       }
3031       
3032       ReleaseReadLock(&afs_xserver);
3033       /* if we didn't find one, start to create one. */
3034       /* Note that it doesn't have a cell yet...     */
3035       if (!matches) {
3036          afs_uint32 temp = sp->host.s_addr;
3037          srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT), 
3038                               WRITE_LOCK, (afsUUID *)0,0);
3039          srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3040          afs_PutServer(srvr, WRITE_LOCK);
3041       }
3042    } /* for all cited preferences */
3043    
3044    ReSortCells(touchedSize, touched, vlonly);
3045    return 0;
3046 }
3047
3048  /* Note that this may only be performed by the local root user.
3049  */
3050 static int 
3051 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3052      struct vcache *avc;
3053      int afun;
3054      struct vrequest *areq;
3055      char *ain, *aout;
3056      afs_int32 ainSize;
3057      struct AFS_UCRED *acred;
3058      afs_int32 *aoutSize;
3059 {
3060   struct setspref *ssp;
3061   AFS_STATCNT(PSetSPrefs);
3062
3063   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
3064         return EIO;          /* Inappropriate ioctl for device */
3065
3066   if (!afs_osi_suser(acred))
3067       return EACCES;
3068
3069   if (ainSize < sizeof(struct setspref)) 
3070     return EINVAL;
3071
3072   ssp = (struct setspref *)ain;
3073   if (ainSize < sizeof(struct spref)*ssp->num_servers) 
3074     return EINVAL;
3075
3076   afs_setsprefs(&(ssp->servers[0]), ssp->num_servers, 
3077                 (ssp->flags & DBservers));
3078   return 0;
3079 }
3080
3081 static int 
3082 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3083     struct vcache *avc;
3084     int afun;
3085     struct vrequest *areq;
3086     char *ain, *aout;
3087     afs_int32 ainSize;
3088     struct AFS_UCRED *acred;
3089     afs_int32 *aoutSize;
3090 {
3091   struct spref *sp;
3092   AFS_STATCNT(PSetSPrefs);
3093   if ( !afs_resourceinit_flag )         /* afs deamons havn't started yet */
3094         return EIO;          /* Inappropriate ioctl for device */
3095
3096
3097   if (!afs_osi_suser(acred))
3098     return EACCES;
3099
3100   sp = (struct spref *)ain;
3101   afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
3102   return 0;
3103 }
3104
3105 /* some notes on the following code...
3106  * in the hash table of server structs, all servers with the same IP address
3107  * will be on the same overflow chain.  
3108  * This could be sped slightly in some circumstances by having it cache the 
3109  * immediately previous slot in the hash table and some supporting information
3110  * Only reports file servers now.
3111  */
3112 static int 
3113      PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3114 struct vcache *avc;
3115 int afun;
3116 struct vrequest *areq;
3117 char *ain, *aout;
3118 afs_int32 ainSize;
3119 afs_int32 *aoutSize;
3120 {
3121    struct sprefrequest *spin; /* input */
3122    struct sprefinfo *spout;   /* output */
3123    struct spref *srvout;      /* one output component */
3124    int i,j;                   /* counters for hash table traversal */
3125    struct server *srvr;       /* one of CM's server structs */
3126    struct srvAddr *sa;
3127    afs_uint32 prevh;
3128    int vlonly;                /* just return vlservers ? */
3129    int isfs;
3130    
3131    AFS_STATCNT(PGetSPrefs);
3132    if ( !afs_resourceinit_flag )        /* afs deamons havn't started yet */
3133         return EIO;          /* Inappropriate ioctl for device */
3134
3135    
3136    if (ainSize < sizeof (struct sprefrequest_33)) {
3137       return ENOENT;
3138    }
3139    else {
3140       spin = ((struct sprefrequest *) ain);
3141    }
3142    
3143    if (ainSize > sizeof  (struct sprefrequest_33)) {
3144       vlonly = (spin->flags & DBservers);
3145    }
3146    else vlonly = 0;
3147    
3148    /* struct sprefinfo includes 1 server struct...  that size gets added
3149     * in during the loop that follows.
3150     */
3151    *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
3152    spout = (struct sprefinfo *) aout;
3153    spout->next_offset = spin->offset;
3154    spout->num_servers = 0;
3155    srvout = spout->servers;
3156    
3157    ObtainReadLock(&afs_xserver);
3158    for (i=0, j=0; j < NSERVERS; j++) {       /* sift through hash table */
3159       for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3160          if (spin->offset > (unsigned short)i) {
3161             continue;                /* catch up to where we left off */
3162          }
3163             spout->next_offset++;
3164          
3165             srvr = sa->server;
3166             isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))  
3167                  || (sa->sa_portal == AFS_FSPORT); 
3168          
3169             if ((vlonly && isfs) || (!vlonly && !isfs)) {
3170                /* only report ranks for vl servers */
3171                continue;
3172             }
3173          
3174          srvout->host.s_addr = sa->sa_ip;
3175          srvout->rank = sa->sa_iprank;
3176          *aoutSize += sizeof(struct spref);
3177          spout->num_servers++;
3178          srvout++;
3179
3180          if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3181             ReleaseReadLock(&afs_xserver);                /* no more room! */
3182             return 0;
3183          }
3184       }
3185    }
3186    ReleaseReadLock(&afs_xserver);
3187    
3188    spout->next_offset = 0;  /* start over from the beginning next time */
3189    return 0;
3190 }
3191
3192 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3193 int  afs_NFSRootOnly = 1;
3194 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3195 struct vcache *avc;
3196 int afun;
3197 struct vrequest *areq;
3198 char *ain, *aout;
3199 afs_int32 ainSize;
3200 afs_int32 *aoutSize;    /* set this */
3201 struct AFS_UCRED *acred;
3202 {
3203     afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3204     extern struct afs_exporter *exporter_find();
3205     register struct afs_exporter *exporter;
3206
3207     AFS_STATCNT(PExportAfs);
3208     memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3209     type = handleValue >> 24;
3210     if (type == 0x71) {
3211         newint = 1;
3212         type = 1;       /* nfs */
3213     }
3214     exporter = exporter_find(type);
3215     if (newint) {
3216         export = handleValue & 3;
3217         changestate = handleValue & 0xff;
3218         smounts = (handleValue >> 2) & 3;
3219         pwsync = (handleValue >> 4) & 3;
3220         convmode = (handleValue >> 6) & 3;
3221     } else {
3222         changestate = (handleValue >> 16) & 0x1;
3223         convmode = (handleValue >> 16) & 0x2;
3224         pwsync = (handleValue >> 16) & 0x4;
3225         smounts = (handleValue >> 16) & 0x8;
3226         export = handleValue & 0xff;
3227     }
3228     if (!exporter) {
3229         /*  Failed finding desired exporter; */
3230         return ENODEV;
3231     }
3232     if (!changestate) {
3233         handleValue = exporter->exp_states;
3234         memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3235         *aoutSize = sizeof(afs_int32);
3236     } else {
3237         if (!afs_osi_suser(acred))
3238             return EACCES;    /* Only superuser can do this */
3239         if (newint) {
3240             if (export & 2) {
3241                 if (export & 1)
3242                     exporter->exp_states |= EXP_EXPORTED;
3243                 else
3244                     exporter->exp_states &= ~EXP_EXPORTED;
3245             }
3246             if (convmode & 2) {
3247                 if (convmode & 1)
3248                     exporter->exp_states |= EXP_UNIXMODE;
3249                 else
3250                     exporter->exp_states &= ~EXP_UNIXMODE;
3251             }
3252             if (pwsync & 2) {
3253                 if (pwsync & 1)
3254                     exporter->exp_states |= EXP_PWSYNC;
3255                 else
3256                     exporter->exp_states &= ~EXP_PWSYNC;
3257             }
3258             if (smounts & 2) {
3259                 if (smounts & 1) {
3260                     afs_NFSRootOnly = 0;
3261                     exporter->exp_states |= EXP_SUBMOUNTS;
3262                 } else {
3263                     afs_NFSRootOnly = 1;
3264                     exporter->exp_states &= ~EXP_SUBMOUNTS;
3265                 }
3266             }
3267             handleValue = exporter->exp_states;
3268             memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3269             *aoutSize = sizeof(afs_int32);
3270         } else {
3271             if (export)
3272                 exporter->exp_states |= EXP_EXPORTED;
3273             else
3274                 exporter->exp_states &= ~EXP_EXPORTED;
3275             if (convmode)
3276                 exporter->exp_states |= EXP_UNIXMODE;
3277             else
3278                 exporter->exp_states &= ~EXP_UNIXMODE;
3279             if (pwsync)
3280                 exporter->exp_states |= EXP_PWSYNC;
3281             else
3282                 exporter->exp_states &= ~EXP_PWSYNC;
3283             if (smounts) {
3284                 afs_NFSRootOnly = 0;
3285                 exporter->exp_states |= EXP_SUBMOUNTS;
3286             } else {
3287                 afs_NFSRootOnly = 1;
3288                 exporter->exp_states &= ~EXP_SUBMOUNTS;
3289             }
3290         }
3291     }
3292
3293     return 0;
3294 }
3295
3296 static int
3297 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3298 struct vcache *avc;
3299 int afun;
3300 struct vrequest *areq;
3301 char *ain, *aout;
3302 afs_int32 ainSize;
3303 struct AFS_UCRED *acred;
3304 afs_int32 *aoutSize;    /* set this */
3305 {
3306 struct gaginfo *gagflags;
3307
3308   if (!afs_osi_suser(acred))
3309     return EACCES;
3310
3311   gagflags = (struct gaginfo *) ain;
3312   afs_showflags = gagflags->showflags;
3313
3314   return 0;
3315 }
3316
3317
3318 static int
3319 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3320 struct vcache *avc;
3321 int afun;
3322 struct vrequest *areq;
3323 char *ain, *aout;
3324 afs_int32 ainSize;
3325 struct AFS_UCRED *acred;
3326 afs_int32 *aoutSize;    
3327 {
3328   struct rxparams *rxp;
3329
3330   if (!afs_osi_suser(acred))
3331     return EACCES;
3332
3333   rxp = (struct rxparams *) ain;
3334
3335   if (rxp->rx_initReceiveWindow)
3336     rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3337   if (rxp->rx_maxReceiveWindow)
3338     rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3339   if (rxp->rx_initSendWindow)
3340     rx_initSendWindow = rxp->rx_initSendWindow;
3341   if (rxp->rx_maxSendWindow)
3342     rx_maxSendWindow = rxp->rx_maxSendWindow;
3343   if (rxp->rxi_nSendFrags)
3344     rxi_nSendFrags = rxp->rxi_nSendFrags;
3345   if (rxp->rxi_nRecvFrags)
3346     rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3347   if (rxp->rxi_OrphanFragSize)
3348     rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3349   if (rxp->rx_maxReceiveSize)
3350   {
3351     rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3352     rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3353   }
3354   if (rxp->rx_MyMaxSendSize)
3355     rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3356  
3357   return 0;
3358 }
3359
3360 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3361      struct vcache *avc;
3362      int afun;
3363      struct vrequest *areq;
3364      register char *ain;
3365      char *aout;
3366      afs_int32 ainSize;
3367      afs_int32 *aoutSize;       /* set this */
3368 {
3369     if (sizeof(struct cm_initparams) > PIGGYSIZE)
3370         return E2BIG;
3371
3372     memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3373     *aoutSize = sizeof(struct cm_initparams);
3374     return 0;
3375 }
3376
3377 #ifdef AFS_SGI65_ENV
3378 /* They took crget() from us, so fake it. */
3379 static cred_t *crget(void)
3380 {
3381     cred_t *cr;
3382     cr = crdup(get_current_cred());
3383     memset((char*)cr, 0, sizeof(cred_t));
3384 #if CELL || CELL_PREPARE
3385     cr->cr_id = -1;
3386 #endif
3387     return cr;
3388 }
3389 #endif
3390
3391 static int
3392 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3393 struct vcache *avc;
3394 int afun;
3395 struct vrequest *areq;
3396 char *ain, *aout;
3397 afs_int32 ainSize;
3398 afs_int32 *aoutSize;
3399 struct AFS_UCRED *acred;
3400 {
3401     memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3402     *aoutSize=sizeof(afs_int32);
3403     return 0;
3404 }
3405
3406 static int
3407 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3408 struct vcache *avc;
3409 int afun;
3410 struct vrequest *areq;
3411 char *ain, *aout;
3412 afs_int32 ainSize;
3413 afs_int32 *aoutSize;
3414 struct AFS_UCRED *acred;
3415 {
3416     afs_int32 tmpval;
3417
3418     if (!afs_osi_suser(acred))
3419       return EPERM;
3420     if (ainSize != sizeof(afs_int32) || ain == NULL)
3421       return EINVAL;
3422     memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3423     /* if new mappings added later this will need to be changed */
3424     if (tmpval != 0 && tmpval != 1)
3425       return EINVAL;
3426     cryptall = tmpval;
3427     return 0;
3428 }
3429
3430 /*
3431  * Create new credentials to correspond to a remote user with given
3432  * <hostaddr, uid, g0, g1>.  This allows a server running as root to
3433  * provide pioctl (and other) services to foreign clients (i.e. nfs
3434  * clients) by using this call to `become' the client.
3435  */
3436 #define PSETPAG         110
3437 #define PIOCTL_HEADER   6
3438 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3439 {
3440     char *ain, *inData;
3441     afs_uint32 hostaddr;
3442     afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3443     extern struct afs_exporter *exporter_find();
3444     struct afs_exporter *exporter, *outexporter;
3445     struct AFS_UCRED *newcred;
3446     struct unixuser *au;
3447
3448 #if     defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3449     return EINVAL;                      /* NFS trans not supported for Ultrix */
3450 #else
3451 #if defined(AFS_SGIMP_ENV)
3452     osi_Assert(ISAFS_GLOCK());
3453 #endif
3454     AFS_STATCNT(HandleClientContext);
3455     if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) { 
3456         /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3457         return EINVAL; /* Too small to be good  */
3458     }
3459     ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3460     AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3461     if (code) {
3462         osi_FreeLargeSpace(inData);
3463         return code;
3464     }
3465
3466     /* Extract information for remote user */
3467     hostaddr = *((afs_uint32 *)ain);
3468     ain += sizeof(hostaddr);
3469     uid = *((afs_uint32 *)ain);
3470     ain += sizeof(uid);
3471     g0 = *((afs_uint32 *)ain);
3472     ain += sizeof(g0);
3473     g1 = *((afs_uint32 *)ain);
3474     ain += sizeof(g1);
3475     *com = *((afs_uint32 *)ain);
3476     ain += sizeof(afs_int32);
3477     exporter_type = *((afs_uint32 *)ain);       /* In case we support more than NFS */
3478
3479     /*
3480      * Of course, one must be root for most of these functions, but
3481      * we'll allow (for knfs) you to set things if the pag is 0 and
3482      * you're setting tokens or unlogging.
3483      */
3484     i = (*com) & 0xff;
3485     if (!afs_osi_suser(credp)) {
3486 #ifdef  AFS_SGI_ENV 
3487 #ifndef AFS_SGI64_ENV
3488         /* Since SGI's suser() returns explicit failure after the call.. */
3489         u.u_error = 0;          
3490 #endif 
3491 #endif
3492         /* check for acceptable opcodes for normal folks, which are, so far,
3493          * set tokens and unlog.
3494          */
3495         if (i != 9 && i != 3 && i != 38 && i != 8)      {
3496             osi_FreeLargeSpace(inData);
3497             return EACCES;
3498         }
3499     }
3500
3501     ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3502     ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3503     osi_FreeLargeSpace(inData);
3504     if (uid == 0) {
3505         /*
3506          * We map uid 0 to nobody to match the mapping that the nfs
3507          * server does and to ensure that the suser() calls in the afs
3508          * code fails for remote client roots.
3509          */
3510         uid = afs_nobody;       /* NFS_NOBODY == -2 */
3511     }
3512     newcred = crget();
3513 #ifdef  AFS_AIX41_ENV
3514     setuerror(0);       
3515 #endif
3516     newcred->cr_gid = RMTUSER_REQ;
3517     newcred->cr_groups[0] = g0;
3518     newcred->cr_groups[1] = g1;
3519 #ifdef AFS_AIX_ENV
3520     newcred->cr_ngrps = 2;
3521 #else
3522 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3523     newcred->cr_ngroups = 2;
3524 #else
3525     for (i=2; i<NGROUPS; i++)
3526         newcred->cr_groups[i] = NOGROUP;
3527 #endif
3528 #endif
3529 #if     !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3530     afs_nfsclient_init();       /* before looking for exporter, ensure one exists */
3531 #endif
3532     if (!(exporter = exporter_find(exporter_type))) {
3533         /* Exporter wasn't initialized or an invalid exporter type */
3534          crfree(newcred);
3535          return EINVAL;
3536     }
3537     if (exporter->exp_states & EXP_PWSYNC) {
3538         if (uid != credp->cr_uid) {
3539             crfree(newcred);
3540             return ENOEXEC;     /* XXX Find a better errno XXX */
3541         }
3542     }
3543     newcred->cr_uid = uid; /* Only temporary  */
3544     code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3545     /* The client's pag is the only unique identifier for it */
3546     newcred->cr_uid = pag;
3547     *acred = newcred;
3548     if (!code && *com == PSETPAG) {
3549       /* Special case for 'setpag' */
3550       afs_uint32 pagvalue = genpag();
3551
3552       au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3553       /*
3554        * Note that we leave the 'outexporter' struct held so it won't
3555        * dissappear on us
3556        */
3557       au->exporter = outexporter;
3558       if (ablob->out_size >= 4) {
3559         AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3560       }
3561       afs_PutUser(au, WRITE_LOCK);
3562       if (code) return code;
3563       return PSETPAG;           /*  Special return for setpag  */
3564     } else if (!code) {
3565         EXP_RELE(outexporter);
3566     }
3567     return code;
3568 #endif  /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3569 }
3570
3571 /* get all interface addresses of this client */
3572
3573 static int
3574 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3575 struct vcache *avc;
3576 int afun;
3577 struct vrequest *areq;
3578 char *ain, *aout;
3579 afs_int32 ainSize;
3580 afs_int32 *aoutSize;
3581 {
3582         struct sprefrequest *spin; /* input */
3583         struct sprefinfo *spout;   /* output */
3584         struct spref *srvout;      /* one output component */
3585         int maxNumber;
3586         int i,j;
3587
3588         AFS_STATCNT(PGetCPrefs);
3589         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3590             return EIO;          /* Inappropriate ioctl for device */
3591
3592         if ( ainSize < sizeof (struct sprefrequest ))
3593                 return EINVAL;
3594         
3595         spin = (struct sprefrequest *) ain;
3596         spout = (struct sprefinfo *) aout;
3597
3598         maxNumber = spin->num_servers; /* max addrs this time */
3599         srvout = spout->servers;
3600
3601         ObtainReadLock(&afs_xinterface);
3602
3603         /* copy out the client interface information from the
3604         ** kernel data structure "interface" to the output buffer
3605         */
3606         for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3607                                    && ( j< maxNumber) ; i++, j++, srvout++)
3608                 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3609         
3610         spout->num_servers = j;
3611         *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3612
3613         if ( i >= afs_cb_interface.numberOfInterfaces )
3614                 spout->next_offset = 0; /* start from beginning again */
3615         else
3616                 spout->next_offset = spin->offset + j;
3617         
3618         ReleaseReadLock(&afs_xinterface);
3619         return 0;
3620 }
3621
3622 static int
3623 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3624 struct vcache *avc;
3625 int afun;
3626 struct vrequest *areq;
3627 char *ain, *aout;
3628 afs_int32 ainSize;
3629 afs_int32 *aoutSize;
3630 {
3631         struct setspref *sin;
3632         int i;
3633
3634         AFS_STATCNT(PSetCPrefs);
3635         if ( !afs_resourceinit_flag )   /* afs deamons havn't started yet */
3636             return EIO;          /* Inappropriate ioctl for device */
3637
3638         sin = (struct setspref *)ain;
3639
3640         if ( ainSize < sizeof(struct setspref) )
3641                 return EINVAL;
3642 #if 0   /* num_servers is unsigned */
3643         if ( sin->num_servers < 0 )
3644                 return EINVAL;
3645 #endif
3646         if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3647                 return ENOMEM;
3648
3649         ObtainWriteLock(&afs_xinterface, 412);
3650         afs_cb_interface.numberOfInterfaces = sin->num_servers;
3651         for ( i=0; (unsigned short)i < sin->num_servers; i++)
3652                 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3653
3654         ReleaseWriteLock(&afs_xinterface);
3655         return 0;
3656 }
3657
3658 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3659     struct vcache *avc;
3660     int afun;
3661     struct vrequest *areq;
3662     char *ain, *aout;
3663     afs_int32 ainSize;
3664     afs_int32 *aoutSize;
3665     struct AFS_UCRED *acred; {
3666     register afs_int32 code;
3667     register struct vcache *tvc;
3668     register struct dcache *tdc;
3669     struct VenusFid tfid;
3670     char *bufp;
3671     struct sysname_info sysState;
3672     afs_size_t offset, len;
3673
3674     AFS_STATCNT(PFlushMount);
3675     if (!avc) return EINVAL;
3676     code = afs_VerifyVCache(avc, areq);
3677     if (code) return code;
3678     if (vType(avc) != VDIR) {
3679         return ENOTDIR;
3680     }
3681     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3682     if (!tdc) return ENOENT;
3683     Check_AtSys(avc, ain, &sysState, areq);
3684     ObtainReadLock(&tdc->lock);
3685     do {
3686       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3687     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3688     ReleaseReadLock(&tdc->lock);
3689     afs_PutDCache(tdc);     /* we're done with the data */
3690     bufp = sysState.name;
3691     if (code) {
3692         goto out;
3693     }
3694     tfid.Cell = avc->fid.Cell;
3695     tfid.Fid.Volume = avc->fid.Fid.Volume;
3696     if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3697         tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3698     } else {
3699         tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3700                             WRITE_LOCK);
3701     }
3702     if (!tvc) {
3703         code = ENOENT;
3704         goto out;
3705     }
3706     if (vType(tvc) != VLNK) {
3707         afs_PutVCache(tvc, WRITE_LOCK);
3708         code = EINVAL;
3709         goto out;
3710     }
3711 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3712     afs_BozonLock(&tvc->pvnLock, tvc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
3713 #endif
3714     ObtainWriteLock(&tvc->lock,649);
3715     ObtainWriteLock(&afs_xcbhash, 650);
3716     afs_DequeueCallback(tvc);
3717     tvc->states &= ~(CStatd | CDirty);  /* next reference will re-stat cache entry */
3718     ReleaseWriteLock(&afs_xcbhash);
3719     /* now find the disk cache entries */
3720     afs_TryToSmush(tvc, acred, 1);
3721     osi_dnlc_purgedp(tvc);
3722     afs_symhint_inval(tvc);
3723     if (tvc->linkData && !(tvc->states & CCore)) {
3724         afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3725         tvc->linkData = (char *) 0;
3726     }
3727     ReleaseWriteLock(&tvc->lock);
3728 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3729     afs_BozonUnlock(&tvc->pvnLock, tvc);
3730 #endif
3731     afs_PutVCache(tvc, WRITE_LOCK);
3732 out:
3733     if (sysState.allocked) osi_FreeLargeSpace(bufp);
3734     return code;
3735 }
3736
3737 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3738     struct vcache *avc;
3739     int afun;
3740     struct vrequest *areq;
3741     char *ain, *aout;
3742     afs_int32 ainSize;
3743     afs_int32 *aoutSize;
3744     struct AFS_UCRED *acred;
3745 {
3746     int code = 0;
3747     afs_int32 flags;
3748
3749     if (!afs_osi_suser(acred)) {
3750         code = EACCES;
3751         goto out;
3752     }
3753     if (ainSize != sizeof(afs_int32)) {
3754         code = EINVAL;
3755         goto out;
3756     }
3757     memcpy((char *)&flags, ain, sizeof(afs_int32));
3758     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3759         code = EINVAL;
3760         goto out;
3761     }
3762     if (flags & AFSCALL_RXSTATS_ENABLE) {
3763         rx_enableProcessRPCStats();
3764     }
3765     if (flags & AFSCALL_RXSTATS_DISABLE) {
3766         rx_disableProcessRPCStats();
3767     }
3768     if (flags & AFSCALL_RXSTATS_CLEAR) {
3769         rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3770     }
3771 out:
3772     *aoutSize = 0;
3773     return code;
3774 }
3775
3776
3777 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3778     struct vcache *avc;
3779     int afun;
3780     struct vrequest *areq;
3781     char *ain, *aout;
3782     afs_int32 ainSize;
3783     afs_int32 *aoutSize;
3784     struct AFS_UCRED *acred;
3785 {
3786     int code = 0;
3787     afs_int32 flags;
3788
3789     if (!afs_osi_suser(acred)) {
3790         code = EACCES;
3791         goto out;
3792     }
3793     if (ainSize != sizeof(afs_int32)) {
3794         code = EINVAL;
3795         goto out;
3796     }
3797     memcpy((char *)&flags, ain, sizeof(afs_int32));
3798     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3799         code = EINVAL;
3800         goto out;
3801     }
3802     if (flags & AFSCALL_RXSTATS_ENABLE) {
3803         rx_enablePeerRPCStats();
3804     }
3805     if (flags & AFSCALL_RXSTATS_DISABLE) {
3806         rx_disablePeerRPCStats();
3807     }
3808     if (flags & AFSCALL_RXSTATS_CLEAR) {
3809         rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3810     }
3811 out:
3812     *aoutSize = 0;
3813     return code;
3814 }
3815
3816 static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
3817   struct vcache *avc;
3818   int afun;
3819   struct vrequest *areq;
3820   char *ain, *aout;
3821   afs_int32 ainSize;
3822   afs_int32 *aoutSize;  /* set this */
3823 {
3824     register afs_int32 code, code1;
3825     afs_int32 bytes;
3826     struct conn *tc;
3827     struct rx_call *tcall;
3828     struct AFSVolSync tsync;
3829     struct AFSFetchStatus OutStatus;
3830     struct AFSCallBack CallBack;
3831     struct VenusFid tfid;
3832     struct AFSFid *Fid;
3833     struct vcache *tvc;
3834     XSTATS_DECLS;
3835
3836     AFS_STATCNT(PSetAcl);
3837     if (!avc)
3838       return EINVAL;
3839
3840     if (ain && (ainSize == 3 * sizeof(afs_int32)))
3841         Fid = (struct AFSFid *) ain;
3842     else
3843         Fid = &avc->fid.Fid;
3844     tfid.Cell = avc->fid.Cell;
3845     tfid.Fid.Volume = Fid->Volume;
3846     tfid.Fid.Vnode = Fid->Vnode;
3847     tfid.Fid.Unique = Fid->Unique;
3848
3849     tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3850                                 WRITE_LOCK);
3851     if (!tvc) {
3852         afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3853                 ICL_TYPE_POINTER, tvc,
3854                 ICL_TYPE_FID, &tfid,
3855                 ICL_TYPE_FID, &avc->fid);
3856         return ENOENT;
3857     }
3858     afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3859                 ICL_TYPE_POINTER, tvc,
3860                 ICL_TYPE_FID, &tfid,
3861                 ICL_TYPE_FID, &tvc->fid);
3862
3863     do {
3864         tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3865         if (tc) {
3866
3867             RX_AFS_GUNLOCK();
3868             tcall = rx_NewCall(tc->id);
3869             code = StartRXAFS_FetchData(tcall,
3870                                 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3871             if (!code) {
3872                 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3873                 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3874             }
3875             code1 = rx_EndCall(tcall, code);
3876             RX_AFS_GLOCK();
3877         } else
3878             code = -1;
3879     } while
3880         (afs_Analyze(tc, code, &tvc->fid, areq, 
3881                 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, 
3882                 (struct cell *)0));
3883     /* This call is done only to have the callback things handled correctly */
3884     afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3885     afs_PutVCache(tvc, WRITE_LOCK);
3886
3887     if (!code) {
3888         *aoutSize = sizeof(afs_int32);
3889     }
3890     return code;
3891 }
3892
3893 static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
3894 struct vcache *avc;
3895 int afun;
3896 struct vrequest *areq;
3897 char *ain, *aout;
3898 afs_int32 ainSize;
3899 afs_int32 *aoutSize;        /* set this */
3900 {
3901     register afs_int32 code;
3902     struct conn *tc;
3903     struct vcache *tvc;
3904     struct ResidencyCmdInputs *Inputs;
3905     struct ResidencyCmdOutputs *Outputs;
3906     struct VenusFid tfid;
3907     struct AFSFid *Fid;
3908
3909     Inputs = (struct ResidencyCmdInputs *) ain;
3910     Outputs = (struct ResidencyCmdOutputs *) aout;
3911     if (!avc) return EINVAL;
3912     if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3913
3914     Fid = &Inputs->fid;
3915     if (!Fid->Volume)
3916         Fid = &avc->fid.Fid;
3917
3918     tfid.Cell = avc->fid.Cell;
3919     tfid.Fid.Volume = Fid->Volume;
3920     tfid.Fid.Vnode = Fid->Vnode;
3921     tfid.Fid.Unique = Fid->Unique;
3922
3923     tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3924                                 WRITE_LOCK);
3925     afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3926                 ICL_TYPE_POINTER, tvc,
3927                 ICL_TYPE_INT32, Inputs->command,
3928                 ICL_TYPE_FID, &tfid);
3929     if (!tvc)
3930         return ENOENT;
3931
3932     if (Inputs->command) {
3933         do {
3934             tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3935             if (tc) {
3936                 RX_AFS_GUNLOCK();
3937                 code = RXAFS_ResidencyCmd(tc->id, Fid,
3938                                  Inputs,
3939                                  (struct ResidencyCmdOutputs *) aout);
3940                 RX_AFS_GLOCK();
3941             } else
3942                 code = -1;
3943         } while
3944           (afs_Analyze(tc, code, &tvc->fid, areq, 
3945                 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3946                 (struct cell *)0));
3947        /* This call is done to have the callback things handled correctly */
3948        afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3949     } else { /* just a status request, return also link data */
3950         code = 0;
3951         Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3952         Outputs->chars[0] = 0;
3953         if (vType(tvc) == VLNK) {
3954             ObtainWriteLock(&tvc->lock,555);
3955             if (afs_HandleLink(tvc, areq) == 0)
3956                 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3957             ReleaseWriteLock(&tvc->lock);
3958         }
3959     }
3960
3961     afs_PutVCache(tvc, WRITE_LOCK);
3962
3963     if (!code) {
3964         *aoutSize = sizeof(struct ResidencyCmdOutputs);
3965     }
3966     return code;
3967 }