Beispiel #1
0
int
lx_sendfile64(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
{
	sysret_t rval;
	off64_t off = 0;
	off64_t *offp = (off64_t *)p3;
	size_t sz = (size_t)p4;
	int error;
	struct sendfilevec64 sfv;
	size_t xferred;

	if (sz > 0 && uucopy(offp, &off, sizeof (off)) != 0)
		return (-errno);

	sfv.sfv_fd = p2;
	sfv.sfv_flag = 0;
	sfv.sfv_off = off;
	sfv.sfv_len = sz;
	error = __systemcall(&rval, SYS_sendfilev, SENDFILEV64, p1, &sfv,
	    1, &xferred);

	if (error == 0 && xferred > 0) {
		off += xferred;
		error = uucopy(&off, offp, sizeof (off));
	}

	return (error ? -error : (int)rval.sys_rval1);
}
Beispiel #2
0
static int
lx_accept(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct sockaddr *name = (struct sockaddr *)args[1];
	socklen_t namelen = 0;
	int r;

	lx_debug("\taccept(%d, 0x%p, 0x%p", sockfd, args[1], args[2]);

	/*
	 * The Linux man page says that -1 is returned and errno is set to
	 * EFAULT if the "name" address is bad, but it is silent on what to
	 * set errno to if the "namelen" address is bad.  Experimentation
	 * shows that Linux (at least the 2.4.21 kernel in CentOS) actually
	 * sets errno to EINVAL in both cases.
	 *
	 * Note that we must first check the name pointer, as the Linux
	 * docs state nothing is copied out if the "name" pointer is NULL.
	 * If it is NULL, we don't care about the namelen pointer's value
	 * or about dereferencing it.
	 *
	 * Happily, Solaris' accept(3SOCKET) treats NULL name pointers and
	 * zero namelens the same way.
	 */
	if ((name != NULL) &&
	    (uucopy((void *)args[2], &namelen, sizeof (socklen_t)) != 0))
		return ((errno == EFAULT) ? -EINVAL : -errno);

	lx_debug("\taccept namelen = %d", namelen);

	if ((r = accept(sockfd, name, &namelen)) < 0)
		return ((errno == EFAULT) ? -EINVAL : -errno);

	lx_debug("\taccept namelen returned %d bytes", namelen);

	/*
	 * In Linux, accept()ed sockets do not inherit anything set by
	 * fcntl(), so filter those out.
	 */
	if (fcntl(r, F_SETFL, 0) < 0)
		return (-errno);

	/*
	 * Once again, a bad "namelen" address sets errno to EINVAL, not
	 * EFAULT.  If namelen was zero, there's no need to copy a zero back
	 * out.
	 *
	 * Logic might dictate that we should check if we can write to
	 * the namelen pointer earlier so we don't accept a pending connection
	 * only to fail the call because we can't write the namelen value back
	 * out. However, testing shows Linux does indeed fail the call after
	 * accepting the connection so we must behave in a compatible manner.
	 */
	if ((name != NULL) && (namelen != 0) &&
	    (uucopy(&namelen, (void *)args[2], sizeof (socklen_t)) != 0))
		return ((errno == EFAULT) ? -EINVAL : -errno);

	return (r);
}
Beispiel #3
0
static int
lx_getpeername(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct sockaddr *name;
	socklen_t namelen;

	if (uucopy((void *)args[2], &namelen, sizeof (socklen_t)) != 0)
		return (-errno);

	lx_debug("\tgetpeername(%d, 0x%p, 0x%p (=%d))",
	    sockfd, args[1], args[2], namelen);

	/*
	 * Linux returns EFAULT in this case, even if the namelen parameter
	 * is 0.  This check will not catch other illegal addresses, but
	 * the benefit catching a non-null illegal address here is not
	 * worth the cost of another system call.
	 */
	if ((void *)args[1] == NULL)
		return (-EFAULT);

	if ((name = SAFE_ALLOCA(namelen)) == NULL)
		return (-EINVAL);
	if ((getpeername(sockfd, name, &namelen)) < 0)
		return (-errno);

	if (uucopy(name, (void *)args[1], namelen) != 0)
		return (-errno);

	if (uucopy(&namelen, (void *)args[2], sizeof (socklen_t)) != 0)
		return (-errno);

	return (0);
}
Beispiel #4
0
long
lx_fcntl64(uintptr_t p1, uintptr_t p2, uintptr_t p3)
{
	int		fd = (int)p1;
	int		cmd = (int)p2;
	struct lx_flock lxflk;
	struct lx_flock64 lxflk64;
	struct flock	fl;
	struct flock64	fl64;
	int		rc;

	if (cmd == LX_F_SETSIG || cmd == LX_F_GETSIG || cmd == LX_F_SETLEASE ||
	    cmd == LX_F_GETLEASE) {
		lx_unsupported("unsupported fcntl64 command: %d", cmd);
		return (-ENOTSUP);
	}

	if (cmd == LX_F_GETLK || cmd == LX_F_SETLK || cmd == LX_F_SETLKW) {
		if (uucopy((void *)p3, (void *)&lxflk,
		    sizeof (struct lx_flock)) != 0)
			return (-errno);
		ltos_flock(&lxflk, &fl);
		rc = lx_fcntl_com(fd, cmd, (ulong_t)&fl);
		if (rc >= 0) {
			stol_flock(&fl, &lxflk);
			if (uucopy((void *)&lxflk, (void *)p3,
			    sizeof (struct lx_flock)) != 0)
				return (-errno);
		}
	} else if (cmd == LX_F_GETLK64 || cmd == LX_F_SETLKW64 || \
	    cmd == LX_F_SETLK64) {
		if (uucopy((void *)p3, (void *)&lxflk64,
		    sizeof (struct lx_flock64)) != 0)
			return (-errno);
		ltos_flock64(&lxflk64, &fl64);
		rc = lx_fcntl_com(fd, cmd, (ulong_t)&fl64);
		if (rc >= 0) {
			stol_flock64(&fl64, &lxflk64);
			if (uucopy((void *)&lxflk64, (void *)p3,
			    sizeof (struct lx_flock64)) != 0)
				return (-errno);
		}
	} else {
		rc = lx_fcntl_com(fd, cmd, (ulong_t)p3);
	}

	return (rc);
}
Beispiel #5
0
/*
 * From the man page:
 * The Linux-specific prlimit() system call combines and extends the
 * functionality of setrlimit() and getrlimit(). It can be used to both set
 * and get the resource limits of an arbitrary process.
 *
 * If pid is 0, then the call applies to the calling process.
 */
int
lx_prlimit64(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
{
	pid_t pid = (pid_t)p1;
	int resource = (int)p2;
	lx_rlimit64_t *nrlp = (lx_rlimit64_t *)p3;
	lx_rlimit64_t *orlp = (lx_rlimit64_t *)p4;
	int rv = 0;
	uint64_t rlim_cur, rlim_max;
	lx_rlimit64_t nrl, orl;

	if (pid != 0) {
		/* XXX TBD if needed */
		lx_unsupported("setting prlimit %d for another process\n",
		    resource);
		return (-ENOTSUP);
	}

	if (orlp != NULL) {
		/* we first get the current limits */
		rv = getrlimit_common(resource, &rlim_cur, &rlim_max);
		if (rv != 0)
			return (rv);
	}

	if (nrlp != NULL) {
		if (uucopy((void *)p3, &nrl, sizeof (nrl)) != 0)
			return (-errno);

		if ((nrl.rlim_max != LX_RLIM64_INFINITY &&
		    nrl.rlim_cur == LX_RLIM64_INFINITY) ||
		    nrl.rlim_cur > nrl.rlim_max)
			return (-EINVAL);

		rv = setrlimit_common(resource, nrl.rlim_cur, nrl.rlim_max);
	}

	if (rv == 0 && orlp != NULL) {
		/* now return the original limits, if necessary */
		orl.rlim_cur = rlim_cur;
		orl.rlim_max = rlim_max;

		if ((uucopy(&orl, orlp, sizeof (orl))) != 0)
			rv = -errno;
	}

	return (rv);
}
Beispiel #6
0
static int
lx_semctl_ipcstat(int semid, void *buf)
{
	struct lx_semid_ds semds;
	struct semid_ds sol_semds;

	if (semctl(semid, 0, IPC_STAT, &sol_semds) != 0)
		return (-errno);

	bzero(&semds, sizeof (semds));
	semds.sem_perm.key = sol_semds.sem_perm.key;
	semds.sem_perm.seq = sol_semds.sem_perm.seq;
	semds.sem_perm.uid = sol_semds.sem_perm.uid;
	semds.sem_perm.gid = sol_semds.sem_perm.gid;
	semds.sem_perm.cuid = sol_semds.sem_perm.cuid;
	semds.sem_perm.cgid = sol_semds.sem_perm.cgid;

	/* Linux only uses the bottom 9 bits */
	semds.sem_perm.mode = sol_semds.sem_perm.mode & S_IAMB;
	semds.sem_otime = sol_semds.sem_otime;
	semds.sem_ctime = sol_semds.sem_ctime;
	semds.sem_nsems = sol_semds.sem_nsems;

	if (uucopy(&semds, buf, sizeof (semds)))
		return (-errno);

	return (0);
}
Beispiel #7
0
/*
 * For the SETALL operation, we have to examine each of the semaphore
 * values to be sure it is legal.
 */
static int
lx_semctl_setall(int semid, ushort_t *arg)
{
	struct semid_ds semds;
	ushort_t *vals;
	int i, sz, r;

	/*
	 * Find out how many semaphores are involved, reserve enough
	 * memory for an internal copy of the array, and then copy it in
	 * from the process.
	 */
	if (semctl(semid, 0, IPC_STAT, &semds) != 0)
		return (-errno);
	sz = semds.sem_nsems * sizeof (ushort_t);
	if ((vals = SAFE_ALLOCA(sz)) == NULL)
		return (-ENOMEM);
	if (uucopy(arg, vals, sz))
		return (-errno);

	/* Validate each of the values. */
	for (i = 0; i < semds.sem_nsems; i++)
		if (vals[i] > LX_SEMVMX)
			return (-ERANGE);

	r = semctl(semid, 0, SETALL, arg);

	return ((r < 0) ? -errno : r);
}
Beispiel #8
0
long
lx_sched_setparam(uintptr_t pid, uintptr_t param)
{
	int	err, policy;
	pid_t	s_pid;
	lwpid_t	s_tid;
	struct lx_sched_param lp;
	struct sched_param sp;

	if (((pid_t)pid < 0) || (param == NULL))
		return (-EINVAL);

	if (lx_lpid_to_spair((pid_t)pid, &s_pid, &s_tid) < 0)
		return (-ESRCH);

	if (s_pid == getpid()) {
		struct sched_param dummy;

		if ((err = pthread_getschedparam(s_tid, &policy, &dummy)) != 0)
			return (-err);
	} else
		if ((policy = sched_getscheduler(s_pid)) < 0)
			return (-errno);

	lx_debug("sched_setparam(): current policy %d", policy);

	if (uucopy((void *)param, &lp, sizeof (lp)) != 0)
		return (-errno);

	/*
	 * In Linux, the only valid SCHED_OTHER scheduler priority is 0
	 */
	if ((policy == SCHED_OTHER) && (lp.lx_sched_prio != 0))
		return (-EINVAL);

	if ((err = ltos_sparam(policy, (struct lx_sched_param *)&lp,
	    &sp)) != 0)
		return (err);

	/*
	 * Check if we're allowed to change the scheduler for the process.
	 *
	 * If we're operating on a thread, we can't just call
	 * pthread_setschedparam() because as all threads reside within a
	 * single Solaris process, Solaris will allow the modification
	 *
	 * If we're operating on a process, we can't just call sched_setparam()
	 * because Solaris will allow the call to succeed if the scheduler
	 * parameters do not differ from those being installed, but Linux wants
	 * the call to fail.
	 */
	if ((err = check_schedperms(s_pid)) != 0)
		return (err);

	if (s_pid == getpid())
		return (((err = pthread_setschedparam(s_tid, policy, &sp)) != 0)
		    ? -err : 0);

	return ((sched_setparam(s_pid, &sp) == -1) ? -errno : 0);
}
Beispiel #9
0
static int
stol_sparam(int policy, struct sched_param *sp, struct lx_sched_param *lsp)
{
	struct lx_sched_param ls;
	int smin = sched_get_priority_min(policy);
	int smax = sched_get_priority_max(policy);

	if (policy == SCHED_OTHER) {
		/*
		 * In Linux, the only valid SCHED_OTHER scheduler priority is 0
		 */
		ls.lx_sched_prio = 0;
	} else {
		/*
		 * Convert Solaris's dynamic, inverted priority range to the
		 * fixed Linux range of 1 - 99.
		 *
		 * The formula is (see above):
		 *
		 *	(smax - s + 2smin) * 99
		 *  l = -----------------------
		 *		smax - smin
		 */
		ls.lx_sched_prio = ((smax - sp->sched_priority + 2*smin) *
		    LX_PRI_MAX) / (smax - smin);
	}

	lx_debug("stol_sparam: policy %d: Solaris prio %d = linux prio %d "
	    "(Solaris range %d,%d)\n", policy,
	    sp->sched_priority, ls.lx_sched_prio, smin, smax);

	return ((uucopy(&ls, lsp, sizeof (struct lx_sched_param)) != 0)
	    ? -errno : 0);
}
Beispiel #10
0
static int
lx_shmctl_ipcstat(int shmid, void *buf)
{
	struct lx_shmid_ds shmds;
	struct shmid_ds sol_shmds;

	if (shmctl(shmid, IPC_STAT, &sol_shmds) != 0)
		return (-errno);

	bzero(&shmds, sizeof (shmds));
	shmds.shm_perm.key = sol_shmds.shm_perm.key;
	shmds.shm_perm.seq = sol_shmds.shm_perm.seq;
	shmds.shm_perm.uid = sol_shmds.shm_perm.uid;
	shmds.shm_perm.gid = sol_shmds.shm_perm.gid;
	shmds.shm_perm.cuid = sol_shmds.shm_perm.cuid;
	shmds.shm_perm.cgid = sol_shmds.shm_perm.cgid;
	shmds.shm_perm.mode = sol_shmds.shm_perm.mode & S_IAMB;
	if (sol_shmds.shm_lkcnt > 0)
		shmds.shm_perm.mode |= LX_SHM_LOCKED;
	shmds.shm_segsz = sol_shmds.shm_segsz;
	shmds.shm_atime	 = sol_shmds.shm_atime;
	shmds.shm_dtime = sol_shmds.shm_dtime;
	shmds.shm_ctime = sol_shmds.shm_ctime;
	shmds.shm_cpid = sol_shmds.shm_cpid;
	shmds.shm_lpid = sol_shmds.shm_lpid;
	shmds.shm_nattch = (ushort_t)sol_shmds.shm_nattch;

	if (uucopy(&shmds, buf, sizeof (shmds)))
		return (-errno);

	return (0);
}
Beispiel #11
0
int
lx_setrlimit(uintptr_t p1, uintptr_t p2)
{
	int resource = (int)p1;
	lx_rlimit_t rl;
	uint64_t rlim_cur, rlim_max;

	if (uucopy((void *)p2, &rl, sizeof (rl)) != 0)
		return (-errno);

	if ((rl.rlim_max != LX_RLIM_INFINITY_N &&
	    rl.rlim_cur == LX_RLIM_INFINITY_N) ||
	    rl.rlim_cur > rl.rlim_max)
		return (-EINVAL);

	if (rl.rlim_cur == LX_RLIM_INFINITY_N)
		rlim_cur = LX_RLIM64_INFINITY;
	else
		rlim_cur = rl.rlim_cur;

	if (rl.rlim_max == LX_RLIM_INFINITY_N)
		rlim_max = LX_RLIM64_INFINITY;
	else
		rlim_max = rl.rlim_max;

	return (setrlimit_common(resource, rlim_cur, rlim_max));
}
Beispiel #12
0
/*
 * We may need a different size socket address vs. the one passed in.
 */
static int
calc_addr_size(struct sockaddr *a, int in_len, lx_addr_type_t *type)
{
	struct sockaddr name;
	boolean_t abst_sock;
	int nlen;

	if (uucopy(a, &name, sizeof (struct sockaddr)) != 0)
		return (-errno);

	/*
	 * Handle Linux abstract sockets, which are UNIX sockets whose path
	 * begins with a NULL character.
	 */
	abst_sock = (name.sa_family == AF_UNIX) && (name.sa_data[0] == '\0');

	/*
	 * Convert_sockaddr will expand the socket path if it is abstract, so
	 * we need to allocate extra memory for it.
	 */

	nlen = in_len;
	if (abst_sock) {
		nlen += ABST_PRFX_LEN;
		*type = lxa_abstract;
	} else {
		*type = lxa_none;
	}

	return (nlen);
}
Beispiel #13
0
static int
lx_socketpair(ulong_t *args)
{
	int domain;
	int type;
	int options;
	int protocol = (int)args[2];
	int *sv = (int *)args[3];
	int fds[2];
	int r;

	r = convert_sock_args((int)args[0], (int)args[1], protocol,
	    &domain, &type, &options);
	if (r != 0)
		return (r);

	lx_debug("\tsocketpair(%d, %d, %d, 0x%p)", domain, type, protocol, sv);

	r = socketpair(domain, type | options, protocol, fds);

	if (r == 0) {
		if (uucopy(fds, sv, sizeof (fds)) != 0) {
			r = errno;
			(void) close(fds[0]);
			(void) close(fds[1]);
			return (-r);
		}
		return (0);
	}

	if (errno == EPROTONOSUPPORT)
		return (-ESOCKTNOSUPPORT);

	return (-errno);
}
Beispiel #14
0
/*
 * setitimer() - the Linux implementation can handle tv_usec values greater
 *		 than 1,000,000 where Illumos would return EINVAL.
 *
 *		 There's still an issue here where Linux can handle a
 *		 tv_sec value greater than 100,000,000 but Illumos cannot,
 *		 but that would also mean setting an interval timer to fire
 *		 over _three years_ in the future so it's unlikely anything
 *		 other than Linux test suites will trip over it.
 */
long
lx_setitimer(uintptr_t p1, uintptr_t p2, uintptr_t p3)
{
	struct itimerval itv;
	struct itimerval *itp = (struct itimerval *)p2;

	if (itp != NULL) {
		if (uucopy(itp, &itv, sizeof (itv)) != 0)
			return (-errno);

		/*
		 * Adjust any tv_usec fields >= 1,000,000 by adding any whole
		 * seconds so indicated to tv_sec and leaving tv_usec as the
		 * remainder.
		 */
		if (itv.it_interval.tv_usec >= MICROSEC) {
			itv.it_interval.tv_sec +=
			    itv.it_interval.tv_usec / MICROSEC;

			itv.it_interval.tv_usec %= MICROSEC;
		}
		if (itv.it_value.tv_usec >= MICROSEC) {
			itv.it_value.tv_sec +=
			    itv.it_value.tv_usec / MICROSEC;

			itv.it_value.tv_usec %= MICROSEC;
		}

		itp = &itv;
	}

	return ((setitimer((int)p1, itp, (struct itimerval *)p3) != 0) ?
	    -errno : 0);
}
Beispiel #15
0
/*
 * This is the 'old' getrlimit, variously called getrlimit or old_getrlimit
 * in Linux headers and code.  The only difference between this and the new
 * getrlimit (variously called getrlimit or ugetrlimit) is the value of
 * RLIM_INFINITY, which is smaller for the older version.
 */
int
lx_oldgetrlimit(uintptr_t p1, uintptr_t p2)
{
	int resource = (int)p1;
	lx_rlimit_t *rlp = (lx_rlimit_t *)p2;
	int rv;
	lx_rlimit_t rl;
	uint64_t rlim_cur, rlim_max;

	rv = getrlimit_common(resource, &rlim_cur, &rlim_max);
	if (rv != 0)
		return (rv);

	if (rlim_cur == LX_RLIM64_INFINITY)
		rl.rlim_cur = LX_RLIM_INFINITY_O;
	else if (rlim_cur > BIG_INFINITY_O)
		rl.rlim_cur = LX_RLIM_INFINITY_O;
	else
		rl.rlim_cur = (ulong_t)rlim_cur;

	if (rlim_max == LX_RLIM64_INFINITY)
		rl.rlim_max = LX_RLIM_INFINITY_O;
	else if (rlim_max > BIG_INFINITY_O)
		rl.rlim_max = LX_RLIM_INFINITY_O;
	else
		rl.rlim_max = (ulong_t)rlim_max;

	if ((uucopy(&rl, rlp, sizeof (rl))) != 0)
		return (-errno);

	return (0);
}
Beispiel #16
0
/*
 * copyoutseg()
 *	Copy out segments to user address space
 *
 * Copies out to the greater of what's in the sysmsg and what's
 * specified by the user message.  Returns number of bytes actually
 * copied, or -1 on error.
 */
copyoutsegs(struct sysmsg *sm)
{
	uint cnt, total = 0;
	struct msg *m = &sm->sm_msg;
	int nsm_segs = sm->sm_nseg, nm_segs = m->m_nseg;
	struct seg **sm_pp = &(sm->sm_seg[0]),
		*sm_segs = *sm_pp++;
	seg_t *m_segs = m->m_seg;

	do {
		/*
		 * Calculate how much we can move this time
		 */
		cnt = MIN(sm_segs->s_len, m_segs->s_buflen);

		/*
		 * If non-zero, move the next batch
		 */
		if (cnt > 0) {
			char *from, *to;

			/*
			 * Copy the memory
			 */
			from = sm_segs->s_pview.p_vaddr;
			from += sm_segs->s_off;
			to = m_segs->s_buf;
			if (uucopy(to, from, cnt)) {
				return(err(EFAULT));
			}
			total += cnt;

			/*
			 * Advance the sysmsg
			 */
			if ((sm_segs->s_len -= cnt) == 0) {
				sm_segs = *sm_pp++;
				if ((--nsm_segs) == 0) {
					return(total);
				}
			} else {
				sm_segs->s_off += cnt;
			}

			/*
			 * Advance the user message
			 */
			if ((m_segs->s_buflen -= cnt) == 0) {
				++m_segs;
				if ((--nm_segs) == 0) {
					return(total);
				}
			} else {
				m_segs->s_buf = ((char *)m_segs->s_buf) + cnt;
			}
		}
	} while (cnt > 0);
	return(total);
}
Beispiel #17
0
long
lx_fcntl(uintptr_t p1, uintptr_t p2, uintptr_t p3)
{
	int		fd = (int)p1;
	int		cmd = (int)p2;
	ulong_t		arg = (ulong_t)p3;
	struct lx_flock lxflk;
	struct flock	fl;
	int		lk = 0;
	int		rc;

	/*
	 * The 64-bit fcntl commands must go through fcntl64().
	 */
	if (cmd == LX_F_GETLK64 || cmd == LX_F_SETLK64 ||
	    cmd == LX_F_SETLKW64)
		return (-EINVAL);

	if (cmd == LX_F_SETSIG || cmd == LX_F_GETSIG || cmd == LX_F_SETLEASE ||
	    cmd == LX_F_GETLEASE) {
		lx_unsupported("unsupported fcntl command: %d", cmd);
		return (-ENOTSUP);
	}

	if (cmd == LX_F_GETLK || cmd == LX_F_SETLK ||
	    cmd == LX_F_SETLKW) {
		if (uucopy((void *)p3, (void *)&lxflk,
		    sizeof (struct lx_flock)) != 0)
			return (-errno);
		lk = 1;
		ltos_flock(&lxflk, &fl);
		arg = (ulong_t)&fl;
	}

	rc = lx_fcntl_com(fd, cmd, arg);

	if (lk && rc >= 0) {
		stol_flock(&fl, &lxflk);
		if (uucopy((void *)&lxflk, (void *)p3,
		    sizeof (struct lx_flock)) != 0)
			return (-errno);
	}

	return (rc);
}
Beispiel #18
0
/*
 * time() - This cannot be passthrough because on Linux a bad buffer will
 *	    set errno to EFAULT, and on Illumos the failure mode is documented
 *	    as "undefined."
 *
 *	    (At present, Illumos' time(2) will segmentation fault, as the call
 *	    is simply a libc wrapper atop the time() syscall that will
 *	    dereference the passed  pointer if it is non-zero.)
 */
long
lx_time(uintptr_t p1)
{
	time_t ret = time((time_t *)0);

	if ((ret == (time_t)-1) ||
	    ((p1 != 0) && (uucopy(&ret, (time_t *)p1, sizeof (ret)) != 0)))
		return (-errno);

	return (ret);
}
Beispiel #19
0
/* ARGSUSED */
long
lx_sched_getaffinity(uintptr_t pid, uintptr_t len, uintptr_t maskp)
{
	int	sz;
	ulong_t	*lmask, *zmask;
	int	i;

	sz = syscall(SYS_brand, B_GET_AFFINITY_MASK, pid, len, maskp);
	if (sz == -1)
		return (-errno);

	/*
	 * If the target LWP hasn't ever had an affinity mask set, the kernel
	 * will return a mask of all 0's. If that is the case we must build a
	 * default mask that has all valid bits turned on.
	 */
	lmask = SAFE_ALLOCA(sz);
	zmask = SAFE_ALLOCA(sz);
	if (lmask == NULL || zmask == NULL)
		return (-ENOMEM);

	bzero(zmask, sz);

	if (uucopy((void *)maskp, lmask, sz) != 0)
		return (-EFAULT);

	if (bcmp(lmask, zmask, sz) != 0)
		return (sz);

	for (i = 0; i < sz * 8; i++) {
		if (p_online(i, P_STATUS) != -1) {
			lmask[BITINDEX(i)] |= BITSHIFT(i);
		}
	}

	if (uucopy(lmask, (void *)maskp, sz) != 0)
		return (-EFAULT);

	return (sz);
}
Beispiel #20
0
/*
 * times() - The Linux implementation avoids writing to NULL, while Illumos
 *	     returns EFAULT.
 */
long
lx_times(uintptr_t p1)
{
	clock_t ret;
	struct tms buf, *tp = (struct tms *)p1;

	ret = times(&buf);

	if ((ret == -1) ||
	    ((tp != NULL) && uucopy((void *)&buf, tp, sizeof (buf)) != 0))
		return (-errno);

	return ((ret == -1) ? -errno : ret);
}
Beispiel #21
0
static int
lx_semctl_ipcinfo(void *buf)
{
	struct lx_seminfo i;
	rctlblk_t *rblk;
	int rblksz;
	uint_t nids;
	int idbuf;
	int err;
	uint64_t val;

	rblksz = rctlblk_size();
	if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
		return (-ENOMEM);

	bzero(&i, sizeof (i));
	err = get_rctlval(rblk, "project.max-sem-ids", (ulong_t)MAXINT, &val);
	if (err < 0)
		return (err);
	i.semmni = (int)val;
	err = get_rctlval(rblk, "process.max-sem-nsems", (ulong_t)MAXINT, &val);
	if (err < 0)
		return (err);
	i.semmsl = (int)val;
	err = get_rctlval(rblk, "process.max-sem-ops", (ulong_t)MAXINT, &val);
	if (err < 0)
		return (err);
	i.semopm = (int)val;

	/*
	 * We don't have corresponding rctls for these fields.  The values
	 * are taken from the formulas used to derive the defaults listed
	 * in the Linux header file.  We're lying, but trying to be
	 * coherent about it.
	 */
	i.semmap = i.semmni;
	i.semmns = i.semmni * i.semmsl;
	i.semmnu = INT_MAX;
	i.semume = INT_MAX;
	i.semvmx = LX_SEMVMX;
	if (semids(&idbuf, 0, &nids) < 0)
		return (-errno);
	i.semusz = nids;
	i.semaem = INT_MAX;

	if (uucopy(&i, buf, sizeof (i)) != 0)
		return (-errno);

	return (nids);
}
Beispiel #22
0
/*
 * Based on the lx_accept code with the addition of the flags handling.
 * See internal comments in that function for more explanation.
 */
static int
lx_accept4(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct sockaddr *name = (struct sockaddr *)args[1];
	socklen_t namelen = 0;
	int lx_flags, flags = 0;
	int r;

	lx_flags = (int)args[3];
	lx_debug("\taccept4(%d, 0x%p, 0x%p 0x%x", sockfd, args[1], args[2],
	    lx_flags);

	if ((name != NULL) &&
	    (uucopy((void *)args[2], &namelen, sizeof (socklen_t)) != 0))
		return ((errno == EFAULT) ? -EINVAL : -errno);

	lx_debug("\taccept4 namelen = %d", namelen);

	if (lx_flags & LX_SOCK_NONBLOCK)
		flags |= SOCK_NONBLOCK;

	if (lx_flags & LX_SOCK_CLOEXEC)
		flags |= SOCK_CLOEXEC;

	if ((r = accept4(sockfd, name, &namelen, flags)) < 0)
		return ((errno == EFAULT) ? -EINVAL : -errno);

	lx_debug("\taccept4 namelen returned %d bytes", namelen);

	if ((name != NULL) && (namelen != 0) &&
	    (uucopy(&namelen, (void *)args[2], sizeof (socklen_t)) != 0))
		return ((errno == EFAULT) ? -EINVAL : -errno);

	return (r);
}
Beispiel #23
0
static int
lx_getsockname(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct sockaddr *name = NULL;
	socklen_t namelen, namelen_orig;

	if (uucopy((void *)args[2], &namelen, sizeof (socklen_t)) != 0)
		return (-errno);
	namelen_orig = namelen;

	lx_debug("\tgetsockname(%d, 0x%p, 0x%p (=%d))",
	    sockfd, args[1], args[2], namelen);

	if (namelen > 0) {
		if ((name = SAFE_ALLOCA(namelen)) == NULL)
			return (-EINVAL);
		bzero(name, namelen);
	}

	if (getsockname(sockfd, name, &namelen) < 0)
		return (-errno);

	/*
	 * If the name that getsockname() wants to return is larger
	 * than namelen, getsockname() will copy out the maximum amount
	 * of data possible and then update namelen to indicate the
	 * actually size of all the data that it wanted to copy out.
	 */
	if (uucopy(name, (void *)args[1], namelen_orig) != 0)
		return (-errno);
	if (uucopy(&namelen, (void *)args[2], sizeof (socklen_t)) != 0)
		return (-errno);

	return (0);
}
Beispiel #24
0
long
lx_settimeofday(uintptr_t p1, uintptr_t p2)
{
	struct timeval tv;
	struct lx_timezone tz;

	if ((p1 != NULL) &&
	    (uucopy((struct timeval *)p1, &tv, sizeof (tv)) < 0))
		return (-errno);

	/*
	 * The Linux man page states use of the second parameter is obsolete,
	 * but settimeofday(2) should still return EFAULT if it is set
	 * to a bad non-NULL pointer (sigh...)
	 */
	if ((p2 != NULL) &&
	    (uucopy((struct lx_timezone *)p2, &tz, sizeof (tz)) < 0))
		return (-errno);

	if ((p1 != NULL) && (settimeofday(&tv, NULL) < 0))
		return (-errno);

	return (0);
}
Beispiel #25
0
/*
 * Build and return a shm_info structure. We only return the bare
 * essentials required by ipcs. The rest of the info is not readily
 * available.
 */
static int
lx_shmctl_shminfo(void *buf)
{
	struct lx_shm_info shminfo;
	uint_t nids;
	int idbuf;

	bzero(&shminfo, sizeof (shminfo));

	if (shmids(&idbuf, 0, &nids) < 0)
		return (-errno);

	shminfo.used_ids = nids;
	if (uucopy(&shminfo, buf, sizeof (shminfo)) != 0)
		return (-errno);

	return (nids);
}
Beispiel #26
0
static int
lx_shmctl_ipcset(int shmid, void *buf)
{
	struct lx_shmid_ds shmds;
	struct shmid_ds sol_shmds;
	int r;

	if (uucopy(buf, &shmds, sizeof (shmds)))
		return (-errno);

	bzero(&sol_shmds, sizeof (sol_shmds));
	sol_shmds.shm_perm.uid = shmds.shm_perm.uid;
	sol_shmds.shm_perm.gid = shmds.shm_perm.gid;
	sol_shmds.shm_perm.mode = shmds.shm_perm.mode & S_IAMB;

	r = shmctl(shmid, IPC_SET, &sol_shmds);
	return (r < 0 ? -errno : r);
}
Beispiel #27
0
long
lx_sched_rr_get_interval(uintptr_t pid, uintptr_t timespec)
{
	struct timespec ts;
	pid_t	s_pid;

	if ((pid_t)pid < 0)
		return (-EINVAL);

	if (lx_lpid_to_spid((pid_t)pid, &s_pid) < 0)
		return (-ESRCH);

	if (uucopy((struct timespec *)timespec, &ts,
	    sizeof (struct timespec)) != 0)
		return (-errno);

	return ((sched_rr_get_interval(s_pid, &ts) == -1) ? -errno : 0);
}
Beispiel #28
0
static int
lx_semctl_ipcset(int semid, void *buf)
{
	struct lx_semid_ds semds;
	struct semid_ds sol_semds;
	int r;

	if (uucopy(buf, &semds, sizeof (semds)))
		return (-errno);

	bzero(&sol_semds, sizeof (sol_semds));
	sol_semds.sem_perm.uid = semds.sem_perm.uid;
	sol_semds.sem_perm.gid = semds.sem_perm.gid;
	sol_semds.sem_perm.mode = semds.sem_perm.mode;

	r = semctl(semid, 0, IPC_SET, &sol_semds);
	return ((r < 0) ? -errno : r);
}
Beispiel #29
0
static int
ltos_sparam(int policy, struct lx_sched_param *lsp, struct sched_param *sp)
{
	struct lx_sched_param ls;
	int smin = sched_get_priority_min(policy);
	int smax = sched_get_priority_max(policy);

	if (uucopy(lsp, &ls, sizeof (struct lx_sched_param)) != 0)
		return (-errno);

	bzero(sp, sizeof (struct sched_param));

	/*
	 * Linux has a fixed priority range, 0 - 99, which we need to convert to
	 * Solaris's dynamic range. Linux considers lower numbers to be
	 * higher priority, so we'll invert the priority within Solaris's range.
	 *
	 * The formula to convert between ranges is:
	 *
	 *	L * (smax - smin)
	 * S =  -----------------  + smin
	 *	  (lmax - lmin)
	 *
	 * where S is the Solaris equivalent of the linux priority L.
	 *
	 * To invert the priority, we use:
	 * S' = smax - S + smin
	 *
	 * Together, these two formulas become:
	 *
	 *		L * (smax - smin)
	 *   S = smax - -----------------  + 2smin
	 *			99
	 */
	sp->sched_priority = smax -
	    ((ls.lx_sched_prio * (smax - smin)) / LX_PRI_MAX) + 2*smin;

	lx_debug("ltos_sparam: linux prio %d = Solaris prio %d "
	    "(Solaris range %d,%d)\n", ls.lx_sched_prio, sp->sched_priority,
	    smin, smax);

	return (0);
}
Beispiel #30
0
static int
lx_msgctl_ipcset(int msgid, void *buf)
{
	struct lx_msqid_ds msgids;
	struct msqid_ds sol_msgids;
	int r;

	if (uucopy(buf, &msgids, sizeof (msgids)))
		return (-errno);

	bzero(&sol_msgids, sizeof (sol_msgids));
	sol_msgids.msg_perm.uid = LX_UID16_TO_UID32(msgids.msg_perm.uid);
	sol_msgids.msg_perm.gid = LX_UID16_TO_UID32(msgids.msg_perm.gid);

	/* Linux only uses the bottom 9 bits */
	sol_msgids.msg_perm.mode = msgids.msg_perm.mode & S_IAMB;
	sol_msgids.msg_qbytes = msgids.msg_qbytes;

	r = msgctl(msgid, IPC_SET, &sol_msgids);
	return (r < 0 ? -errno : r);
}