int linux_sysctl(struct thread *td, struct linux_sysctl_args *args) { struct l___sysctl_args la; struct sbuf *sb; l_int *mib; int error, i; error = copyin(args->args, &la, sizeof(la)); if (error) return (error); if (la.nlen <= 0 || la.nlen > LINUX_CTL_MAXNAME) return (ENOTDIR); mib = malloc(la.nlen * sizeof(l_int), M_TEMP, M_WAITOK); error = copyin(PTRIN(la.name), mib, la.nlen * sizeof(l_int)); if (error) { free(mib, M_TEMP); return (error); } switch (mib[0]) { case LINUX_CTL_KERN: if (la.nlen < 2) break; switch (mib[1]) { case LINUX_KERN_VERSION: error = handle_string(&la, version); free(mib, M_TEMP); return (error); default: break; } break; default: break; } sb = sbuf_new(NULL, NULL, 20 + la.nlen * 5, SBUF_AUTOEXTEND); if (sb == NULL) { linux_msg(td, "sysctl is not implemented"); } else { sbuf_printf(sb, "sysctl "); for (i = 0; i < la.nlen; i++) sbuf_printf(sb, "%c%d", (i) ? ',' : '{', mib[i]); sbuf_printf(sb, "} is not implemented"); sbuf_finish(sb); linux_msg(td, "%s", sbuf_data(sb)); sbuf_delete(sb); } free(mib, M_TEMP); return (ENOTDIR); }
void linux_thread_detach(struct thread *td) { struct linux_sys_futex_args cup; struct linux_emuldata *em; int *child_clear_tid; int error; em = em_find(td); KASSERT(em != NULL, ("thread_detach: emuldata not found.\n")); LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid); release_futexes(td, em); child_clear_tid = em->child_clear_tid; if (child_clear_tid != NULL) { LINUX_CTR2(thread_detach, "thread(%d) %p", em->em_tid, child_clear_tid); error = suword32(child_clear_tid, 0); if (error != 0) return; cup.uaddr = child_clear_tid; cup.op = LINUX_FUTEX_WAKE; cup.val = 1; /* wake one */ cup.timeout = NULL; cup.uaddr2 = NULL; cup.val3 = 0; error = linux_sys_futex(td, &cup); /* * this cannot happen at the moment and if this happens it * probably means there is a user space bug */ if (error != 0) linux_msg(td, "futex stuff in thread_detach failed."); } }
int linux_shmctl(struct thread *td, struct linux_shmctl_args *args) { struct l_shmid_ds linux_shmid; struct l_shminfo linux_shminfo; struct l_shm_info linux_shm_info; struct shmid_ds bsd_shmid; int error; switch (args->cmd & ~LINUX_IPC_64) { case LINUX_IPC_INFO: { struct shminfo bsd_shminfo; /* Perform shmctl wanting removed segments lookup */ error = kern_shmctl(td, args->shmid, IPC_INFO, (void *)&bsd_shminfo, NULL); if (error) return error; bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo); return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, &linux_shminfo, PTRIN(args->buf))); } case LINUX_SHM_INFO: { struct shm_info bsd_shm_info; /* Perform shmctl wanting removed segments lookup */ error = kern_shmctl(td, args->shmid, SHM_INFO, (void *)&bsd_shm_info, NULL); if (error) return error; bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info); return copyout(&linux_shm_info, PTRIN(args->buf), sizeof(struct l_shm_info)); } case LINUX_IPC_STAT: /* Perform shmctl wanting removed segments lookup */ error = kern_shmctl(td, args->shmid, IPC_STAT, (void *)&bsd_shmid, NULL); if (error) return error; bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, &linux_shmid, PTRIN(args->buf))); case LINUX_SHM_STAT: /* Perform shmctl wanting removed segments lookup */ error = kern_shmctl(td, args->shmid, IPC_STAT, (void *)&bsd_shmid, NULL); if (error) return error; bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, &linux_shmid, PTRIN(args->buf))); case LINUX_IPC_SET: error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, &linux_shmid, PTRIN(args->buf)); if (error) return error; linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); /* Perform shmctl wanting removed segments lookup */ return kern_shmctl(td, args->shmid, IPC_SET, (void *)&bsd_shmid, NULL); case LINUX_IPC_RMID: { void *buf; if (args->buf == 0) buf = NULL; else { error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, &linux_shmid, PTRIN(args->buf)); if (error) return error; linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); buf = (void *)&bsd_shmid; } return kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL); } case LINUX_SHM_LOCK: case LINUX_SHM_UNLOCK: default: linux_msg(td, "ipc typ=%d not implemented", args->cmd & ~LINUX_IPC_64); return EINVAL; } }
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 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)); }