int
linux_semctl(struct thread *td, struct linux_semctl_args *args)
{
	struct l_semid_ds linux_semid;
	struct l_seminfo linux_seminfo;
	struct semid_ds semid;
	union semun semun;
	register_t rval;
	int cmd, error;

	switch (args->cmd & ~LINUX_IPC_64) {
	case LINUX_IPC_RMID:
		cmd = IPC_RMID;
		break;
	case LINUX_GETNCNT:
		cmd = GETNCNT;
		break;
	case LINUX_GETPID:
		cmd = GETPID;
		break;
	case LINUX_GETVAL:
		cmd = GETVAL;
		break;
	case LINUX_GETZCNT:
		cmd = GETZCNT;
		break;
	case LINUX_SETVAL:
		cmd = SETVAL;
		semun.val = args->arg.val;
		break;
	case LINUX_IPC_SET:
		cmd = IPC_SET;
		error = linux_semid_pullup(args->cmd & LINUX_IPC_64,
		    &linux_semid, PTRIN(args->arg.buf));
		if (error)
			return (error);
		linux_to_bsd_semid_ds(&linux_semid, &semid);
		semun.buf = &semid;
		return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
		    td->td_retval));
	case LINUX_IPC_STAT:
	case LINUX_SEM_STAT:
		if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT)
			cmd = IPC_STAT;
		else
			cmd = SEM_STAT;
		semun.buf = &semid;
		error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
		    &rval);
		if (error)
			return (error);
		bsd_to_linux_semid_ds(&semid, &linux_semid);
		error = linux_semid_pushdown(args->cmd & LINUX_IPC_64,
		    &linux_semid, PTRIN(args->arg.buf));
		if (error == 0)
			td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0;
		return (error);
	case LINUX_IPC_INFO:
	case LINUX_SEM_INFO:
		bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) );
/* XXX BSD equivalent?
#define used_semids 10
#define used_sems 10
		linux_seminfo.semusz = used_semids;
		linux_seminfo.semaem = used_sems;
*/
		error = copyout(&linux_seminfo,
		    PTRIN(args->arg.buf), sizeof(linux_seminfo));
		if (error)
			return error;
		td->td_retval[0] = seminfo.semmni;
		return 0;			/* No need for __semctl call */
	case LINUX_GETALL:
		cmd = GETALL;
		semun.val = args->arg.val;
		break;
	case LINUX_SETALL:
		cmd = SETALL;
		semun.val = args->arg.val;
		break;
	default:
		linux_msg(td, "ipc type %d is not implemented",
		  args->cmd & ~LINUX_IPC_64);
		return EINVAL;
	}
	return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
	    td->td_retval));
}
Esempio n. 2
0
int
linux_semctl(struct thread *td, struct linux_semctl_args *args)
{
    struct l_semid_ds linux_semid;
    struct l_seminfo linux_seminfo;
    struct semid_ds semid;
    union semun semun;
    register_t rval;
    int cmd, error;

    switch (args->cmd & ~LINUX_IPC_64) {
    case LINUX_IPC_RMID:
        cmd = IPC_RMID;
        break;
    case LINUX_GETNCNT:
        cmd = GETNCNT;
        break;
    case LINUX_GETPID:
        cmd = GETPID;
        break;
    case LINUX_GETVAL:
        cmd = GETVAL;
        break;
    case LINUX_GETZCNT:
        cmd = GETZCNT;
        break;
    case LINUX_SETVAL:
        cmd = SETVAL;
        semun.val = args->arg.val;
        break;
    case LINUX_IPC_SET:
        cmd = IPC_SET;
        error = linux_semid_pullup(args->cmd & LINUX_IPC_64,
                                   &linux_semid, PTRIN(args->arg.buf));
        if (error)
            return (error);
        linux_to_bsd_semid_ds(&linux_semid, &semid);
        semun.buf = &semid;
        return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
                            td->td_retval));
    case LINUX_IPC_STAT:
    case LINUX_SEM_STAT:
        if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT)
            cmd = IPC_STAT;
        else
            cmd = SEM_STAT;
        semun.buf = &semid;
        error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
                            &rval);
        if (error)
            return (error);
        bsd_to_linux_semid_ds(&semid, &linux_semid);
        error = linux_semid_pushdown(args->cmd & LINUX_IPC_64,
                                     &linux_semid, PTRIN(args->arg.buf));
        if (error == 0)
            td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0;
        return (error);
    case LINUX_IPC_INFO:
    case LINUX_SEM_INFO:
        bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) -
              sizeof(linux_seminfo.semmap) );
        /*
         * Linux does not use the semmap field but populates it with
         * the defined value from SEMMAP, which really is redefined to
         * SEMMNS, which they define as SEMMNI * SEMMSL.  Try to
         * simulate this returning our dynamic semmns value.
         */
        linux_seminfo.semmap = linux_seminfo.semmns;
        /* XXX BSD equivalent?
        #define used_semids 10
        #define used_sems 10
        		linux_seminfo.semusz = used_semids;
        		linux_seminfo.semaem = used_sems;
        */
        error = copyout(&linux_seminfo,
                        PTRIN(args->arg.buf), sizeof(linux_seminfo));
        if (error)
            return (error);
        td->td_retval[0] = seminfo.semmni;
        return (0);			/* No need for __semctl call */
    case LINUX_GETALL:
        cmd = GETALL;
        semun.val = args->arg.val;
        break;
    case LINUX_SETALL:
        cmd = SETALL;
        semun.val = args->arg.val;
        break;
    default:
        linux_msg(td, "ipc type %d is not implemented",
                  args->cmd & ~LINUX_IPC_64);
        return (EINVAL);
    }
    return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
                        td->td_retval));
}