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