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