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)); }
int linux_semctl(struct proc *p, struct linux_semctl_args *args) { struct linux_semid_ds linux_semid; struct semid_ds bsd_semid; struct __semctl_args /* { int semid; int semnum; int cmd; union semun *arg; } */ bsd_args; int error; caddr_t sg, unptr, dsp, ldsp; sg = stackgap_init(); bsd_args.semid = args->arg1; bsd_args.semnum = args->arg2; bsd_args.cmd = args->arg3; bsd_args.arg = (union semun *)args->ptr; switch (args->arg3) { case LINUX_IPC_RMID: bsd_args.cmd = IPC_RMID; break; case LINUX_GETNCNT: bsd_args.cmd = GETNCNT; break; case LINUX_GETPID: bsd_args.cmd = GETPID; break; case LINUX_GETVAL: bsd_args.cmd = GETVAL; break; case LINUX_GETZCNT: bsd_args.cmd = GETZCNT; break; case LINUX_SETVAL: bsd_args.cmd = SETVAL; break; case LINUX_IPC_SET: bsd_args.cmd = IPC_SET; error = copyin(args->ptr, &ldsp, sizeof(ldsp)); if (error) return error; error = copyin(ldsp, (caddr_t)&linux_semid, sizeof(linux_semid)); if (error) return error; linux_to_bsd_semid_ds(&linux_semid, &bsd_semid); unptr = stackgap_alloc(&sg, sizeof(union semun)); dsp = stackgap_alloc(&sg, sizeof(struct semid_ds)); error = copyout((caddr_t)&bsd_semid, dsp, sizeof(bsd_semid)); if (error) return error; error = copyout((caddr_t)&dsp, unptr, sizeof(dsp)); if (error) return error; bsd_args.arg = (union semun *)unptr; return __semctl(p, &bsd_args); case LINUX_IPC_STAT: bsd_args.cmd = IPC_STAT; unptr = stackgap_alloc(&sg, sizeof(union semun *)); dsp = stackgap_alloc(&sg, sizeof(struct semid_ds)); error = copyout((caddr_t)&dsp, unptr, sizeof(dsp)); if (error) return error; bsd_args.arg = (union semun *)unptr; error = __semctl(p, &bsd_args); if (error) return error; error = copyin(dsp, (caddr_t)&bsd_semid, sizeof(bsd_semid)); if (error) return error; bsd_to_linux_semid_ds(&bsd_semid, &linux_semid); error = copyin(args->ptr, &ldsp, sizeof(ldsp)); if (error) return error; return copyout((caddr_t)&linux_semid, ldsp, sizeof(linux_semid)); case LINUX_GETALL: /* FALLTHROUGH */ case LINUX_SETALL: /* FALLTHROUGH */ default: uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->arg3); return EINVAL; } return __semctl(p, &bsd_args); }
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)); }