2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include "afs/param.h"
15 #include "afs/sysincludes.h" /* Standard vendor system headers */
17 #include "h/syscallargs.h"
19 #include "afsincludes.h" /* Afs-based standard headers */
20 #include "afs/afs_stats.h" /* afs statistics */
22 #include "rx/rx_globals.h"
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 */
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)
33 /* Prototypes for pioctl routines */
36 DECL_PIOCTL(PStoreBehind);
41 DECL_PIOCTL(PGetFileCell);
42 DECL_PIOCTL(PGetWSCell);
43 DECL_PIOCTL(PGetUserCell);
44 DECL_PIOCTL(PSetTokens);
45 DECL_PIOCTL(PGetVolumeStatus);
46 DECL_PIOCTL(PSetVolumeStatus);
48 DECL_PIOCTL(PNewStatMount);
49 DECL_PIOCTL(PGetTokens);
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);
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);
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);
97 static int (*(VpioctlSw[]))() = {
102 PGetVolumeStatus, /* 4 */
103 PSetVolumeStatus, /* 5 */
108 PCheckServers, /* 10 */
109 PCheckVolNames, /* 11 */
111 PBogus, /* 13 -- used to be quick check time */
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 */
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 */
169 static int (*(CpioctlSw[]))() = {
171 PNewAlias, /* 1 -- create new cell alias */
172 PListAliases, /* 2 -- list cell aliases */
175 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
176 int afs_nobody = NFS_NOBODY;
179 afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst)
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;
188 * If you need to change copyin_afs_ioctl(), you may also need to change
193 copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
197 #if defined(AFS_HPUX_64BIT_ENV)
198 struct afs_ioctl32 dst32;
200 if (is_32bit(u.u_procp)) /* is_32bit() in proc_iface.h */
202 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
204 afs_ioctl32_to_afs_ioctl(&dst32, dst);
207 #endif /* defined(AFS_HPUX_64BIT_ENV) */
209 #if defined(AFS_SUN57_64BIT_ENV)
210 struct afs_ioctl32 dst32;
212 if (get_udatamodel() == DATAMODEL_ILP32) {
213 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
215 afs_ioctl32_to_afs_ioctl(&dst32, dst);
218 #endif /* defined(AFS_SUN57_64BIT_ENV) */
220 #if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)
221 struct afs_ioctl32 dst32;
223 if (!ABI_IS_64BIT(get_current_abi()))
225 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
227 afs_ioctl32_to_afs_ioctl(&dst32, dst);
230 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
232 #if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV) && !defined(AFS_AMD64_LINUX20_ENV)
233 struct afs_ioctl32 dst32;
235 #ifdef AFS_SPARC64_LINUX24_ENV
236 if (current->thread.flags & SPARC_FLAG_32BIT)
237 #elif AFS_SPARC64_LINUX20_ENV
238 if (current->tss.flags & SPARC_FLAG_32BIT)
240 #error Not done for this linux type
241 #endif /* AFS_SPARC64_LINUX20_ENV */
243 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
245 afs_ioctl32_to_afs_ioctl(&dst32, dst);
248 #endif /* defined(AFS_LINUX_64BIT_KERNEL) */
250 AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
254 int HandleIoctl(register struct vcache *avc, register afs_int32 acom, struct afs_ioctl *adata)
256 register afs_int32 code;
259 AFS_STATCNT(HandleIoctl);
261 switch(acom & 0xff) {
263 avc->states |= CSafeStore;
267 /* case 2 used to be abort store, but this is no longer provided,
268 since it is impossible to implement under normal Unix.
272 /* return the name of the cell this file is open on */
273 register struct cell *tcell;
274 register afs_int32 i;
276 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
278 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
280 if (i > adata->out_size) {
281 /* 0 means we're not interested in the output */
282 if (adata->out_size != 0) code = EFAULT;
286 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
288 afs_PutCell(tcell, READ_LOCK);
294 case 49: /* VIOC_GETINITPARAMS */
295 if (adata->out_size < sizeof(struct cm_initparams)) {
299 AFS_COPYOUT(&cm_initParams, adata->out,
300 sizeof(struct cm_initparams), code);
312 return code; /* so far, none implemented */
317 /* For aix we don't temporarily bypass ioctl(2) but rather do our
318 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
319 * is now called from afs_gn_ioctl.
321 int afs_ioctl(struct vcache *tvc, int cmd, int arg)
323 struct afs_ioctl data;
326 AFS_STATCNT(afs_ioctl);
327 if (((cmd >> 8) & 0xff) == 'V') {
328 /* This is a VICEIOCTL call */
329 AFS_COPYIN(arg, (caddr_t) &data, sizeof(data), error);
332 error = HandleIoctl(tvc, cmd, &data);
335 /* No-op call; just return. */
339 #endif /* AFS_AIX_ENV */
341 #if defined(AFS_SGI_ENV)
342 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void * arg, int flag, cred_t *cr, rval_t *rvalp
348 struct afs_ioctl data;
354 AFS_STATCNT(afs_ioctl);
355 if (((cmd >> 8) & 0xff) == 'V') {
356 /* This is a VICEIOCTL call */
357 error = copyin_afs_ioctl(arg, &data);
360 locked = ISAFS_GLOCK();
363 error = HandleIoctl(tvc, cmd, &data);
368 /* No-op call; just return. */
372 #endif /* AFS_SGI_ENV */
374 /* unlike most calls here, this one uses u.u_error to return error conditions,
375 since this is really an intercepted chapter 2 call, rather than a vnode
378 /* AFS_HPUX102 and up uses VNODE ioctl instead */
379 #ifndef AFS_HPUX102_ENV
380 #if !defined(AFS_SGI_ENV)
384 kioctl(fdes, com, arg, ext, arg2, arg3)
385 #else /* __64BIT__ */
386 kioctl32(fdes, com, arg, ext, arg2, arg3)
387 #endif /* __64BIT__ */
390 kioctl(fdes, com, arg, ext)
401 } u_uap, *uap = &u_uap;
403 #if defined(AFS_SUN5_ENV)
405 struct afs_ioctl_sys {
411 afs_xioctl (uap, rvp)
412 struct afs_ioctl_sys *uap;
415 #elif defined(AFS_OSF_ENV)
416 afs_xioctl (p, args, retval)
425 } *uap = (struct a *)args;
426 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
434 afs_xioctl(p, uap, retval)
436 register struct ioctl_args *uap;
439 #elif defined(AFS_LINUX22_ENV)
440 struct afs_ioctl_sys {
444 asmlinkage int afs_xioctl(struct inode *ip, struct file *fp,
445 unsigned int com, unsigned long arg)
447 struct afs_ioctl_sys ua, *uap = &ua;
449 int afs_xioctl (void)
455 } *uap = (struct a *)u.u_ap;
456 #endif /* AFS_SUN5_ENV */
458 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
460 #elif !defined(AFS_LINUX22_ENV)
461 register struct file *fd;
463 #if defined(AFS_XBSD_ENV)
464 register struct filedesc *fdp;
466 register struct vcache *tvc;
467 register int ioctlDone = 0, code = 0;
469 AFS_STATCNT(afs_xioctl);
470 #if defined(AFS_XBSD_ENV)
472 if ((u_int)uap->fd >= fdp->fd_nfiles ||
473 (fd = fdp->fd_ofiles[uap->fd]) == NULL)
475 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
478 #if defined(AFS_DARWIN_ENV)
479 if ((code=fdgetf(p, uap->fd, &fd)))
482 #ifdef AFS_LINUX22_ENV
495 if (setuerror(getf(uap->fd, &fd))) {
501 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
503 #else /* AFS_OSF_ENV */
505 #if defined(AFS_SUN57_ENV)
507 if (!fd) return(EBADF);
508 #elif defined(AFS_SUN54_ENV)
510 if (!fd) return(EBADF);
512 if (code = getf(uap->fd, &fd)) {
518 if (!fd) return(EBADF);
525 /* first determine whether this is any sort of vnode */
526 #if defined(AFS_LINUX22_ENV)
531 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
533 if (fd->f_type == DTYPE_VNODE) {
535 /* good, this is a vnode; next see if it is an AFS vnode */
536 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
537 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
538 #elif defined(AFS_OBSD_ENV)
539 tvc = IsAfsVnode((struct vnode *) fd->f_data) ?
540 VTOAFS((struct vnode *) fd->f_data) : NULL;
542 tvc = VTOAFS((struct vnode*)fd->f_data); /* valid, given a vnode */
544 #endif /* AFS_LINUX22_ENV */
545 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
547 tvc = VTOAFS(afs_gntovn((struct gnode *) tvc));
548 if (!tvc) { /* shouldn't happen with held gnodes */
553 /* This is an AFS vnode */
554 if (((uap->com >> 8) & 0xff) == 'V') {
555 register struct afs_ioctl *datap;
557 datap = (struct afs_ioctl *) osi_AllocSmallSpace(AFS_SMALLOCSIZ);
558 AFS_COPYIN((char *)uap->arg, (caddr_t) datap, sizeof (struct afs_ioctl), code);
560 osi_FreeSmallSpace(datap);
562 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
565 #if defined(AFS_SUN5_ENV)
580 #else /* AFS_OSF_ENV */
584 #ifdef AFS_LINUX22_ENV
594 code = HandleIoctl(tvc, uap->com, datap);
595 osi_FreeSmallSpace(datap);
609 #if defined(AFS_LINUX22_ENV)
621 code = okioctl(fdes, com, arg, ext, arg2, arg3);
622 #else /* __64BIT__ */
623 code = okioctl32(fdes, com, arg, ext, arg2, arg3);
624 #endif /* __64BIT__ */
625 #else /* !AFS_AIX51_ENV */
626 code = okioctl(fdes, com, arg, ext);
627 #endif /* AFS_AIX51_ENV */
629 #else /* !AFS_AIX41_ENV */
631 okioctl(fdes, com, arg, ext);
632 #elif defined(AFS_SUN5_ENV)
633 #if defined(AFS_SUN57_ENV)
635 #elif defined(AFS_SUN54_ENV)
640 code = ioctl(uap, rvp);
641 #elif defined(AFS_FBSD_ENV)
642 return ioctl(p, uap);
643 #elif defined(AFS_OBSD_ENV)
644 code = sys_ioctl(p, uap, retval);
645 #elif defined(AFS_DARWIN_ENV)
646 return ioctl(p, uap, retval);
647 #elif defined(AFS_OSF_ENV)
648 code = ioctl(p, args, retval);
655 #elif !defined(AFS_LINUX22_ENV)
669 #ifdef AFS_LINUX22_ENV
672 #if defined(KERNEL_HAVE_UERROR)
675 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
676 return (getuerror() ? -1 : u.u_ioctlrv);
678 return getuerror() ? -1 : 0;
681 #endif /* AFS_LINUX22_ENV */
682 #endif /* AFS_SUN5_ENV */
683 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
687 #endif /* AFS_SGI_ENV */
688 #endif /* AFS_HPUX102_ENV */
690 #if defined(AFS_SGI_ENV)
691 /* "pioctl" system call entry point; just pass argument to the parameterized
700 afs_pioctl(struct pioctlargs *uap, rval_t *rvp)
704 AFS_STATCNT(afs_pioctl);
706 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
714 #endif /* AFS_SGI_ENV */
717 afs_pioctl(p, args, retval)
727 } *uap = (struct a *) args;
729 AFS_STATCNT(afs_pioctl);
730 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
733 #else /* AFS_OSF_ENV */
734 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
736 afs_pioctl(p, args, retval)
746 } *uap = (struct a *) args;
748 AFS_STATCNT(afs_pioctl);
749 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow, p->p_cred->pc_ucred));
752 #else /* AFS_OSF_ENV */
756 /* macro to avoid adding any more #ifdef's to pioctl code. */
757 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
758 #define PIOCTL_FREE_CRED() crfree(credp)
760 #define PIOCTL_FREE_CRED()
765 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
767 struct AFS_UCRED *credp;
769 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
770 afs_syscall_pioctl(path, com, cmarg, follow, credp)
771 struct AFS_UCRED *credp;
773 afs_syscall_pioctl(path, com, cmarg, follow)
781 struct afs_ioctl data;
782 struct AFS_UCRED *tmpcred, *foreigncreds = 0;
783 register afs_int32 code = 0;
789 struct ucred *credp = crref(); /* don't free until done! */
791 #ifdef AFS_LINUX22_ENV
792 cred_t *credp = crref(); /* don't free until done! */
796 AFS_STATCNT(afs_syscall_pioctl);
797 if (follow) follow = 1; /* compat. with old venus */
798 code = copyin_afs_ioctl(cmarg, &data);
801 #if defined(KERNEL_HAVE_UERROR)
806 if ((com & 0xff) == PSetClientContext) {
807 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
808 return EINVAL; /* Not handling these yet. */
809 #elif defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
810 code = HandleClientContext(&data, &com, &foreigncreds, credp);
812 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
816 crfree(foreigncreds);
819 #if defined(KERNEL_HAVE_UERROR)
820 return (setuerror(code), code);
826 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
829 * We could have done without temporary setting the u.u_cred below
830 * (foreigncreds could be passed as param the pioctl modules)
831 * but calls such as afs_osi_suser() doesn't allow that since it
832 * references u.u_cred directly. We could, of course, do something
833 * like afs_osi_suser(cred) which, I think, is better since it
834 * generalizes and supports multi cred environments...
838 credp = foreigncreds;
841 tmpcred = crref(); /* XXX */
844 #if defined(AFS_HPUX101_ENV)
845 tmpcred = p_cred(u.u_procp);
846 set_p_cred(u.u_procp, foreigncreds);
849 tmpcred = OSI_GET_CURRENT_CRED();
850 OSI_SET_CURRENT_CRED(foreigncreds);
853 tmpcred = osi_curcred();
854 osi_curcred() = foreigncreds;
857 u.u_cred = foreigncreds;
858 #endif /* AFS_SGI64_ENV */
859 #endif /* AFS_HPUX101_ENV */
865 if ((com & 0xff) == 15) {
866 /* special case prefetch so entire pathname eval occurs in helper process.
867 otherwise, the pioctl call is essentially useless */
868 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
869 code = Prefetch(path, &data, follow,
870 foreigncreds ? foreigncreds : credp);
872 code = Prefetch(path, &data, follow, osi_curcred());
875 #if defined(KERNEL_HAVE_UERROR)
883 code = lookupname(path, USR, follow, NULL, &vp,
884 foreigncreds ? foreigncreds : credp);
886 #ifdef AFS_LINUX22_ENV
887 code = gop_lookupname(path, AFS_UIOUSER, follow, NULL, &dp);
889 vp = (struct vnode *)dp->d_inode;
891 code = gop_lookupname(path, AFS_UIOUSER, follow, NULL, &vp);
892 #endif /* AFS_LINUX22_ENV */
893 #endif /* AFS_AIX41_ENV */
897 #if defined(KERNEL_HAVE_UERROR)
905 /* now make the call if we were passed no file, or were passed an AFS file */
906 if (!vp || IsAfsVnode(vp)) {
908 /* Ultrix 4.0: can't get vcache entry unless we've got an AFS gnode.
909 * So, we must test in this part of the code. Also, must arrange to
910 * GRELE the original gnode pointer when we're done, since in Ultrix 4.0,
911 * we hold gnodes, whose references hold our vcache entries.
914 gp = vp; /* remember for "put" */
915 vp = (struct vnode *) afs_gntovn(vp); /* get vcache from gp */
920 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
924 struct ucred *cred1, *cred2;
927 cred1 = cred2 = foreigncreds;
929 cred1 = cred2 = credp;
931 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
932 if (cred1 != cred2) {
933 /* something changed the creds */
938 #if defined(AFS_HPUX101_ENV)
940 struct ucred *cred = p_cred(u.u_procp);
941 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
947 credp = OSI_GET_CURRENT_CRED();
948 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
951 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
952 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
954 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
956 #endif /* AFS_SGI_ENV */
957 #endif /* AFS_HPUX101_ENV */
958 #endif /* AFS_AIX41_ENV */
959 #endif /* AFS_SUN5_ENV */
961 #if defined(KERNEL_HAVE_UERROR)
964 code = EINVAL; /* not in /afs */
975 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
978 crset(tmpcred); /* restore original credentials */
980 #if defined(AFS_HPUX101_ENV)
981 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
982 #elif defined(AFS_SGI_ENV)
983 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
984 #elif !defined(AFS_SUN5_ENV)
985 osi_curcred() = tmpcred; /* restore original credentials */
986 #endif /* AFS_HPUX101_ENV */
987 crfree(foreigncreds);
990 #endif /* LINUX, DARWIN, FBSD */
992 #ifdef AFS_LINUX22_ENV
995 AFS_RELE(vp); /* put vnode back */
999 #if defined(KERNEL_HAVE_UERROR)
1002 return (getuerror());
1009 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1010 register struct afs_ioctl *ablob, int afollow, struct AFS_UCRED **acred)
1013 struct vrequest treq;
1014 register afs_int32 code;
1015 register afs_int32 function, device;
1016 afs_int32 inSize, outSize;
1017 char *inData, *outData;
1018 int (*(*pioctlSw))();
1020 struct afs_fakestat_state fakestate;
1022 avc = avp ? VTOAFS(avp) : NULL;
1023 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1024 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1025 AFS_STATCNT(HandlePioctl);
1026 if ((code = afs_InitReq(&treq, *acred))) return code;
1027 afs_InitFakeStat(&fakestate);
1029 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1031 afs_PutFakeStat(&fakestate);
1035 device = (acom & 0xff00) >> 8;
1037 case 'V': /* Original pioctls */
1038 pioctlSw = VpioctlSw;
1039 pioctlSwSize = sizeof(VpioctlSw);
1041 case 'C': /* Coordinated/common pioctls */
1042 pioctlSw = CpioctlSw;
1043 pioctlSwSize = sizeof(CpioctlSw);
1046 afs_PutFakeStat(&fakestate);
1049 function = acom & 0xff;
1050 if (function >= (pioctlSwSize / sizeof(char *))) {
1051 afs_PutFakeStat(&fakestate);
1052 return EINVAL; /* out of range */
1054 inSize = ablob->in_size;
1055 if (inSize >= PIGGYSIZE) return E2BIG;
1056 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1058 AFS_COPYIN(ablob->in, inData, inSize, code);
1059 inData[inSize]='\0';
1063 osi_FreeLargeSpace(inData);
1064 afs_PutFakeStat(&fakestate);
1067 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1069 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
1070 osi_FreeLargeSpace(inData);
1071 if (code == 0 && ablob->out_size > 0) {
1072 if (outSize > ablob->out_size) outSize = ablob->out_size;
1073 if (outSize >= PIGGYSIZE) code = E2BIG;
1075 outData[outSize]='\0';
1076 AFS_COPYOUT(outData, ablob->out, outSize, code);
1079 osi_FreeLargeSpace(outData);
1080 afs_PutFakeStat(&fakestate);
1081 return afs_CheckCode(code, &treq, 41);
1084 DECL_PIOCTL(PGetFID)
1086 AFS_STATCNT(PGetFID);
1087 if (!avc) return EINVAL;
1088 memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1089 *aoutSize = sizeof(struct VenusFid);
1093 DECL_PIOCTL(PSetAcl)
1095 register afs_int32 code;
1097 struct AFSOpaque acl;
1098 struct AFSVolSync tsync;
1099 struct AFSFetchStatus OutStatus;
1102 AFS_STATCNT(PSetAcl);
1105 if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1108 acl.AFSOpaque_val = ain;
1110 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1112 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1114 code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1115 &acl, &OutStatus, &tsync);
1121 (afs_Analyze(tconn, code, &avc->fid, areq,
1122 AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, NULL));
1124 /* now we've forgotten all of the access info */
1125 ObtainWriteLock(&afs_xcbhash, 455);
1127 afs_DequeueCallback(avc);
1128 avc->states &= ~(CStatd | CUnique);
1129 ReleaseWriteLock(&afs_xcbhash);
1130 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1131 osi_dnlc_purgedp(avc);
1135 int afs_defaultAsynchrony = 0;
1137 DECL_PIOCTL(PStoreBehind)
1140 struct sbstruct *sbr;
1142 sbr = (struct sbstruct *)ain;
1143 if (sbr->sb_default != -1) {
1144 if (afs_osi_suser(*acred))
1145 afs_defaultAsynchrony = sbr->sb_default;
1149 if (avc && (sbr->sb_thisfile != -1)) {
1150 if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER,
1151 areq, DONT_CHECK_MODE_BITS))
1152 avc->asynchrony = sbr->sb_thisfile;
1156 *aoutSize = sizeof(struct sbstruct);
1157 sbr = (struct sbstruct *)aout;
1158 sbr->sb_default = afs_defaultAsynchrony;
1160 sbr->sb_thisfile = avc->asynchrony;
1166 DECL_PIOCTL(PGCPAGs)
1168 if (!afs_osi_suser(*acred)) {
1171 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1175 DECL_PIOCTL(PGetAcl)
1177 struct AFSOpaque acl;
1178 struct AFSVolSync tsync;
1179 struct AFSFetchStatus OutStatus;
1185 AFS_STATCNT(PGetAcl);
1186 if (!avc) return EINVAL;
1187 Fid.Volume = avc->fid.Fid.Volume;
1188 Fid.Vnode = avc->fid.Fid.Vnode;
1189 Fid.Unique = avc->fid.Fid.Unique;
1190 if (avc->states & CForeign) {
1192 * For a dfs xlator acl we have a special hack so that the
1193 * xlator will distinguish which type of acl will return. So
1194 * we currently use the top 2-bytes (vals 0-4) to tell which
1195 * type of acl to bring back. Horrible hack but this will
1196 * cause the least number of changes to code size and interfaces.
1198 if (Fid.Vnode & 0xc0000000)
1200 Fid.Vnode |= (ainSize << 30);
1202 acl.AFSOpaque_val = aout;
1204 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1207 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1209 code = RXAFS_FetchACL(tconn->id, &Fid,
1210 &acl, &OutStatus, &tsync);
1216 (afs_Analyze(tconn, code, &avc->fid, areq,
1217 AFS_STATS_FS_RPCIDX_FETCHACL,
1218 SHARED_LOCK, NULL));
1221 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1234 AFS_STATCNT(PBogus);
1238 DECL_PIOCTL(PGetFileCell)
1240 register struct cell *tcell;
1242 AFS_STATCNT(PGetFileCell);
1243 if (!avc) return EINVAL;
1244 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1245 if (!tcell) return ESRCH;
1246 strcpy(aout, tcell->cellName);
1247 afs_PutCell(tcell, READ_LOCK);
1248 *aoutSize = strlen(aout) + 1;
1252 DECL_PIOCTL(PGetWSCell)
1254 struct cell *tcell = NULL;
1256 AFS_STATCNT(PGetWSCell);
1257 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1258 return EIO; /* Inappropriate ioctl for device */
1260 tcell = afs_GetPrimaryCell(READ_LOCK);
1261 if (!tcell) /* no primary cell? */
1263 strcpy(aout, tcell->cellName);
1264 *aoutSize = strlen(aout) + 1;
1265 afs_PutCell(tcell, READ_LOCK);
1269 DECL_PIOCTL(PGetUserCell)
1271 register afs_int32 i;
1272 register struct unixuser *tu;
1273 register struct cell *tcell;
1275 AFS_STATCNT(PGetUserCell);
1276 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1277 return EIO; /* Inappropriate ioctl for device */
1279 /* return the cell name of the primary cell for this user */
1280 i = UHash(areq->uid);
1281 ObtainWriteLock(&afs_xuser,224);
1282 for(tu = afs_users[i]; tu; tu = tu->next) {
1283 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1285 ReleaseWriteLock(&afs_xuser);
1290 tcell = afs_GetCell(tu->cell, READ_LOCK);
1291 afs_PutUser(tu, WRITE_LOCK);
1292 if (!tcell) return ESRCH;
1294 strcpy(aout, tcell->cellName);
1295 afs_PutCell(tcell, READ_LOCK);
1296 *aoutSize = strlen(aout)+1; /* 1 for the null */
1300 ReleaseWriteLock(&afs_xuser);
1307 DECL_PIOCTL(PSetTokens)
1310 register struct unixuser *tu;
1311 struct ClearToken clear;
1312 register struct cell *tcell;
1315 struct vrequest treq;
1316 afs_int32 flag, set_parent_pag = 0;
1318 AFS_STATCNT(PSetTokens);
1319 if (!afs_resourceinit_flag) {
1322 memcpy((char *)&i, ain, sizeof(afs_int32));
1323 ain += sizeof(afs_int32);
1324 stp = ain; /* remember where the ticket is */
1325 if (i < 0 || i > 2000) return EINVAL; /* malloc may fail */
1326 if (i > MAXKTCTICKETLEN) return EINVAL;
1328 ain += i; /* skip over ticket */
1329 memcpy((char *)&i, ain, sizeof(afs_int32));
1330 ain += sizeof(afs_int32);
1331 if (i != sizeof(struct ClearToken)) {
1334 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1335 if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1336 ain += sizeof(struct ClearToken);
1337 if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1338 /* still stuff left? we've got primary flag and cell name. Set these */
1339 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1340 ain += sizeof(afs_int32); /* skip id field */
1341 /* rest is cell name, look it up */
1342 /* some versions of gcc appear to need != 0 in order to get this right */
1343 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1347 tcell = afs_GetCellByName(ain, READ_LOCK);
1348 if (!tcell) goto nocell;
1351 /* default to primary cell, primary id */
1352 flag = 1; /* primary id */
1353 tcell = afs_GetPrimaryCell(READ_LOCK);
1354 if (!tcell) goto nocell;
1357 afs_PutCell(tcell, READ_LOCK);
1358 if (set_parent_pag) {
1360 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1361 #if defined(AFS_DARWIN_ENV)
1362 struct proc *p = current_proc(); /* XXX */
1364 struct proc *p = curproc; /* XXX */
1366 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1367 p->p_pid, p->p_comm);
1368 if (!setpag(p, acred, -1, &pag, 1)) {
1371 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1373 if (!setpag(acred, -1, &pag, 1)) {
1376 afs_InitReq(&treq, *acred);
1380 /* now we just set the tokens */
1381 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1382 tu->vid = clear.ViceId;
1383 if (tu->stp != NULL) {
1384 afs_osi_Free(tu->stp, tu->stLen);
1386 tu->stp = (char *) afs_osi_Alloc(stLen);
1388 memcpy(tu->stp, stp, stLen);
1391 afs_stats_cmfullperf.authent.TicketUpdates++;
1392 afs_ComputePAGStats();
1393 #endif /* AFS_NOSTATS */
1394 tu->states |= UHasTokens;
1395 tu->states &= ~UTokensBad;
1396 afs_SetPrimary(tu, flag);
1397 tu->tokenTime =osi_Time();
1398 afs_ResetUserConns(tu);
1399 afs_PutUser(tu, WRITE_LOCK);
1414 DECL_PIOCTL(PGetVolumeStatus)
1417 char offLineMsg[256];
1419 register struct conn *tc;
1420 register afs_int32 code;
1421 struct VolumeStatus volstat;
1423 char *Name, *OfflineMsg, *MOTD;
1426 AFS_STATCNT(PGetVolumeStatus);
1427 if (!avc) return EINVAL;
1429 OfflineMsg = offLineMsg;
1432 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1434 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1436 code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1437 &Name, &OfflineMsg, &MOTD);
1443 (afs_Analyze(tc, code, &avc->fid, areq,
1444 AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1445 SHARED_LOCK, NULL));
1447 if (code) return code;
1448 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1450 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1451 cp += sizeof(VolumeStatus);
1452 strcpy(cp, volName);
1453 cp += strlen(volName)+1;
1454 strcpy(cp, offLineMsg);
1455 cp += strlen(offLineMsg)+1;
1457 cp += strlen(motd)+1;
1458 *aoutSize = (cp - aout);
1462 DECL_PIOCTL(PSetVolumeStatus)
1465 char offLineMsg[256];
1467 register struct conn *tc;
1468 register afs_int32 code;
1469 struct AFSFetchVolumeStatus volstat;
1470 struct AFSStoreVolumeStatus storeStat;
1471 register struct volume *tvp;
1475 AFS_STATCNT(PSetVolumeStatus);
1476 if (!avc) return EINVAL;
1478 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1480 if (tvp->states & (VRO | VBackup)) {
1481 afs_PutVolume(tvp, READ_LOCK);
1484 afs_PutVolume(tvp, READ_LOCK);
1487 /* Copy the junk out, using cp as a roving pointer. */
1489 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1490 cp += sizeof(AFSFetchVolumeStatus);
1491 if (strlen(cp) >= sizeof(volName))
1493 strcpy(volName, cp);
1494 cp += strlen(volName)+1;
1495 if (strlen(cp) >= sizeof(offLineMsg))
1497 strcpy(offLineMsg, cp);
1498 cp += strlen(offLineMsg)+1;
1499 if (strlen(cp) >= sizeof(motd))
1503 if (volstat.MinQuota != -1) {
1504 storeStat.MinQuota = volstat.MinQuota;
1505 storeStat.Mask |= AFS_SETMINQUOTA;
1507 if (volstat.MaxQuota != -1) {
1508 storeStat.MaxQuota = volstat.MaxQuota;
1509 storeStat.Mask |= AFS_SETMAXQUOTA;
1512 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1514 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1516 code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1517 &storeStat, volName, offLineMsg, motd);
1523 (afs_Analyze(tc, code, &avc->fid, areq,
1524 AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1525 SHARED_LOCK, NULL));
1527 if (code) return code;
1528 /* we are sending parms back to make compat. with prev system. should
1529 change interface later to not ask for current status, just set new status */
1531 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1532 cp += sizeof(VolumeStatus);
1533 strcpy(cp, volName);
1534 cp += strlen(volName)+1;
1535 strcpy(cp, offLineMsg);
1536 cp += strlen(offLineMsg)+1;
1538 cp += strlen(motd)+1;
1539 *aoutSize = cp - aout;
1545 AFS_STATCNT(PFlush);
1546 if (!avc) return EINVAL;
1547 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1548 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1550 ObtainWriteLock(&avc->lock,225);
1551 ObtainWriteLock(&afs_xcbhash, 456);
1552 afs_DequeueCallback(avc);
1553 avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
1554 ReleaseWriteLock(&afs_xcbhash);
1555 /* now find the disk cache entries */
1556 afs_TryToSmush(avc, *acred, 1);
1557 osi_dnlc_purgedp(avc);
1558 afs_symhint_inval(avc);
1559 if (avc->linkData && !(avc->states & CCore)) {
1560 afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1561 avc->linkData = NULL;
1563 ReleaseWriteLock(&avc->lock);
1564 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1565 afs_BozonUnlock(&avc->pvnLock, avc);
1570 DECL_PIOCTL(PNewStatMount)
1572 register afs_int32 code;
1573 register struct vcache *tvc;
1574 register struct dcache *tdc;
1575 struct VenusFid tfid;
1577 struct sysname_info sysState;
1578 afs_size_t offset, len;
1580 AFS_STATCNT(PNewStatMount);
1581 if (!avc) return EINVAL;
1582 code = afs_VerifyVCache(avc, areq);
1583 if (code) return code;
1584 if (vType(avc) != VDIR) {
1587 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1588 if (!tdc) return ENOENT;
1589 Check_AtSys(avc, ain, &sysState, areq);
1590 ObtainReadLock(&tdc->lock);
1592 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1593 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1594 ReleaseReadLock(&tdc->lock);
1595 afs_PutDCache(tdc); /* we're done with the data */
1596 bufp = sysState.name;
1600 tfid.Cell = avc->fid.Cell;
1601 tfid.Fid.Volume = avc->fid.Fid.Volume;
1602 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1603 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1605 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1611 if (tvc->mvstat != 1) {
1616 ObtainWriteLock(&tvc->lock,226);
1617 code = afs_HandleLink(tvc, areq);
1619 if (tvc->linkData) {
1620 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1623 /* we have the data */
1624 strcpy(aout, tvc->linkData);
1625 *aoutSize = strlen(tvc->linkData)+1;
1630 ReleaseWriteLock(&tvc->lock);
1633 if (sysState.allocked) osi_FreeLargeSpace(bufp);
1637 DECL_PIOCTL(PGetTokens)
1639 register struct cell *tcell;
1640 register afs_int32 i;
1641 register struct unixuser *tu;
1646 AFS_STATCNT(PGetTokens);
1647 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1648 return EIO; /* Inappropriate ioctl for device */
1650 /* weird interface. If input parameter is present, it is an integer and
1651 we're supposed to return the parm'th tokens for this unix uid.
1652 If not present, we just return tokens for cell 1.
1653 If counter out of bounds, return EDOM.
1654 If no tokens for the particular cell, return ENOTCONN.
1655 Also, if this mysterious parm is present, we return, along with the
1656 tokens, the primary cell indicator (an afs_int32 0) and the cell name
1657 at the end, in that order.
1659 if ((newStyle = (ainSize > 0))) {
1660 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1662 i = UHash(areq->uid);
1663 ObtainReadLock(&afs_xuser);
1664 for(tu = afs_users[i]; tu; tu=tu->next) {
1666 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1667 if (iterator-- == 0) break; /* are we done yet? */
1671 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell)) break;
1676 * No need to hold a read lock on each user entry
1680 ReleaseReadLock(&afs_xuser);
1685 if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1686 tu->states |= (UTokensBad | UNeedsReset);
1687 afs_PutUser(tu, READ_LOCK);
1690 /* use iterator for temp */
1692 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1693 if (iterator < 56) iterator = 56; /* # of bytes we're returning */
1694 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1695 cp += sizeof(afs_int32);
1696 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1698 iterator = sizeof(struct ClearToken);
1699 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1700 cp += sizeof(afs_int32);
1701 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1702 cp += sizeof(struct ClearToken);
1704 /* put out primary id and cell name, too */
1705 iterator = (tu->states & UPrimary ? 1 : 0);
1706 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1707 cp += sizeof(afs_int32);
1708 tcell = afs_GetCell(tu->cell, READ_LOCK);
1710 strcpy(cp, tcell->cellName);
1711 cp += strlen(tcell->cellName)+1;
1712 afs_PutCell(tcell, READ_LOCK);
1716 *aoutSize = cp - aout;
1717 afs_PutUser(tu, READ_LOCK);
1723 register afs_int32 i;
1724 register struct unixuser *tu;
1726 AFS_STATCNT(PUnlog);
1727 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1728 return EIO; /* Inappropriate ioctl for device */
1730 i = UHash(areq->uid);
1731 ObtainWriteLock(&afs_xuser,227);
1732 for(tu=afs_users[i]; tu; tu=tu->next) {
1733 if (tu->uid == areq->uid) {
1735 tu->states &= ~UHasTokens;
1736 /* security is not having to say you're sorry */
1737 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
1739 ReleaseWriteLock(&afs_xuser);
1740 /* We have to drop the lock over the call to afs_ResetUserConns, since
1741 * it obtains the afs_xvcache lock. We could also keep the lock, and
1742 * modify ResetUserConns to take parm saying we obtained the lock
1743 * already, but that is overkill. By keeping the "tu" pointer
1744 * held over the released lock, we guarantee that we won't lose our
1745 * place, and that we'll pass over every user conn that existed when
1746 * we began this call.
1748 afs_ResetUserConns(tu);
1750 ObtainWriteLock(&afs_xuser,228);
1752 /* set the expire times to 0, causes
1753 * afs_GCUserData to remove this entry
1755 tu->ct.EndTimestamp = 0;
1757 #endif /* UKERNEL */
1760 ReleaseWriteLock(&afs_xuser);
1764 DECL_PIOCTL(PMariner)
1766 afs_int32 newHostAddr;
1767 afs_int32 oldHostAddr;
1769 AFS_STATCNT(PMariner);
1771 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost, sizeof(afs_int32));
1773 oldHostAddr = 0xffffffff; /* disabled */
1775 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
1776 if (newHostAddr == 0xffffffff) {
1777 /* disable mariner operations */
1780 else if (newHostAddr) {
1782 afs_marinerHost = newHostAddr;
1784 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
1785 *aoutSize = sizeof(afs_int32);
1789 DECL_PIOCTL(PCheckServers)
1791 register char *cp = 0;
1793 register struct server *ts;
1794 afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1796 struct chservinfo *pcheck;
1798 AFS_STATCNT(PCheckServers);
1800 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1801 return EIO; /* Inappropriate ioctl for device */
1803 if (*lp == 0x12345678) { /* For afs3.3 version */
1804 pcheck=(struct chservinfo *)ain;
1805 if (pcheck->tinterval >= 0) {
1807 memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
1808 *aoutSize = sizeof(afs_int32);
1809 if (pcheck->tinterval > 0) {
1810 if (!afs_osi_suser(*acred))
1812 PROBE_INTERVAL=pcheck->tinterval;
1818 temp=pcheck->tflags;
1819 cp = pcheck->tbuffer;
1820 } else { /* For pre afs3.3 versions */
1821 memcpy((char *)&temp, ain, sizeof(afs_int32));
1822 cp = ain+sizeof(afs_int32);
1823 if (ainSize > sizeof(afs_int32))
1828 * 1: fast check, don't contact servers.
1829 * 2: local cell only.
1832 /* have cell name, too */
1833 cellp = afs_GetCellByName(cp, READ_LOCK);
1834 if (!cellp) return ENOENT;
1837 if (!cellp && (temp & 2)) {
1838 /* use local cell */
1839 cellp = afs_GetPrimaryCell(READ_LOCK);
1841 if (!(temp & 1)) { /* if not fast, call server checker routine */
1842 afs_CheckServers(1, cellp); /* check down servers */
1843 afs_CheckServers(0, cellp); /* check up servers */
1845 /* now return the current down server list */
1847 ObtainReadLock(&afs_xserver);
1848 for(i=0;i<NSERVERS;i++) {
1849 for(ts = afs_servers[i]; ts; ts=ts->next) {
1850 if (cellp && ts->cell != cellp) continue; /* cell spec'd and wrong */
1851 if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1852 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
1853 cp += sizeof(afs_int32);
1857 ReleaseReadLock(&afs_xserver);
1858 if (cellp) afs_PutCell(cellp, READ_LOCK);
1859 *aoutSize = cp - aout;
1863 DECL_PIOCTL(PCheckVolNames)
1865 AFS_STATCNT(PCheckVolNames);
1866 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1867 return EIO; /* Inappropriate ioctl for device */
1869 afs_CheckRootVolume();
1870 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
1871 AFS_VOLCHECK_EXPIRED |
1873 AFS_VOLCHECK_MTPTS);
1877 DECL_PIOCTL(PCheckAuth)
1882 struct unixuser *tu;
1885 AFS_STATCNT(PCheckAuth);
1886 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1887 return EIO; /* Inappropriate ioctl for device */
1890 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
1891 if (!tu) retValue = EACCES;
1893 /* we have a user */
1894 ObtainReadLock(&afs_xsrvAddr);
1895 ObtainReadLock(&afs_xconn);
1897 /* any tokens set? */
1898 if ((tu->states & UHasTokens) == 0) retValue = EACCES;
1899 /* all connections in cell 1 working? */
1900 for(i=0;i<NSERVERS;i++) {
1901 for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
1902 for (tc = sa->conns; tc; tc=tc->next) {
1903 if (tc->user == tu && (tu->states & UTokensBad))
1908 ReleaseReadLock(&afs_xsrvAddr);
1909 ReleaseReadLock(&afs_xconn);
1910 afs_PutUser(tu, READ_LOCK);
1912 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
1913 *aoutSize = sizeof(afs_int32);
1917 static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow, struct AFS_UCRED *acred)
1920 register afs_int32 code;
1921 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1927 AFS_STATCNT(Prefetch);
1928 if (!apath) return EINVAL;
1929 tp = osi_AllocLargeSpace(1024);
1930 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
1932 osi_FreeLargeSpace(tp);
1935 if (afs_BBusy()) { /* do this as late as possible */
1936 osi_FreeLargeSpace(tp);
1937 return EWOULDBLOCK; /* pretty close */
1939 afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred,
1940 (afs_size_t) 0, (afs_size_t) 0, tp);
1944 DECL_PIOCTL(PFindVolume)
1946 register struct volume *tvp;
1947 register struct server *ts;
1948 register afs_int32 i;
1951 AFS_STATCNT(PFindVolume);
1952 if (!avc) return EINVAL;
1953 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1956 for(i=0;i<MAXHOSTS;i++) {
1957 ts = tvp->serverHost[i];
1959 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
1960 cp += sizeof(afs_int32);
1963 /* still room for terminating NULL, add it on */
1964 ainSize = 0; /* reuse vbl */
1965 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
1966 cp += sizeof(afs_int32);
1968 *aoutSize = cp - aout;
1969 afs_PutVolume(tvp, READ_LOCK);
1975 DECL_PIOCTL(PViceAccess)
1977 register afs_int32 code;
1980 AFS_STATCNT(PViceAccess);
1981 if (!avc) return EINVAL;
1982 code = afs_VerifyVCache(avc, areq);
1983 if (code) return code;
1984 memcpy((char *)&temp, ain, sizeof(afs_int32));
1985 code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
1990 DECL_PIOCTL(PSetCacheSize)
1995 AFS_STATCNT(PSetCacheSize);
1996 if (!afs_osi_suser(*acred))
1998 /* too many things are setup initially in mem cache version */
1999 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2000 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2001 if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2003 if (newValue < afs_min_cache)
2004 afs_cacheBlocks = afs_min_cache;
2006 afs_cacheBlocks = newValue;
2008 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2009 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2010 afs_MaybeWakeupTruncateDaemon();
2011 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2012 afs_osi_Wait(1000, 0, 0);
2013 afs_MaybeWakeupTruncateDaemon();
2018 #define MAXGCSTATS 16
2019 DECL_PIOCTL(PGetCacheSize)
2021 afs_int32 results[MAXGCSTATS];
2023 AFS_STATCNT(PGetCacheSize);
2024 memset((char *)results, 0, sizeof(results));
2025 results[0] = afs_cacheBlocks;
2026 results[1] = afs_blocksUsed;
2027 memcpy(aout, (char *)results, sizeof(results));
2028 *aoutSize = sizeof(results);
2032 DECL_PIOCTL(PRemoveCallBack)
2034 register struct conn *tc;
2035 register afs_int32 code = 0;
2036 struct AFSCallBack CallBacks_Array[1];
2037 struct AFSCBFids theFids;
2038 struct AFSCBs theCBs;
2041 AFS_STATCNT(PRemoveCallBack);
2042 if (!avc) return EINVAL;
2043 if (avc->states & CRO) return 0; /* read-only-ness can't change */
2044 ObtainWriteLock(&avc->lock,229);
2045 theFids.AFSCBFids_len = 1;
2046 theCBs.AFSCBs_len = 1;
2047 theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2048 theCBs.AFSCBs_val = CallBacks_Array;
2049 CallBacks_Array[0].CallBackType = CB_DROPPED;
2050 if (avc->callback) {
2052 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2054 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2056 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2060 /* don't set code on failure since we wouldn't use it */
2062 (afs_Analyze(tc, code, &avc->fid, areq,
2063 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2064 SHARED_LOCK, NULL));
2066 ObtainWriteLock(&afs_xcbhash, 457);
2067 afs_DequeueCallback(avc);
2069 avc->states &= ~(CStatd | CUnique);
2070 ReleaseWriteLock(&afs_xcbhash);
2071 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2072 osi_dnlc_purgedp(avc);
2074 ReleaseWriteLock(&avc->lock);
2078 DECL_PIOCTL(PNewCell)
2080 /* create a new cell */
2081 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2082 char *newcell=0, *linkedcell=0, *tp= ain;
2083 register afs_int32 code, linkedstate=0, ls;
2084 u_short fsport = 0, vlport = 0;
2087 AFS_STATCNT(PNewCell);
2088 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2089 return EIO; /* Inappropriate ioctl for device */
2091 if (!afs_osi_suser(*acred))
2094 memcpy((char *)&magic, tp, sizeof(afs_int32));
2095 tp += sizeof(afs_int32);
2096 if (magic != 0x12345678)
2099 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2100 * server addresses while the 3.5 fs newcell command passes
2101 * MAXHOSTS. To figure out which is which, check if the cellname
2104 newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2105 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2107 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2108 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2109 tp += (scount * sizeof(afs_int32));
2111 lp = (afs_int32 *)tp;
2114 if (fsport < 1024) fsport = 0; /* Privileged ports not allowed */
2115 if (vlport < 1024) vlport = 0; /* Privileged ports not allowed */
2116 tp += (3 * sizeof(afs_int32));
2118 if ((ls = *lp) & 1) {
2119 linkedcell = tp + strlen(newcell)+1;
2120 linkedstate |= CLinkedCell;
2123 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2124 code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2129 DECL_PIOCTL(PNewAlias)
2131 /* create a new cell alias */
2133 register afs_int32 code;
2134 char *realName, *aliasName;
2136 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2137 return EIO; /* Inappropriate ioctl for device */
2139 if (!afs_osi_suser(*acred))
2143 tp += strlen(aliasName) + 1;
2146 code = afs_NewCellAlias(aliasName, realName);
2151 DECL_PIOCTL(PListCells)
2153 afs_int32 whichCell;
2154 register struct cell *tcell=0;
2155 register afs_int32 i;
2156 register char *cp, *tp = ain;
2158 AFS_STATCNT(PListCells);
2159 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2160 return EIO; /* Inappropriate ioctl for device */
2162 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2163 tp += sizeof(afs_int32);
2164 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2167 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2168 for(i=0;i<MAXCELLHOSTS;i++) {
2169 if (tcell->cellHosts[i] == 0) break;
2170 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip, sizeof(afs_int32));
2171 cp += sizeof(afs_int32);
2173 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2174 strcpy(cp, tcell->cellName);
2175 cp += strlen(tcell->cellName)+1;
2176 *aoutSize = cp - aout;
2177 afs_PutCell(tcell, READ_LOCK);
2179 if (tcell) return 0;
2183 DECL_PIOCTL(PListAliases)
2185 afs_int32 whichAlias;
2186 register struct cell_alias *tcalias=0;
2187 register char *cp, *tp = ain;
2189 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2190 return EIO; /* Inappropriate ioctl for device */
2191 if (ainSize < sizeof(afs_int32))
2194 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2195 tp += sizeof(afs_int32);
2197 tcalias = afs_GetCellAlias(whichAlias);
2200 strcpy(cp, tcalias->alias);
2201 cp += strlen(tcalias->alias)+1;
2202 strcpy(cp, tcalias->cell);
2203 cp += strlen(tcalias->cell)+1;
2204 *aoutSize = cp - aout;
2205 afs_PutCellAlias(tcalias);
2207 if (tcalias) return 0;
2211 DECL_PIOCTL(PRemoveMount)
2213 register afs_int32 code;
2215 struct sysname_info sysState;
2216 afs_size_t offset, len;
2217 register struct conn *tc;
2218 register struct dcache *tdc;
2219 register struct vcache *tvc;
2220 struct AFSFetchStatus OutDirStatus;
2221 struct VenusFid tfid;
2222 struct AFSVolSync tsync;
2226 /* "ain" is the name of the file in this dir to remove */
2228 AFS_STATCNT(PRemoveMount);
2229 if (!avc) return EINVAL;
2230 code = afs_VerifyVCache(avc, areq);
2231 if (code) return code;
2232 if (vType(avc) != VDIR) return ENOTDIR;
2234 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2235 if (!tdc) return ENOENT;
2236 Check_AtSys(avc, ain, &sysState, areq);
2237 ObtainReadLock(&tdc->lock);
2239 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2240 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2241 ReleaseReadLock(&tdc->lock);
2242 bufp = sysState.name;
2247 tfid.Cell = avc->fid.Cell;
2248 tfid.Fid.Volume = avc->fid.Fid.Volume;
2249 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2250 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2252 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2259 if (tvc->mvstat != 1) {
2265 ObtainWriteLock(&tvc->lock,230);
2266 code = afs_HandleLink(tvc, areq);
2268 if (tvc->linkData) {
2269 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2274 ReleaseWriteLock(&tvc->lock);
2275 osi_dnlc_purgedp(tvc);
2281 ObtainWriteLock(&avc->lock,231);
2282 osi_dnlc_remove(avc, bufp, tvc);
2284 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2286 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2288 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2289 bufp, &OutDirStatus, &tsync);
2295 (afs_Analyze(tc, code, &avc->fid, areq,
2296 AFS_STATS_FS_RPCIDX_REMOVEFILE,
2297 SHARED_LOCK, NULL));
2300 if (tdc) afs_PutDCache(tdc);
2301 ReleaseWriteLock(&avc->lock);
2305 /* we have the thing in the cache */
2306 ObtainWriteLock(&tdc->lock, 661);
2307 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2308 /* we can do it locally */
2309 code = afs_dir_Delete(&tdc->f.inode, bufp);
2311 ZapDCE(tdc); /* surprise error -- invalid value */
2312 DZap(&tdc->f.inode);
2315 ReleaseWriteLock(&tdc->lock);
2316 afs_PutDCache(tdc); /* drop ref count */
2318 avc->states &= ~CUnique; /* For the dfs xlator */
2319 ReleaseWriteLock(&avc->lock);
2322 if (sysState.allocked) osi_FreeLargeSpace(bufp);
2326 DECL_PIOCTL(PVenusLogging)
2328 return EINVAL; /* OBSOLETE */
2331 DECL_PIOCTL(PGetCellStatus)
2333 register struct cell *tcell;
2336 AFS_STATCNT(PGetCellStatus);
2337 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2338 return EIO; /* Inappropriate ioctl for device */
2340 tcell = afs_GetCellByName(ain, READ_LOCK);
2341 if (!tcell) return ENOENT;
2342 temp = tcell->states;
2343 afs_PutCell(tcell, READ_LOCK);
2344 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2345 *aoutSize = sizeof(afs_int32);
2349 DECL_PIOCTL(PSetCellStatus)
2351 register struct cell *tcell;
2354 if (!afs_osi_suser(*acred))
2356 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2357 return EIO; /* Inappropriate ioctl for device */
2359 tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2360 if (!tcell) return ENOENT;
2361 memcpy((char *)&temp, ain, sizeof(afs_int32));
2363 tcell->states |= CNoSUID;
2365 tcell->states &= ~CNoSUID;
2366 afs_PutCell(tcell, WRITE_LOCK);
2370 DECL_PIOCTL(PFlushVolumeData)
2372 register afs_int32 i;
2373 register struct dcache *tdc;
2374 register struct vcache *tvc;
2375 register struct volume *tv;
2376 afs_int32 cell, volume;
2378 AFS_STATCNT(PFlushVolumeData);
2381 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2382 return EIO; /* Inappropriate ioctl for device */
2384 volume = avc->fid.Fid.Volume; /* who to zap */
2385 cell = avc->fid.Cell;
2388 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2389 * the vcaches associated with the volume.
2391 ObtainReadLock(&afs_xvcache);
2392 for(i = 0; i < VCSIZE; i++) {
2393 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2394 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2395 #if defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2396 VN_HOLD(AFSTOV(tvc));
2398 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2404 ReleaseReadLock(&afs_xvcache);
2405 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2406 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
2408 ObtainWriteLock(&tvc->lock,232);
2410 ObtainWriteLock(&afs_xcbhash, 458);
2411 afs_DequeueCallback(tvc);
2412 tvc->states &= ~(CStatd | CDirty);
2413 ReleaseWriteLock(&afs_xcbhash);
2414 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2415 osi_dnlc_purgedp(tvc);
2416 afs_TryToSmush(tvc, *acred, 1);
2417 ReleaseWriteLock(&tvc->lock);
2418 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2419 afs_BozonUnlock(&tvc->pvnLock, tvc);
2421 ObtainReadLock(&afs_xvcache);
2422 /* our tvc ptr is still good until now */
2427 ReleaseReadLock(&afs_xvcache);
2430 MObtainWriteLock(&afs_xdcache,328); /* needed if you're going to flush any stuff */
2431 for(i=0;i<afs_cacheFiles;i++) {
2432 if (!(afs_indexFlags[i] & IFEverUsed)) continue; /* never had any data */
2433 tdc = afs_GetDSlot(i, NULL);
2434 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
2435 ReleaseReadLock(&tdc->tlock);
2436 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2437 if (! (afs_indexFlags[i] & IFDataMod)) {
2438 /* if the file is modified, but has a ref cnt of only 1, then
2439 someone probably has the file open and is writing into it.
2440 Better to skip flushing such a file, it will be brought back
2441 immediately on the next write anyway.
2443 If we *must* flush, then this code has to be rearranged to call
2444 afs_storeAllSegments() first */
2445 afs_FlushDCache(tdc);
2449 ReleaseReadLock(&tdc->tlock);
2451 afs_PutDCache(tdc); /* bumped by getdslot */
2453 MReleaseWriteLock(&afs_xdcache);
2455 ObtainReadLock(&afs_xvolume);
2456 for (i=0;i<NVOLS;i++) {
2457 for (tv = afs_volumes[i]; tv; tv=tv->next) {
2458 if (tv->volume == volume) {
2459 afs_ResetVolumeInfo(tv);
2464 ReleaseReadLock(&afs_xvolume);
2466 /* probably, a user is doing this, probably, because things are screwed up.
2467 * maybe it's the dnlc's fault? */
2474 DECL_PIOCTL(PGetVnodeXStatus)
2476 register afs_int32 code;
2477 struct vcxstat stat;
2480 /* AFS_STATCNT(PGetVnodeXStatus); */
2481 if (!avc) return EINVAL;
2482 code = afs_VerifyVCache(avc, areq);
2483 if (code) return code;
2484 if (vType(avc) == VDIR)
2485 mode = PRSFS_LOOKUP;
2488 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2490 stat.fid = avc->fid;
2491 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2492 stat.lock = avc->lock;
2493 stat.parentVnode = avc->parentVnode;
2494 stat.parentUnique = avc->parentUnique;
2495 hset(stat.flushDV, avc->flushDV);
2496 hset(stat.mapDV, avc->mapDV);
2497 stat.truncPos = avc->truncPos;
2498 { /* just grab the first two - won't break anything... */
2499 struct axscache *ac;
2501 for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2502 stat.randomUid[i] = ac->uid;
2503 stat.randomAccess[i] = ac->axess;
2506 stat.callback = afs_data_pointer_to_int32(avc->callback);
2507 stat.cbExpires = avc->cbExpires;
2508 stat.anyAccess = avc->anyAccess;
2509 stat.opens = avc->opens;
2510 stat.execsOrWriters = avc->execsOrWriters;
2511 stat.flockCount = avc->flockCount;
2512 stat.mvstat = avc->mvstat;
2513 stat.states = avc->states;
2514 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
2515 *aoutSize = sizeof(struct vcxstat);
2520 /* We require root for local sysname changes, but not for remote */
2521 /* (since we don't really believe remote uids anyway) */
2522 /* outname[] shouldn't really be needed- this is left as an excercise */
2523 /* for the reader. */
2524 DECL_PIOCTL(PSetSysName)
2526 char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2527 int setsysname, foundname=0;
2528 register struct afs_exporter *exporter;
2529 register struct unixuser *au;
2530 register afs_int32 pag, error;
2534 AFS_STATCNT(PSetSysName);
2535 if (!afs_globalVFS) {
2536 /* Afsd is NOT running; disable it */
2537 #if defined(KERNEL_HAVE_UERROR)
2538 return (setuerror(EINVAL), EINVAL);
2543 memset(inname, 0, MAXSYSNAME);
2544 memcpy((char *)&setsysname, ain, sizeof(afs_int32));
2545 ain += sizeof(afs_int32);
2549 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2551 for(cp = ain,count = 0;count < setsysname;count++) {
2552 /* won't go past end of ain since maxsysname*num < ain length */
2554 if (t >= MAXSYSNAME || t <= 0)
2556 /* check for names that can shoot us in the foot */
2557 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2563 /* inname gets first entry in case we're being a translater */
2565 memcpy(inname, ain, t+1); /* include terminating null */
2568 if ((*acred)->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2569 pag = PagInCred(*acred);
2571 return EINVAL; /* Better than panicing */
2573 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2574 return EINVAL; /* Better than panicing */
2576 if (!(exporter = au->exporter)) {
2577 afs_PutUser(au, READ_LOCK);
2578 return EINVAL; /* Better than panicing */
2580 error = EXP_SYSNAME(exporter, (setsysname? inname : NULL), outname);
2582 if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2584 afs_PutUser(au, READ_LOCK);
2589 afs_PutUser(au, READ_LOCK);
2592 /* Not xlating, so local case */
2593 if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2594 if (!setsysname) { /* user just wants the info */
2595 strcpy(outname, afs_sysname);
2596 foundname = afs_sysnamecount;
2597 } else { /* Local guy; only root can change sysname */
2598 if (!afs_osi_suser(*acred))
2601 /* clear @sys entries from the dnlc, once afs_lookup can
2602 do lookups of @sys entries and thinks it can trust them */
2603 /* privs ok, store the entry, ... */
2604 strcpy(afs_sysname, inname);
2605 if (setsysname > 1) { /* ... or list */
2607 for(count=1; count < setsysname;++count) {
2608 if (!afs_sysnamelist[count])
2609 osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2611 memcpy(afs_sysnamelist[count], cp, t+1); /* include null */
2615 afs_sysnamecount = setsysname;
2619 cp = aout; /* not changing so report back the count and ... */
2620 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
2621 cp += sizeof(afs_int32);
2623 strcpy(cp, outname); /* ... the entry, ... */
2624 cp += strlen(outname)+1;
2625 for(count=1; count < foundname; ++count) { /* ... or list. */
2626 /* Note: we don't support @sys lists for exporters */
2627 if (!afs_sysnamelist[count])
2628 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2629 t = strlen(afs_sysnamelist[count]);
2630 if (t >= MAXSYSNAME)
2631 osi_Panic("PSetSysName: sysname entry garbled\n");
2632 strcpy(cp, afs_sysnamelist[count]);
2636 *aoutSize = cp - aout;
2641 /* sequential search through the list of touched cells is not a good
2642 * long-term solution here. For small n, though, it should be just
2643 * fine. Should consider special-casing the local cell for large n.
2644 * Likewise for PSetSPrefs.
2646 * s - number of ids in array l[] -- NOT index of last id
2647 * l - array of cell ids which have volumes that need to be sorted
2648 * vlonly - sort vl servers or file servers?
2650 static void *ReSortCells_cb(struct cell *cell, void *arg)
2652 afs_int32 *p = (afs_int32 *) arg;
2653 afs_int32 *l = p + 1;
2656 for (i=0; i<s; i++) {
2657 if (l[i] == cell->cellNum) {
2658 ObtainWriteLock(&cell->lock, 690);
2659 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
2660 ReleaseWriteLock(&cell->lock);
2667 static void ReSortCells(int s, afs_int32 *l, int vlonly)
2675 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s+1));
2677 memcpy(p+1, l, s * sizeof(afs_int32));
2678 afs_TraverseCells(&ReSortCells_cb, p);
2679 afs_osi_Free(p, sizeof(afs_int32) * (s+1));
2683 ObtainReadLock(&afs_xvolume);
2684 for (i= 0; i< NVOLS; i++) {
2685 for (j=afs_volumes[i];j;j=j->next) {
2687 if (j->cell == l[k]) {
2688 ObtainWriteLock(&j->lock,233);
2689 afs_SortServers(j->serverHost, MAXHOSTS);
2690 ReleaseWriteLock(&j->lock);
2695 ReleaseReadLock(&afs_xvolume);
2699 static int debugsetsp = 0;
2700 static int afs_setsprefs(sp, num, vlonly)
2703 unsigned int vlonly;
2706 int i,j,k,matches,touchedSize;
2707 struct server *srvr = NULL;
2708 afs_int32 touched[34];
2712 for (k=0; k < num; sp++, k++) {
2714 printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2717 ObtainReadLock(&afs_xserver);
2719 i = SHash(sp->host.s_addr);
2720 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2721 if (sa->sa_ip == sp->host.s_addr) {
2723 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
2724 || (sa->sa_portal == AFS_FSPORT);
2725 if ((!vlonly && isfs) || (vlonly && !isfs)) {
2732 if (sa && matches) { /* found one! */
2734 printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
2736 sa->sa_iprank = sp->rank + afs_randomMod15();
2737 afs_SortOneServer(sa->server);
2740 /* if we don't know yet what cell it's in, this is moot */
2741 for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cellNum; j--)
2742 /* is it in our list of touched cells ? */ ;
2743 if (j < 0) { /* no, it's not */
2744 touched[touchedSize++] = srvr->cell->cellNum;
2745 if (touchedSize >= 32) { /* watch for ovrflow */
2746 ReleaseReadLock(&afs_xserver);
2747 ReSortCells(touchedSize, touched, vlonly);
2749 ObtainReadLock(&afs_xserver);
2755 ReleaseReadLock(&afs_xserver);
2756 /* if we didn't find one, start to create one. */
2757 /* Note that it doesn't have a cell yet... */
2759 afs_uint32 temp = sp->host.s_addr;
2760 srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
2761 WRITE_LOCK, (afsUUID *)0,0);
2762 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
2763 afs_PutServer(srvr, WRITE_LOCK);
2765 } /* for all cited preferences */
2767 ReSortCells(touchedSize, touched, vlonly);
2771 /* Note that this may only be performed by the local root user.
2773 DECL_PIOCTL(PSetSPrefs)
2775 struct setspref *ssp;
2776 AFS_STATCNT(PSetSPrefs);
2778 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2779 return EIO; /* Inappropriate ioctl for device */
2781 if (!afs_osi_suser(*acred))
2784 if (ainSize < sizeof(struct setspref))
2787 ssp = (struct setspref *)ain;
2788 if (ainSize < sizeof(struct spref)*ssp->num_servers)
2791 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
2792 (ssp->flags & DBservers));
2796 DECL_PIOCTL(PSetSPrefs33)
2799 AFS_STATCNT(PSetSPrefs);
2800 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2801 return EIO; /* Inappropriate ioctl for device */
2804 if (!afs_osi_suser(*acred))
2807 sp = (struct spref *)ain;
2808 afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
2812 /* some notes on the following code...
2813 * in the hash table of server structs, all servers with the same IP address
2814 * will be on the same overflow chain.
2815 * This could be sped slightly in some circumstances by having it cache the
2816 * immediately previous slot in the hash table and some supporting information
2817 * Only reports file servers now.
2819 DECL_PIOCTL(PGetSPrefs)
2821 struct sprefrequest *spin; /* input */
2822 struct sprefinfo *spout; /* output */
2823 struct spref *srvout; /* one output component */
2824 int i,j; /* counters for hash table traversal */
2825 struct server *srvr; /* one of CM's server structs */
2827 int vlonly; /* just return vlservers ? */
2830 AFS_STATCNT(PGetSPrefs);
2831 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2832 return EIO; /* Inappropriate ioctl for device */
2835 if (ainSize < sizeof (struct sprefrequest_33)) {
2839 spin = ((struct sprefrequest *) ain);
2842 if (ainSize > sizeof (struct sprefrequest_33)) {
2843 vlonly = (spin->flags & DBservers);
2847 /* struct sprefinfo includes 1 server struct... that size gets added
2848 * in during the loop that follows.
2850 *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
2851 spout = (struct sprefinfo *) aout;
2852 spout->next_offset = spin->offset;
2853 spout->num_servers = 0;
2854 srvout = spout->servers;
2856 ObtainReadLock(&afs_xserver);
2857 for (i=0, j=0; j < NSERVERS; j++) { /* sift through hash table */
2858 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
2859 if (spin->offset > (unsigned short)i) {
2860 continue; /* catch up to where we left off */
2862 spout->next_offset++;
2865 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
2866 || (sa->sa_portal == AFS_FSPORT);
2868 if ((vlonly && isfs) || (!vlonly && !isfs)) {
2869 /* only report ranks for vl servers */
2873 srvout->host.s_addr = sa->sa_ip;
2874 srvout->rank = sa->sa_iprank;
2875 *aoutSize += sizeof(struct spref);
2876 spout->num_servers++;
2879 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
2880 ReleaseReadLock(&afs_xserver); /* no more room! */
2885 ReleaseReadLock(&afs_xserver);
2887 spout->next_offset = 0; /* start over from the beginning next time */
2891 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
2892 int afs_NFSRootOnly = 1;
2893 DECL_PIOCTL(PExportAfs)
2895 afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
2896 register struct afs_exporter *exporter;
2898 AFS_STATCNT(PExportAfs);
2899 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
2900 type = handleValue >> 24;
2905 exporter = exporter_find(type);
2907 export = handleValue & 3;
2908 changestate = handleValue & 0xff;
2909 smounts = (handleValue >> 2) & 3;
2910 pwsync = (handleValue >> 4) & 3;
2911 convmode = (handleValue >> 6) & 3;
2913 changestate = (handleValue >> 16) & 0x1;
2914 convmode = (handleValue >> 16) & 0x2;
2915 pwsync = (handleValue >> 16) & 0x4;
2916 smounts = (handleValue >> 16) & 0x8;
2917 export = handleValue & 0xff;
2920 /* Failed finding desired exporter; */
2924 handleValue = exporter->exp_states;
2925 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
2926 *aoutSize = sizeof(afs_int32);
2928 if (!afs_osi_suser(*acred))
2929 return EACCES; /* Only superuser can do this */
2933 exporter->exp_states |= EXP_EXPORTED;
2935 exporter->exp_states &= ~EXP_EXPORTED;
2939 exporter->exp_states |= EXP_UNIXMODE;
2941 exporter->exp_states &= ~EXP_UNIXMODE;
2945 exporter->exp_states |= EXP_PWSYNC;
2947 exporter->exp_states &= ~EXP_PWSYNC;
2951 afs_NFSRootOnly = 0;
2952 exporter->exp_states |= EXP_SUBMOUNTS;
2954 afs_NFSRootOnly = 1;
2955 exporter->exp_states &= ~EXP_SUBMOUNTS;
2958 handleValue = exporter->exp_states;
2959 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
2960 *aoutSize = sizeof(afs_int32);
2963 exporter->exp_states |= EXP_EXPORTED;
2965 exporter->exp_states &= ~EXP_EXPORTED;
2967 exporter->exp_states |= EXP_UNIXMODE;
2969 exporter->exp_states &= ~EXP_UNIXMODE;
2971 exporter->exp_states |= EXP_PWSYNC;
2973 exporter->exp_states &= ~EXP_PWSYNC;
2975 afs_NFSRootOnly = 0;
2976 exporter->exp_states |= EXP_SUBMOUNTS;
2978 afs_NFSRootOnly = 1;
2979 exporter->exp_states &= ~EXP_SUBMOUNTS;
2989 struct gaginfo *gagflags;
2991 if (!afs_osi_suser(*acred))
2994 gagflags = (struct gaginfo *) ain;
2995 afs_showflags = gagflags->showflags;
3001 DECL_PIOCTL(PTwiddleRx)
3003 struct rxparams *rxp;
3005 if (!afs_osi_suser(*acred))
3008 rxp = (struct rxparams *) ain;
3010 if (rxp->rx_initReceiveWindow)
3011 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3012 if (rxp->rx_maxReceiveWindow)
3013 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3014 if (rxp->rx_initSendWindow)
3015 rx_initSendWindow = rxp->rx_initSendWindow;
3016 if (rxp->rx_maxSendWindow)
3017 rx_maxSendWindow = rxp->rx_maxSendWindow;
3018 if (rxp->rxi_nSendFrags)
3019 rxi_nSendFrags = rxp->rxi_nSendFrags;
3020 if (rxp->rxi_nRecvFrags)
3021 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3022 if (rxp->rxi_OrphanFragSize)
3023 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3024 if (rxp->rx_maxReceiveSize)
3026 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3027 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3029 if (rxp->rx_MyMaxSendSize)
3030 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3035 DECL_PIOCTL(PGetInitParams)
3037 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3040 memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3041 *aoutSize = sizeof(struct cm_initparams);
3045 #ifdef AFS_SGI65_ENV
3046 /* They took crget() from us, so fake it. */
3047 static cred_t *crget(void)
3050 cr = crdup(get_current_cred());
3051 memset((char*)cr, 0, sizeof(cred_t));
3052 #if CELL || CELL_PREPARE
3059 DECL_PIOCTL(PGetRxkcrypt)
3061 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3062 *aoutSize=sizeof(afs_int32);
3066 DECL_PIOCTL(PSetRxkcrypt)
3070 if (!afs_osi_suser(*acred))
3072 if (ainSize != sizeof(afs_int32) || ain == NULL)
3074 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3075 /* if new mappings added later this will need to be changed */
3076 if (tmpval != 0 && tmpval != 1)
3083 * Create new credentials to correspond to a remote user with given
3084 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3085 * provide pioctl (and other) services to foreign clients (i.e. nfs
3086 * clients) by using this call to `become' the client.
3089 #define PIOCTL_HEADER 6
3090 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3092 #if defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3093 return EINVAL; /* NFS trans not supported for Ultrix */
3096 afs_uint32 hostaddr;
3097 afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3098 struct afs_exporter *exporter, *outexporter;
3099 struct AFS_UCRED *newcred;
3100 struct unixuser *au;
3102 #if defined(AFS_SGIMP_ENV)
3103 osi_Assert(ISAFS_GLOCK());
3105 AFS_STATCNT(HandleClientContext);
3106 if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) {
3107 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3108 return EINVAL; /* Too small to be good */
3110 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3111 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3113 osi_FreeLargeSpace(inData);
3117 /* Extract information for remote user */
3118 hostaddr = *((afs_uint32 *)ain);
3119 ain += sizeof(hostaddr);
3120 uid = *((afs_uint32 *)ain);
3122 g0 = *((afs_uint32 *)ain);
3124 g1 = *((afs_uint32 *)ain);
3126 *com = *((afs_uint32 *)ain);
3127 ain += sizeof(afs_int32);
3128 exporter_type = *((afs_uint32 *)ain); /* In case we support more than NFS */
3131 * Of course, one must be root for most of these functions, but
3132 * we'll allow (for knfs) you to set things if the pag is 0 and
3133 * you're setting tokens or unlogging.
3136 if (!afs_osi_suser(credp)) {
3138 #ifndef AFS_SGI64_ENV
3139 /* Since SGI's suser() returns explicit failure after the call.. */
3143 /* check for acceptable opcodes for normal folks, which are, so far,
3144 * set tokens and unlog.
3146 if (i != 9 && i != 3 && i != 38 && i != 8) {
3147 osi_FreeLargeSpace(inData);
3152 ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3153 ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3154 osi_FreeLargeSpace(inData);
3157 * We map uid 0 to nobody to match the mapping that the nfs
3158 * server does and to ensure that the suser() calls in the afs
3159 * code fails for remote client roots.
3161 uid = afs_nobody; /* NFS_NOBODY == -2 */
3164 #ifdef AFS_AIX41_ENV
3167 newcred->cr_gid = RMTUSER_REQ;
3168 #ifdef AFS_AIX51_ENV
3169 newcred->cr_groupset.gs_union.un_groups[0] = g0;
3170 newcred->cr_groupset.gs_union.un_groups[1] = g1;
3172 newcred->cr_groups[0] = g0;
3173 newcred->cr_groups[1] = g1;
3176 newcred->cr_ngrps = 2;
3178 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3179 newcred->cr_ngroups = 2;
3181 for (i=2; i<NGROUPS; i++)
3182 newcred->cr_groups[i] = NOGROUP;
3185 #if !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3186 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
3188 if (!(exporter = exporter_find(exporter_type))) {
3189 /* Exporter wasn't initialized or an invalid exporter type */
3193 if (exporter->exp_states & EXP_PWSYNC) {
3194 if (uid != credp->cr_uid) {
3196 return ENOEXEC; /* XXX Find a better errno XXX */
3199 newcred->cr_uid = uid; /* Only temporary */
3200 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3201 /* The client's pag is the only unique identifier for it */
3202 newcred->cr_uid = pag;
3204 if (!code && *com == PSETPAG) {
3205 /* Special case for 'setpag' */
3206 afs_uint32 pagvalue = genpag();
3208 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3210 * Note that we leave the 'outexporter' struct held so it won't
3213 au->exporter = outexporter;
3214 if (ablob->out_size >= 4) {
3215 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3217 afs_PutUser(au, WRITE_LOCK);
3218 if (code) return code;
3219 return PSETPAG; /* Special return for setpag */
3221 EXP_RELE(outexporter);
3224 #endif /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3227 /* get all interface addresses of this client */
3229 DECL_PIOCTL(PGetCPrefs)
3231 struct sprefrequest *spin; /* input */
3232 struct sprefinfo *spout; /* output */
3233 struct spref *srvout; /* one output component */
3237 AFS_STATCNT(PGetCPrefs);
3238 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
3239 return EIO; /* Inappropriate ioctl for device */
3241 if ( ainSize < sizeof (struct sprefrequest ))
3244 spin = (struct sprefrequest *) ain;
3245 spout = (struct sprefinfo *) aout;
3247 maxNumber = spin->num_servers; /* max addrs this time */
3248 srvout = spout->servers;
3250 ObtainReadLock(&afs_xinterface);
3252 /* copy out the client interface information from the
3253 ** kernel data structure "interface" to the output buffer
3255 for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3256 && ( j< maxNumber) ; i++, j++, srvout++)
3257 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3259 spout->num_servers = j;
3260 *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3262 if ( i >= afs_cb_interface.numberOfInterfaces )
3263 spout->next_offset = 0; /* start from beginning again */
3265 spout->next_offset = spin->offset + j;
3267 ReleaseReadLock(&afs_xinterface);
3271 DECL_PIOCTL(PSetCPrefs)
3273 struct setspref *sin;
3276 AFS_STATCNT(PSetCPrefs);
3277 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
3278 return EIO; /* Inappropriate ioctl for device */
3280 sin = (struct setspref *)ain;
3282 if ( ainSize < sizeof(struct setspref) )
3284 #if 0 /* num_servers is unsigned */
3285 if ( sin->num_servers < 0 )
3288 if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3291 ObtainWriteLock(&afs_xinterface, 412);
3292 afs_cb_interface.numberOfInterfaces = sin->num_servers;
3293 for ( i=0; (unsigned short)i < sin->num_servers; i++)
3294 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3296 ReleaseWriteLock(&afs_xinterface);
3300 DECL_PIOCTL(PFlushMount)
3302 register afs_int32 code;
3303 register struct vcache *tvc;
3304 register struct dcache *tdc;
3305 struct VenusFid tfid;
3307 struct sysname_info sysState;
3308 afs_size_t offset, len;
3310 AFS_STATCNT(PFlushMount);
3311 if (!avc) return EINVAL;
3312 code = afs_VerifyVCache(avc, areq);
3313 if (code) return code;
3314 if (vType(avc) != VDIR) {
3317 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3318 if (!tdc) return ENOENT;
3319 Check_AtSys(avc, ain, &sysState, areq);
3320 ObtainReadLock(&tdc->lock);
3322 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3323 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3324 ReleaseReadLock(&tdc->lock);
3325 afs_PutDCache(tdc); /* we're done with the data */
3326 bufp = sysState.name;
3330 tfid.Cell = avc->fid.Cell;
3331 tfid.Fid.Volume = avc->fid.Fid.Volume;
3332 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3333 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
3335 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
3341 if (tvc->mvstat != 1) {
3346 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3347 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3349 ObtainWriteLock(&tvc->lock,649);
3350 ObtainWriteLock(&afs_xcbhash, 650);
3351 afs_DequeueCallback(tvc);
3352 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
3353 ReleaseWriteLock(&afs_xcbhash);
3354 /* now find the disk cache entries */
3355 afs_TryToSmush(tvc, *acred, 1);
3356 osi_dnlc_purgedp(tvc);
3357 afs_symhint_inval(tvc);
3358 if (tvc->linkData && !(tvc->states & CCore)) {
3359 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3360 tvc->linkData = NULL;
3362 ReleaseWriteLock(&tvc->lock);
3363 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3364 afs_BozonUnlock(&tvc->pvnLock, tvc);
3368 if (sysState.allocked) osi_FreeLargeSpace(bufp);
3372 DECL_PIOCTL(PRxStatProc)
3377 if (!afs_osi_suser(*acred)) {
3381 if (ainSize != sizeof(afs_int32)) {
3385 memcpy((char *)&flags, ain, sizeof(afs_int32));
3386 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3390 if (flags & AFSCALL_RXSTATS_ENABLE) {
3391 rx_enableProcessRPCStats();
3393 if (flags & AFSCALL_RXSTATS_DISABLE) {
3394 rx_disableProcessRPCStats();
3396 if (flags & AFSCALL_RXSTATS_CLEAR) {
3397 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3405 DECL_PIOCTL(PRxStatPeer)
3410 if (!afs_osi_suser(*acred)) {
3414 if (ainSize != sizeof(afs_int32)) {
3418 memcpy((char *)&flags, ain, sizeof(afs_int32));
3419 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3423 if (flags & AFSCALL_RXSTATS_ENABLE) {
3424 rx_enablePeerRPCStats();
3426 if (flags & AFSCALL_RXSTATS_DISABLE) {
3427 rx_disablePeerRPCStats();
3429 if (flags & AFSCALL_RXSTATS_CLEAR) {
3430 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3437 DECL_PIOCTL(PPrefetchFromTape)
3439 register afs_int32 code, code1;
3442 struct rx_call *tcall;
3443 struct AFSVolSync tsync;
3444 struct AFSFetchStatus OutStatus;
3445 struct AFSCallBack CallBack;
3446 struct VenusFid tfid;
3450 AFS_STATCNT(PSetAcl);
3454 if (ain && (ainSize == 3 * sizeof(afs_int32)))
3455 Fid = (struct AFSFid *) ain;
3457 Fid = &avc->fid.Fid;
3458 tfid.Cell = avc->fid.Cell;
3459 tfid.Fid.Volume = Fid->Volume;
3460 tfid.Fid.Vnode = Fid->Vnode;
3461 tfid.Fid.Unique = Fid->Unique;
3463 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
3465 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3466 ICL_TYPE_POINTER, tvc,
3467 ICL_TYPE_FID, &tfid,
3468 ICL_TYPE_FID, &avc->fid);
3471 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3472 ICL_TYPE_POINTER, tvc,
3473 ICL_TYPE_FID, &tfid,
3474 ICL_TYPE_FID, &tvc->fid);
3477 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3481 tcall = rx_NewCall(tc->id);
3482 code = StartRXAFS_FetchData(tcall,
3483 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3485 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3486 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3488 code1 = rx_EndCall(tcall, code);
3493 (afs_Analyze(tc, code, &tvc->fid, areq,
3494 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3496 /* This call is done only to have the callback things handled correctly */
3497 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3501 *aoutSize = sizeof(afs_int32);
3506 DECL_PIOCTL(PResidencyCmd)
3508 register afs_int32 code;
3511 struct ResidencyCmdInputs *Inputs;
3512 struct ResidencyCmdOutputs *Outputs;
3513 struct VenusFid tfid;
3516 Inputs = (struct ResidencyCmdInputs *) ain;
3517 Outputs = (struct ResidencyCmdOutputs *) aout;
3518 if (!avc) return EINVAL;
3519 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3523 Fid = &avc->fid.Fid;
3525 tfid.Cell = avc->fid.Cell;
3526 tfid.Fid.Volume = Fid->Volume;
3527 tfid.Fid.Vnode = Fid->Vnode;
3528 tfid.Fid.Unique = Fid->Unique;
3530 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
3531 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3532 ICL_TYPE_POINTER, tvc,
3533 ICL_TYPE_INT32, Inputs->command,
3534 ICL_TYPE_FID, &tfid);
3538 if (Inputs->command) {
3540 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3543 code = RXAFS_ResidencyCmd(tc->id, Fid,
3545 (struct ResidencyCmdOutputs *) aout);
3550 (afs_Analyze(tc, code, &tvc->fid, areq,
3551 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3553 /* This call is done to have the callback things handled correctly */
3554 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3555 } else { /* just a status request, return also link data */
3557 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3558 Outputs->chars[0] = 0;
3559 if (vType(tvc) == VLNK) {
3560 ObtainWriteLock(&tvc->lock,555);
3561 if (afs_HandleLink(tvc, areq) == 0)
3562 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3563 ReleaseWriteLock(&tvc->lock);
3570 *aoutSize = sizeof(struct ResidencyCmdOutputs);