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