sysv_sem.c revision 220388
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: head/sys/kern/sysv_sem.c 220388 2011-04-06 16:59:54Z trasz $"); 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> 542729Sdfr#include <sys/sem.h> 5569449Salfred#include <sys/syscall.h> 56159991Sjhb#include <sys/syscallsubr.h> 5711626Sbde#include <sys/sysent.h> 5859839Speter#include <sys/sysctl.h> 59159991Sjhb#include <sys/uio.h> 6059839Speter#include <sys/malloc.h> 6168024Srwatson#include <sys/jail.h> 622729Sdfr 63163606Srwatson#include <security/mac/mac_framework.h> 64163606Srwatson 65219028SnetchildFEATURE(sysv_sem, "System V semaphores support"); 66219028Snetchild 6759839Speterstatic MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); 6859839Speter 69100523Salfred#ifdef SEM_DEBUG 70100523Salfred#define DPRINTF(a) printf a 71100523Salfred#else 72100523Salfred#define DPRINTF(a) 73100523Salfred#endif 74100523Salfred 75205323Skibstatic int seminit(void); 7692723Salfredstatic int sysvsem_modload(struct module *, int, void *); 7792723Salfredstatic int semunload(void); 78112564Sjhbstatic void semexit_myhook(void *arg, struct proc *p); 7992723Salfredstatic int sysctl_sema(SYSCTL_HANDLER_ARGS); 80137613Srwatsonstatic int semvalid(int semid, struct semid_kernel *semakptr); 8110358Sjulian 8212866Speter#ifndef _SYS_SYSPROTO_H_ 8312866Speterstruct __semctl_args; 8492723Salfredint __semctl(struct thread *td, struct __semctl_args *uap); 8511626Sbdestruct semget_args; 8692723Salfredint semget(struct thread *td, struct semget_args *uap); 8711626Sbdestruct semop_args; 8892723Salfredint semop(struct thread *td, struct semop_args *uap); 8912866Speter#endif 9011626Sbde 9192723Salfredstatic struct sem_undo *semu_alloc(struct thread *td); 92122201Srwatsonstatic int semundo_adjust(struct thread *td, struct sem_undo **supptr, 93187223Skib int semid, int semseq, int semnum, int adjval); 9492723Salfredstatic void semundo_clear(int semid, int semnum); 9511626Sbde 96101774Salfredstatic struct mtx sem_mtx; /* semaphore global lock */ 97187223Skibstatic struct mtx sem_undo_mtx; 9812819Sphkstatic int semtot = 0; 99137613Srwatsonstatic struct semid_kernel *sema; /* semaphore id pool */ 100101774Salfredstatic struct mtx *sema_mtx; /* semaphore id pool mutexes*/ 10159839Speterstatic struct sem *sem; /* semaphore pool */ 102187223SkibLIST_HEAD(, sem_undo) semu_list; /* list of active undo structures */ 103187223SkibLIST_HEAD(, sem_undo) semu_free_list; /* list of free undo structures */ 10459839Speterstatic int *semu; /* undo structure pool */ 105112564Sjhbstatic eventhandler_tag semexit_tag; 1062729Sdfr 107187223Skib#define SEMUNDO_MTX sem_undo_mtx 108101774Salfred#define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX); 109101774Salfred#define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX); 110101774Salfred#define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how)); 111101774Salfred 11259839Speterstruct sem { 11359839Speter u_short semval; /* semaphore value */ 11459839Speter pid_t sempid; /* pid of last operation */ 11559839Speter u_short semncnt; /* # awaiting semval > cval */ 11659839Speter u_short semzcnt; /* # awaiting semval = 0 */ 11759839Speter}; 11859839Speter 11959839Speter/* 12059839Speter * Undo structure (one per process) 12159839Speter */ 12259839Speterstruct sem_undo { 123187223Skib LIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */ 12459839Speter struct proc *un_proc; /* owner of this structure */ 12559839Speter short un_cnt; /* # of active entries */ 12659839Speter struct undo { 12759839Speter short un_adjval; /* adjust on exit values */ 12859839Speter short un_num; /* semaphore # */ 12959839Speter int un_id; /* semid */ 130187223Skib unsigned short un_seq; 13159839Speter } un_ent[1]; /* undo entries */ 13259839Speter}; 13359839Speter 13459839Speter/* 13559839Speter * Configuration parameters 13659839Speter */ 13759839Speter#ifndef SEMMNI 138209037Sivoras#define SEMMNI 50 /* # of semaphore identifiers */ 13959839Speter#endif 14059839Speter#ifndef SEMMNS 141209037Sivoras#define SEMMNS 340 /* # of semaphores in system */ 14259839Speter#endif 14359839Speter#ifndef SEMUME 144209037Sivoras#define SEMUME 50 /* max # of undo entries per process */ 14559839Speter#endif 14659839Speter#ifndef SEMMNU 147209037Sivoras#define SEMMNU 150 /* # of undo structures in system */ 14859839Speter#endif 14959839Speter 15059839Speter/* shouldn't need tuning */ 15159839Speter#ifndef SEMMAP 15259839Speter#define SEMMAP 30 /* # of entries in semaphore map */ 15359839Speter#endif 15459839Speter#ifndef SEMMSL 15559839Speter#define SEMMSL SEMMNS /* max # of semaphores per id */ 15659839Speter#endif 15759839Speter#ifndef SEMOPM 15859839Speter#define SEMOPM 100 /* max # of operations per semop call */ 15959839Speter#endif 16059839Speter 16159839Speter#define SEMVMX 32767 /* semaphore maximum value */ 16259839Speter#define SEMAEM 16384 /* adjust on exit max value */ 16359839Speter 16459839Speter/* 16559839Speter * Due to the way semaphore memory is allocated, we have to ensure that 16659839Speter * SEMUSZ is properly aligned. 16759839Speter */ 16859839Speter 16959839Speter#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) 17059839Speter 17159839Speter/* actual size of an undo structure */ 17259839Speter#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) 17359839Speter 17459839Speter/* 17559839Speter * Macro to find a particular sem_undo vector 17659839Speter */ 177101350Salfred#define SEMU(ix) \ 178101350Salfred ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) 17959839Speter 18059839Speter/* 18159839Speter * semaphore info struct 18259839Speter */ 18359839Speterstruct seminfo seminfo = { 18459839Speter SEMMAP, /* # of entries in semaphore map */ 18559839Speter SEMMNI, /* # of semaphore identifiers */ 18659839Speter SEMMNS, /* # of semaphores in system */ 18759839Speter SEMMNU, /* # of undo structures in system */ 18859839Speter SEMMSL, /* max # of semaphores per id */ 18959839Speter SEMOPM, /* max # of operations per semop call */ 19059839Speter SEMUME, /* max # of undo entries per process */ 19159839Speter SEMUSZ, /* size in bytes of undo structure */ 19259839Speter SEMVMX, /* semaphore maximum value */ 19359839Speter SEMAEM /* adjust on exit max value */ 19459839Speter}; 19559839Speter 196141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, 197141710Scsjp "Number of entries in the semaphore map"); 198141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, 199141710Scsjp "Number of semaphore identifiers"); 200141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0, 201141710Scsjp "Maximum number of semaphores in the system"); 202141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0, 203141710Scsjp "Maximum number of undo structures in the system"); 204141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, 205141710Scsjp "Max semaphores per id"); 206141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0, 207141710Scsjp "Max operations per semop call"); 208141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0, 209141710Scsjp "Max undo entries per process"); 210141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0, 211141710Scsjp "Size in bytes of undo structure"); 212141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, 213141710Scsjp "Semaphore maximum value"); 214141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, 215141710Scsjp "Adjust on exit max value"); 216217555SmdfSYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLTYPE_OPAQUE | CTLFLAG_RD, 217215281Sbrucec NULL, 0, sysctl_sema, "", "Semaphore id pool"); 21859839Speter 219205323Skibstatic struct syscall_helper_data sem_syscalls[] = { 220205323Skib SYSCALL_INIT_HELPER(__semctl), 221205323Skib SYSCALL_INIT_HELPER(semget), 222205323Skib SYSCALL_INIT_HELPER(semop), 223205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 224205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 225205323Skib SYSCALL_INIT_HELPER(semsys), 226205323Skib SYSCALL_INIT_HELPER(freebsd7___semctl), 227205323Skib#endif 228205323Skib SYSCALL_INIT_LAST 229205323Skib}; 230205323Skib 231205323Skib#ifdef COMPAT_FREEBSD32 232205323Skib#include <compat/freebsd32/freebsd32.h> 233205323Skib#include <compat/freebsd32/freebsd32_ipc.h> 234205323Skib#include <compat/freebsd32/freebsd32_proto.h> 235205323Skib#include <compat/freebsd32/freebsd32_signal.h> 236205323Skib#include <compat/freebsd32/freebsd32_syscall.h> 237205323Skib#include <compat/freebsd32/freebsd32_util.h> 238205323Skib 239205323Skibstatic struct syscall_helper_data sem32_syscalls[] = { 240205323Skib SYSCALL32_INIT_HELPER(freebsd32_semctl), 241205323Skib SYSCALL32_INIT_HELPER(semget), 242205323Skib SYSCALL32_INIT_HELPER(semop), 243205323Skib SYSCALL32_INIT_HELPER(freebsd32_semsys), 244205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 245205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 246205323Skib SYSCALL32_INIT_HELPER(freebsd7_freebsd32_semctl), 247205323Skib#endif 248205323Skib SYSCALL_INIT_LAST 249205323Skib}; 250205323Skib#endif 251205323Skib 252205323Skibstatic int 25369449Salfredseminit(void) 2542729Sdfr{ 255205323Skib int i, error; 2562729Sdfr 25783413Smr TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap); 25883413Smr TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni); 25983413Smr TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns); 26083413Smr TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu); 26183413Smr TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl); 26283413Smr TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm); 26383413Smr TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume); 26483413Smr TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz); 26583413Smr TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx); 26683413Smr TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem); 26783413Smr 268111119Simp sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 269137613Srwatson sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM, 270111119Simp M_WAITOK); 271101774Salfred sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM, 272111119Simp M_WAITOK | M_ZERO); 273111119Simp semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 2742729Sdfr 2752729Sdfr for (i = 0; i < seminfo.semmni; i++) { 276137613Srwatson sema[i].u.sem_base = 0; 277137613Srwatson sema[i].u.sem_perm.mode = 0; 278137613Srwatson sema[i].u.sem_perm.seq = 0; 279140615Srwatson#ifdef MAC 280172930Srwatson mac_sysvsem_init(&sema[i]); 281140615Srwatson#endif 2822729Sdfr } 283101774Salfred for (i = 0; i < seminfo.semmni; i++) 284101774Salfred mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); 285187223Skib LIST_INIT(&semu_free_list); 2862729Sdfr for (i = 0; i < seminfo.semmnu; i++) { 287101350Salfred struct sem_undo *suptr = SEMU(i); 2882729Sdfr suptr->un_proc = NULL; 289187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 2902729Sdfr } 291187223Skib LIST_INIT(&semu_list); 292101774Salfred mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); 293187223Skib mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF); 294112564Sjhb semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, 295112564Sjhb EVENTHANDLER_PRI_ANY); 296205323Skib 297205323Skib error = syscall_helper_register(sem_syscalls); 298205323Skib if (error != 0) 299205323Skib return (error); 300205323Skib#ifdef COMPAT_FREEBSD32 301205323Skib error = syscall32_helper_register(sem32_syscalls); 302205323Skib if (error != 0) 303205323Skib return (error); 304205323Skib#endif 305205323Skib return (0); 3062729Sdfr} 3072729Sdfr 30869449Salfredstatic int 30969449Salfredsemunload(void) 31069449Salfred{ 311101774Salfred int i; 31269449Salfred 313187223Skib /* XXXKIB */ 31469449Salfred if (semtot != 0) 31569449Salfred return (EBUSY); 31669449Salfred 317205323Skib#ifdef COMPAT_FREEBSD32 318205323Skib syscall32_helper_unregister(sem32_syscalls); 319205323Skib#endif 320205323Skib syscall_helper_unregister(sem_syscalls); 321112564Sjhb EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); 322140615Srwatson#ifdef MAC 323140615Srwatson for (i = 0; i < seminfo.semmni; i++) 324172930Srwatson mac_sysvsem_destroy(&sema[i]); 325140615Srwatson#endif 32669449Salfred free(sem, M_SEM); 32769449Salfred free(sema, M_SEM); 32869449Salfred free(semu, M_SEM); 329101774Salfred for (i = 0; i < seminfo.semmni; i++) 330101774Salfred mtx_destroy(&sema_mtx[i]); 331190557Sbrueffer free(sema_mtx, M_SEM); 332101774Salfred mtx_destroy(&sem_mtx); 333187223Skib mtx_destroy(&sem_undo_mtx); 33469449Salfred return (0); 33569449Salfred} 33669449Salfred 33769449Salfredstatic int 33869449Salfredsysvsem_modload(struct module *module, int cmd, void *arg) 33969449Salfred{ 34069449Salfred int error = 0; 34169449Salfred 34269449Salfred switch (cmd) { 34369449Salfred case MOD_LOAD: 344205323Skib error = seminit(); 345205323Skib if (error != 0) 346205323Skib semunload(); 34769449Salfred break; 34869449Salfred case MOD_UNLOAD: 34969449Salfred error = semunload(); 35069449Salfred break; 35169449Salfred case MOD_SHUTDOWN: 35269449Salfred break; 35369449Salfred default: 35469449Salfred error = EINVAL; 35569449Salfred break; 35669449Salfred } 35769449Salfred return (error); 35869449Salfred} 35969449Salfred 36071038Sdesstatic moduledata_t sysvsem_mod = { 36171038Sdes "sysvsem", 36269449Salfred &sysvsem_modload, 36369449Salfred NULL 36469449Salfred}; 36569449Salfred 366194832SjhbDECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 36771038SdesMODULE_VERSION(sysvsem, 1); 36869449Salfred 3692729Sdfr/* 3702729Sdfr * Allocate a new sem_undo structure for a process 3712729Sdfr * (returns ptr to structure or NULL if no more room) 3722729Sdfr */ 3732729Sdfr 37412819Sphkstatic struct sem_undo * 375187223Skibsemu_alloc(struct thread *td) 3762729Sdfr{ 377101350Salfred struct sem_undo *suptr; 3782729Sdfr 379101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 380187223Skib if ((suptr = LIST_FIRST(&semu_free_list)) == NULL) 381187223Skib return (NULL); 382187223Skib LIST_REMOVE(suptr, un_next); 383187223Skib LIST_INSERT_HEAD(&semu_list, suptr, un_next); 384187223Skib suptr->un_cnt = 0; 385187223Skib suptr->un_proc = td->td_proc; 386187223Skib return (suptr); 387187223Skib} 3882729Sdfr 389187223Skibstatic int 390187223Skibsemu_try_free(struct sem_undo *suptr) 391187223Skib{ 3922729Sdfr 393187223Skib SEMUNDO_LOCKASSERT(MA_OWNED); 3942729Sdfr 395187223Skib if (suptr->un_cnt != 0) 396187223Skib return (0); 397187223Skib LIST_REMOVE(suptr, un_next); 398187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 399187223Skib return (1); 4002729Sdfr} 4012729Sdfr 4022729Sdfr/* 4032729Sdfr * Adjust a particular entry for a particular proc 4042729Sdfr */ 4052729Sdfr 40612819Sphkstatic int 407187223Skibsemundo_adjust(struct thread *td, struct sem_undo **supptr, int semid, 408187223Skib int semseq, int semnum, int adjval) 4092729Sdfr{ 41083366Sjulian struct proc *p = td->td_proc; 411101350Salfred struct sem_undo *suptr; 412101350Salfred struct undo *sunptr; 4132729Sdfr int i; 4142729Sdfr 415101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 4162729Sdfr /* Look for and remember the sem_undo if the caller doesn't provide 4172729Sdfr it */ 4182729Sdfr 4192729Sdfr suptr = *supptr; 4202729Sdfr if (suptr == NULL) { 421187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 4222729Sdfr if (suptr->un_proc == p) { 4232729Sdfr *supptr = suptr; 4242729Sdfr break; 4252729Sdfr } 4262729Sdfr } 4272729Sdfr if (suptr == NULL) { 4282729Sdfr if (adjval == 0) 4292729Sdfr return(0); 43083366Sjulian suptr = semu_alloc(td); 4312729Sdfr if (suptr == NULL) 432187223Skib return (ENOSPC); 4332729Sdfr *supptr = suptr; 4342729Sdfr } 4352729Sdfr } 4362729Sdfr 4372729Sdfr /* 4382729Sdfr * Look for the requested entry and adjust it (delete if adjval becomes 4392729Sdfr * 0). 4402729Sdfr */ 4412729Sdfr sunptr = &suptr->un_ent[0]; 4422729Sdfr for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 4432729Sdfr if (sunptr->un_id != semid || sunptr->un_num != semnum) 4442729Sdfr continue; 44584789Smr if (adjval != 0) { 44684789Smr adjval += sunptr->un_adjval; 44784789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 44884789Smr return (ERANGE); 44984789Smr } 45084789Smr sunptr->un_adjval = adjval; 4512729Sdfr if (sunptr->un_adjval == 0) { 4522729Sdfr suptr->un_cnt--; 4532729Sdfr if (i < suptr->un_cnt) 4542729Sdfr suptr->un_ent[i] = 4552729Sdfr suptr->un_ent[suptr->un_cnt]; 456187223Skib if (suptr->un_cnt == 0) 457187223Skib semu_try_free(suptr); 4582729Sdfr } 459187223Skib return (0); 4602729Sdfr } 4612729Sdfr 4622729Sdfr /* Didn't find the right entry - create it */ 4632729Sdfr if (adjval == 0) 464187223Skib return (0); 46584789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 46684789Smr return (ERANGE); 46741774Sdillon if (suptr->un_cnt != seminfo.semume) { 4682729Sdfr sunptr = &suptr->un_ent[suptr->un_cnt]; 4692729Sdfr suptr->un_cnt++; 4702729Sdfr sunptr->un_adjval = adjval; 471187223Skib sunptr->un_id = semid; 472187223Skib sunptr->un_num = semnum; 473187223Skib sunptr->un_seq = semseq; 4742729Sdfr } else 475187223Skib return (EINVAL); 476187223Skib return (0); 4772729Sdfr} 4782729Sdfr 47912819Sphkstatic void 480187223Skibsemundo_clear(int semid, int semnum) 4812729Sdfr{ 482187223Skib struct sem_undo *suptr, *suptr1; 483187223Skib struct undo *sunptr; 484187223Skib int i; 4852729Sdfr 486101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 487187223Skib LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) { 488187223Skib sunptr = &suptr->un_ent[0]; 489187223Skib for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 490187223Skib if (sunptr->un_id != semid) 491187223Skib continue; 492187223Skib if (semnum == -1 || sunptr->un_num == semnum) { 493187223Skib suptr->un_cnt--; 494187223Skib if (i < suptr->un_cnt) { 495187223Skib suptr->un_ent[i] = 496187223Skib suptr->un_ent[suptr->un_cnt]; 497187223Skib continue; 4982729Sdfr } 499187223Skib semu_try_free(suptr); 5002729Sdfr } 501187223Skib if (semnum != -1) 502187223Skib break; 5032729Sdfr } 5042729Sdfr } 5052729Sdfr} 5062729Sdfr 507101774Salfredstatic int 508187223Skibsemvalid(int semid, struct semid_kernel *semakptr) 509101774Salfred{ 510101774Salfred 511137613Srwatson return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 512137613Srwatson semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0); 513101774Salfred} 514101774Salfred 51512866Speter/* 516167211Srwatson * Note that the user-mode half of this passes a union, not a pointer. 51712866Speter */ 51812866Speter#ifndef _SYS_SYSPROTO_H_ 51912866Speterstruct __semctl_args { 5202729Sdfr int semid; 5212729Sdfr int semnum; 5222729Sdfr int cmd; 5232729Sdfr union semun *arg; 5242729Sdfr}; 52512866Speter#endif 52612866Speterint 527187223Skib__semctl(struct thread *td, struct __semctl_args *uap) 5282729Sdfr{ 529160187Sjhb struct semid_ds dsbuf; 530160187Sjhb union semun arg, semun; 531160187Sjhb register_t rval; 532159991Sjhb int error; 533159991Sjhb 534159991Sjhb switch (uap->cmd) { 535159991Sjhb case SEM_STAT: 536159991Sjhb case IPC_SET: 537159991Sjhb case IPC_STAT: 538159991Sjhb case GETALL: 539159991Sjhb case SETVAL: 540159991Sjhb case SETALL: 541160187Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 542159991Sjhb if (error) 543159991Sjhb return (error); 544159991Sjhb break; 545160187Sjhb } 546160187Sjhb 547160187Sjhb switch (uap->cmd) { 548160187Sjhb case SEM_STAT: 549160187Sjhb case IPC_STAT: 550160187Sjhb semun.buf = &dsbuf; 551159991Sjhb break; 552160187Sjhb case IPC_SET: 553160187Sjhb error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 554160187Sjhb if (error) 555160187Sjhb return (error); 556160187Sjhb semun.buf = &dsbuf; 557160187Sjhb break; 558160187Sjhb case GETALL: 559160187Sjhb case SETALL: 560160187Sjhb semun.array = arg.array; 561160187Sjhb break; 562160187Sjhb case SETVAL: 563160187Sjhb semun.val = arg.val; 564160187Sjhb break; 565159991Sjhb } 566160187Sjhb 567160187Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 568160187Sjhb &rval); 569160187Sjhb if (error) 570160187Sjhb return (error); 571160187Sjhb 572160187Sjhb switch (uap->cmd) { 573160187Sjhb case SEM_STAT: 574160187Sjhb case IPC_STAT: 575160187Sjhb error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 576160187Sjhb break; 577160187Sjhb } 578160187Sjhb 579160187Sjhb if (error == 0) 580160187Sjhb td->td_retval[0] = rval; 581160187Sjhb return (error); 582159991Sjhb} 583159991Sjhb 584159991Sjhbint 585160187Sjhbkern_semctl(struct thread *td, int semid, int semnum, int cmd, 586160187Sjhb union semun *arg, register_t *rval) 587159991Sjhb{ 588101774Salfred u_short *array; 58991406Sjhb struct ucred *cred = td->td_ucred; 590160187Sjhb int i, error; 591160187Sjhb struct semid_ds *sbuf; 592137613Srwatson struct semid_kernel *semakptr; 593101774Salfred struct mtx *sema_mtxp; 594101774Salfred u_short usval, count; 595160028Sjhb int semidx; 5962729Sdfr 597160293Skib DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 598100523Salfred semid, semnum, cmd, arg)); 599192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 60091703Sjhb return (ENOSYS); 60191703Sjhb 602101774Salfred array = NULL; 603101774Salfred 60483414Smr switch(cmd) { 60583414Smr case SEM_STAT: 606160028Sjhb /* 607160028Sjhb * For this command we assume semid is an array index 608160028Sjhb * rather than an IPC id. 609160028Sjhb */ 61091744Smaxim if (semid < 0 || semid >= seminfo.semmni) 611101774Salfred return (EINVAL); 612137613Srwatson semakptr = &sema[semid]; 613101774Salfred sema_mtxp = &sema_mtx[semid]; 614101774Salfred mtx_lock(sema_mtxp); 615137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 616101774Salfred error = EINVAL; 617101774Salfred goto done2; 618101774Salfred } 619137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 620101774Salfred goto done2; 621140615Srwatson#ifdef MAC 622172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 623162468Srwatson if (error != 0) 624140615Srwatson goto done2; 625140615Srwatson#endif 626160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 627160187Sjhb *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 628101774Salfred mtx_unlock(sema_mtxp); 629160187Sjhb return (0); 63083414Smr } 63183414Smr 632160028Sjhb semidx = IPCID_TO_IX(semid); 633160028Sjhb if (semidx < 0 || semidx >= seminfo.semmni) 634101774Salfred return (EINVAL); 6352729Sdfr 636160028Sjhb semakptr = &sema[semidx]; 637160028Sjhb sema_mtxp = &sema_mtx[semidx]; 638187223Skib if (cmd == IPC_RMID) 639187223Skib mtx_lock(&sem_mtx); 640160187Sjhb mtx_lock(sema_mtxp); 641140615Srwatson#ifdef MAC 642172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 643162468Srwatson if (error != 0) 644160187Sjhb goto done2; 645140615Srwatson#endif 646145230Srwatson 64782607Sdillon error = 0; 648160187Sjhb *rval = 0; 6492729Sdfr 6502729Sdfr switch (cmd) { 6512729Sdfr case IPC_RMID: 652159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 653101774Salfred goto done2; 654137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 65582607Sdillon goto done2; 656137613Srwatson semakptr->u.sem_perm.cuid = cred->cr_uid; 657137613Srwatson semakptr->u.sem_perm.uid = cred->cr_uid; 658187223Skib semakptr->u.sem_perm.mode = 0; 659220388Strasz crfree(semakptr->cred); 660220388Strasz semakptr->cred = NULL; 661187223Skib SEMUNDO_LOCK(); 662187223Skib semundo_clear(semidx, -1); 663187223Skib SEMUNDO_UNLOCK(); 664187223Skib#ifdef MAC 665187223Skib mac_sysvsem_cleanup(semakptr); 666187223Skib#endif 667187223Skib wakeup(semakptr); 668187223Skib for (i = 0; i < seminfo.semmni; i++) { 669187223Skib if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 670187223Skib sema[i].u.sem_base > semakptr->u.sem_base) 671187223Skib mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); 672187223Skib } 673137613Srwatson for (i = semakptr->u.sem_base - sem; i < semtot; i++) 674137613Srwatson sem[i] = sem[i + semakptr->u.sem_nsems]; 6752729Sdfr for (i = 0; i < seminfo.semmni; i++) { 676137613Srwatson if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 677187223Skib sema[i].u.sem_base > semakptr->u.sem_base) { 678137613Srwatson sema[i].u.sem_base -= semakptr->u.sem_nsems; 679187223Skib mtx_unlock(&sema_mtx[i]); 680187223Skib } 6812729Sdfr } 682187223Skib semtot -= semakptr->u.sem_nsems; 6832729Sdfr break; 6842729Sdfr 6852729Sdfr case IPC_SET: 686159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 687101774Salfred goto done2; 688137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 689101774Salfred goto done2; 690160187Sjhb sbuf = arg->buf; 691160187Sjhb semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 692160187Sjhb semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 693137613Srwatson semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 694160187Sjhb ~0777) | (sbuf->sem_perm.mode & 0777); 695137613Srwatson semakptr->u.sem_ctime = time_second; 6962729Sdfr break; 6972729Sdfr 6982729Sdfr case IPC_STAT: 699159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 700101774Salfred goto done2; 701137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 70282607Sdillon goto done2; 703160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 7042729Sdfr break; 7052729Sdfr 7062729Sdfr case GETNCNT: 707159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 708101774Salfred goto done2; 709137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 71082607Sdillon goto done2; 711137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 71282607Sdillon error = EINVAL; 71382607Sdillon goto done2; 71482607Sdillon } 715160187Sjhb *rval = semakptr->u.sem_base[semnum].semncnt; 7162729Sdfr break; 7172729Sdfr 7182729Sdfr case GETPID: 719159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 720101774Salfred goto done2; 721137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 72282607Sdillon goto done2; 723137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 72482607Sdillon error = EINVAL; 72582607Sdillon goto done2; 72682607Sdillon } 727160187Sjhb *rval = semakptr->u.sem_base[semnum].sempid; 7282729Sdfr break; 7292729Sdfr 7302729Sdfr case GETVAL: 731159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 732101774Salfred goto done2; 733137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 73482607Sdillon goto done2; 735137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 73682607Sdillon error = EINVAL; 73782607Sdillon goto done2; 73882607Sdillon } 739160187Sjhb *rval = semakptr->u.sem_base[semnum].semval; 7402729Sdfr break; 7412729Sdfr 7422729Sdfr case GETALL: 743159991Sjhb /* 744160187Sjhb * Unfortunately, callers of this function don't know 745160187Sjhb * in advance how many semaphores are in this set. 746160187Sjhb * While we could just allocate the maximum size array 747160187Sjhb * and pass the actual size back to the caller, that 748160187Sjhb * won't work for SETALL since we can't copyin() more 749160187Sjhb * data than the user specified as we may return a 750160187Sjhb * spurious EFAULT. 751160187Sjhb * 752160187Sjhb * Note that the number of semaphores in a set is 753160187Sjhb * fixed for the life of that set. The only way that 754160187Sjhb * the 'count' could change while are blocked in 755160187Sjhb * malloc() is if this semaphore set were destroyed 756160187Sjhb * and a new one created with the same index. 757160187Sjhb * However, semvalid() will catch that due to the 758160187Sjhb * sequence number unless exactly 0x8000 (or a 759160187Sjhb * multiple thereof) semaphore sets for the same index 760160187Sjhb * are created and destroyed while we are in malloc! 761160187Sjhb * 762159991Sjhb */ 763160187Sjhb count = semakptr->u.sem_nsems; 764160187Sjhb mtx_unlock(sema_mtxp); 765160187Sjhb array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 766101774Salfred mtx_lock(sema_mtxp); 767159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 768101774Salfred goto done2; 769160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 770137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 77182607Sdillon goto done2; 772137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) 773137613Srwatson array[i] = semakptr->u.sem_base[i].semval; 774101774Salfred mtx_unlock(sema_mtxp); 775160187Sjhb error = copyout(array, arg->array, count * sizeof(*array)); 776160187Sjhb mtx_lock(sema_mtxp); 7772729Sdfr break; 7782729Sdfr 7792729Sdfr case GETZCNT: 780159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 781101774Salfred goto done2; 782137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 78382607Sdillon goto done2; 784137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 78582607Sdillon error = EINVAL; 78682607Sdillon goto done2; 78782607Sdillon } 788160187Sjhb *rval = semakptr->u.sem_base[semnum].semzcnt; 7892729Sdfr break; 7902729Sdfr 7912729Sdfr case SETVAL: 792159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 793101774Salfred goto done2; 794137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 79582607Sdillon goto done2; 796137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 79782607Sdillon error = EINVAL; 79882607Sdillon goto done2; 79982607Sdillon } 800159991Sjhb if (arg->val < 0 || arg->val > seminfo.semvmx) { 80184789Smr error = ERANGE; 80284789Smr goto done2; 80384789Smr } 804159991Sjhb semakptr->u.sem_base[semnum].semval = arg->val; 805101774Salfred SEMUNDO_LOCK(); 806160028Sjhb semundo_clear(semidx, semnum); 807101774Salfred SEMUNDO_UNLOCK(); 808137613Srwatson wakeup(semakptr); 8092729Sdfr break; 8102729Sdfr 8112729Sdfr case SETALL: 812159991Sjhb /* 813160187Sjhb * See comment on GETALL for why 'count' shouldn't change 814160187Sjhb * and why we require a userland buffer. 815159991Sjhb */ 816137613Srwatson count = semakptr->u.sem_nsems; 817160187Sjhb mtx_unlock(sema_mtxp); 818111119Simp array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 819159991Sjhb error = copyin(arg->array, array, count * sizeof(*array)); 820171179Skib mtx_lock(sema_mtxp); 821101774Salfred if (error) 822101774Salfred break; 823159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 824101774Salfred goto done2; 825160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 826137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 827101774Salfred goto done2; 828137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) { 829101774Salfred usval = array[i]; 83084789Smr if (usval > seminfo.semvmx) { 83184789Smr error = ERANGE; 83284789Smr break; 83384789Smr } 834137613Srwatson semakptr->u.sem_base[i].semval = usval; 8352729Sdfr } 836101774Salfred SEMUNDO_LOCK(); 837160028Sjhb semundo_clear(semidx, -1); 838101774Salfred SEMUNDO_UNLOCK(); 839137613Srwatson wakeup(semakptr); 8402729Sdfr break; 8412729Sdfr 8422729Sdfr default: 84382607Sdillon error = EINVAL; 84482607Sdillon break; 8452729Sdfr } 8462729Sdfr 84782607Sdillondone2: 848160187Sjhb mtx_unlock(sema_mtxp); 849187223Skib if (cmd == IPC_RMID) 850187223Skib mtx_unlock(&sem_mtx); 851101774Salfred if (array != NULL) 852101774Salfred free(array, M_TEMP); 85382607Sdillon return(error); 8542729Sdfr} 8552729Sdfr 85612866Speter#ifndef _SYS_SYSPROTO_H_ 8572729Sdfrstruct semget_args { 8582729Sdfr key_t key; 8592729Sdfr int nsems; 8602729Sdfr int semflg; 8612729Sdfr}; 86212866Speter#endif 86312866Speterint 864187223Skibsemget(struct thread *td, struct semget_args *uap) 8652729Sdfr{ 86682607Sdillon int semid, error = 0; 8672729Sdfr int key = uap->key; 8682729Sdfr int nsems = uap->nsems; 8692729Sdfr int semflg = uap->semflg; 87091703Sjhb struct ucred *cred = td->td_ucred; 8712729Sdfr 872100523Salfred DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 873192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 87491703Sjhb return (ENOSYS); 87591703Sjhb 876187223Skib mtx_lock(&sem_mtx); 8772729Sdfr if (key != IPC_PRIVATE) { 8782729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 879137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 880137613Srwatson sema[semid].u.sem_perm.key == key) 8812729Sdfr break; 8822729Sdfr } 8832729Sdfr if (semid < seminfo.semmni) { 884100523Salfred DPRINTF(("found public key\n")); 885137613Srwatson if ((error = ipcperm(td, &sema[semid].u.sem_perm, 88682607Sdillon semflg & 0700))) { 88782607Sdillon goto done2; 88882607Sdillon } 889137613Srwatson if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 890100523Salfred DPRINTF(("too small\n")); 89182607Sdillon error = EINVAL; 89282607Sdillon goto done2; 8932729Sdfr } 8942729Sdfr if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 895100523Salfred DPRINTF(("not exclusive\n")); 89682607Sdillon error = EEXIST; 89782607Sdillon goto done2; 8982729Sdfr } 899140615Srwatson#ifdef MAC 900172930Srwatson error = mac_sysvsem_check_semget(cred, &sema[semid]); 901162468Srwatson if (error != 0) 902140615Srwatson goto done2; 903140615Srwatson#endif 9042729Sdfr goto found; 9052729Sdfr } 9062729Sdfr } 9072729Sdfr 908137613Srwatson DPRINTF(("need to allocate the semid_kernel\n")); 9092729Sdfr if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 9102729Sdfr if (nsems <= 0 || nsems > seminfo.semmsl) { 911100523Salfred DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 912100523Salfred seminfo.semmsl)); 91382607Sdillon error = EINVAL; 91482607Sdillon goto done2; 9152729Sdfr } 9162729Sdfr if (nsems > seminfo.semmns - semtot) { 917100523Salfred DPRINTF(( 918100523Salfred "not enough semaphores left (need %d, got %d)\n", 919100523Salfred nsems, seminfo.semmns - semtot)); 92082607Sdillon error = ENOSPC; 92182607Sdillon goto done2; 9222729Sdfr } 9232729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 924137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 9252729Sdfr break; 9262729Sdfr } 9272729Sdfr if (semid == seminfo.semmni) { 928137613Srwatson DPRINTF(("no more semid_kernel's available\n")); 92982607Sdillon error = ENOSPC; 93082607Sdillon goto done2; 9312729Sdfr } 932100523Salfred DPRINTF(("semid %d is available\n", semid)); 933187298Skib mtx_lock(&sema_mtx[semid]); 934187298Skib KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 935187298Skib ("Lost semaphore %d", semid)); 936137613Srwatson sema[semid].u.sem_perm.key = key; 937137613Srwatson sema[semid].u.sem_perm.cuid = cred->cr_uid; 938137613Srwatson sema[semid].u.sem_perm.uid = cred->cr_uid; 939137613Srwatson sema[semid].u.sem_perm.cgid = cred->cr_gid; 940137613Srwatson sema[semid].u.sem_perm.gid = cred->cr_gid; 941137613Srwatson sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 942220388Strasz crhold(cred); 943220388Strasz sema[semid].cred = cred; 944137613Srwatson sema[semid].u.sem_perm.seq = 945137613Srwatson (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 946137613Srwatson sema[semid].u.sem_nsems = nsems; 947137613Srwatson sema[semid].u.sem_otime = 0; 948137613Srwatson sema[semid].u.sem_ctime = time_second; 949137613Srwatson sema[semid].u.sem_base = &sem[semtot]; 9502729Sdfr semtot += nsems; 951137613Srwatson bzero(sema[semid].u.sem_base, 952137613Srwatson sizeof(sema[semid].u.sem_base[0])*nsems); 953140615Srwatson#ifdef MAC 954172930Srwatson mac_sysvsem_create(cred, &sema[semid]); 955140615Srwatson#endif 956187298Skib mtx_unlock(&sema_mtx[semid]); 957160293Skib DPRINTF(("sembase = %p, next = %p\n", 958137613Srwatson sema[semid].u.sem_base, &sem[semtot])); 9592729Sdfr } else { 960100523Salfred DPRINTF(("didn't find it and wasn't asked to create it\n")); 96182607Sdillon error = ENOENT; 96282607Sdillon goto done2; 9632729Sdfr } 9642729Sdfr 9652729Sdfrfound: 966137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 96782607Sdillondone2: 968187223Skib mtx_unlock(&sem_mtx); 96982607Sdillon return (error); 9702729Sdfr} 9712729Sdfr 97212866Speter#ifndef _SYS_SYSPROTO_H_ 9732729Sdfrstruct semop_args { 9742729Sdfr int semid; 9752729Sdfr struct sembuf *sops; 976109829Salfred size_t nsops; 9772729Sdfr}; 97812866Speter#endif 97912866Speterint 980187223Skibsemop(struct thread *td, struct semop_args *uap) 9812729Sdfr{ 982123667Stjr#define SMALL_SOPS 8 983123667Stjr struct sembuf small_sops[SMALL_SOPS]; 9842729Sdfr int semid = uap->semid; 985109829Salfred size_t nsops = uap->nsops; 986105429Salfred struct sembuf *sops; 987137613Srwatson struct semid_kernel *semakptr; 988101350Salfred struct sembuf *sopptr = 0; 989101350Salfred struct sem *semptr = 0; 99084789Smr struct sem_undo *suptr; 991101774Salfred struct mtx *sema_mtxp; 992110040Stjr size_t i, j, k; 993109829Salfred int error; 9943308Sphk int do_wakeup, do_undos; 995187223Skib unsigned short seq; 9962729Sdfr 997160293Skib#ifdef SEM_DEBUG 998160293Skib sops = NULL; 999160293Skib#endif 1000160293Skib DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 10012729Sdfr 1002192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 100391703Sjhb return (ENOSYS); 100491703Sjhb 10052729Sdfr semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 10062729Sdfr 1007101774Salfred if (semid < 0 || semid >= seminfo.semmni) 1008137644Srwatson return (EINVAL); 1009101774Salfred 1010101774Salfred /* Allocate memory for sem_ops */ 1011123667Stjr if (nsops <= SMALL_SOPS) 1012123667Stjr sops = small_sops; 1013123667Stjr else if (nsops <= seminfo.semopm) 1014123667Stjr sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 1015123667Stjr else { 1016101774Salfred DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1017101774Salfred nsops)); 1018101774Salfred return (E2BIG); 101982607Sdillon } 1020101774Salfred if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1021160293Skib DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1022101774Salfred uap->sops, sops, nsops * sizeof(sops[0]))); 1023123667Stjr if (sops != small_sops) 1024123667Stjr free(sops, M_SEM); 1025101774Salfred return (error); 1026101774Salfred } 10272729Sdfr 1028137613Srwatson semakptr = &sema[semid]; 1029101774Salfred sema_mtxp = &sema_mtx[semid]; 1030101774Salfred mtx_lock(sema_mtxp); 1031137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 103282607Sdillon error = EINVAL; 103382607Sdillon goto done2; 103482607Sdillon } 1035187223Skib seq = semakptr->u.sem_perm.seq; 1036187223Skib if (seq != IPCID_TO_SEQ(uap->semid)) { 103782607Sdillon error = EINVAL; 103882607Sdillon goto done2; 103982607Sdillon } 104084789Smr /* 104184789Smr * Initial pass thru sops to see what permissions are needed. 104284789Smr * Also perform any checks that don't need repeating on each 104384789Smr * attempt to satisfy the request vector. 104484789Smr */ 104584789Smr j = 0; /* permission needed */ 104684789Smr do_undos = 0; 104784789Smr for (i = 0; i < nsops; i++) { 104884789Smr sopptr = &sops[i]; 1049137613Srwatson if (sopptr->sem_num >= semakptr->u.sem_nsems) { 105084789Smr error = EFBIG; 105184789Smr goto done2; 105284789Smr } 105384789Smr if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 105484789Smr do_undos = 1; 105584789Smr j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 105684789Smr } 105784789Smr 1058137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1059100523Salfred DPRINTF(("error = %d from ipaccess\n", error)); 106082607Sdillon goto done2; 10612729Sdfr } 1062140615Srwatson#ifdef MAC 1063172930Srwatson error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1064162468Srwatson if (error != 0) 1065140615Srwatson goto done2; 1066140615Srwatson#endif 10672729Sdfr 10688876Srgrimes /* 10692729Sdfr * Loop trying to satisfy the vector of requests. 10702729Sdfr * If we reach a point where we must wait, any requests already 10712729Sdfr * performed are rolled back and we go to sleep until some other 10722729Sdfr * process wakes us up. At this point, we start all over again. 10732729Sdfr * 10742729Sdfr * This ensures that from the perspective of other tasks, a set 10752729Sdfr * of requests is atomic (never partially satisfied). 10762729Sdfr */ 10772729Sdfr for (;;) { 10782729Sdfr do_wakeup = 0; 107984789Smr error = 0; /* error return if necessary */ 10802729Sdfr 10812729Sdfr for (i = 0; i < nsops; i++) { 10822729Sdfr sopptr = &sops[i]; 1083137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 10842729Sdfr 1085100523Salfred DPRINTF(( 1086160293Skib "semop: semakptr=%p, sem_base=%p, " 1087160293Skib "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1088137613Srwatson semakptr, semakptr->u.sem_base, semptr, 10892729Sdfr sopptr->sem_num, semptr->semval, sopptr->sem_op, 1090100523Salfred (sopptr->sem_flg & IPC_NOWAIT) ? 1091100523Salfred "nowait" : "wait")); 10922729Sdfr 10932729Sdfr if (sopptr->sem_op < 0) { 10942729Sdfr if (semptr->semval + sopptr->sem_op < 0) { 1095100523Salfred DPRINTF(("semop: can't do it now\n")); 10962729Sdfr break; 10972729Sdfr } else { 10982729Sdfr semptr->semval += sopptr->sem_op; 10992729Sdfr if (semptr->semval == 0 && 11002729Sdfr semptr->semzcnt > 0) 11012729Sdfr do_wakeup = 1; 11022729Sdfr } 11032729Sdfr } else if (sopptr->sem_op == 0) { 110484789Smr if (semptr->semval != 0) { 1105100523Salfred DPRINTF(("semop: not zero now\n")); 11062729Sdfr break; 11072729Sdfr } 110884789Smr } else if (semptr->semval + sopptr->sem_op > 110984789Smr seminfo.semvmx) { 111084789Smr error = ERANGE; 111184789Smr break; 11122729Sdfr } else { 11132729Sdfr if (semptr->semncnt > 0) 11142729Sdfr do_wakeup = 1; 11152729Sdfr semptr->semval += sopptr->sem_op; 11162729Sdfr } 11172729Sdfr } 11182729Sdfr 11192729Sdfr /* 11202729Sdfr * Did we get through the entire vector? 11212729Sdfr */ 11222729Sdfr if (i >= nsops) 11232729Sdfr goto done; 11242729Sdfr 11252729Sdfr /* 11262729Sdfr * No ... rollback anything that we've already done 11272729Sdfr */ 1128100523Salfred DPRINTF(("semop: rollback 0 through %d\n", i-1)); 11292729Sdfr for (j = 0; j < i; j++) 1130137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 11312729Sdfr sops[j].sem_op; 11322729Sdfr 113384789Smr /* If we detected an error, return it */ 113484789Smr if (error != 0) 113584789Smr goto done2; 113684789Smr 11372729Sdfr /* 11382729Sdfr * If the request that we couldn't satisfy has the 11392729Sdfr * NOWAIT flag set then return with EAGAIN. 11402729Sdfr */ 114182607Sdillon if (sopptr->sem_flg & IPC_NOWAIT) { 114282607Sdillon error = EAGAIN; 114382607Sdillon goto done2; 114482607Sdillon } 11452729Sdfr 11462729Sdfr if (sopptr->sem_op == 0) 11472729Sdfr semptr->semzcnt++; 11482729Sdfr else 11492729Sdfr semptr->semncnt++; 11502729Sdfr 1151100523Salfred DPRINTF(("semop: good night!\n")); 1152137613Srwatson error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1153101774Salfred "semwait", 0); 1154100523Salfred DPRINTF(("semop: good morning (error=%d)!\n", error)); 1155127108Scperciva /* return code is checked below, after sem[nz]cnt-- */ 11562729Sdfr 11572729Sdfr /* 11582729Sdfr * Make sure that the semaphore still exists 11592729Sdfr */ 1160187223Skib seq = semakptr->u.sem_perm.seq; 1161137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1162187223Skib seq != IPCID_TO_SEQ(uap->semid)) { 116382607Sdillon error = EIDRM; 116482607Sdillon goto done2; 116582607Sdillon } 11662729Sdfr 11672729Sdfr /* 1168179879Sgonzo * Renew the semaphore's pointer after wakeup since 1169179879Sgonzo * during msleep sem_base may have been modified and semptr 1170179879Sgonzo * is not valid any more 1171179879Sgonzo */ 1172179879Sgonzo semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1173179879Sgonzo 1174179879Sgonzo /* 11752729Sdfr * The semaphore is still alive. Readjust the count of 11762729Sdfr * waiting processes. 11772729Sdfr */ 11782729Sdfr if (sopptr->sem_op == 0) 11792729Sdfr semptr->semzcnt--; 11802729Sdfr else 11812729Sdfr semptr->semncnt--; 1182127108Scperciva 1183127108Scperciva /* 1184127108Scperciva * Is it really morning, or was our sleep interrupted? 1185127108Scperciva * (Delayed check of msleep() return code because we 1186127108Scperciva * need to decrement sem[nz]cnt either way.) 1187127108Scperciva */ 1188127108Scperciva if (error != 0) { 1189127108Scperciva error = EINTR; 1190127108Scperciva goto done2; 1191127108Scperciva } 1192127108Scperciva DPRINTF(("semop: good morning!\n")); 11932729Sdfr } 11942729Sdfr 11952729Sdfrdone: 11962729Sdfr /* 11972729Sdfr * Process any SEM_UNDO requests. 11982729Sdfr */ 11992729Sdfr if (do_undos) { 1200101774Salfred SEMUNDO_LOCK(); 120184789Smr suptr = NULL; 12022729Sdfr for (i = 0; i < nsops; i++) { 12032729Sdfr /* 12042729Sdfr * We only need to deal with SEM_UNDO's for non-zero 12052729Sdfr * op's. 12062729Sdfr */ 12072729Sdfr int adjval; 12082729Sdfr 12092729Sdfr if ((sops[i].sem_flg & SEM_UNDO) == 0) 12102729Sdfr continue; 12112729Sdfr adjval = sops[i].sem_op; 12122729Sdfr if (adjval == 0) 12132729Sdfr continue; 1214187223Skib error = semundo_adjust(td, &suptr, semid, seq, 12152729Sdfr sops[i].sem_num, -adjval); 121682607Sdillon if (error == 0) 12172729Sdfr continue; 12182729Sdfr 12192729Sdfr /* 12202729Sdfr * Oh-Oh! We ran out of either sem_undo's or undo's. 12212729Sdfr * Rollback the adjustments to this point and then 12222729Sdfr * rollback the semaphore ups and down so we can return 12232729Sdfr * with an error with all structures restored. We 12242729Sdfr * rollback the undo's in the exact reverse order that 12252729Sdfr * we applied them. This guarantees that we won't run 12262729Sdfr * out of space as we roll things back out. 12272729Sdfr */ 1228110040Stjr for (j = 0; j < i; j++) { 1229110040Stjr k = i - j - 1; 1230110040Stjr if ((sops[k].sem_flg & SEM_UNDO) == 0) 12312729Sdfr continue; 1232110040Stjr adjval = sops[k].sem_op; 12332729Sdfr if (adjval == 0) 12342729Sdfr continue; 1235187223Skib if (semundo_adjust(td, &suptr, semid, seq, 1236110040Stjr sops[k].sem_num, adjval) != 0) 12372729Sdfr panic("semop - can't undo undos"); 12382729Sdfr } 12392729Sdfr 12402729Sdfr for (j = 0; j < nsops; j++) 1241137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 12422729Sdfr sops[j].sem_op; 12432729Sdfr 1244100523Salfred DPRINTF(("error = %d from semundo_adjust\n", error)); 1245101774Salfred SEMUNDO_UNLOCK(); 124682607Sdillon goto done2; 12472729Sdfr } /* loop through the sops */ 1248101774Salfred SEMUNDO_UNLOCK(); 12492729Sdfr } /* if (do_undos) */ 12502729Sdfr 125184789Smr /* We're definitely done - set the sempid's and time */ 12522729Sdfr for (i = 0; i < nsops; i++) { 12532729Sdfr sopptr = &sops[i]; 1254137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 125583366Sjulian semptr->sempid = td->td_proc->p_pid; 12562729Sdfr } 1257137613Srwatson semakptr->u.sem_otime = time_second; 12582729Sdfr 125984789Smr /* 126084789Smr * Do a wakeup if any semaphore was up'd whilst something was 126184789Smr * sleeping on it. 126284789Smr */ 12632729Sdfr if (do_wakeup) { 1264100523Salfred DPRINTF(("semop: doing wakeup\n")); 1265137613Srwatson wakeup(semakptr); 1266100523Salfred DPRINTF(("semop: back from wakeup\n")); 12672729Sdfr } 1268100523Salfred DPRINTF(("semop: done\n")); 126983366Sjulian td->td_retval[0] = 0; 127082607Sdillondone2: 1271101774Salfred mtx_unlock(sema_mtxp); 1272123667Stjr if (sops != small_sops) 1273123667Stjr free(sops, M_SEM); 127482607Sdillon return (error); 12752729Sdfr} 12762729Sdfr 12772729Sdfr/* 12782729Sdfr * Go through the undo structures for this process and apply the adjustments to 12792729Sdfr * semaphores. 12802729Sdfr */ 128169449Salfredstatic void 1282187223Skibsemexit_myhook(void *arg, struct proc *p) 12832729Sdfr{ 1284101350Salfred struct sem_undo *suptr; 1285187223Skib struct semid_kernel *semakptr; 1286187223Skib struct mtx *sema_mtxp; 1287187223Skib int semid, semnum, adjval, ix; 1288187223Skib unsigned short seq; 12892729Sdfr 12902729Sdfr /* 12912729Sdfr * Go through the chain of undo vectors looking for one 12922729Sdfr * associated with this process. 12932729Sdfr */ 1294101774Salfred SEMUNDO_LOCK(); 1295187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 1296187223Skib if (suptr->un_proc == p) 12972729Sdfr break; 12982729Sdfr } 1299187223Skib if (suptr == NULL) { 1300187223Skib SEMUNDO_UNLOCK(); 130159828Speter return; 1302187223Skib } 1303187223Skib LIST_REMOVE(suptr, un_next); 13042729Sdfr 1305160293Skib DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1306100523Salfred suptr->un_cnt)); 13072729Sdfr 13082729Sdfr /* 13092729Sdfr * If there are any active undo elements then process them. 13102729Sdfr */ 13112729Sdfr if (suptr->un_cnt > 0) { 1312187223Skib SEMUNDO_UNLOCK(); 13132729Sdfr for (ix = 0; ix < suptr->un_cnt; ix++) { 1314187223Skib semid = suptr->un_ent[ix].un_id; 1315187223Skib semnum = suptr->un_ent[ix].un_num; 1316187223Skib adjval = suptr->un_ent[ix].un_adjval; 1317187223Skib seq = suptr->un_ent[ix].un_seq; 1318137613Srwatson semakptr = &sema[semid]; 1319101774Salfred sema_mtxp = &sema_mtx[semid]; 1320187223Skib 1321101774Salfred mtx_lock(sema_mtxp); 1322187223Skib if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1323187223Skib (semakptr->u.sem_perm.seq != seq)) { 1324187223Skib mtx_unlock(sema_mtxp); 1325187223Skib continue; 1326187223Skib } 1327137613Srwatson if (semnum >= semakptr->u.sem_nsems) 13282729Sdfr panic("semexit - semnum out of range"); 13292729Sdfr 1330100523Salfred DPRINTF(( 1331160293Skib "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 13322729Sdfr suptr->un_proc, suptr->un_ent[ix].un_id, 13332729Sdfr suptr->un_ent[ix].un_num, 13342729Sdfr suptr->un_ent[ix].un_adjval, 1335137613Srwatson semakptr->u.sem_base[semnum].semval)); 13362729Sdfr 1337187223Skib if (adjval < 0 && semakptr->u.sem_base[semnum].semval < 1338187223Skib -adjval) 1339187223Skib semakptr->u.sem_base[semnum].semval = 0; 1340187223Skib else 1341137613Srwatson semakptr->u.sem_base[semnum].semval += adjval; 13422729Sdfr 1343137613Srwatson wakeup(semakptr); 1344100523Salfred DPRINTF(("semexit: back from wakeup\n")); 1345101774Salfred mtx_unlock(sema_mtxp); 13462729Sdfr } 1347187223Skib SEMUNDO_LOCK(); 13482729Sdfr } 13492729Sdfr 13502729Sdfr /* 13512729Sdfr * Deallocate the undo vector. 13522729Sdfr */ 1353100523Salfred DPRINTF(("removing vector\n")); 13542729Sdfr suptr->un_proc = NULL; 1355187223Skib suptr->un_cnt = 0; 1356187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1357167904Semaste SEMUNDO_UNLOCK(); 13582729Sdfr} 135977461Sdd 136077461Sddstatic int 136177461Sddsysctl_sema(SYSCTL_HANDLER_ARGS) 136277461Sdd{ 136377461Sdd 136477461Sdd return (SYSCTL_OUT(req, sema, 1365137613Srwatson sizeof(struct semid_kernel) * seminfo.semmni)); 136677461Sdd} 1367194894Sjhb 1368194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1369194894Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1370194894Sjhb 1371194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1372194894Sjhbstatic sy_call_t *semcalls[] = { 1373194910Sjhb (sy_call_t *)freebsd7___semctl, (sy_call_t *)semget, 1374194894Sjhb (sy_call_t *)semop 1375194894Sjhb}; 1376194894Sjhb 1377194894Sjhb/* 1378194894Sjhb * Entry point for all SEM calls. 1379194894Sjhb */ 1380194894Sjhbint 1381194894Sjhbsemsys(td, uap) 1382194894Sjhb struct thread *td; 1383194894Sjhb /* XXX actually varargs. */ 1384194894Sjhb struct semsys_args /* { 1385194894Sjhb int which; 1386194894Sjhb int a2; 1387194894Sjhb int a3; 1388194894Sjhb int a4; 1389194894Sjhb int a5; 1390194894Sjhb } */ *uap; 1391194894Sjhb{ 1392194894Sjhb int error; 1393194894Sjhb 1394194894Sjhb if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 1395194894Sjhb return (ENOSYS); 1396194894Sjhb if (uap->which < 0 || 1397194894Sjhb uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) 1398194894Sjhb return (EINVAL); 1399194894Sjhb error = (*semcalls[uap->which])(td, &uap->a2); 1400194894Sjhb return (error); 1401194894Sjhb} 1402194910Sjhb 1403205323Skib#ifndef CP 1404194910Sjhb#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1405205323Skib#endif 1406194910Sjhb 1407194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1408194910Sjhbstruct freebsd7___semctl_args { 1409194910Sjhb int semid; 1410194910Sjhb int semnum; 1411194910Sjhb int cmd; 1412194910Sjhb union semun_old *arg; 1413194910Sjhb}; 1414194910Sjhb#endif 1415194910Sjhbint 1416194910Sjhbfreebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1417194910Sjhb{ 1418194910Sjhb struct semid_ds_old dsold; 1419194910Sjhb struct semid_ds dsbuf; 1420194910Sjhb union semun_old arg; 1421194910Sjhb union semun semun; 1422194910Sjhb register_t rval; 1423194910Sjhb int error; 1424194910Sjhb 1425194910Sjhb switch (uap->cmd) { 1426194910Sjhb case SEM_STAT: 1427194910Sjhb case IPC_SET: 1428194910Sjhb case IPC_STAT: 1429194910Sjhb case GETALL: 1430194910Sjhb case SETVAL: 1431194910Sjhb case SETALL: 1432194910Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 1433194910Sjhb if (error) 1434194910Sjhb return (error); 1435194910Sjhb break; 1436194910Sjhb } 1437194910Sjhb 1438194910Sjhb switch (uap->cmd) { 1439194910Sjhb case SEM_STAT: 1440194910Sjhb case IPC_STAT: 1441194910Sjhb semun.buf = &dsbuf; 1442194910Sjhb break; 1443194910Sjhb case IPC_SET: 1444194910Sjhb error = copyin(arg.buf, &dsold, sizeof(dsold)); 1445194910Sjhb if (error) 1446194910Sjhb return (error); 1447194910Sjhb ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1448194910Sjhb CP(dsold, dsbuf, sem_base); 1449194910Sjhb CP(dsold, dsbuf, sem_nsems); 1450194910Sjhb CP(dsold, dsbuf, sem_otime); 1451194910Sjhb CP(dsold, dsbuf, sem_ctime); 1452194910Sjhb semun.buf = &dsbuf; 1453194910Sjhb break; 1454194910Sjhb case GETALL: 1455194910Sjhb case SETALL: 1456194910Sjhb semun.array = arg.array; 1457194910Sjhb break; 1458194910Sjhb case SETVAL: 1459194910Sjhb semun.val = arg.val; 1460194910Sjhb break; 1461194910Sjhb } 1462194910Sjhb 1463194910Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1464194910Sjhb &rval); 1465194910Sjhb if (error) 1466194910Sjhb return (error); 1467194910Sjhb 1468194910Sjhb switch (uap->cmd) { 1469194910Sjhb case SEM_STAT: 1470194910Sjhb case IPC_STAT: 1471194910Sjhb bzero(&dsold, sizeof(dsold)); 1472194910Sjhb ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1473194910Sjhb CP(dsbuf, dsold, sem_base); 1474194910Sjhb CP(dsbuf, dsold, sem_nsems); 1475194910Sjhb CP(dsbuf, dsold, sem_otime); 1476194910Sjhb CP(dsbuf, dsold, sem_ctime); 1477194910Sjhb error = copyout(&dsold, arg.buf, sizeof(dsold)); 1478194910Sjhb break; 1479194910Sjhb } 1480194910Sjhb 1481194910Sjhb if (error == 0) 1482194910Sjhb td->td_retval[0] = rval; 1483194910Sjhb return (error); 1484194910Sjhb} 1485194910Sjhb 1486205323Skib#endif /* COMPAT_FREEBSD{4,5,6,7} */ 1487194910Sjhb 1488205323Skib#ifdef COMPAT_FREEBSD32 1489205323Skib 1490205323Skibint 1491205323Skibfreebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1492205323Skib{ 1493205323Skib 1494205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1495205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1496205323Skib switch (uap->which) { 1497205323Skib case 0: 1498205323Skib return (freebsd7_freebsd32_semctl(td, 1499205323Skib (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1500205323Skib default: 1501205323Skib return (semsys(td, (struct semsys_args *)uap)); 1502205323Skib } 1503205323Skib#else 1504205323Skib return (nosys(td, NULL)); 1505205323Skib#endif 1506205323Skib} 1507205323Skib 1508205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1509205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1510205323Skibint 1511205323Skibfreebsd7_freebsd32_semctl(struct thread *td, 1512205323Skib struct freebsd7_freebsd32_semctl_args *uap) 1513205323Skib{ 1514205323Skib struct semid_ds32_old dsbuf32; 1515205323Skib struct semid_ds dsbuf; 1516205323Skib union semun semun; 1517205323Skib union semun32 arg; 1518205323Skib register_t rval; 1519205323Skib int error; 1520205323Skib 1521205323Skib switch (uap->cmd) { 1522205323Skib case SEM_STAT: 1523205323Skib case IPC_SET: 1524205323Skib case IPC_STAT: 1525205323Skib case GETALL: 1526205323Skib case SETVAL: 1527205323Skib case SETALL: 1528205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1529205323Skib if (error) 1530205323Skib return (error); 1531205323Skib break; 1532205323Skib } 1533205323Skib 1534205323Skib switch (uap->cmd) { 1535205323Skib case SEM_STAT: 1536205323Skib case IPC_STAT: 1537205323Skib semun.buf = &dsbuf; 1538205323Skib break; 1539205323Skib case IPC_SET: 1540205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1541205323Skib if (error) 1542205323Skib return (error); 1543205323Skib freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1544205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1545205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1546205323Skib CP(dsbuf32, dsbuf, sem_otime); 1547205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1548205323Skib semun.buf = &dsbuf; 1549205323Skib break; 1550205323Skib case GETALL: 1551205323Skib case SETALL: 1552205323Skib semun.array = PTRIN(arg.array); 1553205323Skib break; 1554205323Skib case SETVAL: 1555205323Skib semun.val = arg.val; 1556205323Skib break; 1557205323Skib } 1558205323Skib 1559205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1560205323Skib &rval); 1561205323Skib if (error) 1562205323Skib return (error); 1563205323Skib 1564205323Skib switch (uap->cmd) { 1565205323Skib case SEM_STAT: 1566205323Skib case IPC_STAT: 1567205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1568205323Skib freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1569205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1570205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1571205323Skib CP(dsbuf, dsbuf32, sem_otime); 1572205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1573205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1574205323Skib break; 1575205323Skib } 1576205323Skib 1577205323Skib if (error == 0) 1578205323Skib td->td_retval[0] = rval; 1579205323Skib return (error); 1580205323Skib} 1581205323Skib#endif 1582205323Skib 1583205323Skibint 1584205323Skibfreebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1585205323Skib{ 1586205323Skib struct semid_ds32 dsbuf32; 1587205323Skib struct semid_ds dsbuf; 1588205323Skib union semun semun; 1589205323Skib union semun32 arg; 1590205323Skib register_t rval; 1591205323Skib int error; 1592205323Skib 1593205323Skib switch (uap->cmd) { 1594205323Skib case SEM_STAT: 1595205323Skib case IPC_SET: 1596205323Skib case IPC_STAT: 1597205323Skib case GETALL: 1598205323Skib case SETVAL: 1599205323Skib case SETALL: 1600205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1601205323Skib if (error) 1602205323Skib return (error); 1603205323Skib break; 1604205323Skib } 1605205323Skib 1606205323Skib switch (uap->cmd) { 1607205323Skib case SEM_STAT: 1608205323Skib case IPC_STAT: 1609205323Skib semun.buf = &dsbuf; 1610205323Skib break; 1611205323Skib case IPC_SET: 1612205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1613205323Skib if (error) 1614205323Skib return (error); 1615205323Skib freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1616205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1617205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1618205323Skib CP(dsbuf32, dsbuf, sem_otime); 1619205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1620205323Skib semun.buf = &dsbuf; 1621205323Skib break; 1622205323Skib case GETALL: 1623205323Skib case SETALL: 1624205323Skib semun.array = PTRIN(arg.array); 1625205323Skib break; 1626205323Skib case SETVAL: 1627205323Skib semun.val = arg.val; 1628205323Skib break; 1629205323Skib } 1630205323Skib 1631205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1632205323Skib &rval); 1633205323Skib if (error) 1634205323Skib return (error); 1635205323Skib 1636205323Skib switch (uap->cmd) { 1637205323Skib case SEM_STAT: 1638205323Skib case IPC_STAT: 1639205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1640205323Skib freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1641205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1642205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1643205323Skib CP(dsbuf, dsbuf32, sem_otime); 1644205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1645205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1646205323Skib break; 1647205323Skib } 1648205323Skib 1649205323Skib if (error == 0) 1650205323Skib td->td_retval[0] = rval; 1651205323Skib return (error); 1652205323Skib} 1653205323Skib 1654205323Skib#endif /* COMPAT_FREEBSD32 */ 1655