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