/* uiomove * UIO_READ : dp -> uio * UIO_WRITE : uio -> dp */ int uiomove(char *dp, int length, uio_flag_t rw, struct uio *uiop) { int count; struct iovec *iov; int code; while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) { iov = uiop->uio_iov; count = iov->iov_len; if (!count) { uiop->uio_iov++; uiop->uio_iovcnt--; continue; } if (count > length) count = length; switch (uiop->uio_seg) { case AFS_UIOSYS: switch (rw) { case UIO_READ: memcpy(iov->iov_base, dp, count); break; case UIO_WRITE: memcpy(dp, iov->iov_base, count); break; default: printf("uiomove: Bad rw = %d\n", rw); return -EINVAL; } break; case AFS_UIOUSER: switch (rw) { case UIO_READ: AFS_COPYOUT(dp, iov->iov_base, count, code); break; case UIO_WRITE: AFS_COPYIN(iov->iov_base, dp, count, code); break; default: printf("uiomove: Bad rw = %d\n", rw); return -EINVAL; } break; default: printf("uiomove: Bad seg = %d\n", uiop->uio_seg); return -EINVAL; } dp += count; length -= count; iov->iov_base += count; iov->iov_len -= count; uiop->uio_offset += count; uiop->uio_resid -= count; } return 0; }
copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst) #endif { int code; #if defined(AFS_DARWIN100_ENV) struct afs_ioctl32 dst32; if (!proc_is64bit(current_proc())) { AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); if (!code) afs_ioctl32_to_afs_ioctl(&dst32, dst); return code; } #endif #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL) struct afs_ioctl32 dst32; if (!(IS64U)) { AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); if (!code) afs_ioctl32_to_afs_ioctl(&dst32, dst); return code; } #endif /* defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL) */ #if defined(AFS_HPUX_64BIT_ENV) struct afs_ioctl32 dst32; if (is_32bit(u.u_procp)) { /* is_32bit() in proc_iface.h */ AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); if (!code) afs_ioctl32_to_afs_ioctl(&dst32, dst); return code; } #endif /* defined(AFS_HPUX_64BIT_ENV) */ #if defined(AFS_SUN5_64BIT_ENV) struct afs_ioctl32 dst32; if (get_udatamodel() == DATAMODEL_ILP32) { AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); if (!code) afs_ioctl32_to_afs_ioctl(&dst32, dst); return code; } #endif /* defined(AFS_SUN5_64BIT_ENV) */ #if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) struct afs_ioctl32 dst32; if (!ABI_IS_64BIT(get_current_abi())) { AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); if (!code) afs_ioctl32_to_afs_ioctl(&dst32, dst); return code; } #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */ #if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV) struct afs_ioctl32 dst32; #ifdef AFS_SPARC64_LINUX26_ENV if (test_thread_flag(TIF_32BIT)) #elif defined(AFS_SPARC64_LINUX24_ENV) if (current->thread.flags & SPARC_FLAG_32BIT) #elif defined(AFS_SPARC64_LINUX20_ENV) if (current->tss.flags & SPARC_FLAG_32BIT) #elif defined(AFS_AMD64_LINUX26_ENV) if (test_thread_flag(TIF_IA32)) #elif defined(AFS_AMD64_LINUX20_ENV) if (current->thread.flags & THREAD_IA32) #elif defined(AFS_PPC64_LINUX26_ENV) #if defined(STRUCT_TASK_STRUCT_HAS_THREAD_INFO) if (current->thread_info->flags & _TIF_32BIT) #else if (task_thread_info(current)->flags & _TIF_32BIT) #endif #elif defined(AFS_PPC64_LINUX20_ENV) if (current->thread.flags & PPC_FLAG_32BIT) #elif defined(AFS_S390X_LINUX26_ENV) if (test_thread_flag(TIF_31BIT)) #elif defined(AFS_S390X_LINUX20_ENV) if (current->thread.flags & S390_FLAG_31BIT) #else #error pioctl32 not done for this linux #endif { AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); if (!code) afs_ioctl32_to_afs_ioctl(&dst32, dst); return code; } #endif /* defined(AFS_LINUX_64BIT_KERNEL) */ AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code); return code; }
/* called with the GLOCK held */ int afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow) { cred_t *credp = crref(); /* don't free until done! */ struct afs_ioctl data; struct clientcred ccred; struct rmtbulk idata, odata; short in_size, out_size; afs_int32 code = 0, pag, err; gid_t g0, g1; char *abspath, *pathbuf = 0; AFS_STATCNT(afs_syscall_pioctl); if (follow) follow = 1; /* compat. with old venus */ code = copyin_afs_ioctl(cmarg, &data); if (code) goto out; if ((com & 0xff) == 90) { /* PSetClientContext, in any space */ code = EINVAL; goto out; } /* Special handling for a few pioctls */ switch (com & 0xffff) { case (0x5600 | 3): /* VIOCSETTOK */ code = afspag_PSetTokens(data.in, data.in_size, &credp); if (code) goto out; break; case (0x5600 | 9): /* VIOCUNLOG */ case (0x5600 | 21): /* VIOCUNPAG */ code = afspag_PUnlog(data.in, data.in_size, &credp); if (code) goto out; break; case (0x5600 | 38): /* VIOC_AFS_SYSNAME */ code = afspag_PSetSysName(data.in, data.in_size, &credp); if (code) goto out; break; } /* Set up credentials */ memset(&ccred, 0, sizeof(ccred)); pag = PagInCred(credp); ccred.uid = afs_cr_uid(credp); if (pag != NOPAG) { afs_get_groups_from_pag(pag, &g0, &g1); ccred.group0 = g0; ccred.group1 = g1; } /* * Copy the path and convert to absolute, if one was given. * NB: We can only use osI_AllocLargeSpace here as long as * RMTSYS_MAXPATHLEN is less than AFS_LRALLOCSIZ. */ if (path) { pathbuf = osi_AllocLargeSpace(RMTSYS_MAXPATHLEN); if (!pathbuf) { code = ENOMEM; goto out; } code = osi_abspath(path, pathbuf, RMTSYS_MAXPATHLEN, 0, &abspath); if (code) goto out_path; } else { abspath = NIL_PATHP; } /* Allocate, copy, and convert incoming data */ idata.rmtbulk_len = in_size = data.in_size; if (in_size < 0 || in_size > MAXBUFFERLEN) { code = EINVAL; goto out_path; } if (in_size > AFS_LRALLOCSIZ) idata.rmtbulk_val = osi_Alloc(in_size); else idata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ); if (!idata.rmtbulk_val) { code = ENOMEM; goto out_path; } if (in_size) { AFS_COPYIN(data.in, idata.rmtbulk_val, in_size, code); if (code) goto out_idata; inparam_conversion(com, idata.rmtbulk_val, in_size, 0); } /* Allocate space for outgoing data */ odata.rmtbulk_len = out_size = data.out_size; if (out_size < 0 || out_size > MAXBUFFERLEN) { code = EINVAL; goto out_idata; } if (out_size > AFS_LRALLOCSIZ) odata.rmtbulk_val = osi_Alloc(out_size); else odata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ); if (!odata.rmtbulk_val) { code = ENOMEM; goto out_idata; } AFS_GUNLOCK(); code = RMTSYS_Pioctl(rmtsys_conn, &ccred, abspath, com, follow, &idata, &odata, &err); AFS_GLOCK(); if (code) goto out_odata; /* Convert and copy out the result */ if (odata.rmtbulk_len > out_size) { code = E2BIG; goto out_odata; } if (odata.rmtbulk_len) { outparam_conversion(com, odata.rmtbulk_val, odata.rmtbulk_len, 1); AFS_COPYOUT(odata.rmtbulk_val, data.out, odata.rmtbulk_len, code); } if (!code) code = err; out_odata: if (out_size > AFS_LRALLOCSIZ) osi_Free(odata.rmtbulk_val, out_size); else osi_FreeLargeSpace(odata.rmtbulk_val); out_idata: if (in_size > AFS_LRALLOCSIZ) osi_Free(idata.rmtbulk_val, in_size); else osi_FreeLargeSpace(idata.rmtbulk_val); out_path: if (path) osi_FreeLargeSpace(pathbuf); out: crfree(credp); #if defined(KERNEL_HAVE_UERROR) if (!getuerror()) setuerror(code); return (getuerror()); #else return (code); #endif }
static int copyin_iparam(caddr_t cmarg, struct iparam *dst) { int code; #if defined(AFS_HPUX_64BIT_ENV) struct iparam32 dst32; if (is_32bit(u.u_procp)) { /* is_32bit() in proc_iface.h */ AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); if (!code) iparam32_to_iparam(&dst32, dst); return code; } #endif /* AFS_HPUX_64BIT_ENV */ #if defined(AFS_SUN5_64BIT_ENV) struct iparam32 dst32; if (get_udatamodel() == DATAMODEL_ILP32) { AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); if (!code) iparam32_to_iparam(&dst32, dst); return code; } #endif /* AFS_SUN5_64BIT_ENV */ #if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV) struct iparam32 dst32; #ifdef AFS_SPARC64_LINUX26_ENV if (test_thread_flag(TIF_32BIT)) #elif defined(AFS_SPARC64_LINUX24_ENV) if (current->thread.flags & SPARC_FLAG_32BIT) #elif defined(AFS_SPARC64_LINUX20_ENV) if (current->tss.flags & SPARC_FLAG_32BIT) #elif defined(AFS_AMD64_LINUX26_ENV) if (test_thread_flag(TIF_IA32)) #elif defined(AFS_AMD64_LINUX20_ENV) if (current->thread.flags & THREAD_IA32) #elif defined(AFS_PPC64_LINUX26_ENV) #if defined(STRUCT_TASK_STRUCT_HAS_THREAD_INFO) if (current->thread_info->flags & _TIF_32BIT) #else if (task_thread_info(current)->flags & _TIF_32BIT) #endif #elif defined(AFS_PPC64_LINUX20_ENV) if (current->thread.flags & PPC_FLAG_32BIT) #elif defined(AFS_S390X_LINUX26_ENV) if (test_thread_flag(TIF_31BIT)) #elif defined(AFS_S390X_LINUX20_ENV) if (current->thread.flags & S390_FLAG_31BIT) #else #error iparam32 not done for this linux platform #endif { AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code); if (!code) iparam32_to_iparam(&dst32, dst); return code; } #endif /* AFS_LINUX_64BIT_KERNEL */ AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code); return code; }