sysv_sem.c revision 220398
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 220398 2011-04-06 18:11:24Z 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> 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 SEMMAP 15359839Speter#define SEMMAP 30 /* # of entries in semaphore map */ 15459839Speter#endif 15559839Speter#ifndef SEMMSL 15659839Speter#define SEMMSL SEMMNS /* max # of semaphores per id */ 15759839Speter#endif 15859839Speter#ifndef SEMOPM 15959839Speter#define SEMOPM 100 /* max # of operations per semop call */ 16059839Speter#endif 16159839Speter 16259839Speter#define SEMVMX 32767 /* semaphore maximum value */ 16359839Speter#define SEMAEM 16384 /* adjust on exit max value */ 16459839Speter 16559839Speter/* 16659839Speter * Due to the way semaphore memory is allocated, we have to ensure that 16759839Speter * SEMUSZ is properly aligned. 16859839Speter */ 16959839Speter 17059839Speter#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) 17159839Speter 17259839Speter/* actual size of an undo structure */ 17359839Speter#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) 17459839Speter 17559839Speter/* 17659839Speter * Macro to find a particular sem_undo vector 17759839Speter */ 178101350Salfred#define SEMU(ix) \ 179101350Salfred ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) 18059839Speter 18159839Speter/* 18259839Speter * semaphore info struct 18359839Speter */ 18459839Speterstruct seminfo seminfo = { 18559839Speter SEMMAP, /* # of entries in semaphore map */ 18659839Speter SEMMNI, /* # of semaphore identifiers */ 18759839Speter SEMMNS, /* # of semaphores in system */ 18859839Speter SEMMNU, /* # of undo structures in system */ 18959839Speter SEMMSL, /* max # of semaphores per id */ 19059839Speter SEMOPM, /* max # of operations per semop call */ 19159839Speter SEMUME, /* max # of undo entries per process */ 19259839Speter SEMUSZ, /* size in bytes of undo structure */ 19359839Speter SEMVMX, /* semaphore maximum value */ 19459839Speter SEMAEM /* adjust on exit max value */ 19559839Speter}; 19659839Speter 197141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, 198141710Scsjp "Number of entries in the semaphore map"); 199141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, 200141710Scsjp "Number of semaphore identifiers"); 201141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0, 202141710Scsjp "Maximum number of semaphores in the system"); 203141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0, 204141710Scsjp "Maximum number of undo structures in the system"); 205141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, 206141710Scsjp "Max semaphores per id"); 207141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0, 208141710Scsjp "Max operations per semop call"); 209141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0, 210141710Scsjp "Max undo entries per process"); 211141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0, 212141710Scsjp "Size in bytes of undo structure"); 213141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, 214141710Scsjp "Semaphore maximum value"); 215141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, 216141710Scsjp "Adjust on exit max value"); 217217555SmdfSYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLTYPE_OPAQUE | CTLFLAG_RD, 218215281Sbrucec NULL, 0, sysctl_sema, "", "Semaphore id pool"); 21959839Speter 220205323Skibstatic struct syscall_helper_data sem_syscalls[] = { 221205323Skib SYSCALL_INIT_HELPER(__semctl), 222205323Skib SYSCALL_INIT_HELPER(semget), 223205323Skib SYSCALL_INIT_HELPER(semop), 224205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 225205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 226205323Skib SYSCALL_INIT_HELPER(semsys), 227205323Skib SYSCALL_INIT_HELPER(freebsd7___semctl), 228205323Skib#endif 229205323Skib SYSCALL_INIT_LAST 230205323Skib}; 231205323Skib 232205323Skib#ifdef COMPAT_FREEBSD32 233205323Skib#include <compat/freebsd32/freebsd32.h> 234205323Skib#include <compat/freebsd32/freebsd32_ipc.h> 235205323Skib#include <compat/freebsd32/freebsd32_proto.h> 236205323Skib#include <compat/freebsd32/freebsd32_signal.h> 237205323Skib#include <compat/freebsd32/freebsd32_syscall.h> 238205323Skib#include <compat/freebsd32/freebsd32_util.h> 239205323Skib 240205323Skibstatic struct syscall_helper_data sem32_syscalls[] = { 241205323Skib SYSCALL32_INIT_HELPER(freebsd32_semctl), 242205323Skib SYSCALL32_INIT_HELPER(semget), 243205323Skib SYSCALL32_INIT_HELPER(semop), 244205323Skib SYSCALL32_INIT_HELPER(freebsd32_semsys), 245205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 246205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 247205323Skib SYSCALL32_INIT_HELPER(freebsd7_freebsd32_semctl), 248205323Skib#endif 249205323Skib SYSCALL_INIT_LAST 250205323Skib}; 251205323Skib#endif 252205323Skib 253205323Skibstatic int 25469449Salfredseminit(void) 2552729Sdfr{ 256205323Skib int i, error; 2572729Sdfr 25883413Smr TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap); 25983413Smr TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni); 26083413Smr TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns); 26183413Smr TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu); 26283413Smr TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl); 26383413Smr TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm); 26483413Smr TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume); 26583413Smr TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz); 26683413Smr TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx); 26783413Smr TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem); 26883413Smr 269111119Simp sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 270137613Srwatson sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM, 271111119Simp M_WAITOK); 272101774Salfred sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM, 273111119Simp M_WAITOK | M_ZERO); 274111119Simp semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 2752729Sdfr 2762729Sdfr for (i = 0; i < seminfo.semmni; i++) { 277137613Srwatson sema[i].u.sem_base = 0; 278137613Srwatson sema[i].u.sem_perm.mode = 0; 279137613Srwatson sema[i].u.sem_perm.seq = 0; 280140615Srwatson#ifdef MAC 281172930Srwatson mac_sysvsem_init(&sema[i]); 282140615Srwatson#endif 2832729Sdfr } 284101774Salfred for (i = 0; i < seminfo.semmni; i++) 285101774Salfred mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); 286187223Skib LIST_INIT(&semu_free_list); 2872729Sdfr for (i = 0; i < seminfo.semmnu; i++) { 288101350Salfred struct sem_undo *suptr = SEMU(i); 2892729Sdfr suptr->un_proc = NULL; 290187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 2912729Sdfr } 292187223Skib LIST_INIT(&semu_list); 293101774Salfred mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); 294187223Skib mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF); 295112564Sjhb semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, 296112564Sjhb EVENTHANDLER_PRI_ANY); 297205323Skib 298205323Skib error = syscall_helper_register(sem_syscalls); 299205323Skib if (error != 0) 300205323Skib return (error); 301205323Skib#ifdef COMPAT_FREEBSD32 302205323Skib error = syscall32_helper_register(sem32_syscalls); 303205323Skib if (error != 0) 304205323Skib return (error); 305205323Skib#endif 306205323Skib return (0); 3072729Sdfr} 3082729Sdfr 30969449Salfredstatic int 31069449Salfredsemunload(void) 31169449Salfred{ 312101774Salfred int i; 31369449Salfred 314187223Skib /* XXXKIB */ 31569449Salfred if (semtot != 0) 31669449Salfred return (EBUSY); 31769449Salfred 318205323Skib#ifdef COMPAT_FREEBSD32 319205323Skib syscall32_helper_unregister(sem32_syscalls); 320205323Skib#endif 321205323Skib syscall_helper_unregister(sem_syscalls); 322112564Sjhb EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); 323140615Srwatson#ifdef MAC 324140615Srwatson for (i = 0; i < seminfo.semmni; i++) 325172930Srwatson mac_sysvsem_destroy(&sema[i]); 326140615Srwatson#endif 32769449Salfred free(sem, M_SEM); 32869449Salfred free(sema, M_SEM); 32969449Salfred free(semu, M_SEM); 330101774Salfred for (i = 0; i < seminfo.semmni; i++) 331101774Salfred mtx_destroy(&sema_mtx[i]); 332190557Sbrueffer free(sema_mtx, M_SEM); 333101774Salfred mtx_destroy(&sem_mtx); 334187223Skib mtx_destroy(&sem_undo_mtx); 33569449Salfred return (0); 33669449Salfred} 33769449Salfred 33869449Salfredstatic int 33969449Salfredsysvsem_modload(struct module *module, int cmd, void *arg) 34069449Salfred{ 34169449Salfred int error = 0; 34269449Salfred 34369449Salfred switch (cmd) { 34469449Salfred case MOD_LOAD: 345205323Skib error = seminit(); 346205323Skib if (error != 0) 347205323Skib semunload(); 34869449Salfred break; 34969449Salfred case MOD_UNLOAD: 35069449Salfred error = semunload(); 35169449Salfred break; 35269449Salfred case MOD_SHUTDOWN: 35369449Salfred break; 35469449Salfred default: 35569449Salfred error = EINVAL; 35669449Salfred break; 35769449Salfred } 35869449Salfred return (error); 35969449Salfred} 36069449Salfred 36171038Sdesstatic moduledata_t sysvsem_mod = { 36271038Sdes "sysvsem", 36369449Salfred &sysvsem_modload, 36469449Salfred NULL 36569449Salfred}; 36669449Salfred 367194832SjhbDECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 36871038SdesMODULE_VERSION(sysvsem, 1); 36969449Salfred 3702729Sdfr/* 3712729Sdfr * Allocate a new sem_undo structure for a process 3722729Sdfr * (returns ptr to structure or NULL if no more room) 3732729Sdfr */ 3742729Sdfr 37512819Sphkstatic struct sem_undo * 376187223Skibsemu_alloc(struct thread *td) 3772729Sdfr{ 378101350Salfred struct sem_undo *suptr; 3792729Sdfr 380101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 381187223Skib if ((suptr = LIST_FIRST(&semu_free_list)) == NULL) 382187223Skib return (NULL); 383187223Skib LIST_REMOVE(suptr, un_next); 384187223Skib LIST_INSERT_HEAD(&semu_list, suptr, un_next); 385187223Skib suptr->un_cnt = 0; 386187223Skib suptr->un_proc = td->td_proc; 387187223Skib return (suptr); 388187223Skib} 3892729Sdfr 390187223Skibstatic int 391187223Skibsemu_try_free(struct sem_undo *suptr) 392187223Skib{ 3932729Sdfr 394187223Skib SEMUNDO_LOCKASSERT(MA_OWNED); 3952729Sdfr 396187223Skib if (suptr->un_cnt != 0) 397187223Skib return (0); 398187223Skib LIST_REMOVE(suptr, un_next); 399187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 400187223Skib return (1); 4012729Sdfr} 4022729Sdfr 4032729Sdfr/* 4042729Sdfr * Adjust a particular entry for a particular proc 4052729Sdfr */ 4062729Sdfr 40712819Sphkstatic int 408187223Skibsemundo_adjust(struct thread *td, struct sem_undo **supptr, int semid, 409187223Skib int semseq, int semnum, int adjval) 4102729Sdfr{ 41183366Sjulian struct proc *p = td->td_proc; 412101350Salfred struct sem_undo *suptr; 413101350Salfred struct undo *sunptr; 4142729Sdfr int i; 4152729Sdfr 416101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 4172729Sdfr /* Look for and remember the sem_undo if the caller doesn't provide 4182729Sdfr it */ 4192729Sdfr 4202729Sdfr suptr = *supptr; 4212729Sdfr if (suptr == NULL) { 422187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 4232729Sdfr if (suptr->un_proc == p) { 4242729Sdfr *supptr = suptr; 4252729Sdfr break; 4262729Sdfr } 4272729Sdfr } 4282729Sdfr if (suptr == NULL) { 4292729Sdfr if (adjval == 0) 4302729Sdfr return(0); 43183366Sjulian suptr = semu_alloc(td); 4322729Sdfr if (suptr == NULL) 433187223Skib return (ENOSPC); 4342729Sdfr *supptr = suptr; 4352729Sdfr } 4362729Sdfr } 4372729Sdfr 4382729Sdfr /* 4392729Sdfr * Look for the requested entry and adjust it (delete if adjval becomes 4402729Sdfr * 0). 4412729Sdfr */ 4422729Sdfr sunptr = &suptr->un_ent[0]; 4432729Sdfr for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 4442729Sdfr if (sunptr->un_id != semid || sunptr->un_num != semnum) 4452729Sdfr continue; 44684789Smr if (adjval != 0) { 44784789Smr adjval += sunptr->un_adjval; 44884789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 44984789Smr return (ERANGE); 45084789Smr } 45184789Smr sunptr->un_adjval = adjval; 4522729Sdfr if (sunptr->un_adjval == 0) { 4532729Sdfr suptr->un_cnt--; 4542729Sdfr if (i < suptr->un_cnt) 4552729Sdfr suptr->un_ent[i] = 4562729Sdfr suptr->un_ent[suptr->un_cnt]; 457187223Skib if (suptr->un_cnt == 0) 458187223Skib semu_try_free(suptr); 4592729Sdfr } 460187223Skib return (0); 4612729Sdfr } 4622729Sdfr 4632729Sdfr /* Didn't find the right entry - create it */ 4642729Sdfr if (adjval == 0) 465187223Skib return (0); 46684789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 46784789Smr return (ERANGE); 46841774Sdillon if (suptr->un_cnt != seminfo.semume) { 4692729Sdfr sunptr = &suptr->un_ent[suptr->un_cnt]; 4702729Sdfr suptr->un_cnt++; 4712729Sdfr sunptr->un_adjval = adjval; 472187223Skib sunptr->un_id = semid; 473187223Skib sunptr->un_num = semnum; 474187223Skib sunptr->un_seq = semseq; 4752729Sdfr } else 476187223Skib return (EINVAL); 477187223Skib return (0); 4782729Sdfr} 4792729Sdfr 48012819Sphkstatic void 481187223Skibsemundo_clear(int semid, int semnum) 4822729Sdfr{ 483187223Skib struct sem_undo *suptr, *suptr1; 484187223Skib struct undo *sunptr; 485187223Skib int i; 4862729Sdfr 487101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 488187223Skib LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) { 489187223Skib sunptr = &suptr->un_ent[0]; 490187223Skib for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 491187223Skib if (sunptr->un_id != semid) 492187223Skib continue; 493187223Skib if (semnum == -1 || sunptr->un_num == semnum) { 494187223Skib suptr->un_cnt--; 495187223Skib if (i < suptr->un_cnt) { 496187223Skib suptr->un_ent[i] = 497187223Skib suptr->un_ent[suptr->un_cnt]; 498187223Skib continue; 4992729Sdfr } 500187223Skib semu_try_free(suptr); 5012729Sdfr } 502187223Skib if (semnum != -1) 503187223Skib break; 5042729Sdfr } 5052729Sdfr } 5062729Sdfr} 5072729Sdfr 508101774Salfredstatic int 509187223Skibsemvalid(int semid, struct semid_kernel *semakptr) 510101774Salfred{ 511101774Salfred 512137613Srwatson return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 513137613Srwatson semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0); 514101774Salfred} 515101774Salfred 51612866Speter/* 517167211Srwatson * Note that the user-mode half of this passes a union, not a pointer. 51812866Speter */ 51912866Speter#ifndef _SYS_SYSPROTO_H_ 52012866Speterstruct __semctl_args { 5212729Sdfr int semid; 5222729Sdfr int semnum; 5232729Sdfr int cmd; 5242729Sdfr union semun *arg; 5252729Sdfr}; 52612866Speter#endif 52712866Speterint 528187223Skib__semctl(struct thread *td, struct __semctl_args *uap) 5292729Sdfr{ 530160187Sjhb struct semid_ds dsbuf; 531160187Sjhb union semun arg, semun; 532160187Sjhb register_t rval; 533159991Sjhb int error; 534159991Sjhb 535159991Sjhb switch (uap->cmd) { 536159991Sjhb case SEM_STAT: 537159991Sjhb case IPC_SET: 538159991Sjhb case IPC_STAT: 539159991Sjhb case GETALL: 540159991Sjhb case SETVAL: 541159991Sjhb case SETALL: 542160187Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 543159991Sjhb if (error) 544159991Sjhb return (error); 545159991Sjhb break; 546160187Sjhb } 547160187Sjhb 548160187Sjhb switch (uap->cmd) { 549160187Sjhb case SEM_STAT: 550160187Sjhb case IPC_STAT: 551160187Sjhb semun.buf = &dsbuf; 552159991Sjhb break; 553160187Sjhb case IPC_SET: 554160187Sjhb error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 555160187Sjhb if (error) 556160187Sjhb return (error); 557160187Sjhb semun.buf = &dsbuf; 558160187Sjhb break; 559160187Sjhb case GETALL: 560160187Sjhb case SETALL: 561160187Sjhb semun.array = arg.array; 562160187Sjhb break; 563160187Sjhb case SETVAL: 564160187Sjhb semun.val = arg.val; 565160187Sjhb break; 566159991Sjhb } 567160187Sjhb 568160187Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 569160187Sjhb &rval); 570160187Sjhb if (error) 571160187Sjhb return (error); 572160187Sjhb 573160187Sjhb switch (uap->cmd) { 574160187Sjhb case SEM_STAT: 575160187Sjhb case IPC_STAT: 576160187Sjhb error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 577160187Sjhb break; 578160187Sjhb } 579160187Sjhb 580160187Sjhb if (error == 0) 581160187Sjhb td->td_retval[0] = rval; 582160187Sjhb return (error); 583159991Sjhb} 584159991Sjhb 585159991Sjhbint 586160187Sjhbkern_semctl(struct thread *td, int semid, int semnum, int cmd, 587160187Sjhb union semun *arg, register_t *rval) 588159991Sjhb{ 589101774Salfred u_short *array; 59091406Sjhb struct ucred *cred = td->td_ucred; 591160187Sjhb int i, error; 592160187Sjhb struct semid_ds *sbuf; 593137613Srwatson struct semid_kernel *semakptr; 594101774Salfred struct mtx *sema_mtxp; 595101774Salfred u_short usval, count; 596160028Sjhb int semidx; 5972729Sdfr 598160293Skib DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 599100523Salfred semid, semnum, cmd, arg)); 600192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 60191703Sjhb return (ENOSYS); 60291703Sjhb 603101774Salfred array = NULL; 604101774Salfred 60583414Smr switch(cmd) { 60683414Smr case SEM_STAT: 607160028Sjhb /* 608160028Sjhb * For this command we assume semid is an array index 609160028Sjhb * rather than an IPC id. 610160028Sjhb */ 61191744Smaxim if (semid < 0 || semid >= seminfo.semmni) 612101774Salfred return (EINVAL); 613137613Srwatson semakptr = &sema[semid]; 614101774Salfred sema_mtxp = &sema_mtx[semid]; 615101774Salfred mtx_lock(sema_mtxp); 616137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 617101774Salfred error = EINVAL; 618101774Salfred goto done2; 619101774Salfred } 620137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 621101774Salfred goto done2; 622140615Srwatson#ifdef MAC 623172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 624162468Srwatson if (error != 0) 625140615Srwatson goto done2; 626140615Srwatson#endif 627160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 628160187Sjhb *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 629101774Salfred mtx_unlock(sema_mtxp); 630160187Sjhb return (0); 63183414Smr } 63283414Smr 633160028Sjhb semidx = IPCID_TO_IX(semid); 634160028Sjhb if (semidx < 0 || semidx >= seminfo.semmni) 635101774Salfred return (EINVAL); 6362729Sdfr 637160028Sjhb semakptr = &sema[semidx]; 638160028Sjhb sema_mtxp = &sema_mtx[semidx]; 639187223Skib if (cmd == IPC_RMID) 640187223Skib mtx_lock(&sem_mtx); 641160187Sjhb mtx_lock(sema_mtxp); 642140615Srwatson#ifdef MAC 643172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 644162468Srwatson if (error != 0) 645160187Sjhb goto done2; 646140615Srwatson#endif 647145230Srwatson 64882607Sdillon error = 0; 649160187Sjhb *rval = 0; 6502729Sdfr 6512729Sdfr switch (cmd) { 6522729Sdfr case IPC_RMID: 653159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 654101774Salfred goto done2; 655137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 65682607Sdillon goto done2; 657137613Srwatson semakptr->u.sem_perm.cuid = cred->cr_uid; 658137613Srwatson semakptr->u.sem_perm.uid = cred->cr_uid; 659187223Skib semakptr->u.sem_perm.mode = 0; 660220398Strasz racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems); 661220388Strasz crfree(semakptr->cred); 662220388Strasz semakptr->cred = NULL; 663187223Skib SEMUNDO_LOCK(); 664187223Skib semundo_clear(semidx, -1); 665187223Skib SEMUNDO_UNLOCK(); 666187223Skib#ifdef MAC 667187223Skib mac_sysvsem_cleanup(semakptr); 668187223Skib#endif 669187223Skib wakeup(semakptr); 670187223Skib for (i = 0; i < seminfo.semmni; i++) { 671187223Skib if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 672187223Skib sema[i].u.sem_base > semakptr->u.sem_base) 673187223Skib mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); 674187223Skib } 675137613Srwatson for (i = semakptr->u.sem_base - sem; i < semtot; i++) 676137613Srwatson sem[i] = sem[i + semakptr->u.sem_nsems]; 6772729Sdfr for (i = 0; i < seminfo.semmni; i++) { 678137613Srwatson if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 679187223Skib sema[i].u.sem_base > semakptr->u.sem_base) { 680137613Srwatson sema[i].u.sem_base -= semakptr->u.sem_nsems; 681187223Skib mtx_unlock(&sema_mtx[i]); 682187223Skib } 6832729Sdfr } 684187223Skib semtot -= semakptr->u.sem_nsems; 6852729Sdfr break; 6862729Sdfr 6872729Sdfr case IPC_SET: 688159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 689101774Salfred goto done2; 690137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 691101774Salfred goto done2; 692160187Sjhb sbuf = arg->buf; 693160187Sjhb semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 694160187Sjhb semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 695137613Srwatson semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 696160187Sjhb ~0777) | (sbuf->sem_perm.mode & 0777); 697137613Srwatson semakptr->u.sem_ctime = time_second; 6982729Sdfr break; 6992729Sdfr 7002729Sdfr case IPC_STAT: 701159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 702101774Salfred goto done2; 703137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 70482607Sdillon goto done2; 705160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 7062729Sdfr break; 7072729Sdfr 7082729Sdfr case GETNCNT: 709159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 710101774Salfred goto done2; 711137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 71282607Sdillon goto done2; 713137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 71482607Sdillon error = EINVAL; 71582607Sdillon goto done2; 71682607Sdillon } 717160187Sjhb *rval = semakptr->u.sem_base[semnum].semncnt; 7182729Sdfr break; 7192729Sdfr 7202729Sdfr case GETPID: 721159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 722101774Salfred goto done2; 723137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 72482607Sdillon goto done2; 725137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 72682607Sdillon error = EINVAL; 72782607Sdillon goto done2; 72882607Sdillon } 729160187Sjhb *rval = semakptr->u.sem_base[semnum].sempid; 7302729Sdfr break; 7312729Sdfr 7322729Sdfr case GETVAL: 733159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 734101774Salfred goto done2; 735137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 73682607Sdillon goto done2; 737137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 73882607Sdillon error = EINVAL; 73982607Sdillon goto done2; 74082607Sdillon } 741160187Sjhb *rval = semakptr->u.sem_base[semnum].semval; 7422729Sdfr break; 7432729Sdfr 7442729Sdfr case GETALL: 745159991Sjhb /* 746160187Sjhb * Unfortunately, callers of this function don't know 747160187Sjhb * in advance how many semaphores are in this set. 748160187Sjhb * While we could just allocate the maximum size array 749160187Sjhb * and pass the actual size back to the caller, that 750160187Sjhb * won't work for SETALL since we can't copyin() more 751160187Sjhb * data than the user specified as we may return a 752160187Sjhb * spurious EFAULT. 753160187Sjhb * 754160187Sjhb * Note that the number of semaphores in a set is 755160187Sjhb * fixed for the life of that set. The only way that 756160187Sjhb * the 'count' could change while are blocked in 757160187Sjhb * malloc() is if this semaphore set were destroyed 758160187Sjhb * and a new one created with the same index. 759160187Sjhb * However, semvalid() will catch that due to the 760160187Sjhb * sequence number unless exactly 0x8000 (or a 761160187Sjhb * multiple thereof) semaphore sets for the same index 762160187Sjhb * are created and destroyed while we are in malloc! 763160187Sjhb * 764159991Sjhb */ 765160187Sjhb count = semakptr->u.sem_nsems; 766160187Sjhb mtx_unlock(sema_mtxp); 767160187Sjhb array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 768101774Salfred mtx_lock(sema_mtxp); 769159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 770101774Salfred goto done2; 771160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 772137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 77382607Sdillon goto done2; 774137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) 775137613Srwatson array[i] = semakptr->u.sem_base[i].semval; 776101774Salfred mtx_unlock(sema_mtxp); 777160187Sjhb error = copyout(array, arg->array, count * sizeof(*array)); 778160187Sjhb mtx_lock(sema_mtxp); 7792729Sdfr break; 7802729Sdfr 7812729Sdfr case GETZCNT: 782159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 783101774Salfred goto done2; 784137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 78582607Sdillon goto done2; 786137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 78782607Sdillon error = EINVAL; 78882607Sdillon goto done2; 78982607Sdillon } 790160187Sjhb *rval = semakptr->u.sem_base[semnum].semzcnt; 7912729Sdfr break; 7922729Sdfr 7932729Sdfr case SETVAL: 794159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 795101774Salfred goto done2; 796137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 79782607Sdillon goto done2; 798137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 79982607Sdillon error = EINVAL; 80082607Sdillon goto done2; 80182607Sdillon } 802159991Sjhb if (arg->val < 0 || arg->val > seminfo.semvmx) { 80384789Smr error = ERANGE; 80484789Smr goto done2; 80584789Smr } 806159991Sjhb semakptr->u.sem_base[semnum].semval = arg->val; 807101774Salfred SEMUNDO_LOCK(); 808160028Sjhb semundo_clear(semidx, semnum); 809101774Salfred SEMUNDO_UNLOCK(); 810137613Srwatson wakeup(semakptr); 8112729Sdfr break; 8122729Sdfr 8132729Sdfr case SETALL: 814159991Sjhb /* 815160187Sjhb * See comment on GETALL for why 'count' shouldn't change 816160187Sjhb * and why we require a userland buffer. 817159991Sjhb */ 818137613Srwatson count = semakptr->u.sem_nsems; 819160187Sjhb mtx_unlock(sema_mtxp); 820111119Simp array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 821159991Sjhb error = copyin(arg->array, array, count * sizeof(*array)); 822171179Skib mtx_lock(sema_mtxp); 823101774Salfred if (error) 824101774Salfred break; 825159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 826101774Salfred goto done2; 827160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 828137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 829101774Salfred goto done2; 830137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) { 831101774Salfred usval = array[i]; 83284789Smr if (usval > seminfo.semvmx) { 83384789Smr error = ERANGE; 83484789Smr break; 83584789Smr } 836137613Srwatson semakptr->u.sem_base[i].semval = usval; 8372729Sdfr } 838101774Salfred SEMUNDO_LOCK(); 839160028Sjhb semundo_clear(semidx, -1); 840101774Salfred SEMUNDO_UNLOCK(); 841137613Srwatson wakeup(semakptr); 8422729Sdfr break; 8432729Sdfr 8442729Sdfr default: 84582607Sdillon error = EINVAL; 84682607Sdillon break; 8472729Sdfr } 8482729Sdfr 84982607Sdillondone2: 850160187Sjhb mtx_unlock(sema_mtxp); 851187223Skib if (cmd == IPC_RMID) 852187223Skib mtx_unlock(&sem_mtx); 853101774Salfred if (array != NULL) 854101774Salfred free(array, M_TEMP); 85582607Sdillon return(error); 8562729Sdfr} 8572729Sdfr 85812866Speter#ifndef _SYS_SYSPROTO_H_ 8592729Sdfrstruct semget_args { 8602729Sdfr key_t key; 8612729Sdfr int nsems; 8622729Sdfr int semflg; 8632729Sdfr}; 86412866Speter#endif 86512866Speterint 866187223Skibsemget(struct thread *td, struct semget_args *uap) 8672729Sdfr{ 86882607Sdillon int semid, error = 0; 8692729Sdfr int key = uap->key; 8702729Sdfr int nsems = uap->nsems; 8712729Sdfr int semflg = uap->semflg; 87291703Sjhb struct ucred *cred = td->td_ucred; 8732729Sdfr 874100523Salfred DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 875192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 87691703Sjhb return (ENOSYS); 87791703Sjhb 878187223Skib mtx_lock(&sem_mtx); 8792729Sdfr if (key != IPC_PRIVATE) { 8802729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 881137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 882137613Srwatson sema[semid].u.sem_perm.key == key) 8832729Sdfr break; 8842729Sdfr } 8852729Sdfr if (semid < seminfo.semmni) { 886100523Salfred DPRINTF(("found public key\n")); 887137613Srwatson if ((error = ipcperm(td, &sema[semid].u.sem_perm, 88882607Sdillon semflg & 0700))) { 88982607Sdillon goto done2; 89082607Sdillon } 891137613Srwatson if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 892100523Salfred DPRINTF(("too small\n")); 89382607Sdillon error = EINVAL; 89482607Sdillon goto done2; 8952729Sdfr } 8962729Sdfr if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 897100523Salfred DPRINTF(("not exclusive\n")); 89882607Sdillon error = EEXIST; 89982607Sdillon goto done2; 9002729Sdfr } 901140615Srwatson#ifdef MAC 902172930Srwatson error = mac_sysvsem_check_semget(cred, &sema[semid]); 903162468Srwatson if (error != 0) 904140615Srwatson goto done2; 905140615Srwatson#endif 9062729Sdfr goto found; 9072729Sdfr } 9082729Sdfr } 9092729Sdfr 910137613Srwatson DPRINTF(("need to allocate the semid_kernel\n")); 9112729Sdfr if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 9122729Sdfr if (nsems <= 0 || nsems > seminfo.semmsl) { 913100523Salfred DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 914100523Salfred seminfo.semmsl)); 91582607Sdillon error = EINVAL; 91682607Sdillon goto done2; 9172729Sdfr } 9182729Sdfr if (nsems > seminfo.semmns - semtot) { 919100523Salfred DPRINTF(( 920100523Salfred "not enough semaphores left (need %d, got %d)\n", 921100523Salfred nsems, seminfo.semmns - semtot)); 92282607Sdillon error = ENOSPC; 92382607Sdillon goto done2; 9242729Sdfr } 9252729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 926137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 9272729Sdfr break; 9282729Sdfr } 9292729Sdfr if (semid == seminfo.semmni) { 930137613Srwatson DPRINTF(("no more semid_kernel's available\n")); 93182607Sdillon error = ENOSPC; 93282607Sdillon goto done2; 9332729Sdfr } 934220398Strasz PROC_LOCK(td->td_proc); 935220398Strasz error = racct_add(td->td_proc, RACCT_NSEM, nsems); 936220398Strasz PROC_UNLOCK(td->td_proc); 937220398Strasz if (error != 0) { 938220398Strasz error = ENOSPC; 939220398Strasz goto done2; 940220398Strasz } 941100523Salfred DPRINTF(("semid %d is available\n", semid)); 942187298Skib mtx_lock(&sema_mtx[semid]); 943187298Skib KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 944187298Skib ("Lost semaphore %d", semid)); 945137613Srwatson sema[semid].u.sem_perm.key = key; 946137613Srwatson sema[semid].u.sem_perm.cuid = cred->cr_uid; 947137613Srwatson sema[semid].u.sem_perm.uid = cred->cr_uid; 948137613Srwatson sema[semid].u.sem_perm.cgid = cred->cr_gid; 949137613Srwatson sema[semid].u.sem_perm.gid = cred->cr_gid; 950137613Srwatson sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 951220388Strasz crhold(cred); 952220388Strasz sema[semid].cred = cred; 953137613Srwatson sema[semid].u.sem_perm.seq = 954137613Srwatson (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 955137613Srwatson sema[semid].u.sem_nsems = nsems; 956137613Srwatson sema[semid].u.sem_otime = 0; 957137613Srwatson sema[semid].u.sem_ctime = time_second; 958137613Srwatson sema[semid].u.sem_base = &sem[semtot]; 9592729Sdfr semtot += nsems; 960137613Srwatson bzero(sema[semid].u.sem_base, 961137613Srwatson sizeof(sema[semid].u.sem_base[0])*nsems); 962140615Srwatson#ifdef MAC 963172930Srwatson mac_sysvsem_create(cred, &sema[semid]); 964140615Srwatson#endif 965187298Skib mtx_unlock(&sema_mtx[semid]); 966160293Skib DPRINTF(("sembase = %p, next = %p\n", 967137613Srwatson sema[semid].u.sem_base, &sem[semtot])); 9682729Sdfr } else { 969100523Salfred DPRINTF(("didn't find it and wasn't asked to create it\n")); 97082607Sdillon error = ENOENT; 97182607Sdillon goto done2; 9722729Sdfr } 9732729Sdfr 9742729Sdfrfound: 975137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 97682607Sdillondone2: 977187223Skib mtx_unlock(&sem_mtx); 97882607Sdillon return (error); 9792729Sdfr} 9802729Sdfr 98112866Speter#ifndef _SYS_SYSPROTO_H_ 9822729Sdfrstruct semop_args { 9832729Sdfr int semid; 9842729Sdfr struct sembuf *sops; 985109829Salfred size_t nsops; 9862729Sdfr}; 98712866Speter#endif 98812866Speterint 989187223Skibsemop(struct thread *td, struct semop_args *uap) 9902729Sdfr{ 991123667Stjr#define SMALL_SOPS 8 992123667Stjr struct sembuf small_sops[SMALL_SOPS]; 9932729Sdfr int semid = uap->semid; 994109829Salfred size_t nsops = uap->nsops; 995105429Salfred struct sembuf *sops; 996137613Srwatson struct semid_kernel *semakptr; 997101350Salfred struct sembuf *sopptr = 0; 998101350Salfred struct sem *semptr = 0; 99984789Smr struct sem_undo *suptr; 1000101774Salfred struct mtx *sema_mtxp; 1001110040Stjr size_t i, j, k; 1002109829Salfred int error; 10033308Sphk int do_wakeup, do_undos; 1004187223Skib unsigned short seq; 10052729Sdfr 1006160293Skib#ifdef SEM_DEBUG 1007160293Skib sops = NULL; 1008160293Skib#endif 1009160293Skib DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 10102729Sdfr 1011192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 101291703Sjhb return (ENOSYS); 101391703Sjhb 10142729Sdfr semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 10152729Sdfr 1016101774Salfred if (semid < 0 || semid >= seminfo.semmni) 1017137644Srwatson return (EINVAL); 1018101774Salfred 1019101774Salfred /* Allocate memory for sem_ops */ 1020123667Stjr if (nsops <= SMALL_SOPS) 1021123667Stjr sops = small_sops; 1022220398Strasz else if (nsops > seminfo.semopm) { 1023101774Salfred DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1024101774Salfred nsops)); 1025101774Salfred return (E2BIG); 1026220398Strasz } else { 1027220398Strasz PROC_LOCK(td->td_proc); 1028220398Strasz if (nsops > racct_get_available(td->td_proc, RACCT_NSEMOP)) { 1029220398Strasz PROC_UNLOCK(td->td_proc); 1030220398Strasz return (E2BIG); 1031220398Strasz } 1032220398Strasz PROC_UNLOCK(td->td_proc); 1033220398Strasz 1034220398Strasz sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 103582607Sdillon } 1036101774Salfred if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1037160293Skib DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1038101774Salfred uap->sops, sops, nsops * sizeof(sops[0]))); 1039123667Stjr if (sops != small_sops) 1040123667Stjr free(sops, M_SEM); 1041101774Salfred return (error); 1042101774Salfred } 10432729Sdfr 1044137613Srwatson semakptr = &sema[semid]; 1045101774Salfred sema_mtxp = &sema_mtx[semid]; 1046101774Salfred mtx_lock(sema_mtxp); 1047137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 104882607Sdillon error = EINVAL; 104982607Sdillon goto done2; 105082607Sdillon } 1051187223Skib seq = semakptr->u.sem_perm.seq; 1052187223Skib if (seq != IPCID_TO_SEQ(uap->semid)) { 105382607Sdillon error = EINVAL; 105482607Sdillon goto done2; 105582607Sdillon } 105684789Smr /* 105784789Smr * Initial pass thru sops to see what permissions are needed. 105884789Smr * Also perform any checks that don't need repeating on each 105984789Smr * attempt to satisfy the request vector. 106084789Smr */ 106184789Smr j = 0; /* permission needed */ 106284789Smr do_undos = 0; 106384789Smr for (i = 0; i < nsops; i++) { 106484789Smr sopptr = &sops[i]; 1065137613Srwatson if (sopptr->sem_num >= semakptr->u.sem_nsems) { 106684789Smr error = EFBIG; 106784789Smr goto done2; 106884789Smr } 106984789Smr if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 107084789Smr do_undos = 1; 107184789Smr j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 107284789Smr } 107384789Smr 1074137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1075100523Salfred DPRINTF(("error = %d from ipaccess\n", error)); 107682607Sdillon goto done2; 10772729Sdfr } 1078140615Srwatson#ifdef MAC 1079172930Srwatson error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1080162468Srwatson if (error != 0) 1081140615Srwatson goto done2; 1082140615Srwatson#endif 10832729Sdfr 10848876Srgrimes /* 10852729Sdfr * Loop trying to satisfy the vector of requests. 10862729Sdfr * If we reach a point where we must wait, any requests already 10872729Sdfr * performed are rolled back and we go to sleep until some other 10882729Sdfr * process wakes us up. At this point, we start all over again. 10892729Sdfr * 10902729Sdfr * This ensures that from the perspective of other tasks, a set 10912729Sdfr * of requests is atomic (never partially satisfied). 10922729Sdfr */ 10932729Sdfr for (;;) { 10942729Sdfr do_wakeup = 0; 109584789Smr error = 0; /* error return if necessary */ 10962729Sdfr 10972729Sdfr for (i = 0; i < nsops; i++) { 10982729Sdfr sopptr = &sops[i]; 1099137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 11002729Sdfr 1101100523Salfred DPRINTF(( 1102160293Skib "semop: semakptr=%p, sem_base=%p, " 1103160293Skib "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1104137613Srwatson semakptr, semakptr->u.sem_base, semptr, 11052729Sdfr sopptr->sem_num, semptr->semval, sopptr->sem_op, 1106100523Salfred (sopptr->sem_flg & IPC_NOWAIT) ? 1107100523Salfred "nowait" : "wait")); 11082729Sdfr 11092729Sdfr if (sopptr->sem_op < 0) { 11102729Sdfr if (semptr->semval + sopptr->sem_op < 0) { 1111100523Salfred DPRINTF(("semop: can't do it now\n")); 11122729Sdfr break; 11132729Sdfr } else { 11142729Sdfr semptr->semval += sopptr->sem_op; 11152729Sdfr if (semptr->semval == 0 && 11162729Sdfr semptr->semzcnt > 0) 11172729Sdfr do_wakeup = 1; 11182729Sdfr } 11192729Sdfr } else if (sopptr->sem_op == 0) { 112084789Smr if (semptr->semval != 0) { 1121100523Salfred DPRINTF(("semop: not zero now\n")); 11222729Sdfr break; 11232729Sdfr } 112484789Smr } else if (semptr->semval + sopptr->sem_op > 112584789Smr seminfo.semvmx) { 112684789Smr error = ERANGE; 112784789Smr break; 11282729Sdfr } else { 11292729Sdfr if (semptr->semncnt > 0) 11302729Sdfr do_wakeup = 1; 11312729Sdfr semptr->semval += sopptr->sem_op; 11322729Sdfr } 11332729Sdfr } 11342729Sdfr 11352729Sdfr /* 11362729Sdfr * Did we get through the entire vector? 11372729Sdfr */ 11382729Sdfr if (i >= nsops) 11392729Sdfr goto done; 11402729Sdfr 11412729Sdfr /* 11422729Sdfr * No ... rollback anything that we've already done 11432729Sdfr */ 1144100523Salfred DPRINTF(("semop: rollback 0 through %d\n", i-1)); 11452729Sdfr for (j = 0; j < i; j++) 1146137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 11472729Sdfr sops[j].sem_op; 11482729Sdfr 114984789Smr /* If we detected an error, return it */ 115084789Smr if (error != 0) 115184789Smr goto done2; 115284789Smr 11532729Sdfr /* 11542729Sdfr * If the request that we couldn't satisfy has the 11552729Sdfr * NOWAIT flag set then return with EAGAIN. 11562729Sdfr */ 115782607Sdillon if (sopptr->sem_flg & IPC_NOWAIT) { 115882607Sdillon error = EAGAIN; 115982607Sdillon goto done2; 116082607Sdillon } 11612729Sdfr 11622729Sdfr if (sopptr->sem_op == 0) 11632729Sdfr semptr->semzcnt++; 11642729Sdfr else 11652729Sdfr semptr->semncnt++; 11662729Sdfr 1167100523Salfred DPRINTF(("semop: good night!\n")); 1168137613Srwatson error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1169101774Salfred "semwait", 0); 1170100523Salfred DPRINTF(("semop: good morning (error=%d)!\n", error)); 1171127108Scperciva /* return code is checked below, after sem[nz]cnt-- */ 11722729Sdfr 11732729Sdfr /* 11742729Sdfr * Make sure that the semaphore still exists 11752729Sdfr */ 1176187223Skib seq = semakptr->u.sem_perm.seq; 1177137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1178187223Skib seq != IPCID_TO_SEQ(uap->semid)) { 117982607Sdillon error = EIDRM; 118082607Sdillon goto done2; 118182607Sdillon } 11822729Sdfr 11832729Sdfr /* 1184179879Sgonzo * Renew the semaphore's pointer after wakeup since 1185179879Sgonzo * during msleep sem_base may have been modified and semptr 1186179879Sgonzo * is not valid any more 1187179879Sgonzo */ 1188179879Sgonzo semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1189179879Sgonzo 1190179879Sgonzo /* 11912729Sdfr * The semaphore is still alive. Readjust the count of 11922729Sdfr * waiting processes. 11932729Sdfr */ 11942729Sdfr if (sopptr->sem_op == 0) 11952729Sdfr semptr->semzcnt--; 11962729Sdfr else 11972729Sdfr semptr->semncnt--; 1198127108Scperciva 1199127108Scperciva /* 1200127108Scperciva * Is it really morning, or was our sleep interrupted? 1201127108Scperciva * (Delayed check of msleep() return code because we 1202127108Scperciva * need to decrement sem[nz]cnt either way.) 1203127108Scperciva */ 1204127108Scperciva if (error != 0) { 1205127108Scperciva error = EINTR; 1206127108Scperciva goto done2; 1207127108Scperciva } 1208127108Scperciva DPRINTF(("semop: good morning!\n")); 12092729Sdfr } 12102729Sdfr 12112729Sdfrdone: 12122729Sdfr /* 12132729Sdfr * Process any SEM_UNDO requests. 12142729Sdfr */ 12152729Sdfr if (do_undos) { 1216101774Salfred SEMUNDO_LOCK(); 121784789Smr suptr = NULL; 12182729Sdfr for (i = 0; i < nsops; i++) { 12192729Sdfr /* 12202729Sdfr * We only need to deal with SEM_UNDO's for non-zero 12212729Sdfr * op's. 12222729Sdfr */ 12232729Sdfr int adjval; 12242729Sdfr 12252729Sdfr if ((sops[i].sem_flg & SEM_UNDO) == 0) 12262729Sdfr continue; 12272729Sdfr adjval = sops[i].sem_op; 12282729Sdfr if (adjval == 0) 12292729Sdfr continue; 1230187223Skib error = semundo_adjust(td, &suptr, semid, seq, 12312729Sdfr sops[i].sem_num, -adjval); 123282607Sdillon if (error == 0) 12332729Sdfr continue; 12342729Sdfr 12352729Sdfr /* 12362729Sdfr * Oh-Oh! We ran out of either sem_undo's or undo's. 12372729Sdfr * Rollback the adjustments to this point and then 12382729Sdfr * rollback the semaphore ups and down so we can return 12392729Sdfr * with an error with all structures restored. We 12402729Sdfr * rollback the undo's in the exact reverse order that 12412729Sdfr * we applied them. This guarantees that we won't run 12422729Sdfr * out of space as we roll things back out. 12432729Sdfr */ 1244110040Stjr for (j = 0; j < i; j++) { 1245110040Stjr k = i - j - 1; 1246110040Stjr if ((sops[k].sem_flg & SEM_UNDO) == 0) 12472729Sdfr continue; 1248110040Stjr adjval = sops[k].sem_op; 12492729Sdfr if (adjval == 0) 12502729Sdfr continue; 1251187223Skib if (semundo_adjust(td, &suptr, semid, seq, 1252110040Stjr sops[k].sem_num, adjval) != 0) 12532729Sdfr panic("semop - can't undo undos"); 12542729Sdfr } 12552729Sdfr 12562729Sdfr for (j = 0; j < nsops; j++) 1257137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 12582729Sdfr sops[j].sem_op; 12592729Sdfr 1260100523Salfred DPRINTF(("error = %d from semundo_adjust\n", error)); 1261101774Salfred SEMUNDO_UNLOCK(); 126282607Sdillon goto done2; 12632729Sdfr } /* loop through the sops */ 1264101774Salfred SEMUNDO_UNLOCK(); 12652729Sdfr } /* if (do_undos) */ 12662729Sdfr 126784789Smr /* We're definitely done - set the sempid's and time */ 12682729Sdfr for (i = 0; i < nsops; i++) { 12692729Sdfr sopptr = &sops[i]; 1270137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 127183366Sjulian semptr->sempid = td->td_proc->p_pid; 12722729Sdfr } 1273137613Srwatson semakptr->u.sem_otime = time_second; 12742729Sdfr 127584789Smr /* 127684789Smr * Do a wakeup if any semaphore was up'd whilst something was 127784789Smr * sleeping on it. 127884789Smr */ 12792729Sdfr if (do_wakeup) { 1280100523Salfred DPRINTF(("semop: doing wakeup\n")); 1281137613Srwatson wakeup(semakptr); 1282100523Salfred DPRINTF(("semop: back from wakeup\n")); 12832729Sdfr } 1284100523Salfred DPRINTF(("semop: done\n")); 128583366Sjulian td->td_retval[0] = 0; 128682607Sdillondone2: 1287101774Salfred mtx_unlock(sema_mtxp); 1288123667Stjr if (sops != small_sops) 1289123667Stjr free(sops, M_SEM); 129082607Sdillon return (error); 12912729Sdfr} 12922729Sdfr 12932729Sdfr/* 12942729Sdfr * Go through the undo structures for this process and apply the adjustments to 12952729Sdfr * semaphores. 12962729Sdfr */ 129769449Salfredstatic void 1298187223Skibsemexit_myhook(void *arg, struct proc *p) 12992729Sdfr{ 1300101350Salfred struct sem_undo *suptr; 1301187223Skib struct semid_kernel *semakptr; 1302187223Skib struct mtx *sema_mtxp; 1303187223Skib int semid, semnum, adjval, ix; 1304187223Skib unsigned short seq; 13052729Sdfr 13062729Sdfr /* 13072729Sdfr * Go through the chain of undo vectors looking for one 13082729Sdfr * associated with this process. 13092729Sdfr */ 1310101774Salfred SEMUNDO_LOCK(); 1311187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 1312187223Skib if (suptr->un_proc == p) 13132729Sdfr break; 13142729Sdfr } 1315187223Skib if (suptr == NULL) { 1316187223Skib SEMUNDO_UNLOCK(); 131759828Speter return; 1318187223Skib } 1319187223Skib LIST_REMOVE(suptr, un_next); 13202729Sdfr 1321160293Skib DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1322100523Salfred suptr->un_cnt)); 13232729Sdfr 13242729Sdfr /* 13252729Sdfr * If there are any active undo elements then process them. 13262729Sdfr */ 13272729Sdfr if (suptr->un_cnt > 0) { 1328187223Skib SEMUNDO_UNLOCK(); 13292729Sdfr for (ix = 0; ix < suptr->un_cnt; ix++) { 1330187223Skib semid = suptr->un_ent[ix].un_id; 1331187223Skib semnum = suptr->un_ent[ix].un_num; 1332187223Skib adjval = suptr->un_ent[ix].un_adjval; 1333187223Skib seq = suptr->un_ent[ix].un_seq; 1334137613Srwatson semakptr = &sema[semid]; 1335101774Salfred sema_mtxp = &sema_mtx[semid]; 1336187223Skib 1337101774Salfred mtx_lock(sema_mtxp); 1338187223Skib if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1339187223Skib (semakptr->u.sem_perm.seq != seq)) { 1340187223Skib mtx_unlock(sema_mtxp); 1341187223Skib continue; 1342187223Skib } 1343137613Srwatson if (semnum >= semakptr->u.sem_nsems) 13442729Sdfr panic("semexit - semnum out of range"); 13452729Sdfr 1346100523Salfred DPRINTF(( 1347160293Skib "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 13482729Sdfr suptr->un_proc, suptr->un_ent[ix].un_id, 13492729Sdfr suptr->un_ent[ix].un_num, 13502729Sdfr suptr->un_ent[ix].un_adjval, 1351137613Srwatson semakptr->u.sem_base[semnum].semval)); 13522729Sdfr 1353187223Skib if (adjval < 0 && semakptr->u.sem_base[semnum].semval < 1354187223Skib -adjval) 1355187223Skib semakptr->u.sem_base[semnum].semval = 0; 1356187223Skib else 1357137613Srwatson semakptr->u.sem_base[semnum].semval += adjval; 13582729Sdfr 1359137613Srwatson wakeup(semakptr); 1360100523Salfred DPRINTF(("semexit: back from wakeup\n")); 1361101774Salfred mtx_unlock(sema_mtxp); 13622729Sdfr } 1363187223Skib SEMUNDO_LOCK(); 13642729Sdfr } 13652729Sdfr 13662729Sdfr /* 13672729Sdfr * Deallocate the undo vector. 13682729Sdfr */ 1369100523Salfred DPRINTF(("removing vector\n")); 13702729Sdfr suptr->un_proc = NULL; 1371187223Skib suptr->un_cnt = 0; 1372187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1373167904Semaste SEMUNDO_UNLOCK(); 13742729Sdfr} 137577461Sdd 137677461Sddstatic int 137777461Sddsysctl_sema(SYSCTL_HANDLER_ARGS) 137877461Sdd{ 137977461Sdd 138077461Sdd return (SYSCTL_OUT(req, sema, 1381137613Srwatson sizeof(struct semid_kernel) * seminfo.semmni)); 138277461Sdd} 1383194894Sjhb 1384194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1385194894Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1386194894Sjhb 1387194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1388194894Sjhbstatic sy_call_t *semcalls[] = { 1389194910Sjhb (sy_call_t *)freebsd7___semctl, (sy_call_t *)semget, 1390194894Sjhb (sy_call_t *)semop 1391194894Sjhb}; 1392194894Sjhb 1393194894Sjhb/* 1394194894Sjhb * Entry point for all SEM calls. 1395194894Sjhb */ 1396194894Sjhbint 1397194894Sjhbsemsys(td, uap) 1398194894Sjhb struct thread *td; 1399194894Sjhb /* XXX actually varargs. */ 1400194894Sjhb struct semsys_args /* { 1401194894Sjhb int which; 1402194894Sjhb int a2; 1403194894Sjhb int a3; 1404194894Sjhb int a4; 1405194894Sjhb int a5; 1406194894Sjhb } */ *uap; 1407194894Sjhb{ 1408194894Sjhb int error; 1409194894Sjhb 1410194894Sjhb if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 1411194894Sjhb return (ENOSYS); 1412194894Sjhb if (uap->which < 0 || 1413194894Sjhb uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) 1414194894Sjhb return (EINVAL); 1415194894Sjhb error = (*semcalls[uap->which])(td, &uap->a2); 1416194894Sjhb return (error); 1417194894Sjhb} 1418194910Sjhb 1419205323Skib#ifndef CP 1420194910Sjhb#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1421205323Skib#endif 1422194910Sjhb 1423194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1424194910Sjhbstruct freebsd7___semctl_args { 1425194910Sjhb int semid; 1426194910Sjhb int semnum; 1427194910Sjhb int cmd; 1428194910Sjhb union semun_old *arg; 1429194910Sjhb}; 1430194910Sjhb#endif 1431194910Sjhbint 1432194910Sjhbfreebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1433194910Sjhb{ 1434194910Sjhb struct semid_ds_old dsold; 1435194910Sjhb struct semid_ds dsbuf; 1436194910Sjhb union semun_old arg; 1437194910Sjhb union semun semun; 1438194910Sjhb register_t rval; 1439194910Sjhb int error; 1440194910Sjhb 1441194910Sjhb switch (uap->cmd) { 1442194910Sjhb case SEM_STAT: 1443194910Sjhb case IPC_SET: 1444194910Sjhb case IPC_STAT: 1445194910Sjhb case GETALL: 1446194910Sjhb case SETVAL: 1447194910Sjhb case SETALL: 1448194910Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 1449194910Sjhb if (error) 1450194910Sjhb return (error); 1451194910Sjhb break; 1452194910Sjhb } 1453194910Sjhb 1454194910Sjhb switch (uap->cmd) { 1455194910Sjhb case SEM_STAT: 1456194910Sjhb case IPC_STAT: 1457194910Sjhb semun.buf = &dsbuf; 1458194910Sjhb break; 1459194910Sjhb case IPC_SET: 1460194910Sjhb error = copyin(arg.buf, &dsold, sizeof(dsold)); 1461194910Sjhb if (error) 1462194910Sjhb return (error); 1463194910Sjhb ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1464194910Sjhb CP(dsold, dsbuf, sem_base); 1465194910Sjhb CP(dsold, dsbuf, sem_nsems); 1466194910Sjhb CP(dsold, dsbuf, sem_otime); 1467194910Sjhb CP(dsold, dsbuf, sem_ctime); 1468194910Sjhb semun.buf = &dsbuf; 1469194910Sjhb break; 1470194910Sjhb case GETALL: 1471194910Sjhb case SETALL: 1472194910Sjhb semun.array = arg.array; 1473194910Sjhb break; 1474194910Sjhb case SETVAL: 1475194910Sjhb semun.val = arg.val; 1476194910Sjhb break; 1477194910Sjhb } 1478194910Sjhb 1479194910Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1480194910Sjhb &rval); 1481194910Sjhb if (error) 1482194910Sjhb return (error); 1483194910Sjhb 1484194910Sjhb switch (uap->cmd) { 1485194910Sjhb case SEM_STAT: 1486194910Sjhb case IPC_STAT: 1487194910Sjhb bzero(&dsold, sizeof(dsold)); 1488194910Sjhb ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1489194910Sjhb CP(dsbuf, dsold, sem_base); 1490194910Sjhb CP(dsbuf, dsold, sem_nsems); 1491194910Sjhb CP(dsbuf, dsold, sem_otime); 1492194910Sjhb CP(dsbuf, dsold, sem_ctime); 1493194910Sjhb error = copyout(&dsold, arg.buf, sizeof(dsold)); 1494194910Sjhb break; 1495194910Sjhb } 1496194910Sjhb 1497194910Sjhb if (error == 0) 1498194910Sjhb td->td_retval[0] = rval; 1499194910Sjhb return (error); 1500194910Sjhb} 1501194910Sjhb 1502205323Skib#endif /* COMPAT_FREEBSD{4,5,6,7} */ 1503194910Sjhb 1504205323Skib#ifdef COMPAT_FREEBSD32 1505205323Skib 1506205323Skibint 1507205323Skibfreebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1508205323Skib{ 1509205323Skib 1510205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1511205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1512205323Skib switch (uap->which) { 1513205323Skib case 0: 1514205323Skib return (freebsd7_freebsd32_semctl(td, 1515205323Skib (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1516205323Skib default: 1517205323Skib return (semsys(td, (struct semsys_args *)uap)); 1518205323Skib } 1519205323Skib#else 1520205323Skib return (nosys(td, NULL)); 1521205323Skib#endif 1522205323Skib} 1523205323Skib 1524205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1525205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1526205323Skibint 1527205323Skibfreebsd7_freebsd32_semctl(struct thread *td, 1528205323Skib struct freebsd7_freebsd32_semctl_args *uap) 1529205323Skib{ 1530205323Skib struct semid_ds32_old dsbuf32; 1531205323Skib struct semid_ds dsbuf; 1532205323Skib union semun semun; 1533205323Skib union semun32 arg; 1534205323Skib register_t rval; 1535205323Skib int error; 1536205323Skib 1537205323Skib switch (uap->cmd) { 1538205323Skib case SEM_STAT: 1539205323Skib case IPC_SET: 1540205323Skib case IPC_STAT: 1541205323Skib case GETALL: 1542205323Skib case SETVAL: 1543205323Skib case SETALL: 1544205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1545205323Skib if (error) 1546205323Skib return (error); 1547205323Skib break; 1548205323Skib } 1549205323Skib 1550205323Skib switch (uap->cmd) { 1551205323Skib case SEM_STAT: 1552205323Skib case IPC_STAT: 1553205323Skib semun.buf = &dsbuf; 1554205323Skib break; 1555205323Skib case IPC_SET: 1556205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1557205323Skib if (error) 1558205323Skib return (error); 1559205323Skib freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1560205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1561205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1562205323Skib CP(dsbuf32, dsbuf, sem_otime); 1563205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1564205323Skib semun.buf = &dsbuf; 1565205323Skib break; 1566205323Skib case GETALL: 1567205323Skib case SETALL: 1568205323Skib semun.array = PTRIN(arg.array); 1569205323Skib break; 1570205323Skib case SETVAL: 1571205323Skib semun.val = arg.val; 1572205323Skib break; 1573205323Skib } 1574205323Skib 1575205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1576205323Skib &rval); 1577205323Skib if (error) 1578205323Skib return (error); 1579205323Skib 1580205323Skib switch (uap->cmd) { 1581205323Skib case SEM_STAT: 1582205323Skib case IPC_STAT: 1583205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1584205323Skib freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1585205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1586205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1587205323Skib CP(dsbuf, dsbuf32, sem_otime); 1588205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1589205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1590205323Skib break; 1591205323Skib } 1592205323Skib 1593205323Skib if (error == 0) 1594205323Skib td->td_retval[0] = rval; 1595205323Skib return (error); 1596205323Skib} 1597205323Skib#endif 1598205323Skib 1599205323Skibint 1600205323Skibfreebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1601205323Skib{ 1602205323Skib struct semid_ds32 dsbuf32; 1603205323Skib struct semid_ds dsbuf; 1604205323Skib union semun semun; 1605205323Skib union semun32 arg; 1606205323Skib register_t rval; 1607205323Skib int error; 1608205323Skib 1609205323Skib switch (uap->cmd) { 1610205323Skib case SEM_STAT: 1611205323Skib case IPC_SET: 1612205323Skib case IPC_STAT: 1613205323Skib case GETALL: 1614205323Skib case SETVAL: 1615205323Skib case SETALL: 1616205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1617205323Skib if (error) 1618205323Skib return (error); 1619205323Skib break; 1620205323Skib } 1621205323Skib 1622205323Skib switch (uap->cmd) { 1623205323Skib case SEM_STAT: 1624205323Skib case IPC_STAT: 1625205323Skib semun.buf = &dsbuf; 1626205323Skib break; 1627205323Skib case IPC_SET: 1628205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1629205323Skib if (error) 1630205323Skib return (error); 1631205323Skib freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1632205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1633205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1634205323Skib CP(dsbuf32, dsbuf, sem_otime); 1635205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1636205323Skib semun.buf = &dsbuf; 1637205323Skib break; 1638205323Skib case GETALL: 1639205323Skib case SETALL: 1640205323Skib semun.array = PTRIN(arg.array); 1641205323Skib break; 1642205323Skib case SETVAL: 1643205323Skib semun.val = arg.val; 1644205323Skib break; 1645205323Skib } 1646205323Skib 1647205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1648205323Skib &rval); 1649205323Skib if (error) 1650205323Skib return (error); 1651205323Skib 1652205323Skib switch (uap->cmd) { 1653205323Skib case SEM_STAT: 1654205323Skib case IPC_STAT: 1655205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1656205323Skib freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1657205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1658205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1659205323Skib CP(dsbuf, dsbuf32, sem_otime); 1660205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1661205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1662205323Skib break; 1663205323Skib } 1664205323Skib 1665205323Skib if (error == 0) 1666205323Skib td->td_retval[0] = rval; 1667205323Skib return (error); 1668205323Skib} 1669205323Skib 1670205323Skib#endif /* COMPAT_FREEBSD32 */ 1671