/* 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; }
/* 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 }