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"
20 #include "h/sysproto.h"
22 #include "afsincludes.h" /* Afs-based standard headers */
23 #include "afs/afs_stats.h" /* afs statistics */
25 #include "rx/rx_globals.h"
27 struct VenusFid afs_rootFid;
28 afs_int32 afs_waitForever=0;
29 short afs_waitForeverCount = 0;
30 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
32 #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
33 char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
34 struct AFS_UCRED **acred)
36 /* Prototypes for pioctl routines */
39 DECL_PIOCTL(PStoreBehind);
44 DECL_PIOCTL(PGetFileCell);
45 DECL_PIOCTL(PGetWSCell);
46 DECL_PIOCTL(PGetUserCell);
47 DECL_PIOCTL(PSetTokens);
48 DECL_PIOCTL(PGetVolumeStatus);
49 DECL_PIOCTL(PSetVolumeStatus);
51 DECL_PIOCTL(PNewStatMount);
52 DECL_PIOCTL(PGetTokens);
54 DECL_PIOCTL(PMariner);
55 DECL_PIOCTL(PCheckServers);
56 DECL_PIOCTL(PCheckVolNames);
57 DECL_PIOCTL(PCheckAuth);
58 DECL_PIOCTL(PFindVolume);
59 DECL_PIOCTL(PViceAccess);
60 DECL_PIOCTL(PSetCacheSize);
61 DECL_PIOCTL(PGetCacheSize);
62 DECL_PIOCTL(PRemoveCallBack);
63 DECL_PIOCTL(PNewCell);
64 DECL_PIOCTL(PNewAlias);
65 DECL_PIOCTL(PListCells);
66 DECL_PIOCTL(PListAliases);
67 DECL_PIOCTL(PRemoveMount);
68 DECL_PIOCTL(PVenusLogging);
69 DECL_PIOCTL(PGetCellStatus);
70 DECL_PIOCTL(PSetCellStatus);
71 DECL_PIOCTL(PFlushVolumeData);
72 DECL_PIOCTL(PGetVnodeXStatus);
73 DECL_PIOCTL(PSetSysName);
74 DECL_PIOCTL(PSetSPrefs);
75 DECL_PIOCTL(PSetSPrefs33);
76 DECL_PIOCTL(PGetSPrefs);
77 DECL_PIOCTL(PExportAfs);
79 DECL_PIOCTL(PTwiddleRx);
80 DECL_PIOCTL(PGetInitParams);
81 DECL_PIOCTL(PGetRxkcrypt);
82 DECL_PIOCTL(PSetRxkcrypt);
83 DECL_PIOCTL(PGetCPrefs);
84 DECL_PIOCTL(PSetCPrefs);
85 DECL_PIOCTL(PFlushMount);
86 DECL_PIOCTL(PRxStatProc);
87 DECL_PIOCTL(PRxStatPeer);
88 DECL_PIOCTL(PPrefetchFromTape);
89 DECL_PIOCTL(PResidencyCmd);
92 * A macro that says whether we're going to need HandleClientContext().
93 * This is currently used only by the nfs translator.
95 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
96 #define AFS_NEED_CLIENTCONTEXT
99 /* Prototypes for private routines */
100 #ifdef AFS_NEED_CLIENTCONTEXT
101 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
102 struct AFS_UCRED **acred, struct AFS_UCRED *credp);
104 int HandleIoctl(register struct vcache *avc, register afs_int32 acom, struct afs_ioctl *adata);
105 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
106 register struct afs_ioctl *ablob, int afollow, struct AFS_UCRED **acred);
107 static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow, struct AFS_UCRED *acred);
110 static int (*(VpioctlSw[]))() = {
115 PGetVolumeStatus, /* 4 */
116 PSetVolumeStatus, /* 5 */
121 PCheckServers, /* 10 */
122 PCheckVolNames, /* 11 */
124 PBogus, /* 13 -- used to be quick check time */
126 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
127 PBogus, /* 16 -- used to be testing code */
128 PNoop, /* 17 -- used to be enable group */
129 PNoop, /* 18 -- used to be disable group */
130 PBogus, /* 19 -- used to be list group */
131 PViceAccess, /* 20 */
132 PUnlog, /* 21 -- unlog *is* unpag in this system */
133 PGetFID, /* 22 -- get file ID */
134 PBogus, /* 23 -- used to be waitforever */
135 PSetCacheSize, /* 24 */
136 PRemoveCallBack, /* 25 -- flush only the callback */
139 PRemoveMount, /* 28 -- delete mount point */
140 PNewStatMount, /* 29 -- new style mount point stat */
141 PGetFileCell, /* 30 -- get cell name for input file */
142 PGetWSCell, /* 31 -- get cell name for workstation */
143 PMariner, /* 32 - set/get mariner host */
144 PGetUserCell, /* 33 -- get cell name for user */
145 PVenusLogging, /* 34 -- Enable/Disable logging */
146 PGetCellStatus, /* 35 */
147 PSetCellStatus, /* 36 */
148 PFlushVolumeData, /* 37 -- flush all data from a volume */
149 PSetSysName, /* 38 - Set system name */
150 PExportAfs, /* 39 - Export Afs to remote nfs clients */
151 PGetCacheSize, /* 40 - get cache size and usage */
152 PGetVnodeXStatus, /* 41 - get vcache's special status */
153 PSetSPrefs33, /* 42 - Set CM Server preferences... */
154 PGetSPrefs, /* 43 - Get CM Server preferences... */
155 PGag, /* 44 - turn off/on all CM messages */
156 PTwiddleRx, /* 45 - adjust some RX params */
157 PSetSPrefs, /* 46 - Set CM Server preferences... */
158 PStoreBehind, /* 47 - set degree of store behind to be done */
159 PGCPAGs, /* 48 - disable automatic pag gc-ing */
160 PGetInitParams, /* 49 - get initial cm params */
161 PGetCPrefs, /* 50 - get client interface addresses */
162 PSetCPrefs, /* 51 - set client interface addresses */
163 PFlushMount, /* 52 - flush mount symlink data */
164 PRxStatProc, /* 53 - control process RX statistics */
165 PRxStatPeer, /* 54 - control peer RX statistics */
166 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
167 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
168 PBogus, /* 57 -- arla: set file prio */
169 PBogus, /* 58 -- arla: fallback getfh */
170 PBogus, /* 59 -- arla: fallback fhopen */
171 PBogus, /* 60 -- arla: controls xfsdebug */
172 PBogus, /* 61 -- arla: controls arla debug */
173 PBogus, /* 62 -- arla: debug interface */
174 PBogus, /* 63 -- arla: print xfs status */
175 PBogus, /* 64 -- arla: force cache check */
176 PBogus, /* 65 -- arla: break callback */
177 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
178 PResidencyCmd, /* 67 -- MR-AFS: generic commnd interface */
179 PBogus, /* 68 -- arla: fetch stats */
182 static int (*(CpioctlSw[]))() = {
184 PNewAlias, /* 1 -- create new cell alias */
185 PListAliases, /* 2 -- list cell aliases */
188 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
189 int afs_nobody = NFS_NOBODY;
192 afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst)
194 dst->in = (char *)(unsigned long)src->in;
195 dst->out = (char *)(unsigned long)src->out;
196 dst->in_size = src->in_size;
197 dst->out_size = src->out_size;
201 * If you need to change copyin_afs_ioctl(), you may also need to change
206 copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
209 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
210 struct afs_ioctl32 dst32;
213 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
215 afs_ioctl32_to_afs_ioctl(&dst32, dst);
218 #endif /* defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL) */
221 #if defined(AFS_HPUX_64BIT_ENV)
222 struct afs_ioctl32 dst32;
224 if (is_32bit(u.u_procp)) /* is_32bit() in proc_iface.h */
226 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
228 afs_ioctl32_to_afs_ioctl(&dst32, dst);
231 #endif /* defined(AFS_HPUX_64BIT_ENV) */
233 #if defined(AFS_SUN57_64BIT_ENV)
234 struct afs_ioctl32 dst32;
236 if (get_udatamodel() == DATAMODEL_ILP32) {
237 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
239 afs_ioctl32_to_afs_ioctl(&dst32, dst);
242 #endif /* defined(AFS_SUN57_64BIT_ENV) */
244 #if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)
245 struct afs_ioctl32 dst32;
247 if (!ABI_IS_64BIT(get_current_abi()))
249 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
251 afs_ioctl32_to_afs_ioctl(&dst32, dst);
254 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
256 #if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV)
257 struct afs_ioctl32 dst32;
259 #ifdef AFS_SPARC64_LINUX24_ENV
260 if (current->thread.flags & SPARC_FLAG_32BIT)
261 #elif defined(AFS_SPARC64_LINUX20_ENV)
262 if (current->tss.flags & SPARC_FLAG_32BIT)
263 #elif defined(AFS_AMD64_LINUX20_ENV)
264 if (current->thread.flags & THREAD_IA32)
266 #error Not done for this linux type
269 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
271 afs_ioctl32_to_afs_ioctl(&dst32, dst);
274 #endif /* defined(AFS_LINUX_64BIT_KERNEL) */
276 AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
280 int HandleIoctl(register struct vcache *avc, register afs_int32 acom, struct afs_ioctl *adata)
282 register afs_int32 code;
285 AFS_STATCNT(HandleIoctl);
287 switch(acom & 0xff) {
289 avc->states |= CSafeStore;
293 /* case 2 used to be abort store, but this is no longer provided,
294 since it is impossible to implement under normal Unix.
298 /* return the name of the cell this file is open on */
299 register struct cell *tcell;
300 register afs_int32 i;
302 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
304 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
306 if (i > adata->out_size) {
307 /* 0 means we're not interested in the output */
308 if (adata->out_size != 0) code = EFAULT;
312 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
314 afs_PutCell(tcell, READ_LOCK);
320 case 49: /* VIOC_GETINITPARAMS */
321 if (adata->out_size < sizeof(struct cm_initparams)) {
325 AFS_COPYOUT(&cm_initParams, adata->out,
326 sizeof(struct cm_initparams), code);
338 return code; /* so far, none implemented */
343 /* For aix we don't temporarily bypass ioctl(2) but rather do our
344 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
345 * is now called from afs_gn_ioctl.
347 int afs_ioctl(struct vcache *tvc, int cmd, int arg)
349 struct afs_ioctl data;
352 AFS_STATCNT(afs_ioctl);
353 if (((cmd >> 8) & 0xff) == 'V') {
354 /* This is a VICEIOCTL call */
355 AFS_COPYIN(arg, (caddr_t) &data, sizeof(data), error);
358 error = HandleIoctl(tvc, cmd, &data);
361 /* No-op call; just return. */
365 #endif /* AFS_AIX_ENV */
367 #if defined(AFS_SGI_ENV)
368 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void * arg, int flag, cred_t *cr, rval_t *rvalp
374 struct afs_ioctl data;
380 AFS_STATCNT(afs_ioctl);
381 if (((cmd >> 8) & 0xff) == 'V') {
382 /* This is a VICEIOCTL call */
383 error = copyin_afs_ioctl(arg, &data);
386 locked = ISAFS_GLOCK();
389 error = HandleIoctl(tvc, cmd, &data);
394 /* No-op call; just return. */
398 #endif /* AFS_SGI_ENV */
400 /* unlike most calls here, this one uses u.u_error to return error conditions,
401 since this is really an intercepted chapter 2 call, rather than a vnode
404 /* AFS_HPUX102 and up uses VNODE ioctl instead */
405 #ifndef AFS_HPUX102_ENV
406 #if !defined(AFS_SGI_ENV)
410 kioctl(fdes, com, arg, ext, arg2, arg3)
411 #else /* __64BIT__ */
412 kioctl32(fdes, com, arg, ext, arg2, arg3)
413 #endif /* __64BIT__ */
416 kioctl(fdes, com, arg, ext)
427 } u_uap, *uap = &u_uap;
429 #if defined(AFS_SUN5_ENV)
431 struct afs_ioctl_sys {
437 afs_xioctl (uap, rvp)
438 struct afs_ioctl_sys *uap;
441 #elif defined(AFS_OSF_ENV)
442 afs_xioctl (p, args, retval)
451 } *uap = (struct a *)args;
452 #elif defined(AFS_FBSD50_ENV)
455 afs_xioctl(td, uap, retval)
457 register struct ioctl_args *uap;
460 struct proc *p = td->td_proc;
461 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
469 afs_xioctl(p, uap, retval)
471 register struct ioctl_args *uap;
474 #elif defined(AFS_LINUX22_ENV)
475 struct afs_ioctl_sys {
479 asmlinkage int afs_xioctl(struct inode *ip, struct file *fp,
480 unsigned int com, unsigned long arg)
482 struct afs_ioctl_sys ua, *uap = &ua;
484 int afs_xioctl (void)
490 } *uap = (struct a *)u.u_ap;
491 #endif /* AFS_SUN5_ENV */
493 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
495 #elif !defined(AFS_LINUX22_ENV)
496 register struct file *fd;
498 #if defined(AFS_XBSD_ENV)
499 register struct filedesc *fdp;
501 register struct vcache *tvc;
502 register int ioctlDone = 0, code = 0;
504 AFS_STATCNT(afs_xioctl);
505 #if defined(AFS_XBSD_ENV)
507 if ((u_int)uap->fd >= fdp->fd_nfiles ||
508 (fd = fdp->fd_ofiles[uap->fd]) == NULL)
510 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
512 #elif defined(AFS_DARWIN_ENV)
513 if ((code=fdgetf(p, uap->fd, &fd)))
515 #elif defined(AFS_LINUX22_ENV)
518 #elif defined(AFS_AIX32_ENV)
526 if (setuerror(getf(uap->fd, &fd))) {
529 #elif defined(AFS_OSF_ENV)
531 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
533 #elif defined(AFS_SUN5_ENV)
534 # if defined(AFS_SUN57_ENV)
536 if (!fd) return(EBADF);
537 # elif defined(AFS_SUN54_ENV)
539 if (!fd) return(EBADF);
541 if (code = getf(uap->fd, &fd)) {
544 # endif /* AFS_SUN57_ENV */
547 if (!fd) return(EBADF);
549 /* first determine whether this is any sort of vnode */
550 #if defined(AFS_LINUX22_ENV)
555 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
557 if (fd->f_type == DTYPE_VNODE) {
559 /* good, this is a vnode; next see if it is an AFS vnode */
560 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
561 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
562 #elif defined(AFS_OBSD_ENV)
563 tvc = IsAfsVnode((struct vnode *) fd->f_data) ?
564 VTOAFS((struct vnode *) fd->f_data) : NULL;
566 tvc = VTOAFS((struct vnode*)fd->f_data); /* valid, given a vnode */
568 #endif /* AFS_LINUX22_ENV */
569 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
571 tvc = VTOAFS(afs_gntovn((struct gnode *) tvc));
572 if (!tvc) { /* shouldn't happen with held gnodes */
577 /* This is an AFS vnode */
578 if (((uap->com >> 8) & 0xff) == 'V') {
579 register struct afs_ioctl *datap;
581 datap = (struct afs_ioctl *) osi_AllocSmallSpace(AFS_SMALLOCSIZ);
582 AFS_COPYIN((char *)uap->arg, (caddr_t) datap, sizeof (struct afs_ioctl), code);
584 osi_FreeSmallSpace(datap);
586 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
589 #if defined(AFS_SUN5_ENV)
604 #else /* AFS_OSF_ENV */
608 #ifdef AFS_LINUX22_ENV
618 code = HandleIoctl(tvc, uap->com, datap);
619 osi_FreeSmallSpace(datap);
633 #if defined(AFS_LINUX22_ENV)
645 code = okioctl(fdes, com, arg, ext, arg2, arg3);
646 #else /* __64BIT__ */
647 code = okioctl32(fdes, com, arg, ext, arg2, arg3);
648 #endif /* __64BIT__ */
649 #else /* !AFS_AIX51_ENV */
650 code = okioctl(fdes, com, arg, ext);
651 #endif /* AFS_AIX51_ENV */
653 #else /* !AFS_AIX41_ENV */
655 okioctl(fdes, com, arg, ext);
656 #elif defined(AFS_SUN5_ENV)
657 #if defined(AFS_SUN57_ENV)
659 #elif defined(AFS_SUN54_ENV)
664 code = ioctl(uap, rvp);
665 #elif defined(AFS_FBSD50_ENV)
666 return ioctl(td, uap);
667 #elif defined(AFS_FBSD_ENV)
668 return ioctl(p, uap);
669 #elif defined(AFS_OBSD_ENV)
670 code = sys_ioctl(p, uap, retval);
671 #elif defined(AFS_DARWIN_ENV)
672 return ioctl(p, uap, retval);
673 #elif defined(AFS_OSF_ENV)
674 code = ioctl(p, args, retval);
681 #elif !defined(AFS_LINUX22_ENV)
695 #ifdef AFS_LINUX22_ENV
698 #if defined(KERNEL_HAVE_UERROR)
701 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
702 return (getuerror() ? -1 : u.u_ioctlrv);
704 return getuerror() ? -1 : 0;
707 #endif /* AFS_LINUX22_ENV */
708 #endif /* AFS_SUN5_ENV */
709 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
713 #endif /* AFS_SGI_ENV */
714 #endif /* AFS_HPUX102_ENV */
716 #if defined(AFS_SGI_ENV)
717 /* "pioctl" system call entry point; just pass argument to the parameterized
726 afs_pioctl(struct pioctlargs *uap, rval_t *rvp)
730 AFS_STATCNT(afs_pioctl);
732 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
741 #elif defined(AFS_OSF_ENV)
742 afs_pioctl(p, args, retval)
752 } *uap = (struct a *) args;
754 AFS_STATCNT(afs_pioctl);
755 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
758 #elif defined(AFS_FBSD50_ENV)
760 afs_pioctl(td, args, retval)
770 } *uap = (struct a *) args;
772 AFS_STATCNT(afs_pioctl);
773 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
776 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
778 afs_pioctl(p, args, retval)
788 } *uap = (struct a *) args;
790 AFS_STATCNT(afs_pioctl);
791 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow, p->p_cred->pc_ucred));
796 /* macro to avoid adding any more #ifdef's to pioctl code. */
797 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
798 #define PIOCTL_FREE_CRED() crfree(credp)
800 #define PIOCTL_FREE_CRED()
805 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
807 struct AFS_UCRED *credp;
809 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
810 afs_syscall_pioctl(path, com, cmarg, follow, credp)
811 struct AFS_UCRED *credp;
813 afs_syscall_pioctl(path, com, cmarg, follow)
821 struct afs_ioctl data;
822 struct AFS_UCRED *tmpcred, *foreigncreds = NULL;
823 register afs_int32 code = 0;
829 struct ucred *credp = crref(); /* don't free until done! */
831 #ifdef AFS_LINUX22_ENV
832 cred_t *credp = crref(); /* don't free until done! */
836 AFS_STATCNT(afs_syscall_pioctl);
837 if (follow) follow = 1; /* compat. with old venus */
838 code = copyin_afs_ioctl(cmarg, &data);
841 #if defined(KERNEL_HAVE_UERROR)
846 if ((com & 0xff) == PSetClientContext) {
847 #ifdef AFS_NEED_CLIENTCONTEXT
848 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV)
849 code = HandleClientContext(&data, &com, &foreigncreds, credp);
851 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
855 crfree(foreigncreds);
858 #if defined(KERNEL_HAVE_UERROR)
859 return (setuerror(code), code);
864 #else /* AFS_NEED_CLIENTCONTEXT */
866 #endif /* AFS_NEED_CLIENTCONTEXT */
868 #ifdef AFS_NEED_CLIENTCONTEXT
871 * We could have done without temporary setting the u.u_cred below
872 * (foreigncreds could be passed as param the pioctl modules)
873 * but calls such as afs_osi_suser() doesn't allow that since it
874 * references u.u_cred directly. We could, of course, do something
875 * like afs_osi_suser(cred) which, I think, is better since it
876 * generalizes and supports multi cred environments...
880 credp = foreigncreds;
881 #elif defined(AFS_AIX41_ENV)
882 tmpcred = crref(); /* XXX */
884 #elif defined(AFS_HPUX101_ENV)
885 tmpcred = p_cred(u.u_procp);
886 set_p_cred(u.u_procp, foreigncreds);
887 #elif defined(AFS_SGI_ENV)
888 tmpcred = OSI_GET_CURRENT_CRED();
889 OSI_SET_CURRENT_CRED(foreigncreds);
892 u.u_cred = foreigncreds;
895 #endif /* AFS_NEED_CLIENTCONTEXT */
896 if ((com & 0xff) == 15) {
897 /* special case prefetch so entire pathname eval occurs in helper process.
898 otherwise, the pioctl call is essentially useless */
899 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
900 code = Prefetch(path, &data, follow,
901 foreigncreds ? foreigncreds : credp);
903 code = Prefetch(path, &data, follow, osi_curcred());
906 #if defined(KERNEL_HAVE_UERROR)
914 code = lookupname(path, USR, follow, NULL, &vp,
915 foreigncreds ? foreigncreds : credp);
917 #ifdef AFS_LINUX22_ENV
918 code = gop_lookupname(path, AFS_UIOUSER, follow, NULL, &dp);
920 vp = (struct vnode *)dp->d_inode;
922 code = gop_lookupname(path, AFS_UIOUSER, follow, NULL, &vp);
923 #endif /* AFS_LINUX22_ENV */
924 #endif /* AFS_AIX41_ENV */
928 #if defined(KERNEL_HAVE_UERROR)
936 /* now make the call if we were passed no file, or were passed an AFS file */
937 if (!vp || IsAfsVnode(vp)) {
938 #if defined(AFS_DEC_ENV)
939 /* Ultrix 4.0: can't get vcache entry unless we've got an AFS gnode.
940 * So, we must test in this part of the code. Also, must arrange to
941 * GRELE the original gnode pointer when we're done, since in Ultrix 4.0,
942 * we hold gnodes, whose references hold our vcache entries.
945 gp = vp; /* remember for "put" */
946 vp = (struct vnode *) afs_gntovn(vp); /* get vcache from gp */
949 #elif defined(AFS_SUN5_ENV)
950 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
951 #elif defined(AFS_AIX41_ENV)
953 struct ucred *cred1, *cred2;
956 cred1 = cred2 = foreigncreds;
958 cred1 = cred2 = credp;
960 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
961 if (cred1 != cred2) {
962 /* something changed the creds */
966 #elif defined(AFS_HPUX101_ENV)
968 struct ucred *cred = p_cred(u.u_procp);
969 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
971 #elif defined(AFS_SGI_ENV)
974 credp = OSI_GET_CURRENT_CRED();
975 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
977 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
978 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
980 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
983 #if defined(KERNEL_HAVE_UERROR)
986 code = EINVAL; /* not in /afs */
997 #if defined(AFS_NEED_CLIENTCONTEXT)
1000 crset(tmpcred); /* restore original credentials */
1002 #if defined(AFS_HPUX101_ENV)
1003 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
1004 #elif defined(AFS_SGI_ENV)
1005 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
1006 #elif !defined(AFS_SUN5_ENV)
1007 osi_curcred() = tmpcred; /* restore original credentials */
1008 #endif /* AFS_HPUX101_ENV */
1009 crfree(foreigncreds);
1012 #endif /* AFS_NEED_CLIENTCONTEXT */
1014 #ifdef AFS_LINUX22_ENV
1017 AFS_RELE(vp); /* put vnode back */
1021 #if defined(KERNEL_HAVE_UERROR)
1024 return (getuerror());
1031 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1032 register struct afs_ioctl *ablob, int afollow, struct AFS_UCRED **acred)
1035 struct vrequest treq;
1036 register afs_int32 code;
1037 register afs_int32 function, device;
1038 afs_int32 inSize, outSize;
1039 char *inData, *outData;
1040 int (*(*pioctlSw))();
1042 struct afs_fakestat_state fakestate;
1044 avc = avp ? VTOAFS(avp) : NULL;
1045 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1046 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1047 AFS_STATCNT(HandlePioctl);
1048 if ((code = afs_InitReq(&treq, *acred))) return code;
1049 afs_InitFakeStat(&fakestate);
1051 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1053 afs_PutFakeStat(&fakestate);
1057 device = (acom & 0xff00) >> 8;
1059 case 'V': /* Original pioctls */
1060 pioctlSw = VpioctlSw;
1061 pioctlSwSize = sizeof(VpioctlSw);
1063 case 'C': /* Coordinated/common pioctls */
1064 pioctlSw = CpioctlSw;
1065 pioctlSwSize = sizeof(CpioctlSw);
1068 afs_PutFakeStat(&fakestate);
1071 function = acom & 0xff;
1072 if (function >= (pioctlSwSize / sizeof(char *))) {
1073 afs_PutFakeStat(&fakestate);
1074 return EINVAL; /* out of range */
1076 inSize = ablob->in_size;
1078 /* Do all range checking before continuing */
1079 if (inSize >= PIGGYSIZE || inSize < 0 || ablob->out_size < 0)
1082 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1084 AFS_COPYIN(ablob->in, inData, inSize, code);
1085 inData[inSize]='\0';
1089 osi_FreeLargeSpace(inData);
1090 afs_PutFakeStat(&fakestate);
1093 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1095 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
1096 osi_FreeLargeSpace(inData);
1097 if (code == 0 && ablob->out_size > 0) {
1098 if (outSize > ablob->out_size) outSize = ablob->out_size;
1099 if (outSize >= PIGGYSIZE) code = E2BIG;
1101 outData[outSize]='\0';
1102 AFS_COPYOUT(outData, ablob->out, outSize, code);
1105 osi_FreeLargeSpace(outData);
1106 afs_PutFakeStat(&fakestate);
1107 return afs_CheckCode(code, &treq, 41);
1110 DECL_PIOCTL(PGetFID)
1112 AFS_STATCNT(PGetFID);
1113 if (!avc) return EINVAL;
1114 memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1115 *aoutSize = sizeof(struct VenusFid);
1119 DECL_PIOCTL(PSetAcl)
1121 register afs_int32 code;
1123 struct AFSOpaque acl;
1124 struct AFSVolSync tsync;
1125 struct AFSFetchStatus OutStatus;
1128 AFS_STATCNT(PSetAcl);
1131 if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1134 acl.AFSOpaque_val = ain;
1136 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1138 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1140 code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1141 &acl, &OutStatus, &tsync);
1147 (afs_Analyze(tconn, code, &avc->fid, areq,
1148 AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, NULL));
1150 /* now we've forgotten all of the access info */
1151 ObtainWriteLock(&afs_xcbhash, 455);
1153 afs_DequeueCallback(avc);
1154 avc->states &= ~(CStatd | CUnique);
1155 ReleaseWriteLock(&afs_xcbhash);
1156 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1157 osi_dnlc_purgedp(avc);
1161 int afs_defaultAsynchrony = 0;
1163 DECL_PIOCTL(PStoreBehind)
1166 struct sbstruct *sbr;
1168 sbr = (struct sbstruct *)ain;
1169 if (sbr->sb_default != -1) {
1170 if (afs_osi_suser(*acred))
1171 afs_defaultAsynchrony = sbr->sb_default;
1175 if (avc && (sbr->sb_thisfile != -1)) {
1176 if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER,
1177 areq, DONT_CHECK_MODE_BITS))
1178 avc->asynchrony = sbr->sb_thisfile;
1182 *aoutSize = sizeof(struct sbstruct);
1183 sbr = (struct sbstruct *)aout;
1184 sbr->sb_default = afs_defaultAsynchrony;
1186 sbr->sb_thisfile = avc->asynchrony;
1192 DECL_PIOCTL(PGCPAGs)
1194 if (!afs_osi_suser(*acred)) {
1197 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1201 DECL_PIOCTL(PGetAcl)
1203 struct AFSOpaque acl;
1204 struct AFSVolSync tsync;
1205 struct AFSFetchStatus OutStatus;
1211 AFS_STATCNT(PGetAcl);
1212 if (!avc) return EINVAL;
1213 Fid.Volume = avc->fid.Fid.Volume;
1214 Fid.Vnode = avc->fid.Fid.Vnode;
1215 Fid.Unique = avc->fid.Fid.Unique;
1216 if (avc->states & CForeign) {
1218 * For a dfs xlator acl we have a special hack so that the
1219 * xlator will distinguish which type of acl will return. So
1220 * we currently use the top 2-bytes (vals 0-4) to tell which
1221 * type of acl to bring back. Horrible hack but this will
1222 * cause the least number of changes to code size and interfaces.
1224 if (Fid.Vnode & 0xc0000000)
1226 Fid.Vnode |= (ainSize << 30);
1228 acl.AFSOpaque_val = aout;
1230 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1233 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1235 code = RXAFS_FetchACL(tconn->id, &Fid,
1236 &acl, &OutStatus, &tsync);
1242 (afs_Analyze(tconn, code, &avc->fid, areq,
1243 AFS_STATS_FS_RPCIDX_FETCHACL,
1244 SHARED_LOCK, NULL));
1247 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1260 AFS_STATCNT(PBogus);
1264 DECL_PIOCTL(PGetFileCell)
1266 register struct cell *tcell;
1268 AFS_STATCNT(PGetFileCell);
1269 if (!avc) return EINVAL;
1270 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1271 if (!tcell) return ESRCH;
1272 strcpy(aout, tcell->cellName);
1273 afs_PutCell(tcell, READ_LOCK);
1274 *aoutSize = strlen(aout) + 1;
1278 DECL_PIOCTL(PGetWSCell)
1280 struct cell *tcell = NULL;
1282 AFS_STATCNT(PGetWSCell);
1283 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1284 return EIO; /* Inappropriate ioctl for device */
1286 tcell = afs_GetPrimaryCell(READ_LOCK);
1287 if (!tcell) /* no primary cell? */
1289 strcpy(aout, tcell->cellName);
1290 *aoutSize = strlen(aout) + 1;
1291 afs_PutCell(tcell, READ_LOCK);
1295 DECL_PIOCTL(PGetUserCell)
1297 register afs_int32 i;
1298 register struct unixuser *tu;
1299 register struct cell *tcell;
1301 AFS_STATCNT(PGetUserCell);
1302 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1303 return EIO; /* Inappropriate ioctl for device */
1305 /* return the cell name of the primary cell for this user */
1306 i = UHash(areq->uid);
1307 ObtainWriteLock(&afs_xuser,224);
1308 for(tu = afs_users[i]; tu; tu = tu->next) {
1309 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1311 ReleaseWriteLock(&afs_xuser);
1316 tcell = afs_GetCell(tu->cell, READ_LOCK);
1317 afs_PutUser(tu, WRITE_LOCK);
1318 if (!tcell) return ESRCH;
1320 strcpy(aout, tcell->cellName);
1321 afs_PutCell(tcell, READ_LOCK);
1322 *aoutSize = strlen(aout)+1; /* 1 for the null */
1326 ReleaseWriteLock(&afs_xuser);
1333 DECL_PIOCTL(PSetTokens)
1336 register struct unixuser *tu;
1337 struct ClearToken clear;
1338 register struct cell *tcell;
1341 struct vrequest treq;
1342 afs_int32 flag, set_parent_pag = 0;
1344 AFS_STATCNT(PSetTokens);
1345 if (!afs_resourceinit_flag) {
1348 memcpy((char *)&i, ain, sizeof(afs_int32));
1349 ain += sizeof(afs_int32);
1350 stp = ain; /* remember where the ticket is */
1351 if (i < 0 || i > 2000) return EINVAL; /* malloc may fail */
1352 if (i > MAXKTCTICKETLEN) return EINVAL;
1354 ain += i; /* skip over ticket */
1355 memcpy((char *)&i, ain, sizeof(afs_int32));
1356 ain += sizeof(afs_int32);
1357 if (i != sizeof(struct ClearToken)) {
1360 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1361 if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1362 ain += sizeof(struct ClearToken);
1363 if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1364 /* still stuff left? we've got primary flag and cell name. Set these */
1365 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1366 ain += sizeof(afs_int32); /* skip id field */
1367 /* rest is cell name, look it up */
1368 /* some versions of gcc appear to need != 0 in order to get this right */
1369 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1373 tcell = afs_GetCellByName(ain, READ_LOCK);
1374 if (!tcell) goto nocell;
1377 /* default to primary cell, primary id */
1378 flag = 1; /* primary id */
1379 tcell = afs_GetPrimaryCell(READ_LOCK);
1380 if (!tcell) goto nocell;
1383 afs_PutCell(tcell, READ_LOCK);
1384 if (set_parent_pag) {
1386 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1387 #if defined(AFS_DARWIN_ENV)
1388 struct proc *p = current_proc(); /* XXX */
1390 struct proc *p = curproc; /* XXX */
1392 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1393 p->p_pid, p->p_comm);
1394 if (!setpag(p, acred, -1, &pag, 1)) {
1397 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1399 if (!setpag(acred, -1, &pag, 1)) {
1402 afs_InitReq(&treq, *acred);
1406 /* now we just set the tokens */
1407 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1408 tu->vid = clear.ViceId;
1409 if (tu->stp != NULL) {
1410 afs_osi_Free(tu->stp, tu->stLen);
1412 tu->stp = (char *) afs_osi_Alloc(stLen);
1414 memcpy(tu->stp, stp, stLen);
1417 afs_stats_cmfullperf.authent.TicketUpdates++;
1418 afs_ComputePAGStats();
1419 #endif /* AFS_NOSTATS */
1420 tu->states |= UHasTokens;
1421 tu->states &= ~UTokensBad;
1422 afs_SetPrimary(tu, flag);
1423 tu->tokenTime =osi_Time();
1424 afs_ResetUserConns(tu);
1425 afs_PutUser(tu, WRITE_LOCK);
1440 DECL_PIOCTL(PGetVolumeStatus)
1443 char *offLineMsg = afs_osi_Alloc(256);
1444 char *motd = afs_osi_Alloc(256);
1445 register struct conn *tc;
1446 register afs_int32 code = 0;
1447 struct VolumeStatus volstat;
1449 char *Name, *OfflineMsg, *MOTD;
1452 AFS_STATCNT(PGetVolumeStatus);
1458 OfflineMsg = offLineMsg;
1461 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1463 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1465 code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1466 &Name, &OfflineMsg, &MOTD);
1472 (afs_Analyze(tc, code, &avc->fid, areq,
1473 AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1474 SHARED_LOCK, NULL));
1477 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1479 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1480 cp += sizeof(VolumeStatus);
1481 strcpy(cp, volName);
1482 cp += strlen(volName)+1;
1483 strcpy(cp, offLineMsg);
1484 cp += strlen(offLineMsg)+1;
1486 cp += strlen(motd)+1;
1487 *aoutSize = (cp - aout);
1489 afs_osi_Free(offLineMsg, 256);
1490 afs_osi_Free(motd, 256);
1494 DECL_PIOCTL(PSetVolumeStatus)
1497 char *offLineMsg = afs_osi_Alloc(256);
1498 char *motd = afs_osi_Alloc(256);
1499 register struct conn *tc;
1500 register afs_int32 code = 0;
1501 struct AFSFetchVolumeStatus volstat;
1502 struct AFSStoreVolumeStatus storeStat;
1503 register struct volume *tvp;
1507 AFS_STATCNT(PSetVolumeStatus);
1508 if (!avc) return EINVAL;
1510 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1512 if (tvp->states & (VRO | VBackup)) {
1513 afs_PutVolume(tvp, READ_LOCK);
1516 afs_PutVolume(tvp, READ_LOCK);
1519 /* Copy the junk out, using cp as a roving pointer. */
1521 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1522 cp += sizeof(AFSFetchVolumeStatus);
1523 if (strlen(cp) >= sizeof(volName))
1525 strcpy(volName, cp);
1526 cp += strlen(volName)+1;
1527 if (strlen(cp) >= sizeof(offLineMsg))
1529 strcpy(offLineMsg, cp);
1530 cp += strlen(offLineMsg)+1;
1531 if (strlen(cp) >= sizeof(motd))
1535 if (volstat.MinQuota != -1) {
1536 storeStat.MinQuota = volstat.MinQuota;
1537 storeStat.Mask |= AFS_SETMINQUOTA;
1539 if (volstat.MaxQuota != -1) {
1540 storeStat.MaxQuota = volstat.MaxQuota;
1541 storeStat.Mask |= AFS_SETMAXQUOTA;
1544 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1546 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1548 code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1549 &storeStat, volName, offLineMsg, motd);
1555 (afs_Analyze(tc, code, &avc->fid, areq,
1556 AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1557 SHARED_LOCK, NULL));
1560 /* we are sending parms back to make compat. with prev system. should
1561 change interface later to not ask for current status, just set new status */
1563 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1564 cp += sizeof(VolumeStatus);
1565 strcpy(cp, volName);
1566 cp += strlen(volName)+1;
1567 strcpy(cp, offLineMsg);
1568 cp += strlen(offLineMsg)+1;
1570 cp += strlen(motd)+1;
1571 *aoutSize = cp - aout;
1573 afs_osi_Free(offLineMsg, 256);
1574 afs_osi_Free(motd, 256);
1580 AFS_STATCNT(PFlush);
1581 if (!avc) return EINVAL;
1582 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1583 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1585 ObtainWriteLock(&avc->lock,225);
1586 ObtainWriteLock(&afs_xcbhash, 456);
1587 afs_DequeueCallback(avc);
1588 avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
1589 ReleaseWriteLock(&afs_xcbhash);
1590 /* now find the disk cache entries */
1591 afs_TryToSmush(avc, *acred, 1);
1592 osi_dnlc_purgedp(avc);
1593 afs_symhint_inval(avc);
1594 if (avc->linkData && !(avc->states & CCore)) {
1595 afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1596 avc->linkData = NULL;
1598 ReleaseWriteLock(&avc->lock);
1599 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1600 afs_BozonUnlock(&avc->pvnLock, avc);
1605 DECL_PIOCTL(PNewStatMount)
1607 register afs_int32 code;
1608 register struct vcache *tvc;
1609 register struct dcache *tdc;
1610 struct VenusFid tfid;
1612 struct sysname_info sysState;
1613 afs_size_t offset, len;
1615 AFS_STATCNT(PNewStatMount);
1616 if (!avc) return EINVAL;
1617 code = afs_VerifyVCache(avc, areq);
1618 if (code) return code;
1619 if (vType(avc) != VDIR) {
1622 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1623 if (!tdc) return ENOENT;
1624 Check_AtSys(avc, ain, &sysState, areq);
1625 ObtainReadLock(&tdc->lock);
1627 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1628 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1629 ReleaseReadLock(&tdc->lock);
1630 afs_PutDCache(tdc); /* we're done with the data */
1631 bufp = sysState.name;
1635 tfid.Cell = avc->fid.Cell;
1636 tfid.Fid.Volume = avc->fid.Fid.Volume;
1637 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1638 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1640 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1646 if (tvc->mvstat != 1) {
1651 ObtainWriteLock(&tvc->lock,226);
1652 code = afs_HandleLink(tvc, areq);
1654 if (tvc->linkData) {
1655 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1658 /* we have the data */
1659 strcpy(aout, tvc->linkData);
1660 *aoutSize = strlen(tvc->linkData)+1;
1665 ReleaseWriteLock(&tvc->lock);
1668 if (sysState.allocked) osi_FreeLargeSpace(bufp);
1672 DECL_PIOCTL(PGetTokens)
1674 register struct cell *tcell;
1675 register afs_int32 i;
1676 register struct unixuser *tu;
1681 AFS_STATCNT(PGetTokens);
1682 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1683 return EIO; /* Inappropriate ioctl for device */
1685 /* weird interface. If input parameter is present, it is an integer and
1686 we're supposed to return the parm'th tokens for this unix uid.
1687 If not present, we just return tokens for cell 1.
1688 If counter out of bounds, return EDOM.
1689 If no tokens for the particular cell, return ENOTCONN.
1690 Also, if this mysterious parm is present, we return, along with the
1691 tokens, the primary cell indicator (an afs_int32 0) and the cell name
1692 at the end, in that order.
1694 if ((newStyle = (ainSize > 0))) {
1695 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1697 i = UHash(areq->uid);
1698 ObtainReadLock(&afs_xuser);
1699 for(tu = afs_users[i]; tu; tu=tu->next) {
1701 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1702 if (iterator-- == 0) break; /* are we done yet? */
1706 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell)) break;
1711 * No need to hold a read lock on each user entry
1715 ReleaseReadLock(&afs_xuser);
1720 if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1721 tu->states |= (UTokensBad | UNeedsReset);
1722 afs_PutUser(tu, READ_LOCK);
1725 /* use iterator for temp */
1727 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1728 if (iterator < 56) iterator = 56; /* # of bytes we're returning */
1729 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1730 cp += sizeof(afs_int32);
1731 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1733 iterator = sizeof(struct ClearToken);
1734 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1735 cp += sizeof(afs_int32);
1736 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1737 cp += sizeof(struct ClearToken);
1739 /* put out primary id and cell name, too */
1740 iterator = (tu->states & UPrimary ? 1 : 0);
1741 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1742 cp += sizeof(afs_int32);
1743 tcell = afs_GetCell(tu->cell, READ_LOCK);
1745 strcpy(cp, tcell->cellName);
1746 cp += strlen(tcell->cellName)+1;
1747 afs_PutCell(tcell, READ_LOCK);
1751 *aoutSize = cp - aout;
1752 afs_PutUser(tu, READ_LOCK);
1758 register afs_int32 i;
1759 register struct unixuser *tu;
1761 AFS_STATCNT(PUnlog);
1762 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1763 return EIO; /* Inappropriate ioctl for device */
1765 i = UHash(areq->uid);
1766 ObtainWriteLock(&afs_xuser,227);
1767 for(tu=afs_users[i]; tu; tu=tu->next) {
1768 if (tu->uid == areq->uid) {
1770 tu->states &= ~UHasTokens;
1771 /* security is not having to say you're sorry */
1772 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
1774 ReleaseWriteLock(&afs_xuser);
1775 /* We have to drop the lock over the call to afs_ResetUserConns, since
1776 * it obtains the afs_xvcache lock. We could also keep the lock, and
1777 * modify ResetUserConns to take parm saying we obtained the lock
1778 * already, but that is overkill. By keeping the "tu" pointer
1779 * held over the released lock, we guarantee that we won't lose our
1780 * place, and that we'll pass over every user conn that existed when
1781 * we began this call.
1783 afs_ResetUserConns(tu);
1785 ObtainWriteLock(&afs_xuser,228);
1787 /* set the expire times to 0, causes
1788 * afs_GCUserData to remove this entry
1790 tu->ct.EndTimestamp = 0;
1792 #endif /* UKERNEL */
1795 ReleaseWriteLock(&afs_xuser);
1799 DECL_PIOCTL(PMariner)
1801 afs_int32 newHostAddr;
1802 afs_int32 oldHostAddr;
1804 AFS_STATCNT(PMariner);
1806 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost, sizeof(afs_int32));
1808 oldHostAddr = 0xffffffff; /* disabled */
1810 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
1811 if (newHostAddr == 0xffffffff) {
1812 /* disable mariner operations */
1815 else if (newHostAddr) {
1817 afs_marinerHost = newHostAddr;
1819 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
1820 *aoutSize = sizeof(afs_int32);
1824 DECL_PIOCTL(PCheckServers)
1826 register char *cp = 0;
1828 register struct server *ts;
1829 afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1831 struct chservinfo *pcheck;
1833 AFS_STATCNT(PCheckServers);
1835 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1836 return EIO; /* Inappropriate ioctl for device */
1838 if (*lp == 0x12345678) { /* For afs3.3 version */
1839 pcheck=(struct chservinfo *)ain;
1840 if (pcheck->tinterval >= 0) {
1842 memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
1843 *aoutSize = sizeof(afs_int32);
1844 if (pcheck->tinterval > 0) {
1845 if (!afs_osi_suser(*acred))
1847 PROBE_INTERVAL=pcheck->tinterval;
1853 temp=pcheck->tflags;
1854 cp = pcheck->tbuffer;
1855 } else { /* For pre afs3.3 versions */
1856 memcpy((char *)&temp, ain, sizeof(afs_int32));
1857 cp = ain+sizeof(afs_int32);
1858 if (ainSize > sizeof(afs_int32))
1863 * 1: fast check, don't contact servers.
1864 * 2: local cell only.
1867 /* have cell name, too */
1868 cellp = afs_GetCellByName(cp, READ_LOCK);
1869 if (!cellp) return ENOENT;
1872 if (!cellp && (temp & 2)) {
1873 /* use local cell */
1874 cellp = afs_GetPrimaryCell(READ_LOCK);
1876 if (!(temp & 1)) { /* if not fast, call server checker routine */
1877 afs_CheckServers(1, cellp); /* check down servers */
1878 afs_CheckServers(0, cellp); /* check up servers */
1880 /* now return the current down server list */
1882 ObtainReadLock(&afs_xserver);
1883 for(i=0;i<NSERVERS;i++) {
1884 for(ts = afs_servers[i]; ts; ts=ts->next) {
1885 if (cellp && ts->cell != cellp) continue; /* cell spec'd and wrong */
1886 if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1887 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
1888 cp += sizeof(afs_int32);
1892 ReleaseReadLock(&afs_xserver);
1893 if (cellp) afs_PutCell(cellp, READ_LOCK);
1894 *aoutSize = cp - aout;
1898 DECL_PIOCTL(PCheckVolNames)
1900 AFS_STATCNT(PCheckVolNames);
1901 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1902 return EIO; /* Inappropriate ioctl for device */
1904 afs_CheckRootVolume();
1905 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
1906 AFS_VOLCHECK_EXPIRED |
1908 AFS_VOLCHECK_MTPTS);
1912 DECL_PIOCTL(PCheckAuth)
1917 struct unixuser *tu;
1920 AFS_STATCNT(PCheckAuth);
1921 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
1922 return EIO; /* Inappropriate ioctl for device */
1925 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
1926 if (!tu) retValue = EACCES;
1928 /* we have a user */
1929 ObtainReadLock(&afs_xsrvAddr);
1930 ObtainReadLock(&afs_xconn);
1932 /* any tokens set? */
1933 if ((tu->states & UHasTokens) == 0) retValue = EACCES;
1934 /* all connections in cell 1 working? */
1935 for(i=0;i<NSERVERS;i++) {
1936 for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
1937 for (tc = sa->conns; tc; tc=tc->next) {
1938 if (tc->user == tu && (tu->states & UTokensBad))
1943 ReleaseReadLock(&afs_xsrvAddr);
1944 ReleaseReadLock(&afs_xconn);
1945 afs_PutUser(tu, READ_LOCK);
1947 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
1948 *aoutSize = sizeof(afs_int32);
1952 static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow, struct AFS_UCRED *acred)
1955 register afs_int32 code;
1956 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1962 AFS_STATCNT(Prefetch);
1963 if (!apath) return EINVAL;
1964 tp = osi_AllocLargeSpace(1024);
1965 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
1967 osi_FreeLargeSpace(tp);
1970 if (afs_BBusy()) { /* do this as late as possible */
1971 osi_FreeLargeSpace(tp);
1972 return EWOULDBLOCK; /* pretty close */
1974 afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred,
1975 (afs_size_t) 0, (afs_size_t) 0, tp);
1979 DECL_PIOCTL(PFindVolume)
1981 register struct volume *tvp;
1982 register struct server *ts;
1983 register afs_int32 i;
1986 AFS_STATCNT(PFindVolume);
1987 if (!avc) return EINVAL;
1988 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1991 for(i=0;i<MAXHOSTS;i++) {
1992 ts = tvp->serverHost[i];
1994 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
1995 cp += sizeof(afs_int32);
1998 /* still room for terminating NULL, add it on */
1999 ainSize = 0; /* reuse vbl */
2000 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2001 cp += sizeof(afs_int32);
2003 *aoutSize = cp - aout;
2004 afs_PutVolume(tvp, READ_LOCK);
2010 DECL_PIOCTL(PViceAccess)
2012 register afs_int32 code;
2015 AFS_STATCNT(PViceAccess);
2016 if (!avc) return EINVAL;
2017 code = afs_VerifyVCache(avc, areq);
2018 if (code) return code;
2019 memcpy((char *)&temp, ain, sizeof(afs_int32));
2020 code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2025 DECL_PIOCTL(PSetCacheSize)
2030 AFS_STATCNT(PSetCacheSize);
2031 if (!afs_osi_suser(*acred))
2033 /* too many things are setup initially in mem cache version */
2034 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2035 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2036 if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2038 if (newValue < afs_min_cache)
2039 afs_cacheBlocks = afs_min_cache;
2041 afs_cacheBlocks = newValue;
2043 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2044 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2045 afs_MaybeWakeupTruncateDaemon();
2046 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2047 afs_osi_Wait(1000, 0, 0);
2048 afs_MaybeWakeupTruncateDaemon();
2053 #define MAXGCSTATS 16
2054 DECL_PIOCTL(PGetCacheSize)
2056 afs_int32 results[MAXGCSTATS];
2058 AFS_STATCNT(PGetCacheSize);
2059 memset((char *)results, 0, sizeof(results));
2060 results[0] = afs_cacheBlocks;
2061 results[1] = afs_blocksUsed;
2062 memcpy(aout, (char *)results, sizeof(results));
2063 *aoutSize = sizeof(results);
2067 DECL_PIOCTL(PRemoveCallBack)
2069 register struct conn *tc;
2070 register afs_int32 code = 0;
2071 struct AFSCallBack CallBacks_Array[1];
2072 struct AFSCBFids theFids;
2073 struct AFSCBs theCBs;
2076 AFS_STATCNT(PRemoveCallBack);
2077 if (!avc) return EINVAL;
2078 if (avc->states & CRO) return 0; /* read-only-ness can't change */
2079 ObtainWriteLock(&avc->lock,229);
2080 theFids.AFSCBFids_len = 1;
2081 theCBs.AFSCBs_len = 1;
2082 theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2083 theCBs.AFSCBs_val = CallBacks_Array;
2084 CallBacks_Array[0].CallBackType = CB_DROPPED;
2085 if (avc->callback) {
2087 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2089 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2091 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2095 /* don't set code on failure since we wouldn't use it */
2097 (afs_Analyze(tc, code, &avc->fid, areq,
2098 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2099 SHARED_LOCK, NULL));
2101 ObtainWriteLock(&afs_xcbhash, 457);
2102 afs_DequeueCallback(avc);
2104 avc->states &= ~(CStatd | CUnique);
2105 ReleaseWriteLock(&afs_xcbhash);
2106 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2107 osi_dnlc_purgedp(avc);
2109 ReleaseWriteLock(&avc->lock);
2113 DECL_PIOCTL(PNewCell)
2115 /* create a new cell */
2116 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2117 char *newcell=0, *linkedcell=0, *tp= ain;
2118 register afs_int32 code, linkedstate=0, ls;
2119 u_short fsport = 0, vlport = 0;
2122 AFS_STATCNT(PNewCell);
2123 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2124 return EIO; /* Inappropriate ioctl for device */
2126 if (!afs_osi_suser(*acred))
2129 memcpy((char *)&magic, tp, sizeof(afs_int32));
2130 tp += sizeof(afs_int32);
2131 if (magic != 0x12345678)
2134 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2135 * server addresses while the 3.5 fs newcell command passes
2136 * MAXHOSTS. To figure out which is which, check if the cellname
2139 newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2140 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2142 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2143 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2144 tp += (scount * sizeof(afs_int32));
2146 lp = (afs_int32 *)tp;
2149 if (fsport < 1024) fsport = 0; /* Privileged ports not allowed */
2150 if (vlport < 1024) vlport = 0; /* Privileged ports not allowed */
2151 tp += (3 * sizeof(afs_int32));
2153 if ((ls = *lp) & 1) {
2154 linkedcell = tp + strlen(newcell)+1;
2155 linkedstate |= CLinkedCell;
2158 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2159 code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2164 DECL_PIOCTL(PNewAlias)
2166 /* create a new cell alias */
2168 register afs_int32 code;
2169 char *realName, *aliasName;
2171 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2172 return EIO; /* Inappropriate ioctl for device */
2174 if (!afs_osi_suser(*acred))
2178 tp += strlen(aliasName) + 1;
2181 code = afs_NewCellAlias(aliasName, realName);
2186 DECL_PIOCTL(PListCells)
2188 afs_int32 whichCell;
2189 register struct cell *tcell=0;
2190 register afs_int32 i;
2191 register char *cp, *tp = ain;
2193 AFS_STATCNT(PListCells);
2194 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2195 return EIO; /* Inappropriate ioctl for device */
2197 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2198 tp += sizeof(afs_int32);
2199 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2202 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2203 for(i=0;i<MAXCELLHOSTS;i++) {
2204 if (tcell->cellHosts[i] == 0) break;
2205 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip, sizeof(afs_int32));
2206 cp += sizeof(afs_int32);
2208 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2209 strcpy(cp, tcell->cellName);
2210 cp += strlen(tcell->cellName)+1;
2211 *aoutSize = cp - aout;
2212 afs_PutCell(tcell, READ_LOCK);
2214 if (tcell) return 0;
2218 DECL_PIOCTL(PListAliases)
2220 afs_int32 whichAlias;
2221 register struct cell_alias *tcalias=0;
2222 register char *cp, *tp = ain;
2224 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2225 return EIO; /* Inappropriate ioctl for device */
2226 if (ainSize < sizeof(afs_int32))
2229 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2230 tp += sizeof(afs_int32);
2232 tcalias = afs_GetCellAlias(whichAlias);
2235 strcpy(cp, tcalias->alias);
2236 cp += strlen(tcalias->alias)+1;
2237 strcpy(cp, tcalias->cell);
2238 cp += strlen(tcalias->cell)+1;
2239 *aoutSize = cp - aout;
2240 afs_PutCellAlias(tcalias);
2242 if (tcalias) return 0;
2246 DECL_PIOCTL(PRemoveMount)
2248 register afs_int32 code;
2250 struct sysname_info sysState;
2251 afs_size_t offset, len;
2252 register struct conn *tc;
2253 register struct dcache *tdc;
2254 register struct vcache *tvc;
2255 struct AFSFetchStatus OutDirStatus;
2256 struct VenusFid tfid;
2257 struct AFSVolSync tsync;
2261 /* "ain" is the name of the file in this dir to remove */
2263 AFS_STATCNT(PRemoveMount);
2264 if (!avc) return EINVAL;
2265 code = afs_VerifyVCache(avc, areq);
2266 if (code) return code;
2267 if (vType(avc) != VDIR) return ENOTDIR;
2269 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2270 if (!tdc) return ENOENT;
2271 Check_AtSys(avc, ain, &sysState, areq);
2272 ObtainReadLock(&tdc->lock);
2274 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2275 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2276 ReleaseReadLock(&tdc->lock);
2277 bufp = sysState.name;
2282 tfid.Cell = avc->fid.Cell;
2283 tfid.Fid.Volume = avc->fid.Fid.Volume;
2284 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2285 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2287 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2294 if (tvc->mvstat != 1) {
2300 ObtainWriteLock(&tvc->lock,230);
2301 code = afs_HandleLink(tvc, areq);
2303 if (tvc->linkData) {
2304 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2309 ReleaseWriteLock(&tvc->lock);
2310 osi_dnlc_purgedp(tvc);
2316 ObtainWriteLock(&avc->lock,231);
2317 osi_dnlc_remove(avc, bufp, tvc);
2319 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2321 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2323 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2324 bufp, &OutDirStatus, &tsync);
2330 (afs_Analyze(tc, code, &avc->fid, areq,
2331 AFS_STATS_FS_RPCIDX_REMOVEFILE,
2332 SHARED_LOCK, NULL));
2335 if (tdc) afs_PutDCache(tdc);
2336 ReleaseWriteLock(&avc->lock);
2340 /* we have the thing in the cache */
2341 ObtainWriteLock(&tdc->lock, 661);
2342 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2343 /* we can do it locally */
2344 code = afs_dir_Delete(&tdc->f.inode, bufp);
2346 ZapDCE(tdc); /* surprise error -- invalid value */
2347 DZap(&tdc->f.inode);
2350 ReleaseWriteLock(&tdc->lock);
2351 afs_PutDCache(tdc); /* drop ref count */
2353 avc->states &= ~CUnique; /* For the dfs xlator */
2354 ReleaseWriteLock(&avc->lock);
2357 if (sysState.allocked) osi_FreeLargeSpace(bufp);
2361 DECL_PIOCTL(PVenusLogging)
2363 return EINVAL; /* OBSOLETE */
2366 DECL_PIOCTL(PGetCellStatus)
2368 register struct cell *tcell;
2371 AFS_STATCNT(PGetCellStatus);
2372 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2373 return EIO; /* Inappropriate ioctl for device */
2375 tcell = afs_GetCellByName(ain, READ_LOCK);
2376 if (!tcell) return ENOENT;
2377 temp = tcell->states;
2378 afs_PutCell(tcell, READ_LOCK);
2379 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2380 *aoutSize = sizeof(afs_int32);
2384 DECL_PIOCTL(PSetCellStatus)
2386 register struct cell *tcell;
2389 if (!afs_osi_suser(*acred))
2391 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2392 return EIO; /* Inappropriate ioctl for device */
2394 tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2395 if (!tcell) return ENOENT;
2396 memcpy((char *)&temp, ain, sizeof(afs_int32));
2398 tcell->states |= CNoSUID;
2400 tcell->states &= ~CNoSUID;
2401 afs_PutCell(tcell, WRITE_LOCK);
2405 DECL_PIOCTL(PFlushVolumeData)
2407 register afs_int32 i;
2408 register struct dcache *tdc;
2409 register struct vcache *tvc;
2410 register struct volume *tv;
2411 afs_int32 cell, volume;
2413 AFS_STATCNT(PFlushVolumeData);
2416 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2417 return EIO; /* Inappropriate ioctl for device */
2419 volume = avc->fid.Fid.Volume; /* who to zap */
2420 cell = avc->fid.Cell;
2423 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2424 * the vcaches associated with the volume.
2426 ObtainReadLock(&afs_xvcache);
2427 for(i = 0; i < VCSIZE; i++) {
2428 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2429 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2430 #if defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2431 VN_HOLD(AFSTOV(tvc));
2433 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2439 ReleaseReadLock(&afs_xvcache);
2440 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2441 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
2443 ObtainWriteLock(&tvc->lock,232);
2445 ObtainWriteLock(&afs_xcbhash, 458);
2446 afs_DequeueCallback(tvc);
2447 tvc->states &= ~(CStatd | CDirty);
2448 ReleaseWriteLock(&afs_xcbhash);
2449 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2450 osi_dnlc_purgedp(tvc);
2451 afs_TryToSmush(tvc, *acred, 1);
2452 ReleaseWriteLock(&tvc->lock);
2453 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2454 afs_BozonUnlock(&tvc->pvnLock, tvc);
2456 ObtainReadLock(&afs_xvcache);
2457 /* our tvc ptr is still good until now */
2462 ReleaseReadLock(&afs_xvcache);
2465 MObtainWriteLock(&afs_xdcache,328); /* needed if you're going to flush any stuff */
2466 for(i=0;i<afs_cacheFiles;i++) {
2467 if (!(afs_indexFlags[i] & IFEverUsed)) continue; /* never had any data */
2468 tdc = afs_GetDSlot(i, NULL);
2469 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
2470 ReleaseReadLock(&tdc->tlock);
2471 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2472 if (! (afs_indexFlags[i] & IFDataMod)) {
2473 /* if the file is modified, but has a ref cnt of only 1, then
2474 someone probably has the file open and is writing into it.
2475 Better to skip flushing such a file, it will be brought back
2476 immediately on the next write anyway.
2478 If we *must* flush, then this code has to be rearranged to call
2479 afs_storeAllSegments() first */
2480 afs_FlushDCache(tdc);
2484 ReleaseReadLock(&tdc->tlock);
2486 afs_PutDCache(tdc); /* bumped by getdslot */
2488 MReleaseWriteLock(&afs_xdcache);
2490 ObtainReadLock(&afs_xvolume);
2491 for (i=0;i<NVOLS;i++) {
2492 for (tv = afs_volumes[i]; tv; tv=tv->next) {
2493 if (tv->volume == volume) {
2494 afs_ResetVolumeInfo(tv);
2499 ReleaseReadLock(&afs_xvolume);
2501 /* probably, a user is doing this, probably, because things are screwed up.
2502 * maybe it's the dnlc's fault? */
2509 DECL_PIOCTL(PGetVnodeXStatus)
2511 register afs_int32 code;
2512 struct vcxstat stat;
2515 /* AFS_STATCNT(PGetVnodeXStatus); */
2516 if (!avc) return EINVAL;
2517 code = afs_VerifyVCache(avc, areq);
2518 if (code) return code;
2519 if (vType(avc) == VDIR)
2520 mode = PRSFS_LOOKUP;
2523 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2525 stat.fid = avc->fid;
2526 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2527 stat.lock = avc->lock;
2528 stat.parentVnode = avc->parentVnode;
2529 stat.parentUnique = avc->parentUnique;
2530 hset(stat.flushDV, avc->flushDV);
2531 hset(stat.mapDV, avc->mapDV);
2532 stat.truncPos = avc->truncPos;
2533 { /* just grab the first two - won't break anything... */
2534 struct axscache *ac;
2536 for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2537 stat.randomUid[i] = ac->uid;
2538 stat.randomAccess[i] = ac->axess;
2541 stat.callback = afs_data_pointer_to_int32(avc->callback);
2542 stat.cbExpires = avc->cbExpires;
2543 stat.anyAccess = avc->anyAccess;
2544 stat.opens = avc->opens;
2545 stat.execsOrWriters = avc->execsOrWriters;
2546 stat.flockCount = avc->flockCount;
2547 stat.mvstat = avc->mvstat;
2548 stat.states = avc->states;
2549 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
2550 *aoutSize = sizeof(struct vcxstat);
2555 /* We require root for local sysname changes, but not for remote */
2556 /* (since we don't really believe remote uids anyway) */
2557 /* outname[] shouldn't really be needed- this is left as an excercise */
2558 /* for the reader. */
2559 DECL_PIOCTL(PSetSysName)
2561 char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2562 int setsysname, foundname=0;
2563 register struct afs_exporter *exporter;
2564 register struct unixuser *au;
2565 register afs_int32 pag, error;
2569 AFS_STATCNT(PSetSysName);
2570 if (!afs_globalVFS) {
2571 /* Afsd is NOT running; disable it */
2572 #if defined(KERNEL_HAVE_UERROR)
2573 return (setuerror(EINVAL), EINVAL);
2578 memset(inname, 0, MAXSYSNAME);
2579 memcpy((char *)&setsysname, ain, sizeof(afs_int32));
2580 ain += sizeof(afs_int32);
2584 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2586 for(cp = ain,count = 0;count < setsysname;count++) {
2587 /* won't go past end of ain since maxsysname*num < ain length */
2589 if (t >= MAXSYSNAME || t <= 0)
2591 /* check for names that can shoot us in the foot */
2592 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2598 /* inname gets first entry in case we're being a translater */
2600 memcpy(inname, ain, t+1); /* include terminating null */
2603 if ((*acred)->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2604 pag = PagInCred(*acred);
2606 return EINVAL; /* Better than panicing */
2608 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2609 return EINVAL; /* Better than panicing */
2611 if (!(exporter = au->exporter)) {
2612 afs_PutUser(au, READ_LOCK);
2613 return EINVAL; /* Better than panicing */
2615 error = EXP_SYSNAME(exporter, (setsysname? inname : NULL), outname);
2617 if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2619 afs_PutUser(au, READ_LOCK);
2624 afs_PutUser(au, READ_LOCK);
2627 /* Not xlating, so local case */
2628 if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2629 if (!setsysname) { /* user just wants the info */
2630 strcpy(outname, afs_sysname);
2631 foundname = afs_sysnamecount;
2632 } else { /* Local guy; only root can change sysname */
2633 if (!afs_osi_suser(*acred))
2636 /* clear @sys entries from the dnlc, once afs_lookup can
2637 do lookups of @sys entries and thinks it can trust them */
2638 /* privs ok, store the entry, ... */
2639 strcpy(afs_sysname, inname);
2640 if (setsysname > 1) { /* ... or list */
2642 for(count=1; count < setsysname;++count) {
2643 if (!afs_sysnamelist[count])
2644 osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2646 memcpy(afs_sysnamelist[count], cp, t+1); /* include null */
2650 afs_sysnamecount = setsysname;
2654 cp = aout; /* not changing so report back the count and ... */
2655 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
2656 cp += sizeof(afs_int32);
2658 strcpy(cp, outname); /* ... the entry, ... */
2659 cp += strlen(outname)+1;
2660 for(count=1; count < foundname; ++count) { /* ... or list. */
2661 /* Note: we don't support @sys lists for exporters */
2662 if (!afs_sysnamelist[count])
2663 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2664 t = strlen(afs_sysnamelist[count]);
2665 if (t >= MAXSYSNAME)
2666 osi_Panic("PSetSysName: sysname entry garbled\n");
2667 strcpy(cp, afs_sysnamelist[count]);
2671 *aoutSize = cp - aout;
2676 /* sequential search through the list of touched cells is not a good
2677 * long-term solution here. For small n, though, it should be just
2678 * fine. Should consider special-casing the local cell for large n.
2679 * Likewise for PSetSPrefs.
2681 * s - number of ids in array l[] -- NOT index of last id
2682 * l - array of cell ids which have volumes that need to be sorted
2683 * vlonly - sort vl servers or file servers?
2685 static void *ReSortCells_cb(struct cell *cell, void *arg)
2687 afs_int32 *p = (afs_int32 *) arg;
2688 afs_int32 *l = p + 1;
2691 for (i=0; i<s; i++) {
2692 if (l[i] == cell->cellNum) {
2693 ObtainWriteLock(&cell->lock, 690);
2694 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
2695 ReleaseWriteLock(&cell->lock);
2702 static void ReSortCells(int s, afs_int32 *l, int vlonly)
2710 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s+1));
2712 memcpy(p+1, l, s * sizeof(afs_int32));
2713 afs_TraverseCells(&ReSortCells_cb, p);
2714 afs_osi_Free(p, sizeof(afs_int32) * (s+1));
2718 ObtainReadLock(&afs_xvolume);
2719 for (i= 0; i< NVOLS; i++) {
2720 for (j=afs_volumes[i];j;j=j->next) {
2722 if (j->cell == l[k]) {
2723 ObtainWriteLock(&j->lock,233);
2724 afs_SortServers(j->serverHost, MAXHOSTS);
2725 ReleaseWriteLock(&j->lock);
2730 ReleaseReadLock(&afs_xvolume);
2734 static int debugsetsp = 0;
2735 static int afs_setsprefs(sp, num, vlonly)
2738 unsigned int vlonly;
2741 int i,j,k,matches,touchedSize;
2742 struct server *srvr = NULL;
2743 afs_int32 touched[34];
2747 for (k=0; k < num; sp++, k++) {
2749 printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2752 ObtainReadLock(&afs_xserver);
2754 i = SHash(sp->host.s_addr);
2755 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2756 if (sa->sa_ip == sp->host.s_addr) {
2758 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
2759 || (sa->sa_portal == AFS_FSPORT);
2760 if ((!vlonly && isfs) || (vlonly && !isfs)) {
2767 if (sa && matches) { /* found one! */
2769 printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
2771 sa->sa_iprank = sp->rank + afs_randomMod15();
2772 afs_SortOneServer(sa->server);
2775 /* if we don't know yet what cell it's in, this is moot */
2776 for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cellNum; j--)
2777 /* is it in our list of touched cells ? */ ;
2778 if (j < 0) { /* no, it's not */
2779 touched[touchedSize++] = srvr->cell->cellNum;
2780 if (touchedSize >= 32) { /* watch for ovrflow */
2781 ReleaseReadLock(&afs_xserver);
2782 ReSortCells(touchedSize, touched, vlonly);
2784 ObtainReadLock(&afs_xserver);
2790 ReleaseReadLock(&afs_xserver);
2791 /* if we didn't find one, start to create one. */
2792 /* Note that it doesn't have a cell yet... */
2794 afs_uint32 temp = sp->host.s_addr;
2795 srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
2796 WRITE_LOCK, (afsUUID *)0,0);
2797 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
2798 afs_PutServer(srvr, WRITE_LOCK);
2800 } /* for all cited preferences */
2802 ReSortCells(touchedSize, touched, vlonly);
2806 /* Note that this may only be performed by the local root user.
2808 DECL_PIOCTL(PSetSPrefs)
2810 struct setspref *ssp;
2811 AFS_STATCNT(PSetSPrefs);
2813 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2814 return EIO; /* Inappropriate ioctl for device */
2816 if (!afs_osi_suser(*acred))
2819 if (ainSize < sizeof(struct setspref))
2822 ssp = (struct setspref *)ain;
2823 if (ainSize < sizeof(struct spref)*ssp->num_servers)
2826 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
2827 (ssp->flags & DBservers));
2831 DECL_PIOCTL(PSetSPrefs33)
2834 AFS_STATCNT(PSetSPrefs);
2835 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2836 return EIO; /* Inappropriate ioctl for device */
2839 if (!afs_osi_suser(*acred))
2842 sp = (struct spref *)ain;
2843 afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
2847 /* some notes on the following code...
2848 * in the hash table of server structs, all servers with the same IP address
2849 * will be on the same overflow chain.
2850 * This could be sped slightly in some circumstances by having it cache the
2851 * immediately previous slot in the hash table and some supporting information
2852 * Only reports file servers now.
2854 DECL_PIOCTL(PGetSPrefs)
2856 struct sprefrequest *spin; /* input */
2857 struct sprefinfo *spout; /* output */
2858 struct spref *srvout; /* one output component */
2859 int i,j; /* counters for hash table traversal */
2860 struct server *srvr; /* one of CM's server structs */
2862 int vlonly; /* just return vlservers ? */
2865 AFS_STATCNT(PGetSPrefs);
2866 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
2867 return EIO; /* Inappropriate ioctl for device */
2870 if (ainSize < sizeof (struct sprefrequest_33)) {
2874 spin = ((struct sprefrequest *) ain);
2877 if (ainSize > sizeof (struct sprefrequest_33)) {
2878 vlonly = (spin->flags & DBservers);
2882 /* struct sprefinfo includes 1 server struct... that size gets added
2883 * in during the loop that follows.
2885 *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
2886 spout = (struct sprefinfo *) aout;
2887 spout->next_offset = spin->offset;
2888 spout->num_servers = 0;
2889 srvout = spout->servers;
2891 ObtainReadLock(&afs_xserver);
2892 for (i=0, j=0; j < NSERVERS; j++) { /* sift through hash table */
2893 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
2894 if (spin->offset > (unsigned short)i) {
2895 continue; /* catch up to where we left off */
2897 spout->next_offset++;
2900 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
2901 || (sa->sa_portal == AFS_FSPORT);
2903 if ((vlonly && isfs) || (!vlonly && !isfs)) {
2904 /* only report ranks for vl servers */
2908 srvout->host.s_addr = sa->sa_ip;
2909 srvout->rank = sa->sa_iprank;
2910 *aoutSize += sizeof(struct spref);
2911 spout->num_servers++;
2914 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
2915 ReleaseReadLock(&afs_xserver); /* no more room! */
2920 ReleaseReadLock(&afs_xserver);
2922 spout->next_offset = 0; /* start over from the beginning next time */
2926 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
2927 int afs_NFSRootOnly = 1;
2928 DECL_PIOCTL(PExportAfs)
2930 afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
2931 register struct afs_exporter *exporter;
2933 AFS_STATCNT(PExportAfs);
2934 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
2935 type = handleValue >> 24;
2940 exporter = exporter_find(type);
2942 export = handleValue & 3;
2943 changestate = handleValue & 0xff;
2944 smounts = (handleValue >> 2) & 3;
2945 pwsync = (handleValue >> 4) & 3;
2946 convmode = (handleValue >> 6) & 3;
2948 changestate = (handleValue >> 16) & 0x1;
2949 convmode = (handleValue >> 16) & 0x2;
2950 pwsync = (handleValue >> 16) & 0x4;
2951 smounts = (handleValue >> 16) & 0x8;
2952 export = handleValue & 0xff;
2955 /* Failed finding desired exporter; */
2959 handleValue = exporter->exp_states;
2960 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
2961 *aoutSize = sizeof(afs_int32);
2963 if (!afs_osi_suser(*acred))
2964 return EACCES; /* Only superuser can do this */
2968 exporter->exp_states |= EXP_EXPORTED;
2970 exporter->exp_states &= ~EXP_EXPORTED;
2974 exporter->exp_states |= EXP_UNIXMODE;
2976 exporter->exp_states &= ~EXP_UNIXMODE;
2980 exporter->exp_states |= EXP_PWSYNC;
2982 exporter->exp_states &= ~EXP_PWSYNC;
2986 afs_NFSRootOnly = 0;
2987 exporter->exp_states |= EXP_SUBMOUNTS;
2989 afs_NFSRootOnly = 1;
2990 exporter->exp_states &= ~EXP_SUBMOUNTS;
2993 handleValue = exporter->exp_states;
2994 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
2995 *aoutSize = sizeof(afs_int32);
2998 exporter->exp_states |= EXP_EXPORTED;
3000 exporter->exp_states &= ~EXP_EXPORTED;
3002 exporter->exp_states |= EXP_UNIXMODE;
3004 exporter->exp_states &= ~EXP_UNIXMODE;
3006 exporter->exp_states |= EXP_PWSYNC;
3008 exporter->exp_states &= ~EXP_PWSYNC;
3010 afs_NFSRootOnly = 0;
3011 exporter->exp_states |= EXP_SUBMOUNTS;
3013 afs_NFSRootOnly = 1;
3014 exporter->exp_states &= ~EXP_SUBMOUNTS;
3024 struct gaginfo *gagflags;
3026 if (!afs_osi_suser(*acred))
3029 gagflags = (struct gaginfo *) ain;
3030 afs_showflags = gagflags->showflags;
3036 DECL_PIOCTL(PTwiddleRx)
3038 struct rxparams *rxp;
3040 if (!afs_osi_suser(*acred))
3043 rxp = (struct rxparams *) ain;
3045 if (rxp->rx_initReceiveWindow)
3046 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3047 if (rxp->rx_maxReceiveWindow)
3048 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3049 if (rxp->rx_initSendWindow)
3050 rx_initSendWindow = rxp->rx_initSendWindow;
3051 if (rxp->rx_maxSendWindow)
3052 rx_maxSendWindow = rxp->rx_maxSendWindow;
3053 if (rxp->rxi_nSendFrags)
3054 rxi_nSendFrags = rxp->rxi_nSendFrags;
3055 if (rxp->rxi_nRecvFrags)
3056 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3057 if (rxp->rxi_OrphanFragSize)
3058 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3059 if (rxp->rx_maxReceiveSize)
3061 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3062 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3064 if (rxp->rx_MyMaxSendSize)
3065 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3070 DECL_PIOCTL(PGetInitParams)
3072 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3075 memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3076 *aoutSize = sizeof(struct cm_initparams);
3080 #ifdef AFS_SGI65_ENV
3081 /* They took crget() from us, so fake it. */
3082 static cred_t *crget(void)
3085 cr = crdup(get_current_cred());
3086 memset((char*)cr, 0, sizeof(cred_t));
3087 #if CELL || CELL_PREPARE
3094 DECL_PIOCTL(PGetRxkcrypt)
3096 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3097 *aoutSize=sizeof(afs_int32);
3101 DECL_PIOCTL(PSetRxkcrypt)
3105 if (!afs_osi_suser(*acred))
3107 if (ainSize != sizeof(afs_int32) || ain == NULL)
3109 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3110 /* if new mappings added later this will need to be changed */
3111 if (tmpval != 0 && tmpval != 1)
3117 #ifdef AFS_NEED_CLIENTCONTEXT
3119 * Create new credentials to correspond to a remote user with given
3120 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3121 * provide pioctl (and other) services to foreign clients (i.e. nfs
3122 * clients) by using this call to `become' the client.
3125 #define PIOCTL_HEADER 6
3126 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3129 afs_uint32 hostaddr;
3130 afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3131 struct afs_exporter *exporter, *outexporter;
3132 struct AFS_UCRED *newcred;
3133 struct unixuser *au;
3135 #if defined(AFS_SGIMP_ENV)
3136 osi_Assert(ISAFS_GLOCK());
3138 AFS_STATCNT(HandleClientContext);
3139 if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) {
3140 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3141 return EINVAL; /* Too small to be good */
3143 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3144 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3146 osi_FreeLargeSpace(inData);
3150 /* Extract information for remote user */
3151 hostaddr = *((afs_uint32 *)ain);
3152 ain += sizeof(hostaddr);
3153 uid = *((afs_uint32 *)ain);
3155 g0 = *((afs_uint32 *)ain);
3157 g1 = *((afs_uint32 *)ain);
3159 *com = *((afs_uint32 *)ain);
3160 ain += sizeof(afs_int32);
3161 exporter_type = *((afs_uint32 *)ain); /* In case we support more than NFS */
3164 * Of course, one must be root for most of these functions, but
3165 * we'll allow (for knfs) you to set things if the pag is 0 and
3166 * you're setting tokens or unlogging.
3169 if (!afs_osi_suser(credp)) {
3170 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
3171 /* Since SGI's suser() returns explicit failure after the call.. */
3174 /* check for acceptable opcodes for normal folks, which are, so far,
3175 * set tokens and unlog.
3177 if (i != 9 && i != 3 && i != 38 && i != 8) {
3178 osi_FreeLargeSpace(inData);
3183 ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3184 ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3185 osi_FreeLargeSpace(inData);
3188 * We map uid 0 to nobody to match the mapping that the nfs
3189 * server does and to ensure that the suser() calls in the afs
3190 * code fails for remote client roots.
3192 uid = afs_nobody; /* NFS_NOBODY == -2 */
3195 #ifdef AFS_AIX41_ENV
3198 newcred->cr_gid = RMTUSER_REQ;
3199 #ifdef AFS_AIX51_ENV
3200 newcred->cr_groupset.gs_union.un_groups[0] = g0;
3201 newcred->cr_groupset.gs_union.un_groups[1] = g1;
3203 newcred->cr_groups[0] = g0;
3204 newcred->cr_groups[1] = g1;
3207 newcred->cr_ngrps = 2;
3209 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3210 newcred->cr_ngroups = 2;
3212 for (i=2; i < NGROUPS; i++)
3213 newcred->cr_groups[i] = NOGROUP;
3216 #if !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3217 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
3219 if (!(exporter = exporter_find(exporter_type))) {
3220 /* Exporter wasn't initialized or an invalid exporter type */
3224 if (exporter->exp_states & EXP_PWSYNC) {
3225 if (uid != credp->cr_uid) {
3227 return ENOEXEC; /* XXX Find a better errno XXX */
3230 newcred->cr_uid = uid; /* Only temporary */
3231 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3232 /* The client's pag is the only unique identifier for it */
3233 newcred->cr_uid = pag;
3235 if (!code && *com == PSETPAG) {
3236 /* Special case for 'setpag' */
3237 afs_uint32 pagvalue = genpag();
3239 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3241 * Note that we leave the 'outexporter' struct held so it won't
3244 au->exporter = outexporter;
3245 if (ablob->out_size >= 4) {
3246 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3248 afs_PutUser(au, WRITE_LOCK);
3249 if (code) return code;
3250 return PSETPAG; /* Special return for setpag */
3252 EXP_RELE(outexporter);
3256 #endif /* AFS_NEED_CLIENTCONTEXT */
3258 /* get all interface addresses of this client */
3260 DECL_PIOCTL(PGetCPrefs)
3262 struct sprefrequest *spin; /* input */
3263 struct sprefinfo *spout; /* output */
3264 struct spref *srvout; /* one output component */
3268 AFS_STATCNT(PGetCPrefs);
3269 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
3270 return EIO; /* Inappropriate ioctl for device */
3272 if ( ainSize < sizeof (struct sprefrequest ))
3275 spin = (struct sprefrequest *) ain;
3276 spout = (struct sprefinfo *) aout;
3278 maxNumber = spin->num_servers; /* max addrs this time */
3279 srvout = spout->servers;
3281 ObtainReadLock(&afs_xinterface);
3283 /* copy out the client interface information from the
3284 ** kernel data structure "interface" to the output buffer
3286 for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3287 && ( j< maxNumber) ; i++, j++, srvout++)
3288 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3290 spout->num_servers = j;
3291 *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3293 if ( i >= afs_cb_interface.numberOfInterfaces )
3294 spout->next_offset = 0; /* start from beginning again */
3296 spout->next_offset = spin->offset + j;
3298 ReleaseReadLock(&afs_xinterface);
3302 DECL_PIOCTL(PSetCPrefs)
3304 struct setspref *sin;
3307 AFS_STATCNT(PSetCPrefs);
3308 if ( !afs_resourceinit_flag ) /* afs daemons haven't started yet */
3309 return EIO; /* Inappropriate ioctl for device */
3311 sin = (struct setspref *)ain;
3313 if ( ainSize < sizeof(struct setspref) )
3315 #if 0 /* num_servers is unsigned */
3316 if ( sin->num_servers < 0 )
3319 if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3322 ObtainWriteLock(&afs_xinterface, 412);
3323 afs_cb_interface.numberOfInterfaces = sin->num_servers;
3324 for ( i=0; (unsigned short)i < sin->num_servers; i++)
3325 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3327 ReleaseWriteLock(&afs_xinterface);
3331 DECL_PIOCTL(PFlushMount)
3333 register afs_int32 code;
3334 register struct vcache *tvc;
3335 register struct dcache *tdc;
3336 struct VenusFid tfid;
3338 struct sysname_info sysState;
3339 afs_size_t offset, len;
3341 AFS_STATCNT(PFlushMount);
3342 if (!avc) return EINVAL;
3343 code = afs_VerifyVCache(avc, areq);
3344 if (code) return code;
3345 if (vType(avc) != VDIR) {
3348 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3349 if (!tdc) return ENOENT;
3350 Check_AtSys(avc, ain, &sysState, areq);
3351 ObtainReadLock(&tdc->lock);
3353 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3354 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3355 ReleaseReadLock(&tdc->lock);
3356 afs_PutDCache(tdc); /* we're done with the data */
3357 bufp = sysState.name;
3361 tfid.Cell = avc->fid.Cell;
3362 tfid.Fid.Volume = avc->fid.Fid.Volume;
3363 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3364 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
3366 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
3372 if (tvc->mvstat != 1) {
3377 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3378 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3380 ObtainWriteLock(&tvc->lock,649);
3381 ObtainWriteLock(&afs_xcbhash, 650);
3382 afs_DequeueCallback(tvc);
3383 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
3384 ReleaseWriteLock(&afs_xcbhash);
3385 /* now find the disk cache entries */
3386 afs_TryToSmush(tvc, *acred, 1);
3387 osi_dnlc_purgedp(tvc);
3388 afs_symhint_inval(tvc);
3389 if (tvc->linkData && !(tvc->states & CCore)) {
3390 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3391 tvc->linkData = NULL;
3393 ReleaseWriteLock(&tvc->lock);
3394 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3395 afs_BozonUnlock(&tvc->pvnLock, tvc);
3399 if (sysState.allocked) osi_FreeLargeSpace(bufp);
3403 DECL_PIOCTL(PRxStatProc)
3408 if (!afs_osi_suser(*acred)) {
3412 if (ainSize != sizeof(afs_int32)) {
3416 memcpy((char *)&flags, ain, sizeof(afs_int32));
3417 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3421 if (flags & AFSCALL_RXSTATS_ENABLE) {
3422 rx_enableProcessRPCStats();
3424 if (flags & AFSCALL_RXSTATS_DISABLE) {
3425 rx_disableProcessRPCStats();
3427 if (flags & AFSCALL_RXSTATS_CLEAR) {
3428 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3436 DECL_PIOCTL(PRxStatPeer)
3441 if (!afs_osi_suser(*acred)) {
3445 if (ainSize != sizeof(afs_int32)) {
3449 memcpy((char *)&flags, ain, sizeof(afs_int32));
3450 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3454 if (flags & AFSCALL_RXSTATS_ENABLE) {
3455 rx_enablePeerRPCStats();
3457 if (flags & AFSCALL_RXSTATS_DISABLE) {
3458 rx_disablePeerRPCStats();
3460 if (flags & AFSCALL_RXSTATS_CLEAR) {
3461 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3468 DECL_PIOCTL(PPrefetchFromTape)
3470 register afs_int32 code, code1;
3473 struct rx_call *tcall;
3474 struct AFSVolSync tsync;
3475 struct AFSFetchStatus OutStatus;
3476 struct AFSCallBack CallBack;
3477 struct VenusFid tfid;
3481 AFS_STATCNT(PSetAcl);
3485 if (ain && (ainSize == 3 * sizeof(afs_int32)))
3486 Fid = (struct AFSFid *) ain;
3488 Fid = &avc->fid.Fid;
3489 tfid.Cell = avc->fid.Cell;
3490 tfid.Fid.Volume = Fid->Volume;
3491 tfid.Fid.Vnode = Fid->Vnode;
3492 tfid.Fid.Unique = Fid->Unique;
3494 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
3496 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3497 ICL_TYPE_POINTER, tvc,
3498 ICL_TYPE_FID, &tfid,
3499 ICL_TYPE_FID, &avc->fid);
3502 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3503 ICL_TYPE_POINTER, tvc,
3504 ICL_TYPE_FID, &tfid,
3505 ICL_TYPE_FID, &tvc->fid);
3508 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3512 tcall = rx_NewCall(tc->id);
3513 code = StartRXAFS_FetchData(tcall,
3514 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3516 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3517 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3519 code1 = rx_EndCall(tcall, code);
3524 (afs_Analyze(tc, code, &tvc->fid, areq,
3525 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3527 /* This call is done only to have the callback things handled correctly */
3528 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3532 *aoutSize = sizeof(afs_int32);
3537 DECL_PIOCTL(PResidencyCmd)
3539 register afs_int32 code;
3542 struct ResidencyCmdInputs *Inputs;
3543 struct ResidencyCmdOutputs *Outputs;
3544 struct VenusFid tfid;
3547 Inputs = (struct ResidencyCmdInputs *) ain;
3548 Outputs = (struct ResidencyCmdOutputs *) aout;
3549 if (!avc) return EINVAL;
3550 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3554 Fid = &avc->fid.Fid;
3556 tfid.Cell = avc->fid.Cell;
3557 tfid.Fid.Volume = Fid->Volume;
3558 tfid.Fid.Vnode = Fid->Vnode;
3559 tfid.Fid.Unique = Fid->Unique;
3561 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
3562 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3563 ICL_TYPE_POINTER, tvc,
3564 ICL_TYPE_INT32, Inputs->command,
3565 ICL_TYPE_FID, &tfid);
3569 if (Inputs->command) {
3571 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3574 code = RXAFS_ResidencyCmd(tc->id, Fid,
3576 (struct ResidencyCmdOutputs *) aout);
3581 (afs_Analyze(tc, code, &tvc->fid, areq,
3582 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3584 /* This call is done to have the callback things handled correctly */
3585 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3586 } else { /* just a status request, return also link data */
3588 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3589 Outputs->chars[0] = 0;
3590 if (vType(tvc) == VLNK) {
3591 ObtainWriteLock(&tvc->lock,555);
3592 if (afs_HandleLink(tvc, areq) == 0)
3593 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3594 ReleaseWriteLock(&tvc->lock);
3601 *aoutSize = sizeof(struct ResidencyCmdOutputs);