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