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