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