1139804Simp/*- 22729Sdfr * Implementation of SVID semaphores 32729Sdfr * 42729Sdfr * Author: Daniel Boulet 52729Sdfr * 62729Sdfr * This software is provided ``AS IS'' without any warranties of any kind. 72729Sdfr */ 8140615Srwatson/*- 9140615Srwatson * Copyright (c) 2003-2005 McAfee, Inc. 10140615Srwatson * All rights reserved. 11140615Srwatson * 12140615Srwatson * This software was developed for the FreeBSD Project in part by McAfee 13140615Srwatson * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR 14140615Srwatson * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research 15140615Srwatson * program. 16140615Srwatson * 17140615Srwatson * Redistribution and use in source and binary forms, with or without 18140615Srwatson * modification, are permitted provided that the following conditions 19140615Srwatson * are met: 20140615Srwatson * 1. Redistributions of source code must retain the above copyright 21140615Srwatson * notice, this list of conditions and the following disclaimer. 22140615Srwatson * 2. Redistributions in binary form must reproduce the above copyright 23140615Srwatson * notice, this list of conditions and the following disclaimer in the 24140615Srwatson * documentation and/or other materials provided with the distribution. 25140615Srwatson * 26140615Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27140615Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28140615Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29140615Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30140615Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31140615Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32140615Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33140615Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34140615Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35140615Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36140615Srwatson * SUCH DAMAGE. 37140615Srwatson */ 382729Sdfr 39116182Sobrien#include <sys/cdefs.h> 40116182Sobrien__FBSDID("$FreeBSD$"); 41116182Sobrien 42194894Sjhb#include "opt_compat.h" 4359839Speter#include "opt_sysvipc.h" 4459839Speter 452729Sdfr#include <sys/param.h> 462729Sdfr#include <sys/systm.h> 4711626Sbde#include <sys/sysproto.h> 48112564Sjhb#include <sys/eventhandler.h> 492729Sdfr#include <sys/kernel.h> 502729Sdfr#include <sys/proc.h> 5182607Sdillon#include <sys/lock.h> 52129882Sphk#include <sys/module.h> 5382607Sdillon#include <sys/mutex.h> 54220398Strasz#include <sys/racct.h> 552729Sdfr#include <sys/sem.h> 5669449Salfred#include <sys/syscall.h> 57159991Sjhb#include <sys/syscallsubr.h> 5811626Sbde#include <sys/sysent.h> 5959839Speter#include <sys/sysctl.h> 60159991Sjhb#include <sys/uio.h> 6159839Speter#include <sys/malloc.h> 6268024Srwatson#include <sys/jail.h> 632729Sdfr 64163606Srwatson#include <security/mac/mac_framework.h> 65163606Srwatson 66219028SnetchildFEATURE(sysv_sem, "System V semaphores support"); 67219028Snetchild 6859839Speterstatic MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); 6959839Speter 70100523Salfred#ifdef SEM_DEBUG 71100523Salfred#define DPRINTF(a) printf a 72100523Salfred#else 73100523Salfred#define DPRINTF(a) 74100523Salfred#endif 75100523Salfred 76205323Skibstatic int seminit(void); 7792723Salfredstatic int sysvsem_modload(struct module *, int, void *); 7892723Salfredstatic int semunload(void); 79112564Sjhbstatic void semexit_myhook(void *arg, struct proc *p); 8092723Salfredstatic int sysctl_sema(SYSCTL_HANDLER_ARGS); 81137613Srwatsonstatic int semvalid(int semid, struct semid_kernel *semakptr); 8210358Sjulian 8312866Speter#ifndef _SYS_SYSPROTO_H_ 8412866Speterstruct __semctl_args; 8592723Salfredint __semctl(struct thread *td, struct __semctl_args *uap); 8611626Sbdestruct semget_args; 8792723Salfredint semget(struct thread *td, struct semget_args *uap); 8811626Sbdestruct semop_args; 8992723Salfredint semop(struct thread *td, struct semop_args *uap); 9012866Speter#endif 9111626Sbde 9292723Salfredstatic struct sem_undo *semu_alloc(struct thread *td); 93122201Srwatsonstatic int semundo_adjust(struct thread *td, struct sem_undo **supptr, 94187223Skib int semid, int semseq, int semnum, int adjval); 9592723Salfredstatic void semundo_clear(int semid, int semnum); 9611626Sbde 97101774Salfredstatic struct mtx sem_mtx; /* semaphore global lock */ 98187223Skibstatic struct mtx sem_undo_mtx; 9912819Sphkstatic int semtot = 0; 100137613Srwatsonstatic struct semid_kernel *sema; /* semaphore id pool */ 101101774Salfredstatic struct mtx *sema_mtx; /* semaphore id pool mutexes*/ 10259839Speterstatic struct sem *sem; /* semaphore pool */ 103187223SkibLIST_HEAD(, sem_undo) semu_list; /* list of active undo structures */ 104187223SkibLIST_HEAD(, sem_undo) semu_free_list; /* list of free undo structures */ 10559839Speterstatic int *semu; /* undo structure pool */ 106112564Sjhbstatic eventhandler_tag semexit_tag; 1072729Sdfr 108187223Skib#define SEMUNDO_MTX sem_undo_mtx 109101774Salfred#define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX); 110101774Salfred#define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX); 111101774Salfred#define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how)); 112101774Salfred 11359839Speterstruct sem { 11459839Speter u_short semval; /* semaphore value */ 11559839Speter pid_t sempid; /* pid of last operation */ 11659839Speter u_short semncnt; /* # awaiting semval > cval */ 11759839Speter u_short semzcnt; /* # awaiting semval = 0 */ 11859839Speter}; 11959839Speter 12059839Speter/* 12159839Speter * Undo structure (one per process) 12259839Speter */ 12359839Speterstruct sem_undo { 124187223Skib LIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */ 12559839Speter struct proc *un_proc; /* owner of this structure */ 12659839Speter short un_cnt; /* # of active entries */ 12759839Speter struct undo { 12859839Speter short un_adjval; /* adjust on exit values */ 12959839Speter short un_num; /* semaphore # */ 13059839Speter int un_id; /* semid */ 131187223Skib unsigned short un_seq; 13259839Speter } un_ent[1]; /* undo entries */ 13359839Speter}; 13459839Speter 13559839Speter/* 13659839Speter * Configuration parameters 13759839Speter */ 13859839Speter#ifndef SEMMNI 139209037Sivoras#define SEMMNI 50 /* # of semaphore identifiers */ 14059839Speter#endif 14159839Speter#ifndef SEMMNS 142209037Sivoras#define SEMMNS 340 /* # of semaphores in system */ 14359839Speter#endif 14459839Speter#ifndef SEMUME 145209037Sivoras#define SEMUME 50 /* max # of undo entries per process */ 14659839Speter#endif 14759839Speter#ifndef SEMMNU 148209037Sivoras#define SEMMNU 150 /* # of undo structures in system */ 14959839Speter#endif 15059839Speter 15159839Speter/* shouldn't need tuning */ 15259839Speter#ifndef SEMMSL 15359839Speter#define SEMMSL SEMMNS /* max # of semaphores per id */ 15459839Speter#endif 15559839Speter#ifndef SEMOPM 15659839Speter#define SEMOPM 100 /* max # of operations per semop call */ 15759839Speter#endif 15859839Speter 15959839Speter#define SEMVMX 32767 /* semaphore maximum value */ 16059839Speter#define SEMAEM 16384 /* adjust on exit max value */ 16159839Speter 16259839Speter/* 16359839Speter * Due to the way semaphore memory is allocated, we have to ensure that 16459839Speter * SEMUSZ is properly aligned. 16559839Speter */ 16659839Speter 16759839Speter#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) 16859839Speter 16959839Speter/* actual size of an undo structure */ 17059839Speter#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) 17159839Speter 17259839Speter/* 17359839Speter * Macro to find a particular sem_undo vector 17459839Speter */ 175101350Salfred#define SEMU(ix) \ 176101350Salfred ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) 17759839Speter 17859839Speter/* 17959839Speter * semaphore info struct 18059839Speter */ 18159839Speterstruct seminfo seminfo = { 18259839Speter SEMMNI, /* # of semaphore identifiers */ 18359839Speter SEMMNS, /* # of semaphores in system */ 18459839Speter SEMMNU, /* # of undo structures in system */ 18559839Speter SEMMSL, /* max # of semaphores per id */ 18659839Speter SEMOPM, /* max # of operations per semop call */ 18759839Speter SEMUME, /* max # of undo entries per process */ 18859839Speter SEMUSZ, /* size in bytes of undo structure */ 18959839Speter SEMVMX, /* semaphore maximum value */ 19059839Speter SEMAEM /* adjust on exit max value */ 19159839Speter}; 19259839Speter 193141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, 194141710Scsjp "Number of semaphore identifiers"); 195141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0, 196141710Scsjp "Maximum number of semaphores in the system"); 197141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0, 198141710Scsjp "Maximum number of undo structures in the system"); 199141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, 200141710Scsjp "Max semaphores per id"); 201141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0, 202141710Scsjp "Max operations per semop call"); 203141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0, 204141710Scsjp "Max undo entries per process"); 205141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0, 206141710Scsjp "Size in bytes of undo structure"); 207141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, 208141710Scsjp "Semaphore maximum value"); 209141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, 210141710Scsjp "Adjust on exit max value"); 211217555SmdfSYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLTYPE_OPAQUE | CTLFLAG_RD, 212215281Sbrucec NULL, 0, sysctl_sema, "", "Semaphore id pool"); 21359839Speter 214205323Skibstatic struct syscall_helper_data sem_syscalls[] = { 215205323Skib SYSCALL_INIT_HELPER(__semctl), 216205323Skib SYSCALL_INIT_HELPER(semget), 217205323Skib SYSCALL_INIT_HELPER(semop), 218205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 219205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 220205323Skib SYSCALL_INIT_HELPER(semsys), 221225617Skmacy SYSCALL_INIT_HELPER_COMPAT(freebsd7___semctl), 222205323Skib#endif 223205323Skib SYSCALL_INIT_LAST 224205323Skib}; 225205323Skib 226205323Skib#ifdef COMPAT_FREEBSD32 227205323Skib#include <compat/freebsd32/freebsd32.h> 228205323Skib#include <compat/freebsd32/freebsd32_ipc.h> 229205323Skib#include <compat/freebsd32/freebsd32_proto.h> 230205323Skib#include <compat/freebsd32/freebsd32_signal.h> 231205323Skib#include <compat/freebsd32/freebsd32_syscall.h> 232205323Skib#include <compat/freebsd32/freebsd32_util.h> 233205323Skib 234205323Skibstatic struct syscall_helper_data sem32_syscalls[] = { 235205323Skib SYSCALL32_INIT_HELPER(freebsd32_semctl), 236225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(semget), 237225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(semop), 238205323Skib SYSCALL32_INIT_HELPER(freebsd32_semsys), 239205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 240205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 241205323Skib SYSCALL32_INIT_HELPER(freebsd7_freebsd32_semctl), 242205323Skib#endif 243205323Skib SYSCALL_INIT_LAST 244205323Skib}; 245205323Skib#endif 246205323Skib 247205323Skibstatic int 24869449Salfredseminit(void) 2492729Sdfr{ 250205323Skib int i, error; 2512729Sdfr 25283413Smr TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni); 25383413Smr TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns); 25483413Smr TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu); 25583413Smr TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl); 25683413Smr TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm); 25783413Smr TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume); 25883413Smr TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz); 25983413Smr TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx); 26083413Smr TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem); 26183413Smr 262111119Simp sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 263137613Srwatson sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM, 264111119Simp M_WAITOK); 265101774Salfred sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM, 266111119Simp M_WAITOK | M_ZERO); 267111119Simp semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 2682729Sdfr 2692729Sdfr for (i = 0; i < seminfo.semmni; i++) { 270137613Srwatson sema[i].u.sem_base = 0; 271137613Srwatson sema[i].u.sem_perm.mode = 0; 272137613Srwatson sema[i].u.sem_perm.seq = 0; 273140615Srwatson#ifdef MAC 274172930Srwatson mac_sysvsem_init(&sema[i]); 275140615Srwatson#endif 2762729Sdfr } 277101774Salfred for (i = 0; i < seminfo.semmni; i++) 278101774Salfred mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); 279187223Skib LIST_INIT(&semu_free_list); 2802729Sdfr for (i = 0; i < seminfo.semmnu; i++) { 281101350Salfred struct sem_undo *suptr = SEMU(i); 2822729Sdfr suptr->un_proc = NULL; 283187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 2842729Sdfr } 285187223Skib LIST_INIT(&semu_list); 286101774Salfred mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); 287187223Skib mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF); 288112564Sjhb semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, 289112564Sjhb EVENTHANDLER_PRI_ANY); 290205323Skib 291205323Skib error = syscall_helper_register(sem_syscalls); 292205323Skib if (error != 0) 293205323Skib return (error); 294205323Skib#ifdef COMPAT_FREEBSD32 295205323Skib error = syscall32_helper_register(sem32_syscalls); 296205323Skib if (error != 0) 297205323Skib return (error); 298205323Skib#endif 299205323Skib return (0); 3002729Sdfr} 3012729Sdfr 30269449Salfredstatic int 30369449Salfredsemunload(void) 30469449Salfred{ 305101774Salfred int i; 30669449Salfred 307187223Skib /* XXXKIB */ 30869449Salfred if (semtot != 0) 30969449Salfred return (EBUSY); 31069449Salfred 311205323Skib#ifdef COMPAT_FREEBSD32 312205323Skib syscall32_helper_unregister(sem32_syscalls); 313205323Skib#endif 314205323Skib syscall_helper_unregister(sem_syscalls); 315112564Sjhb EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); 316140615Srwatson#ifdef MAC 317140615Srwatson for (i = 0; i < seminfo.semmni; i++) 318172930Srwatson mac_sysvsem_destroy(&sema[i]); 319140615Srwatson#endif 32069449Salfred free(sem, M_SEM); 32169449Salfred free(sema, M_SEM); 32269449Salfred free(semu, M_SEM); 323101774Salfred for (i = 0; i < seminfo.semmni; i++) 324101774Salfred mtx_destroy(&sema_mtx[i]); 325190557Sbrueffer free(sema_mtx, M_SEM); 326101774Salfred mtx_destroy(&sem_mtx); 327187223Skib mtx_destroy(&sem_undo_mtx); 32869449Salfred return (0); 32969449Salfred} 33069449Salfred 33169449Salfredstatic int 33269449Salfredsysvsem_modload(struct module *module, int cmd, void *arg) 33369449Salfred{ 33469449Salfred int error = 0; 33569449Salfred 33669449Salfred switch (cmd) { 33769449Salfred case MOD_LOAD: 338205323Skib error = seminit(); 339205323Skib if (error != 0) 340205323Skib semunload(); 34169449Salfred break; 34269449Salfred case MOD_UNLOAD: 34369449Salfred error = semunload(); 34469449Salfred break; 34569449Salfred case MOD_SHUTDOWN: 34669449Salfred break; 34769449Salfred default: 34869449Salfred error = EINVAL; 34969449Salfred break; 35069449Salfred } 35169449Salfred return (error); 35269449Salfred} 35369449Salfred 35471038Sdesstatic moduledata_t sysvsem_mod = { 35571038Sdes "sysvsem", 35669449Salfred &sysvsem_modload, 35769449Salfred NULL 35869449Salfred}; 35969449Salfred 360194832SjhbDECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 36171038SdesMODULE_VERSION(sysvsem, 1); 36269449Salfred 3632729Sdfr/* 3642729Sdfr * Allocate a new sem_undo structure for a process 3652729Sdfr * (returns ptr to structure or NULL if no more room) 3662729Sdfr */ 3672729Sdfr 36812819Sphkstatic struct sem_undo * 369187223Skibsemu_alloc(struct thread *td) 3702729Sdfr{ 371101350Salfred struct sem_undo *suptr; 3722729Sdfr 373101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 374187223Skib if ((suptr = LIST_FIRST(&semu_free_list)) == NULL) 375187223Skib return (NULL); 376187223Skib LIST_REMOVE(suptr, un_next); 377187223Skib LIST_INSERT_HEAD(&semu_list, suptr, un_next); 378187223Skib suptr->un_cnt = 0; 379187223Skib suptr->un_proc = td->td_proc; 380187223Skib return (suptr); 381187223Skib} 3822729Sdfr 383187223Skibstatic int 384187223Skibsemu_try_free(struct sem_undo *suptr) 385187223Skib{ 3862729Sdfr 387187223Skib SEMUNDO_LOCKASSERT(MA_OWNED); 3882729Sdfr 389187223Skib if (suptr->un_cnt != 0) 390187223Skib return (0); 391187223Skib LIST_REMOVE(suptr, un_next); 392187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 393187223Skib return (1); 3942729Sdfr} 3952729Sdfr 3962729Sdfr/* 3972729Sdfr * Adjust a particular entry for a particular proc 3982729Sdfr */ 3992729Sdfr 40012819Sphkstatic int 401187223Skibsemundo_adjust(struct thread *td, struct sem_undo **supptr, int semid, 402187223Skib int semseq, int semnum, int adjval) 4032729Sdfr{ 40483366Sjulian struct proc *p = td->td_proc; 405101350Salfred struct sem_undo *suptr; 406101350Salfred struct undo *sunptr; 4072729Sdfr int i; 4082729Sdfr 409101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 4102729Sdfr /* Look for and remember the sem_undo if the caller doesn't provide 4112729Sdfr it */ 4122729Sdfr 4132729Sdfr suptr = *supptr; 4142729Sdfr if (suptr == NULL) { 415187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 4162729Sdfr if (suptr->un_proc == p) { 4172729Sdfr *supptr = suptr; 4182729Sdfr break; 4192729Sdfr } 4202729Sdfr } 4212729Sdfr if (suptr == NULL) { 4222729Sdfr if (adjval == 0) 4232729Sdfr return(0); 42483366Sjulian suptr = semu_alloc(td); 4252729Sdfr if (suptr == NULL) 426187223Skib return (ENOSPC); 4272729Sdfr *supptr = suptr; 4282729Sdfr } 4292729Sdfr } 4302729Sdfr 4312729Sdfr /* 4322729Sdfr * Look for the requested entry and adjust it (delete if adjval becomes 4332729Sdfr * 0). 4342729Sdfr */ 4352729Sdfr sunptr = &suptr->un_ent[0]; 4362729Sdfr for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 4372729Sdfr if (sunptr->un_id != semid || sunptr->un_num != semnum) 4382729Sdfr continue; 43984789Smr if (adjval != 0) { 44084789Smr adjval += sunptr->un_adjval; 44184789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 44284789Smr return (ERANGE); 44384789Smr } 44484789Smr sunptr->un_adjval = adjval; 4452729Sdfr if (sunptr->un_adjval == 0) { 4462729Sdfr suptr->un_cnt--; 4472729Sdfr if (i < suptr->un_cnt) 4482729Sdfr suptr->un_ent[i] = 4492729Sdfr suptr->un_ent[suptr->un_cnt]; 450187223Skib if (suptr->un_cnt == 0) 451187223Skib semu_try_free(suptr); 4522729Sdfr } 453187223Skib return (0); 4542729Sdfr } 4552729Sdfr 4562729Sdfr /* Didn't find the right entry - create it */ 4572729Sdfr if (adjval == 0) 458187223Skib return (0); 45984789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 46084789Smr return (ERANGE); 46141774Sdillon if (suptr->un_cnt != seminfo.semume) { 4622729Sdfr sunptr = &suptr->un_ent[suptr->un_cnt]; 4632729Sdfr suptr->un_cnt++; 4642729Sdfr sunptr->un_adjval = adjval; 465187223Skib sunptr->un_id = semid; 466187223Skib sunptr->un_num = semnum; 467187223Skib sunptr->un_seq = semseq; 4682729Sdfr } else 469187223Skib return (EINVAL); 470187223Skib return (0); 4712729Sdfr} 4722729Sdfr 47312819Sphkstatic void 474187223Skibsemundo_clear(int semid, int semnum) 4752729Sdfr{ 476187223Skib struct sem_undo *suptr, *suptr1; 477187223Skib struct undo *sunptr; 478187223Skib int i; 4792729Sdfr 480101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 481187223Skib LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) { 482187223Skib sunptr = &suptr->un_ent[0]; 483187223Skib for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 484187223Skib if (sunptr->un_id != semid) 485187223Skib continue; 486187223Skib if (semnum == -1 || sunptr->un_num == semnum) { 487187223Skib suptr->un_cnt--; 488187223Skib if (i < suptr->un_cnt) { 489187223Skib suptr->un_ent[i] = 490187223Skib suptr->un_ent[suptr->un_cnt]; 491187223Skib continue; 4922729Sdfr } 493187223Skib semu_try_free(suptr); 4942729Sdfr } 495187223Skib if (semnum != -1) 496187223Skib break; 4972729Sdfr } 4982729Sdfr } 4992729Sdfr} 5002729Sdfr 501101774Salfredstatic int 502187223Skibsemvalid(int semid, struct semid_kernel *semakptr) 503101774Salfred{ 504101774Salfred 505137613Srwatson return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 506137613Srwatson semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0); 507101774Salfred} 508101774Salfred 50912866Speter/* 510167211Srwatson * Note that the user-mode half of this passes a union, not a pointer. 51112866Speter */ 51212866Speter#ifndef _SYS_SYSPROTO_H_ 51312866Speterstruct __semctl_args { 5142729Sdfr int semid; 5152729Sdfr int semnum; 5162729Sdfr int cmd; 5172729Sdfr union semun *arg; 5182729Sdfr}; 51912866Speter#endif 52012866Speterint 521225617Skmacysys___semctl(struct thread *td, struct __semctl_args *uap) 5222729Sdfr{ 523160187Sjhb struct semid_ds dsbuf; 524160187Sjhb union semun arg, semun; 525160187Sjhb register_t rval; 526159991Sjhb int error; 527159991Sjhb 528159991Sjhb switch (uap->cmd) { 529159991Sjhb case SEM_STAT: 530159991Sjhb case IPC_SET: 531159991Sjhb case IPC_STAT: 532159991Sjhb case GETALL: 533159991Sjhb case SETVAL: 534159991Sjhb case SETALL: 535160187Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 536159991Sjhb if (error) 537159991Sjhb return (error); 538159991Sjhb break; 539160187Sjhb } 540160187Sjhb 541160187Sjhb switch (uap->cmd) { 542160187Sjhb case SEM_STAT: 543160187Sjhb case IPC_STAT: 544160187Sjhb semun.buf = &dsbuf; 545159991Sjhb break; 546160187Sjhb case IPC_SET: 547160187Sjhb error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 548160187Sjhb if (error) 549160187Sjhb return (error); 550160187Sjhb semun.buf = &dsbuf; 551160187Sjhb break; 552160187Sjhb case GETALL: 553160187Sjhb case SETALL: 554160187Sjhb semun.array = arg.array; 555160187Sjhb break; 556160187Sjhb case SETVAL: 557160187Sjhb semun.val = arg.val; 558160187Sjhb break; 559159991Sjhb } 560160187Sjhb 561160187Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 562160187Sjhb &rval); 563160187Sjhb if (error) 564160187Sjhb return (error); 565160187Sjhb 566160187Sjhb switch (uap->cmd) { 567160187Sjhb case SEM_STAT: 568160187Sjhb case IPC_STAT: 569160187Sjhb error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 570160187Sjhb break; 571160187Sjhb } 572160187Sjhb 573160187Sjhb if (error == 0) 574160187Sjhb td->td_retval[0] = rval; 575160187Sjhb return (error); 576159991Sjhb} 577159991Sjhb 578159991Sjhbint 579160187Sjhbkern_semctl(struct thread *td, int semid, int semnum, int cmd, 580160187Sjhb union semun *arg, register_t *rval) 581159991Sjhb{ 582101774Salfred u_short *array; 58391406Sjhb struct ucred *cred = td->td_ucred; 584160187Sjhb int i, error; 585160187Sjhb struct semid_ds *sbuf; 586137613Srwatson struct semid_kernel *semakptr; 587101774Salfred struct mtx *sema_mtxp; 588101774Salfred u_short usval, count; 589160028Sjhb int semidx; 5902729Sdfr 591160293Skib DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 592100523Salfred semid, semnum, cmd, arg)); 593192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 59491703Sjhb return (ENOSYS); 59591703Sjhb 596101774Salfred array = NULL; 597101774Salfred 59883414Smr switch(cmd) { 59983414Smr case SEM_STAT: 600160028Sjhb /* 601160028Sjhb * For this command we assume semid is an array index 602160028Sjhb * rather than an IPC id. 603160028Sjhb */ 60491744Smaxim if (semid < 0 || semid >= seminfo.semmni) 605101774Salfred return (EINVAL); 606137613Srwatson semakptr = &sema[semid]; 607101774Salfred sema_mtxp = &sema_mtx[semid]; 608101774Salfred mtx_lock(sema_mtxp); 609137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 610101774Salfred error = EINVAL; 611101774Salfred goto done2; 612101774Salfred } 613137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 614101774Salfred goto done2; 615140615Srwatson#ifdef MAC 616172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 617162468Srwatson if (error != 0) 618140615Srwatson goto done2; 619140615Srwatson#endif 620160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 621160187Sjhb *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 622101774Salfred mtx_unlock(sema_mtxp); 623160187Sjhb return (0); 62483414Smr } 62583414Smr 626160028Sjhb semidx = IPCID_TO_IX(semid); 627160028Sjhb if (semidx < 0 || semidx >= seminfo.semmni) 628101774Salfred return (EINVAL); 6292729Sdfr 630160028Sjhb semakptr = &sema[semidx]; 631160028Sjhb sema_mtxp = &sema_mtx[semidx]; 632187223Skib if (cmd == IPC_RMID) 633187223Skib mtx_lock(&sem_mtx); 634160187Sjhb mtx_lock(sema_mtxp); 635140615Srwatson#ifdef MAC 636172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 637162468Srwatson if (error != 0) 638160187Sjhb goto done2; 639140615Srwatson#endif 640145230Srwatson 64182607Sdillon error = 0; 642160187Sjhb *rval = 0; 6432729Sdfr 6442729Sdfr switch (cmd) { 6452729Sdfr case IPC_RMID: 646159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 647101774Salfred goto done2; 648137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 64982607Sdillon goto done2; 650137613Srwatson semakptr->u.sem_perm.cuid = cred->cr_uid; 651137613Srwatson semakptr->u.sem_perm.uid = cred->cr_uid; 652187223Skib semakptr->u.sem_perm.mode = 0; 653220398Strasz racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems); 654220388Strasz crfree(semakptr->cred); 655220388Strasz semakptr->cred = NULL; 656187223Skib SEMUNDO_LOCK(); 657187223Skib semundo_clear(semidx, -1); 658187223Skib SEMUNDO_UNLOCK(); 659187223Skib#ifdef MAC 660187223Skib mac_sysvsem_cleanup(semakptr); 661187223Skib#endif 662187223Skib wakeup(semakptr); 663187223Skib for (i = 0; i < seminfo.semmni; i++) { 664187223Skib if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 665187223Skib sema[i].u.sem_base > semakptr->u.sem_base) 666187223Skib mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); 667187223Skib } 668137613Srwatson for (i = semakptr->u.sem_base - sem; i < semtot; i++) 669137613Srwatson sem[i] = sem[i + semakptr->u.sem_nsems]; 6702729Sdfr for (i = 0; i < seminfo.semmni; i++) { 671137613Srwatson if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 672187223Skib sema[i].u.sem_base > semakptr->u.sem_base) { 673137613Srwatson sema[i].u.sem_base -= semakptr->u.sem_nsems; 674187223Skib mtx_unlock(&sema_mtx[i]); 675187223Skib } 6762729Sdfr } 677187223Skib semtot -= semakptr->u.sem_nsems; 6782729Sdfr break; 6792729Sdfr 6802729Sdfr case IPC_SET: 681159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 682101774Salfred goto done2; 683137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 684101774Salfred goto done2; 685160187Sjhb sbuf = arg->buf; 686160187Sjhb semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 687160187Sjhb semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 688137613Srwatson semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 689160187Sjhb ~0777) | (sbuf->sem_perm.mode & 0777); 690137613Srwatson semakptr->u.sem_ctime = time_second; 6912729Sdfr break; 6922729Sdfr 6932729Sdfr case IPC_STAT: 694159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 695101774Salfred goto done2; 696137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 69782607Sdillon goto done2; 698160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 6992729Sdfr break; 7002729Sdfr 7012729Sdfr case GETNCNT: 702159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 703101774Salfred goto done2; 704137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 70582607Sdillon goto done2; 706137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 70782607Sdillon error = EINVAL; 70882607Sdillon goto done2; 70982607Sdillon } 710160187Sjhb *rval = semakptr->u.sem_base[semnum].semncnt; 7112729Sdfr break; 7122729Sdfr 7132729Sdfr case GETPID: 714159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 715101774Salfred goto done2; 716137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 71782607Sdillon goto done2; 718137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 71982607Sdillon error = EINVAL; 72082607Sdillon goto done2; 72182607Sdillon } 722160187Sjhb *rval = semakptr->u.sem_base[semnum].sempid; 7232729Sdfr break; 7242729Sdfr 7252729Sdfr case GETVAL: 726159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 727101774Salfred goto done2; 728137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 72982607Sdillon goto done2; 730137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 73182607Sdillon error = EINVAL; 73282607Sdillon goto done2; 73382607Sdillon } 734160187Sjhb *rval = semakptr->u.sem_base[semnum].semval; 7352729Sdfr break; 7362729Sdfr 7372729Sdfr case GETALL: 738159991Sjhb /* 739160187Sjhb * Unfortunately, callers of this function don't know 740160187Sjhb * in advance how many semaphores are in this set. 741160187Sjhb * While we could just allocate the maximum size array 742160187Sjhb * and pass the actual size back to the caller, that 743160187Sjhb * won't work for SETALL since we can't copyin() more 744160187Sjhb * data than the user specified as we may return a 745160187Sjhb * spurious EFAULT. 746160187Sjhb * 747160187Sjhb * Note that the number of semaphores in a set is 748160187Sjhb * fixed for the life of that set. The only way that 749160187Sjhb * the 'count' could change while are blocked in 750160187Sjhb * malloc() is if this semaphore set were destroyed 751160187Sjhb * and a new one created with the same index. 752160187Sjhb * However, semvalid() will catch that due to the 753160187Sjhb * sequence number unless exactly 0x8000 (or a 754160187Sjhb * multiple thereof) semaphore sets for the same index 755160187Sjhb * are created and destroyed while we are in malloc! 756160187Sjhb * 757159991Sjhb */ 758160187Sjhb count = semakptr->u.sem_nsems; 759160187Sjhb mtx_unlock(sema_mtxp); 760160187Sjhb array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 761101774Salfred mtx_lock(sema_mtxp); 762159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 763101774Salfred goto done2; 764160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 765137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 76682607Sdillon goto done2; 767137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) 768137613Srwatson array[i] = semakptr->u.sem_base[i].semval; 769101774Salfred mtx_unlock(sema_mtxp); 770160187Sjhb error = copyout(array, arg->array, count * sizeof(*array)); 771160187Sjhb mtx_lock(sema_mtxp); 7722729Sdfr break; 7732729Sdfr 7742729Sdfr case GETZCNT: 775159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 776101774Salfred goto done2; 777137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 77882607Sdillon goto done2; 779137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 78082607Sdillon error = EINVAL; 78182607Sdillon goto done2; 78282607Sdillon } 783160187Sjhb *rval = semakptr->u.sem_base[semnum].semzcnt; 7842729Sdfr break; 7852729Sdfr 7862729Sdfr case SETVAL: 787159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 788101774Salfred goto done2; 789137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 79082607Sdillon goto done2; 791137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 79282607Sdillon error = EINVAL; 79382607Sdillon goto done2; 79482607Sdillon } 795159991Sjhb if (arg->val < 0 || arg->val > seminfo.semvmx) { 79684789Smr error = ERANGE; 79784789Smr goto done2; 79884789Smr } 799159991Sjhb semakptr->u.sem_base[semnum].semval = arg->val; 800101774Salfred SEMUNDO_LOCK(); 801160028Sjhb semundo_clear(semidx, semnum); 802101774Salfred SEMUNDO_UNLOCK(); 803137613Srwatson wakeup(semakptr); 8042729Sdfr break; 8052729Sdfr 8062729Sdfr case SETALL: 807159991Sjhb /* 808160187Sjhb * See comment on GETALL for why 'count' shouldn't change 809160187Sjhb * and why we require a userland buffer. 810159991Sjhb */ 811137613Srwatson count = semakptr->u.sem_nsems; 812160187Sjhb mtx_unlock(sema_mtxp); 813111119Simp array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 814159991Sjhb error = copyin(arg->array, array, count * sizeof(*array)); 815171179Skib mtx_lock(sema_mtxp); 816101774Salfred if (error) 817101774Salfred break; 818159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 819101774Salfred goto done2; 820160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 821137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 822101774Salfred goto done2; 823137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) { 824101774Salfred usval = array[i]; 82584789Smr if (usval > seminfo.semvmx) { 82684789Smr error = ERANGE; 82784789Smr break; 82884789Smr } 829137613Srwatson semakptr->u.sem_base[i].semval = usval; 8302729Sdfr } 831101774Salfred SEMUNDO_LOCK(); 832160028Sjhb semundo_clear(semidx, -1); 833101774Salfred SEMUNDO_UNLOCK(); 834137613Srwatson wakeup(semakptr); 8352729Sdfr break; 8362729Sdfr 8372729Sdfr default: 83882607Sdillon error = EINVAL; 83982607Sdillon break; 8402729Sdfr } 8412729Sdfr 84282607Sdillondone2: 843160187Sjhb mtx_unlock(sema_mtxp); 844187223Skib if (cmd == IPC_RMID) 845187223Skib mtx_unlock(&sem_mtx); 846101774Salfred if (array != NULL) 847101774Salfred free(array, M_TEMP); 84882607Sdillon return(error); 8492729Sdfr} 8502729Sdfr 85112866Speter#ifndef _SYS_SYSPROTO_H_ 8522729Sdfrstruct semget_args { 8532729Sdfr key_t key; 8542729Sdfr int nsems; 8552729Sdfr int semflg; 8562729Sdfr}; 85712866Speter#endif 85812866Speterint 859225617Skmacysys_semget(struct thread *td, struct semget_args *uap) 8602729Sdfr{ 86182607Sdillon int semid, error = 0; 8622729Sdfr int key = uap->key; 8632729Sdfr int nsems = uap->nsems; 8642729Sdfr int semflg = uap->semflg; 86591703Sjhb struct ucred *cred = td->td_ucred; 8662729Sdfr 867100523Salfred DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 868192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 86991703Sjhb return (ENOSYS); 87091703Sjhb 871187223Skib mtx_lock(&sem_mtx); 8722729Sdfr if (key != IPC_PRIVATE) { 8732729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 874137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 875137613Srwatson sema[semid].u.sem_perm.key == key) 8762729Sdfr break; 8772729Sdfr } 8782729Sdfr if (semid < seminfo.semmni) { 879100523Salfred DPRINTF(("found public key\n")); 880137613Srwatson if ((error = ipcperm(td, &sema[semid].u.sem_perm, 88182607Sdillon semflg & 0700))) { 88282607Sdillon goto done2; 88382607Sdillon } 884137613Srwatson if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 885100523Salfred DPRINTF(("too small\n")); 88682607Sdillon error = EINVAL; 88782607Sdillon goto done2; 8882729Sdfr } 8892729Sdfr if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 890100523Salfred DPRINTF(("not exclusive\n")); 89182607Sdillon error = EEXIST; 89282607Sdillon goto done2; 8932729Sdfr } 894140615Srwatson#ifdef MAC 895172930Srwatson error = mac_sysvsem_check_semget(cred, &sema[semid]); 896162468Srwatson if (error != 0) 897140615Srwatson goto done2; 898140615Srwatson#endif 8992729Sdfr goto found; 9002729Sdfr } 9012729Sdfr } 9022729Sdfr 903137613Srwatson DPRINTF(("need to allocate the semid_kernel\n")); 9042729Sdfr if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 9052729Sdfr if (nsems <= 0 || nsems > seminfo.semmsl) { 906100523Salfred DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 907100523Salfred seminfo.semmsl)); 90882607Sdillon error = EINVAL; 90982607Sdillon goto done2; 9102729Sdfr } 9112729Sdfr if (nsems > seminfo.semmns - semtot) { 912100523Salfred DPRINTF(( 913100523Salfred "not enough semaphores left (need %d, got %d)\n", 914100523Salfred nsems, seminfo.semmns - semtot)); 91582607Sdillon error = ENOSPC; 91682607Sdillon goto done2; 9172729Sdfr } 9182729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 919137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 9202729Sdfr break; 9212729Sdfr } 9222729Sdfr if (semid == seminfo.semmni) { 923137613Srwatson DPRINTF(("no more semid_kernel's available\n")); 92482607Sdillon error = ENOSPC; 92582607Sdillon goto done2; 9262729Sdfr } 927223825Strasz#ifdef RACCT 928220398Strasz PROC_LOCK(td->td_proc); 929220398Strasz error = racct_add(td->td_proc, RACCT_NSEM, nsems); 930220398Strasz PROC_UNLOCK(td->td_proc); 931220398Strasz if (error != 0) { 932220398Strasz error = ENOSPC; 933220398Strasz goto done2; 934220398Strasz } 935223825Strasz#endif 936100523Salfred DPRINTF(("semid %d is available\n", semid)); 937187298Skib mtx_lock(&sema_mtx[semid]); 938187298Skib KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 939187298Skib ("Lost semaphore %d", semid)); 940137613Srwatson sema[semid].u.sem_perm.key = key; 941137613Srwatson sema[semid].u.sem_perm.cuid = cred->cr_uid; 942137613Srwatson sema[semid].u.sem_perm.uid = cred->cr_uid; 943137613Srwatson sema[semid].u.sem_perm.cgid = cred->cr_gid; 944137613Srwatson sema[semid].u.sem_perm.gid = cred->cr_gid; 945137613Srwatson sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 946220399Strasz sema[semid].cred = crhold(cred); 947137613Srwatson sema[semid].u.sem_perm.seq = 948137613Srwatson (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 949137613Srwatson sema[semid].u.sem_nsems = nsems; 950137613Srwatson sema[semid].u.sem_otime = 0; 951137613Srwatson sema[semid].u.sem_ctime = time_second; 952137613Srwatson sema[semid].u.sem_base = &sem[semtot]; 9532729Sdfr semtot += nsems; 954137613Srwatson bzero(sema[semid].u.sem_base, 955137613Srwatson sizeof(sema[semid].u.sem_base[0])*nsems); 956140615Srwatson#ifdef MAC 957172930Srwatson mac_sysvsem_create(cred, &sema[semid]); 958140615Srwatson#endif 959187298Skib mtx_unlock(&sema_mtx[semid]); 960160293Skib DPRINTF(("sembase = %p, next = %p\n", 961137613Srwatson sema[semid].u.sem_base, &sem[semtot])); 9622729Sdfr } else { 963100523Salfred DPRINTF(("didn't find it and wasn't asked to create it\n")); 96482607Sdillon error = ENOENT; 96582607Sdillon goto done2; 9662729Sdfr } 9672729Sdfr 9682729Sdfrfound: 969137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 97082607Sdillondone2: 971187223Skib mtx_unlock(&sem_mtx); 97282607Sdillon return (error); 9732729Sdfr} 9742729Sdfr 97512866Speter#ifndef _SYS_SYSPROTO_H_ 9762729Sdfrstruct semop_args { 9772729Sdfr int semid; 9782729Sdfr struct sembuf *sops; 979109829Salfred size_t nsops; 9802729Sdfr}; 98112866Speter#endif 98212866Speterint 983225617Skmacysys_semop(struct thread *td, struct semop_args *uap) 9842729Sdfr{ 985123667Stjr#define SMALL_SOPS 8 986123667Stjr struct sembuf small_sops[SMALL_SOPS]; 9872729Sdfr int semid = uap->semid; 988109829Salfred size_t nsops = uap->nsops; 989105429Salfred struct sembuf *sops; 990137613Srwatson struct semid_kernel *semakptr; 991101350Salfred struct sembuf *sopptr = 0; 992101350Salfred struct sem *semptr = 0; 99384789Smr struct sem_undo *suptr; 994101774Salfred struct mtx *sema_mtxp; 995110040Stjr size_t i, j, k; 996109829Salfred int error; 9973308Sphk int do_wakeup, do_undos; 998187223Skib unsigned short seq; 9992729Sdfr 1000160293Skib#ifdef SEM_DEBUG 1001160293Skib sops = NULL; 1002160293Skib#endif 1003160293Skib DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 10042729Sdfr 1005192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 100691703Sjhb return (ENOSYS); 100791703Sjhb 10082729Sdfr semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 10092729Sdfr 1010101774Salfred if (semid < 0 || semid >= seminfo.semmni) 1011137644Srwatson return (EINVAL); 1012101774Salfred 1013101774Salfred /* Allocate memory for sem_ops */ 1014123667Stjr if (nsops <= SMALL_SOPS) 1015123667Stjr sops = small_sops; 1016220398Strasz else if (nsops > seminfo.semopm) { 1017101774Salfred DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1018101774Salfred nsops)); 1019101774Salfred return (E2BIG); 1020220398Strasz } else { 1021223825Strasz#ifdef RACCT 1022220398Strasz PROC_LOCK(td->td_proc); 1023220398Strasz if (nsops > racct_get_available(td->td_proc, RACCT_NSEMOP)) { 1024220398Strasz PROC_UNLOCK(td->td_proc); 1025220398Strasz return (E2BIG); 1026220398Strasz } 1027220398Strasz PROC_UNLOCK(td->td_proc); 1028223825Strasz#endif 1029220398Strasz 1030220398Strasz sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 103182607Sdillon } 1032101774Salfred if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1033160293Skib DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1034101774Salfred uap->sops, sops, nsops * sizeof(sops[0]))); 1035123667Stjr if (sops != small_sops) 1036123667Stjr free(sops, M_SEM); 1037101774Salfred return (error); 1038101774Salfred } 10392729Sdfr 1040137613Srwatson semakptr = &sema[semid]; 1041101774Salfred sema_mtxp = &sema_mtx[semid]; 1042101774Salfred mtx_lock(sema_mtxp); 1043137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 104482607Sdillon error = EINVAL; 104582607Sdillon goto done2; 104682607Sdillon } 1047187223Skib seq = semakptr->u.sem_perm.seq; 1048187223Skib if (seq != IPCID_TO_SEQ(uap->semid)) { 104982607Sdillon error = EINVAL; 105082607Sdillon goto done2; 105182607Sdillon } 105284789Smr /* 105384789Smr * Initial pass thru sops to see what permissions are needed. 105484789Smr * Also perform any checks that don't need repeating on each 105584789Smr * attempt to satisfy the request vector. 105684789Smr */ 105784789Smr j = 0; /* permission needed */ 105884789Smr do_undos = 0; 105984789Smr for (i = 0; i < nsops; i++) { 106084789Smr sopptr = &sops[i]; 1061137613Srwatson if (sopptr->sem_num >= semakptr->u.sem_nsems) { 106284789Smr error = EFBIG; 106384789Smr goto done2; 106484789Smr } 106584789Smr if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 106684789Smr do_undos = 1; 106784789Smr j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 106884789Smr } 106984789Smr 1070137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1071100523Salfred DPRINTF(("error = %d from ipaccess\n", error)); 107282607Sdillon goto done2; 10732729Sdfr } 1074140615Srwatson#ifdef MAC 1075172930Srwatson error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1076162468Srwatson if (error != 0) 1077140615Srwatson goto done2; 1078140615Srwatson#endif 10792729Sdfr 10808876Srgrimes /* 10812729Sdfr * Loop trying to satisfy the vector of requests. 10822729Sdfr * If we reach a point where we must wait, any requests already 10832729Sdfr * performed are rolled back and we go to sleep until some other 10842729Sdfr * process wakes us up. At this point, we start all over again. 10852729Sdfr * 10862729Sdfr * This ensures that from the perspective of other tasks, a set 10872729Sdfr * of requests is atomic (never partially satisfied). 10882729Sdfr */ 10892729Sdfr for (;;) { 10902729Sdfr do_wakeup = 0; 109184789Smr error = 0; /* error return if necessary */ 10922729Sdfr 10932729Sdfr for (i = 0; i < nsops; i++) { 10942729Sdfr sopptr = &sops[i]; 1095137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 10962729Sdfr 1097100523Salfred DPRINTF(( 1098160293Skib "semop: semakptr=%p, sem_base=%p, " 1099160293Skib "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1100137613Srwatson semakptr, semakptr->u.sem_base, semptr, 11012729Sdfr sopptr->sem_num, semptr->semval, sopptr->sem_op, 1102100523Salfred (sopptr->sem_flg & IPC_NOWAIT) ? 1103100523Salfred "nowait" : "wait")); 11042729Sdfr 11052729Sdfr if (sopptr->sem_op < 0) { 11062729Sdfr if (semptr->semval + sopptr->sem_op < 0) { 1107100523Salfred DPRINTF(("semop: can't do it now\n")); 11082729Sdfr break; 11092729Sdfr } else { 11102729Sdfr semptr->semval += sopptr->sem_op; 11112729Sdfr if (semptr->semval == 0 && 11122729Sdfr semptr->semzcnt > 0) 11132729Sdfr do_wakeup = 1; 11142729Sdfr } 11152729Sdfr } else if (sopptr->sem_op == 0) { 111684789Smr if (semptr->semval != 0) { 1117100523Salfred DPRINTF(("semop: not zero now\n")); 11182729Sdfr break; 11192729Sdfr } 112084789Smr } else if (semptr->semval + sopptr->sem_op > 112184789Smr seminfo.semvmx) { 112284789Smr error = ERANGE; 112384789Smr break; 11242729Sdfr } else { 11252729Sdfr if (semptr->semncnt > 0) 11262729Sdfr do_wakeup = 1; 11272729Sdfr semptr->semval += sopptr->sem_op; 11282729Sdfr } 11292729Sdfr } 11302729Sdfr 11312729Sdfr /* 11322729Sdfr * Did we get through the entire vector? 11332729Sdfr */ 11342729Sdfr if (i >= nsops) 11352729Sdfr goto done; 11362729Sdfr 11372729Sdfr /* 11382729Sdfr * No ... rollback anything that we've already done 11392729Sdfr */ 1140100523Salfred DPRINTF(("semop: rollback 0 through %d\n", i-1)); 11412729Sdfr for (j = 0; j < i; j++) 1142137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 11432729Sdfr sops[j].sem_op; 11442729Sdfr 114584789Smr /* If we detected an error, return it */ 114684789Smr if (error != 0) 114784789Smr goto done2; 114884789Smr 11492729Sdfr /* 11502729Sdfr * If the request that we couldn't satisfy has the 11512729Sdfr * NOWAIT flag set then return with EAGAIN. 11522729Sdfr */ 115382607Sdillon if (sopptr->sem_flg & IPC_NOWAIT) { 115482607Sdillon error = EAGAIN; 115582607Sdillon goto done2; 115682607Sdillon } 11572729Sdfr 11582729Sdfr if (sopptr->sem_op == 0) 11592729Sdfr semptr->semzcnt++; 11602729Sdfr else 11612729Sdfr semptr->semncnt++; 11622729Sdfr 1163100523Salfred DPRINTF(("semop: good night!\n")); 1164137613Srwatson error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1165101774Salfred "semwait", 0); 1166100523Salfred DPRINTF(("semop: good morning (error=%d)!\n", error)); 1167127108Scperciva /* return code is checked below, after sem[nz]cnt-- */ 11682729Sdfr 11692729Sdfr /* 11702729Sdfr * Make sure that the semaphore still exists 11712729Sdfr */ 1172187223Skib seq = semakptr->u.sem_perm.seq; 1173137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1174187223Skib seq != IPCID_TO_SEQ(uap->semid)) { 117582607Sdillon error = EIDRM; 117682607Sdillon goto done2; 117782607Sdillon } 11782729Sdfr 11792729Sdfr /* 1180179879Sgonzo * Renew the semaphore's pointer after wakeup since 1181179879Sgonzo * during msleep sem_base may have been modified and semptr 1182179879Sgonzo * is not valid any more 1183179879Sgonzo */ 1184179879Sgonzo semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1185179879Sgonzo 1186179879Sgonzo /* 11872729Sdfr * The semaphore is still alive. Readjust the count of 11882729Sdfr * waiting processes. 11892729Sdfr */ 11902729Sdfr if (sopptr->sem_op == 0) 11912729Sdfr semptr->semzcnt--; 11922729Sdfr else 11932729Sdfr semptr->semncnt--; 1194127108Scperciva 1195127108Scperciva /* 1196127108Scperciva * Is it really morning, or was our sleep interrupted? 1197127108Scperciva * (Delayed check of msleep() return code because we 1198127108Scperciva * need to decrement sem[nz]cnt either way.) 1199127108Scperciva */ 1200127108Scperciva if (error != 0) { 1201127108Scperciva error = EINTR; 1202127108Scperciva goto done2; 1203127108Scperciva } 1204127108Scperciva DPRINTF(("semop: good morning!\n")); 12052729Sdfr } 12062729Sdfr 12072729Sdfrdone: 12082729Sdfr /* 12092729Sdfr * Process any SEM_UNDO requests. 12102729Sdfr */ 12112729Sdfr if (do_undos) { 1212101774Salfred SEMUNDO_LOCK(); 121384789Smr suptr = NULL; 12142729Sdfr for (i = 0; i < nsops; i++) { 12152729Sdfr /* 12162729Sdfr * We only need to deal with SEM_UNDO's for non-zero 12172729Sdfr * op's. 12182729Sdfr */ 12192729Sdfr int adjval; 12202729Sdfr 12212729Sdfr if ((sops[i].sem_flg & SEM_UNDO) == 0) 12222729Sdfr continue; 12232729Sdfr adjval = sops[i].sem_op; 12242729Sdfr if (adjval == 0) 12252729Sdfr continue; 1226187223Skib error = semundo_adjust(td, &suptr, semid, seq, 12272729Sdfr sops[i].sem_num, -adjval); 122882607Sdillon if (error == 0) 12292729Sdfr continue; 12302729Sdfr 12312729Sdfr /* 12322729Sdfr * Oh-Oh! We ran out of either sem_undo's or undo's. 12332729Sdfr * Rollback the adjustments to this point and then 12342729Sdfr * rollback the semaphore ups and down so we can return 12352729Sdfr * with an error with all structures restored. We 12362729Sdfr * rollback the undo's in the exact reverse order that 12372729Sdfr * we applied them. This guarantees that we won't run 12382729Sdfr * out of space as we roll things back out. 12392729Sdfr */ 1240110040Stjr for (j = 0; j < i; j++) { 1241110040Stjr k = i - j - 1; 1242110040Stjr if ((sops[k].sem_flg & SEM_UNDO) == 0) 12432729Sdfr continue; 1244110040Stjr adjval = sops[k].sem_op; 12452729Sdfr if (adjval == 0) 12462729Sdfr continue; 1247187223Skib if (semundo_adjust(td, &suptr, semid, seq, 1248110040Stjr sops[k].sem_num, adjval) != 0) 12492729Sdfr panic("semop - can't undo undos"); 12502729Sdfr } 12512729Sdfr 12522729Sdfr for (j = 0; j < nsops; j++) 1253137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 12542729Sdfr sops[j].sem_op; 12552729Sdfr 1256100523Salfred DPRINTF(("error = %d from semundo_adjust\n", error)); 1257101774Salfred SEMUNDO_UNLOCK(); 125882607Sdillon goto done2; 12592729Sdfr } /* loop through the sops */ 1260101774Salfred SEMUNDO_UNLOCK(); 12612729Sdfr } /* if (do_undos) */ 12622729Sdfr 126384789Smr /* We're definitely done - set the sempid's and time */ 12642729Sdfr for (i = 0; i < nsops; i++) { 12652729Sdfr sopptr = &sops[i]; 1266137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 126783366Sjulian semptr->sempid = td->td_proc->p_pid; 12682729Sdfr } 1269137613Srwatson semakptr->u.sem_otime = time_second; 12702729Sdfr 127184789Smr /* 127284789Smr * Do a wakeup if any semaphore was up'd whilst something was 127384789Smr * sleeping on it. 127484789Smr */ 12752729Sdfr if (do_wakeup) { 1276100523Salfred DPRINTF(("semop: doing wakeup\n")); 1277137613Srwatson wakeup(semakptr); 1278100523Salfred DPRINTF(("semop: back from wakeup\n")); 12792729Sdfr } 1280100523Salfred DPRINTF(("semop: done\n")); 128183366Sjulian td->td_retval[0] = 0; 128282607Sdillondone2: 1283101774Salfred mtx_unlock(sema_mtxp); 1284123667Stjr if (sops != small_sops) 1285123667Stjr free(sops, M_SEM); 128682607Sdillon return (error); 12872729Sdfr} 12882729Sdfr 12892729Sdfr/* 12902729Sdfr * Go through the undo structures for this process and apply the adjustments to 12912729Sdfr * semaphores. 12922729Sdfr */ 129369449Salfredstatic void 1294187223Skibsemexit_myhook(void *arg, struct proc *p) 12952729Sdfr{ 1296101350Salfred struct sem_undo *suptr; 1297187223Skib struct semid_kernel *semakptr; 1298187223Skib struct mtx *sema_mtxp; 1299187223Skib int semid, semnum, adjval, ix; 1300187223Skib unsigned short seq; 13012729Sdfr 13022729Sdfr /* 13032729Sdfr * Go through the chain of undo vectors looking for one 13042729Sdfr * associated with this process. 13052729Sdfr */ 1306101774Salfred SEMUNDO_LOCK(); 1307187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 1308187223Skib if (suptr->un_proc == p) 13092729Sdfr break; 13102729Sdfr } 1311187223Skib if (suptr == NULL) { 1312187223Skib SEMUNDO_UNLOCK(); 131359828Speter return; 1314187223Skib } 1315187223Skib LIST_REMOVE(suptr, un_next); 13162729Sdfr 1317160293Skib DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1318100523Salfred suptr->un_cnt)); 13192729Sdfr 13202729Sdfr /* 13212729Sdfr * If there are any active undo elements then process them. 13222729Sdfr */ 13232729Sdfr if (suptr->un_cnt > 0) { 1324187223Skib SEMUNDO_UNLOCK(); 13252729Sdfr for (ix = 0; ix < suptr->un_cnt; ix++) { 1326187223Skib semid = suptr->un_ent[ix].un_id; 1327187223Skib semnum = suptr->un_ent[ix].un_num; 1328187223Skib adjval = suptr->un_ent[ix].un_adjval; 1329187223Skib seq = suptr->un_ent[ix].un_seq; 1330137613Srwatson semakptr = &sema[semid]; 1331101774Salfred sema_mtxp = &sema_mtx[semid]; 1332187223Skib 1333101774Salfred mtx_lock(sema_mtxp); 1334187223Skib if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1335187223Skib (semakptr->u.sem_perm.seq != seq)) { 1336187223Skib mtx_unlock(sema_mtxp); 1337187223Skib continue; 1338187223Skib } 1339137613Srwatson if (semnum >= semakptr->u.sem_nsems) 13402729Sdfr panic("semexit - semnum out of range"); 13412729Sdfr 1342100523Salfred DPRINTF(( 1343160293Skib "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 13442729Sdfr suptr->un_proc, suptr->un_ent[ix].un_id, 13452729Sdfr suptr->un_ent[ix].un_num, 13462729Sdfr suptr->un_ent[ix].un_adjval, 1347137613Srwatson semakptr->u.sem_base[semnum].semval)); 13482729Sdfr 1349187223Skib if (adjval < 0 && semakptr->u.sem_base[semnum].semval < 1350187223Skib -adjval) 1351187223Skib semakptr->u.sem_base[semnum].semval = 0; 1352187223Skib else 1353137613Srwatson semakptr->u.sem_base[semnum].semval += adjval; 13542729Sdfr 1355137613Srwatson wakeup(semakptr); 1356100523Salfred DPRINTF(("semexit: back from wakeup\n")); 1357101774Salfred mtx_unlock(sema_mtxp); 13582729Sdfr } 1359187223Skib SEMUNDO_LOCK(); 13602729Sdfr } 13612729Sdfr 13622729Sdfr /* 13632729Sdfr * Deallocate the undo vector. 13642729Sdfr */ 1365100523Salfred DPRINTF(("removing vector\n")); 13662729Sdfr suptr->un_proc = NULL; 1367187223Skib suptr->un_cnt = 0; 1368187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1369167904Semaste SEMUNDO_UNLOCK(); 13702729Sdfr} 137177461Sdd 137277461Sddstatic int 137377461Sddsysctl_sema(SYSCTL_HANDLER_ARGS) 137477461Sdd{ 137577461Sdd 137677461Sdd return (SYSCTL_OUT(req, sema, 1377137613Srwatson sizeof(struct semid_kernel) * seminfo.semmni)); 137877461Sdd} 1379194894Sjhb 1380194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1381194894Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1382194894Sjhb 1383194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1384194894Sjhbstatic sy_call_t *semcalls[] = { 1385225617Skmacy (sy_call_t *)freebsd7___semctl, (sy_call_t *)sys_semget, 1386225617Skmacy (sy_call_t *)sys_semop 1387194894Sjhb}; 1388194894Sjhb 1389194894Sjhb/* 1390194894Sjhb * Entry point for all SEM calls. 1391194894Sjhb */ 1392194894Sjhbint 1393225617Skmacysys_semsys(td, uap) 1394194894Sjhb struct thread *td; 1395194894Sjhb /* XXX actually varargs. */ 1396194894Sjhb struct semsys_args /* { 1397194894Sjhb int which; 1398194894Sjhb int a2; 1399194894Sjhb int a3; 1400194894Sjhb int a4; 1401194894Sjhb int a5; 1402194894Sjhb } */ *uap; 1403194894Sjhb{ 1404194894Sjhb int error; 1405194894Sjhb 1406194894Sjhb if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 1407194894Sjhb return (ENOSYS); 1408194894Sjhb if (uap->which < 0 || 1409194894Sjhb uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) 1410194894Sjhb return (EINVAL); 1411194894Sjhb error = (*semcalls[uap->which])(td, &uap->a2); 1412194894Sjhb return (error); 1413194894Sjhb} 1414194910Sjhb 1415205323Skib#ifndef CP 1416194910Sjhb#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1417205323Skib#endif 1418194910Sjhb 1419194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1420194910Sjhbstruct freebsd7___semctl_args { 1421194910Sjhb int semid; 1422194910Sjhb int semnum; 1423194910Sjhb int cmd; 1424194910Sjhb union semun_old *arg; 1425194910Sjhb}; 1426194910Sjhb#endif 1427194910Sjhbint 1428194910Sjhbfreebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1429194910Sjhb{ 1430194910Sjhb struct semid_ds_old dsold; 1431194910Sjhb struct semid_ds dsbuf; 1432194910Sjhb union semun_old arg; 1433194910Sjhb union semun semun; 1434194910Sjhb register_t rval; 1435194910Sjhb int error; 1436194910Sjhb 1437194910Sjhb switch (uap->cmd) { 1438194910Sjhb case SEM_STAT: 1439194910Sjhb case IPC_SET: 1440194910Sjhb case IPC_STAT: 1441194910Sjhb case GETALL: 1442194910Sjhb case SETVAL: 1443194910Sjhb case SETALL: 1444194910Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 1445194910Sjhb if (error) 1446194910Sjhb return (error); 1447194910Sjhb break; 1448194910Sjhb } 1449194910Sjhb 1450194910Sjhb switch (uap->cmd) { 1451194910Sjhb case SEM_STAT: 1452194910Sjhb case IPC_STAT: 1453194910Sjhb semun.buf = &dsbuf; 1454194910Sjhb break; 1455194910Sjhb case IPC_SET: 1456194910Sjhb error = copyin(arg.buf, &dsold, sizeof(dsold)); 1457194910Sjhb if (error) 1458194910Sjhb return (error); 1459194910Sjhb ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1460194910Sjhb CP(dsold, dsbuf, sem_base); 1461194910Sjhb CP(dsold, dsbuf, sem_nsems); 1462194910Sjhb CP(dsold, dsbuf, sem_otime); 1463194910Sjhb CP(dsold, dsbuf, sem_ctime); 1464194910Sjhb semun.buf = &dsbuf; 1465194910Sjhb break; 1466194910Sjhb case GETALL: 1467194910Sjhb case SETALL: 1468194910Sjhb semun.array = arg.array; 1469194910Sjhb break; 1470194910Sjhb case SETVAL: 1471194910Sjhb semun.val = arg.val; 1472194910Sjhb break; 1473194910Sjhb } 1474194910Sjhb 1475194910Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1476194910Sjhb &rval); 1477194910Sjhb if (error) 1478194910Sjhb return (error); 1479194910Sjhb 1480194910Sjhb switch (uap->cmd) { 1481194910Sjhb case SEM_STAT: 1482194910Sjhb case IPC_STAT: 1483194910Sjhb bzero(&dsold, sizeof(dsold)); 1484194910Sjhb ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1485194910Sjhb CP(dsbuf, dsold, sem_base); 1486194910Sjhb CP(dsbuf, dsold, sem_nsems); 1487194910Sjhb CP(dsbuf, dsold, sem_otime); 1488194910Sjhb CP(dsbuf, dsold, sem_ctime); 1489194910Sjhb error = copyout(&dsold, arg.buf, sizeof(dsold)); 1490194910Sjhb break; 1491194910Sjhb } 1492194910Sjhb 1493194910Sjhb if (error == 0) 1494194910Sjhb td->td_retval[0] = rval; 1495194910Sjhb return (error); 1496194910Sjhb} 1497194910Sjhb 1498205323Skib#endif /* COMPAT_FREEBSD{4,5,6,7} */ 1499194910Sjhb 1500205323Skib#ifdef COMPAT_FREEBSD32 1501205323Skib 1502205323Skibint 1503205323Skibfreebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1504205323Skib{ 1505205323Skib 1506205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1507205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1508205323Skib switch (uap->which) { 1509205323Skib case 0: 1510205323Skib return (freebsd7_freebsd32_semctl(td, 1511205323Skib (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1512205323Skib default: 1513225617Skmacy return (sys_semsys(td, (struct semsys_args *)uap)); 1514205323Skib } 1515205323Skib#else 1516205323Skib return (nosys(td, NULL)); 1517205323Skib#endif 1518205323Skib} 1519205323Skib 1520205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1521205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1522205323Skibint 1523205323Skibfreebsd7_freebsd32_semctl(struct thread *td, 1524205323Skib struct freebsd7_freebsd32_semctl_args *uap) 1525205323Skib{ 1526205323Skib struct semid_ds32_old dsbuf32; 1527205323Skib struct semid_ds dsbuf; 1528205323Skib union semun semun; 1529205323Skib union semun32 arg; 1530205323Skib register_t rval; 1531205323Skib int error; 1532205323Skib 1533205323Skib switch (uap->cmd) { 1534205323Skib case SEM_STAT: 1535205323Skib case IPC_SET: 1536205323Skib case IPC_STAT: 1537205323Skib case GETALL: 1538205323Skib case SETVAL: 1539205323Skib case SETALL: 1540205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1541205323Skib if (error) 1542205323Skib return (error); 1543205323Skib break; 1544205323Skib } 1545205323Skib 1546205323Skib switch (uap->cmd) { 1547205323Skib case SEM_STAT: 1548205323Skib case IPC_STAT: 1549205323Skib semun.buf = &dsbuf; 1550205323Skib break; 1551205323Skib case IPC_SET: 1552205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1553205323Skib if (error) 1554205323Skib return (error); 1555205323Skib freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1556205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1557205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1558205323Skib CP(dsbuf32, dsbuf, sem_otime); 1559205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1560205323Skib semun.buf = &dsbuf; 1561205323Skib break; 1562205323Skib case GETALL: 1563205323Skib case SETALL: 1564205323Skib semun.array = PTRIN(arg.array); 1565205323Skib break; 1566205323Skib case SETVAL: 1567205323Skib semun.val = arg.val; 1568205323Skib break; 1569205323Skib } 1570205323Skib 1571205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1572205323Skib &rval); 1573205323Skib if (error) 1574205323Skib return (error); 1575205323Skib 1576205323Skib switch (uap->cmd) { 1577205323Skib case SEM_STAT: 1578205323Skib case IPC_STAT: 1579205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1580205323Skib freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1581205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1582205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1583205323Skib CP(dsbuf, dsbuf32, sem_otime); 1584205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1585205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1586205323Skib break; 1587205323Skib } 1588205323Skib 1589205323Skib if (error == 0) 1590205323Skib td->td_retval[0] = rval; 1591205323Skib return (error); 1592205323Skib} 1593205323Skib#endif 1594205323Skib 1595205323Skibint 1596205323Skibfreebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1597205323Skib{ 1598205323Skib struct semid_ds32 dsbuf32; 1599205323Skib struct semid_ds dsbuf; 1600205323Skib union semun semun; 1601205323Skib union semun32 arg; 1602205323Skib register_t rval; 1603205323Skib int error; 1604205323Skib 1605205323Skib switch (uap->cmd) { 1606205323Skib case SEM_STAT: 1607205323Skib case IPC_SET: 1608205323Skib case IPC_STAT: 1609205323Skib case GETALL: 1610205323Skib case SETVAL: 1611205323Skib case SETALL: 1612205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1613205323Skib if (error) 1614205323Skib return (error); 1615205323Skib break; 1616205323Skib } 1617205323Skib 1618205323Skib switch (uap->cmd) { 1619205323Skib case SEM_STAT: 1620205323Skib case IPC_STAT: 1621205323Skib semun.buf = &dsbuf; 1622205323Skib break; 1623205323Skib case IPC_SET: 1624205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1625205323Skib if (error) 1626205323Skib return (error); 1627205323Skib freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1628205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1629205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1630205323Skib CP(dsbuf32, dsbuf, sem_otime); 1631205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1632205323Skib semun.buf = &dsbuf; 1633205323Skib break; 1634205323Skib case GETALL: 1635205323Skib case SETALL: 1636205323Skib semun.array = PTRIN(arg.array); 1637205323Skib break; 1638205323Skib case SETVAL: 1639205323Skib semun.val = arg.val; 1640205323Skib break; 1641205323Skib } 1642205323Skib 1643205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1644205323Skib &rval); 1645205323Skib if (error) 1646205323Skib return (error); 1647205323Skib 1648205323Skib switch (uap->cmd) { 1649205323Skib case SEM_STAT: 1650205323Skib case IPC_STAT: 1651205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1652205323Skib freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1653205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1654205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1655205323Skib CP(dsbuf, dsbuf32, sem_otime); 1656205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1657205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1658205323Skib break; 1659205323Skib } 1660205323Skib 1661205323Skib if (error == 0) 1662205323Skib td->td_retval[0] = rval; 1663205323Skib return (error); 1664205323Skib} 1665205323Skib 1666205323Skib#endif /* COMPAT_FREEBSD32 */ 1667