182657471SMarkus Pfeiffer /* 282657471SMarkus Pfeiffer * Copyright (c) 2013 Larisa Grigore <larisagrigore@gmail.com>. 382657471SMarkus Pfeiffer * 482657471SMarkus Pfeiffer * Redistribution and use in source and binary forms, with or without 582657471SMarkus Pfeiffer * modification, are permitted provided that the following conditions 682657471SMarkus Pfeiffer * are met: 782657471SMarkus Pfeiffer * 1. Redistributions of source code must retain the above copyright 882657471SMarkus Pfeiffer * notice, this list of conditions and the following disclaimer. 982657471SMarkus Pfeiffer * 2. Redistributions in binary form must reproduce the above copyright 1082657471SMarkus Pfeiffer * notice, this list of conditions and the following disclaimer in the 1182657471SMarkus Pfeiffer * documentation and/or other materials provided with the distribution. 1282657471SMarkus Pfeiffer * 3. All advertising materials mentioning features or use of this software 1382657471SMarkus Pfeiffer * must display the following acknowledgement: 1482657471SMarkus Pfeiffer * This product includes software developed by Adam Glass and Charles 1582657471SMarkus Pfeiffer * Hannum. 1682657471SMarkus Pfeiffer * 4. The names of the authors may not be used to endorse or promote products 1782657471SMarkus Pfeiffer * derived from this software without specific prior written permission. 1882657471SMarkus Pfeiffer * 1982657471SMarkus Pfeiffer * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 2082657471SMarkus Pfeiffer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2182657471SMarkus Pfeiffer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2282657471SMarkus Pfeiffer * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2382657471SMarkus Pfeiffer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2482657471SMarkus Pfeiffer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2582657471SMarkus Pfeiffer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2682657471SMarkus Pfeiffer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2782657471SMarkus Pfeiffer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2882657471SMarkus Pfeiffer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2982657471SMarkus Pfeiffer */ 3082657471SMarkus Pfeiffer 3182657471SMarkus Pfeiffer #include "namespace.h" 3282657471SMarkus Pfeiffer #include <sys/param.h> 3382657471SMarkus Pfeiffer #include <sys/queue.h> 3482657471SMarkus Pfeiffer #include <sys/mman.h> 3582657471SMarkus Pfeiffer #include <sys/shm.h> 36*7d692414Szrj #include <stdint.h> 3782657471SMarkus Pfeiffer #include <stdio.h> 3882657471SMarkus Pfeiffer #include <stdlib.h> 3982657471SMarkus Pfeiffer #include <errno.h> 4082657471SMarkus Pfeiffer #include <fcntl.h> 4182657471SMarkus Pfeiffer #include <err.h> 4282657471SMarkus Pfeiffer #include <pthread.h> 4382657471SMarkus Pfeiffer #include <unistd.h> 4482657471SMarkus Pfeiffer #include "un-namespace.h" 4582657471SMarkus Pfeiffer 4682657471SMarkus Pfeiffer #include "sysvipc_lock.h" 4782657471SMarkus Pfeiffer #include "sysvipc_ipc.h" 4882657471SMarkus Pfeiffer #include "sysvipc_sockets.h" 4982657471SMarkus Pfeiffer #include "sysvipc_shm.h" 5082657471SMarkus Pfeiffer #include "sysvipc_hash.h" 5182657471SMarkus Pfeiffer 5282657471SMarkus Pfeiffer #define SYSV_MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) 5382657471SMarkus Pfeiffer #define SYSV_MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) 5482657471SMarkus Pfeiffer #define SYSV_MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x) 5582657471SMarkus Pfeiffer 5682657471SMarkus Pfeiffer struct hashtable *shmres = NULL; 5782657471SMarkus Pfeiffer struct hashtable *shmaddrs = NULL; 5882657471SMarkus Pfeiffer pthread_mutex_t lock_resources = PTHREAD_MUTEX_INITIALIZER; 5982657471SMarkus Pfeiffer 6082657471SMarkus Pfeiffer /* File descriptor used to communicate with the daemon. */ 6182657471SMarkus Pfeiffer extern int daemon_fd; 6282657471SMarkus Pfeiffer /* Structure used to save semaphore operation with SEMUNDO flag. */ 6382657471SMarkus Pfeiffer extern struct sem_undo *undos; 6482657471SMarkus Pfeiffer 6582657471SMarkus Pfeiffer static int 66ff86f401SSascha Wildner shminit(void) 67ff86f401SSascha Wildner { 6882657471SMarkus Pfeiffer if (shmres) { 6982657471SMarkus Pfeiffer errno = EPERM; 7082657471SMarkus Pfeiffer return (-1); 7182657471SMarkus Pfeiffer } 7282657471SMarkus Pfeiffer 7382657471SMarkus Pfeiffer shmres = _hash_init(MAXSIZE); 7482657471SMarkus Pfeiffer if (!shmres) 7582657471SMarkus Pfeiffer goto out_resources; 7682657471SMarkus Pfeiffer 7782657471SMarkus Pfeiffer shmaddrs = _hash_init(MAXSIZE); 7882657471SMarkus Pfeiffer if (!shmaddrs) 7982657471SMarkus Pfeiffer goto out_addrs; 8082657471SMarkus Pfeiffer 8182657471SMarkus Pfeiffer return 0; 8282657471SMarkus Pfeiffer 8382657471SMarkus Pfeiffer out_addrs: 8482657471SMarkus Pfeiffer _hash_destroy(shmres); 8582657471SMarkus Pfeiffer out_resources: 8682657471SMarkus Pfeiffer return -1; 8782657471SMarkus Pfeiffer } 8882657471SMarkus Pfeiffer 8982657471SMarkus Pfeiffer /*static int 90ff86f401SSascha Wildner shmexit(void) 91ff86f401SSascha Wildner { 9282657471SMarkus Pfeiffer if (!shmres) 9382657471SMarkus Pfeiffer return -EPERM; 9482657471SMarkus Pfeiffer 9582657471SMarkus Pfeiffer _hash_destroy(shmres); 9682657471SMarkus Pfeiffer _hash_destroy(shmaddrs); 9782657471SMarkus Pfeiffer SYSV_MUTEX_DESTROY(lock_resources); 9882657471SMarkus Pfeiffer 9982657471SMarkus Pfeiffer return 0; 10082657471SMarkus Pfeiffer }*/ 10182657471SMarkus Pfeiffer 10282657471SMarkus Pfeiffer /* Init sysv ipc resources and those used for shared memory. */ 10382657471SMarkus Pfeiffer static int 104ff86f401SSascha Wildner shmcheck(void) 105ff86f401SSascha Wildner { 10682657471SMarkus Pfeiffer int ret; 10782657471SMarkus Pfeiffer 10882657471SMarkus Pfeiffer /* Init sysv resources. */ 10982657471SMarkus Pfeiffer if ((ret = sysvinit()) != 0) 11082657471SMarkus Pfeiffer return (ret); 11182657471SMarkus Pfeiffer /* Init resorces used for shared memory. */ 11282657471SMarkus Pfeiffer if ((ret = shminit()) < 0) 11382657471SMarkus Pfeiffer return (ret); 11482657471SMarkus Pfeiffer return (0); 11582657471SMarkus Pfeiffer } 11682657471SMarkus Pfeiffer 11782657471SMarkus Pfeiffer /* Check if sysv ipc resources are initialized. */ 11882657471SMarkus Pfeiffer static int 119ff86f401SSascha Wildner is_shm_started(void) 120ff86f401SSascha Wildner { 12182657471SMarkus Pfeiffer if (!is_sysvinit()) 12282657471SMarkus Pfeiffer return (0); 12382657471SMarkus Pfeiffer if (!shmres) 12482657471SMarkus Pfeiffer return (0); 12582657471SMarkus Pfeiffer return (1); 12682657471SMarkus Pfeiffer } 12782657471SMarkus Pfeiffer 12882657471SMarkus Pfeiffer /* OBS: It is used only a rwlock for both hashtables and 12982657471SMarkus Pfeiffer * socket. I've made that choice because is I considered to 13082657471SMarkus Pfeiffer * be much expensive to acquire/release more than one especially 13182657471SMarkus Pfeiffer * as the daemon is not multithreading. 13282657471SMarkus Pfeiffer */ 13382657471SMarkus Pfeiffer 13482657471SMarkus Pfeiffer /* This function has another parameter apart from shmget. 13582657471SMarkus Pfeiffer * The parameter has information about the type of sysv 13682657471SMarkus Pfeiffer * ipc resource (shm, sem, msg, undo). 13782657471SMarkus Pfeiffer * The undo segment is used for sem ops with UNDO flag set. 13882657471SMarkus Pfeiffer */ 13982657471SMarkus Pfeiffer int 140ff86f401SSascha Wildner _shmget(key_t key, size_t size, int shmflg, int type) 141ff86f401SSascha Wildner { 14282657471SMarkus Pfeiffer struct shmget_msg msg; 14382657471SMarkus Pfeiffer struct shm_data *data; 14482657471SMarkus Pfeiffer int shmid, fd; 14582657471SMarkus Pfeiffer int flags; 14682657471SMarkus Pfeiffer 14782657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_resources); 14882657471SMarkus Pfeiffer if (shmcheck() < 0) { 14982657471SMarkus Pfeiffer sysv_print_err("init sysv ipc\n"); 15082657471SMarkus Pfeiffer goto done; 15182657471SMarkus Pfeiffer } 15282657471SMarkus Pfeiffer 15382657471SMarkus Pfeiffer msg.key = key; 15482657471SMarkus Pfeiffer msg.size = size; 15582657471SMarkus Pfeiffer msg.shmflg = shmflg; 15682657471SMarkus Pfeiffer msg.type = type; 15782657471SMarkus Pfeiffer 15882657471SMarkus Pfeiffer send_message(daemon_fd, type, (char *)&msg, sizeof(msg)); 15982657471SMarkus Pfeiffer 16082657471SMarkus Pfeiffer /* Accept a file installed by the daemon. 16182657471SMarkus Pfeiffer * The file is used as shared memory. */ 16282657471SMarkus Pfeiffer fd = receive_fd(daemon_fd); 16382657471SMarkus Pfeiffer if (fd < 0) { 16482657471SMarkus Pfeiffer shmid = -1; 16582657471SMarkus Pfeiffer goto done; 16682657471SMarkus Pfeiffer } 16782657471SMarkus Pfeiffer 16882657471SMarkus Pfeiffer flags = _fcntl(fd, F_GETFD, 0); 16982657471SMarkus Pfeiffer if (_fcntl(fd, F_SETFD, flags & FD_CLOEXEC) == -1) { 17082657471SMarkus Pfeiffer sysv_print_err("fcntl error\n"); 17182657471SMarkus Pfeiffer shmid = -1; 17282657471SMarkus Pfeiffer goto done; 17382657471SMarkus Pfeiffer } 17482657471SMarkus Pfeiffer 17582657471SMarkus Pfeiffer /* Receive the resource id or error. */ 17682657471SMarkus Pfeiffer receive_message(daemon_fd, (char *)&shmid, sizeof(shmid)); 17782657471SMarkus Pfeiffer 17882657471SMarkus Pfeiffer if (shmid < 0) { 17982657471SMarkus Pfeiffer errno = -shmid; 18082657471SMarkus Pfeiffer shmid = -1; 18182657471SMarkus Pfeiffer goto done; 18282657471SMarkus Pfeiffer } 18382657471SMarkus Pfeiffer 18482657471SMarkus Pfeiffer /* Do we already have an entry for this resource? */ 18582657471SMarkus Pfeiffer data = _hash_lookup(shmres, shmid); 18682657471SMarkus Pfeiffer if (data) 18782657471SMarkus Pfeiffer goto done; 18882657471SMarkus Pfeiffer 18982657471SMarkus Pfeiffer /* If not, add necessary data about it. */ 19082657471SMarkus Pfeiffer data = malloc(sizeof(struct shm_data)); 19182657471SMarkus Pfeiffer data->fd = fd; 19282657471SMarkus Pfeiffer data->size = size; 19382657471SMarkus Pfeiffer data->shmid = shmid; 19482657471SMarkus Pfeiffer data->type = type; 19582657471SMarkus Pfeiffer data->used = 0; 19682657471SMarkus Pfeiffer data->removed = 0; 19782657471SMarkus Pfeiffer data->access = 0; /* Used for sems. */ 19882657471SMarkus Pfeiffer 19982657471SMarkus Pfeiffer /* Insert data in hashtable using the shmid. */ 20082657471SMarkus Pfeiffer _hash_insert(shmres, shmid, data); 20182657471SMarkus Pfeiffer done: 20282657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources); 20382657471SMarkus Pfeiffer return (shmid); 20482657471SMarkus Pfeiffer } 20582657471SMarkus Pfeiffer 20682657471SMarkus Pfeiffer int 207ff86f401SSascha Wildner sysvipc_shmget(key_t key, size_t size, int shmflg) 208ff86f401SSascha Wildner { 20982657471SMarkus Pfeiffer return (_shmget(key, size, shmflg, SHMGET)); 21082657471SMarkus Pfeiffer } 21182657471SMarkus Pfeiffer 21282657471SMarkus Pfeiffer void * 213ff86f401SSascha Wildner sysvipc_shmat(int shmid, const void *shmaddr, int shmflg) 214ff86f401SSascha Wildner { 21582657471SMarkus Pfeiffer struct shmat_msg msg; 21682657471SMarkus Pfeiffer void *addr = NULL; 21782657471SMarkus Pfeiffer int error; 21882657471SMarkus Pfeiffer int flags, prot; 21982657471SMarkus Pfeiffer size_t size; 22082657471SMarkus Pfeiffer struct shm_data *data; 22182657471SMarkus Pfeiffer 22282657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_resources); 22382657471SMarkus Pfeiffer if (!is_shm_started()) { 22482657471SMarkus Pfeiffer errno = EINVAL; 22582657471SMarkus Pfeiffer goto done; 22682657471SMarkus Pfeiffer } 22782657471SMarkus Pfeiffer 22882657471SMarkus Pfeiffer /* Get data using shmid. */ 22982657471SMarkus Pfeiffer data = _hash_lookup(shmres, shmid); 23082657471SMarkus Pfeiffer if (data == NULL) { 23182657471SMarkus Pfeiffer errno = EINVAL; 23282657471SMarkus Pfeiffer goto done; 23382657471SMarkus Pfeiffer } 23482657471SMarkus Pfeiffer 23582657471SMarkus Pfeiffer size = round_page(data->size); 23682657471SMarkus Pfeiffer 23782657471SMarkus Pfeiffer #ifdef VM_PROT_READ_IS_EXEC 23882657471SMarkus Pfeiffer prot = PROT_READ | PROT_EXECUTE; 23982657471SMarkus Pfeiffer #else 24082657471SMarkus Pfeiffer prot = PROT_READ; 24182657471SMarkus Pfeiffer #endif 24282657471SMarkus Pfeiffer if ((shmflg & SHM_RDONLY) == 0) 24382657471SMarkus Pfeiffer prot |= PROT_WRITE; 24482657471SMarkus Pfeiffer 24582657471SMarkus Pfeiffer flags = MAP_SHARED; 24682657471SMarkus Pfeiffer if (shmaddr) { 24782657471SMarkus Pfeiffer if (shmflg & SHM_RND) { 248*7d692414Szrj addr = (void *)((uintptr_t)shmaddr & ~(SHMLBA-1)); 249*7d692414Szrj } else if (((uintptr_t)shmaddr & (SHMLBA-1)) == 0) { 25082657471SMarkus Pfeiffer addr = __DECONST(void *, shmaddr); 25182657471SMarkus Pfeiffer } else { 25282657471SMarkus Pfeiffer errno = EINVAL; 25382657471SMarkus Pfeiffer goto done; 25482657471SMarkus Pfeiffer } 25582657471SMarkus Pfeiffer } 25682657471SMarkus Pfeiffer 25782657471SMarkus Pfeiffer msg.shmid = shmid; 25882657471SMarkus Pfeiffer msg.shmaddr = shmaddr; 25982657471SMarkus Pfeiffer msg.shmflg = shmflg; 26082657471SMarkus Pfeiffer msg.size = data->size; /* For undo segment. */ 26182657471SMarkus Pfeiffer 26282657471SMarkus Pfeiffer send_message(daemon_fd, SHMAT, (char *)&msg, sizeof(msg)); 26382657471SMarkus Pfeiffer receive_message(daemon_fd, (char *)&error, sizeof(error)); 26482657471SMarkus Pfeiffer if (error) { 26582657471SMarkus Pfeiffer errno = error; 26682657471SMarkus Pfeiffer goto done; 26782657471SMarkus Pfeiffer } 26882657471SMarkus Pfeiffer 26982657471SMarkus Pfeiffer addr = mmap(addr, size, prot, flags, data->fd, 0); 27082657471SMarkus Pfeiffer if (!addr) { 27182657471SMarkus Pfeiffer sysv_print_err("mmap\n"); 27282657471SMarkus Pfeiffer /* Detach ourselves from the segment. */ 27382657471SMarkus Pfeiffer send_message(daemon_fd, SHMDT, (char *)&shmid, sizeof(shmid)); 27482657471SMarkus Pfeiffer goto done; 27582657471SMarkus Pfeiffer } 27682657471SMarkus Pfeiffer 27782657471SMarkus Pfeiffer /* Necessary for SEMGET, MSGGET, UNDOGET. */ 27882657471SMarkus Pfeiffer data->internal = addr; 27982657471SMarkus Pfeiffer 28082657471SMarkus Pfeiffer /* Save the mapped address for munmap call. */ 28182657471SMarkus Pfeiffer _hash_insert(shmaddrs, (u_long)addr, data); 28282657471SMarkus Pfeiffer done: 28382657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources); 28482657471SMarkus Pfeiffer return (addr); 28582657471SMarkus Pfeiffer } 28682657471SMarkus Pfeiffer 28782657471SMarkus Pfeiffer /* Remove a sysv ipc resource. */ 28882657471SMarkus Pfeiffer static 289ff86f401SSascha Wildner void shmremove(int shmid) 290ff86f401SSascha Wildner { 29182657471SMarkus Pfeiffer struct shm_data *data; 29282657471SMarkus Pfeiffer data = _hash_remove(shmres, shmid); 29382657471SMarkus Pfeiffer 29482657471SMarkus Pfeiffer //TODO nu trebuie demapat? 29582657471SMarkus Pfeiffer _close(data->fd); 29682657471SMarkus Pfeiffer free(data); 29782657471SMarkus Pfeiffer data = NULL; 29882657471SMarkus Pfeiffer } 29982657471SMarkus Pfeiffer 30082657471SMarkus Pfeiffer int 301ff86f401SSascha Wildner sysvipc_shmctl(int shmid, int cmd, struct shmid_ds *buf) 302ff86f401SSascha Wildner { 30382657471SMarkus Pfeiffer int size, ret; 30482657471SMarkus Pfeiffer struct shmctl_msg *msg; 30582657471SMarkus Pfeiffer 30682657471SMarkus Pfeiffer /* if (cmd == IPC_SET) 30782657471SMarkus Pfeiffer size = sizeof(struct shmctl_msg) + sizeof(struct shmid_ds); 30882657471SMarkus Pfeiffer else 30982657471SMarkus Pfeiffer size = sizeof(struct shmctl_msg); 31082657471SMarkus Pfeiffer */ 31182657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_resources); 31282657471SMarkus Pfeiffer 31382657471SMarkus Pfeiffer ret = -1; 31482657471SMarkus Pfeiffer 31582657471SMarkus Pfeiffer if (!is_shm_started()) { 31682657471SMarkus Pfeiffer errno = EINVAL; 31782657471SMarkus Pfeiffer goto done; 31882657471SMarkus Pfeiffer } 31982657471SMarkus Pfeiffer 32082657471SMarkus Pfeiffer size = sizeof(struct shmctl_msg); 32182657471SMarkus Pfeiffer msg = malloc(size); 32282657471SMarkus Pfeiffer msg->shmid = shmid; 32382657471SMarkus Pfeiffer msg->cmd = cmd; 32482657471SMarkus Pfeiffer 32582657471SMarkus Pfeiffer if (cmd == IPC_SET) 32682657471SMarkus Pfeiffer msg->buf = *buf; 32782657471SMarkus Pfeiffer 32882657471SMarkus Pfeiffer send_message(daemon_fd, SHMCTL, (char *)msg, sizeof(*msg)); 32982657471SMarkus Pfeiffer 33082657471SMarkus Pfeiffer receive_message(daemon_fd, (char *)&ret, sizeof(ret)); 33182657471SMarkus Pfeiffer 33282657471SMarkus Pfeiffer /* Get data in IPC_STAT case. */ 33382657471SMarkus Pfeiffer if (ret == 0 && cmd == IPC_STAT) 33482657471SMarkus Pfeiffer receive_message(daemon_fd, (char *)buf, sizeof(*buf)); 33582657471SMarkus Pfeiffer 33682657471SMarkus Pfeiffer /* Free all resources specific to a shmid in IPC_RMID case. */ 33782657471SMarkus Pfeiffer if (ret == 0 && cmd == IPC_RMID) 33882657471SMarkus Pfeiffer shmremove(shmid); 33982657471SMarkus Pfeiffer 34082657471SMarkus Pfeiffer errno = ret; 34182657471SMarkus Pfeiffer done: 34282657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources); 34382657471SMarkus Pfeiffer return (ret == 0 ? 0 : -1); 34482657471SMarkus Pfeiffer } 34582657471SMarkus Pfeiffer 34682657471SMarkus Pfeiffer /* Functionality of shmdt with the possibility to inform or not 34782657471SMarkus Pfeiffer * the daemon. 34882657471SMarkus Pfeiffer * Inform the daemon when shmdt is called and not when an error 34982657471SMarkus Pfeiffer * occurs and the daemon doesn't know that the process is attaced. 35082657471SMarkus Pfeiffer */ 35182657471SMarkus Pfeiffer static int 352ff86f401SSascha Wildner _shmdt(const void *shmaddr, int send_to_daemon) 353ff86f401SSascha Wildner { 35482657471SMarkus Pfeiffer int ret; 35582657471SMarkus Pfeiffer size_t size; 35682657471SMarkus Pfeiffer struct shm_data *data; 35782657471SMarkus Pfeiffer 35882657471SMarkus Pfeiffer ret = -1; 35982657471SMarkus Pfeiffer 36082657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_resources); 36182657471SMarkus Pfeiffer if (!is_shm_started()) { 36282657471SMarkus Pfeiffer errno = EINVAL; 36382657471SMarkus Pfeiffer goto done; 36482657471SMarkus Pfeiffer } 36582657471SMarkus Pfeiffer 36682657471SMarkus Pfeiffer /* Verify if shmaddr was returned from a shmat call. */ 36782657471SMarkus Pfeiffer data = _hash_remove(shmaddrs, (u_long)shmaddr); 36882657471SMarkus Pfeiffer if (data == NULL) { 36982657471SMarkus Pfeiffer errno = EINVAL; 37082657471SMarkus Pfeiffer goto done; 37182657471SMarkus Pfeiffer } 37282657471SMarkus Pfeiffer 37382657471SMarkus Pfeiffer size = round_page(data->size); 37482657471SMarkus Pfeiffer 37582657471SMarkus Pfeiffer ret = munmap(__DECONST(void *, shmaddr), size); 37682657471SMarkus Pfeiffer if (ret) 37782657471SMarkus Pfeiffer goto done; 37882657471SMarkus Pfeiffer 37982657471SMarkus Pfeiffer if (send_to_daemon) 38082657471SMarkus Pfeiffer send_message(daemon_fd, SHMDT, (char *)&data->shmid, sizeof(int)); 38182657471SMarkus Pfeiffer 38282657471SMarkus Pfeiffer shmaddr = NULL; 38382657471SMarkus Pfeiffer free(data); 38482657471SMarkus Pfeiffer data = NULL; 38582657471SMarkus Pfeiffer done: 38682657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources); 38782657471SMarkus Pfeiffer return (ret); 38882657471SMarkus Pfeiffer } 38982657471SMarkus Pfeiffer 39082657471SMarkus Pfeiffer int 391ff86f401SSascha Wildner sysvipc_shmdt(const void *shmaddr) 392ff86f401SSascha Wildner { 39382657471SMarkus Pfeiffer return (_shmdt(shmaddr, 1)); 39482657471SMarkus Pfeiffer } 39582657471SMarkus Pfeiffer 39682657471SMarkus Pfeiffer void 397ff86f401SSascha Wildner shmchild(void) 398ff86f401SSascha Wildner { 39982657471SMarkus Pfeiffer int i; 40082657471SMarkus Pfeiffer struct entries_list *list; 40182657471SMarkus Pfeiffer struct hashentry *tmp, *ttmp; 40282657471SMarkus Pfeiffer struct shmat_msg msg; 40382657471SMarkus Pfeiffer struct shm_data *data; 40482657471SMarkus Pfeiffer int error; 40582657471SMarkus Pfeiffer 40682657471SMarkus Pfeiffer /* OBS: no locking is necessary because this function is called 40782657471SMarkus Pfeiffer * after the child is created and at that moment only one thread 40882657471SMarkus Pfeiffer * exists in the process. 40982657471SMarkus Pfeiffer */ 41082657471SMarkus Pfeiffer for (i=0; i<get_hash_size(MAXSIZE); i++) { 41182657471SMarkus Pfeiffer list = &shmaddrs->entries[i]; 41282657471SMarkus Pfeiffer if (LIST_EMPTY(list)) 41382657471SMarkus Pfeiffer continue; 41482657471SMarkus Pfeiffer LIST_FOREACH_MUTABLE(tmp, list, entry_link, ttmp) { 41582657471SMarkus Pfeiffer data = (struct shm_data*)tmp->value; 41682657471SMarkus Pfeiffer /* Inform daemon that we are attached. */ 41782657471SMarkus Pfeiffer 41882657471SMarkus Pfeiffer if (data->type == UNDOGET) { 41982657471SMarkus Pfeiffer continue; 42082657471SMarkus Pfeiffer } 42182657471SMarkus Pfeiffer 42282657471SMarkus Pfeiffer msg.shmid = data->shmid; 42382657471SMarkus Pfeiffer msg.shmaddr = data->internal; 42482657471SMarkus Pfeiffer msg.shmflg = 0; /* This is enough at this moment. */ 42582657471SMarkus Pfeiffer msg.size = data->size; 42682657471SMarkus Pfeiffer /* Last field is not necessary because it is used only 42782657471SMarkus Pfeiffer * for undo segments. 42882657471SMarkus Pfeiffer */ 42982657471SMarkus Pfeiffer 43082657471SMarkus Pfeiffer send_message(daemon_fd, SHMAT, (char *)&msg, sizeof(msg)); 43182657471SMarkus Pfeiffer receive_message(daemon_fd, (char *)&error, sizeof(error)); 43282657471SMarkus Pfeiffer 43382657471SMarkus Pfeiffer /* If the daemon returned error munmap the region. */ 43482657471SMarkus Pfeiffer if (error) { 43582657471SMarkus Pfeiffer errno = error; 43682657471SMarkus Pfeiffer _shmdt(data->internal, 0); 43782657471SMarkus Pfeiffer shmremove(data->shmid); 43882657471SMarkus Pfeiffer sysv_print_err(" %d shmchild\n", error); 43982657471SMarkus Pfeiffer sleep(20); 44082657471SMarkus Pfeiffer } 44182657471SMarkus Pfeiffer 44282657471SMarkus Pfeiffer } 44382657471SMarkus Pfeiffer } 44482657471SMarkus Pfeiffer 44582657471SMarkus Pfeiffer /* Remove semundo structures. Those are specific only for the parent. 44682657471SMarkus Pfeiffer * The child must create for itself a new one. 44782657471SMarkus Pfeiffer */ 44882657471SMarkus Pfeiffer data = _hash_remove(shmaddrs, (u_long)undos); 44982657471SMarkus Pfeiffer if (undos) { 45082657471SMarkus Pfeiffer munmap(undos, round_page(data->size)); 45182657471SMarkus Pfeiffer undos = NULL; 45282657471SMarkus Pfeiffer } 45382657471SMarkus Pfeiffer } 45482657471SMarkus Pfeiffer 45582657471SMarkus Pfeiffer /* Called each time a thread tries to access the sem/msg. 45682657471SMarkus Pfeiffer * It is used in order to protect data against its removal 45782657471SMarkus Pfeiffer * by another thread. 45882657471SMarkus Pfeiffer */ 45982657471SMarkus Pfeiffer struct shm_data * 460ff86f401SSascha Wildner get_shmdata(int id, int to_remove, int shm_access) 461ff86f401SSascha Wildner { 46282657471SMarkus Pfeiffer struct shm_data *data = NULL; 46382657471SMarkus Pfeiffer 46482657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_resources); 46582657471SMarkus Pfeiffer if (!is_shm_started()) { 46682657471SMarkus Pfeiffer errno = EINVAL; 46782657471SMarkus Pfeiffer goto done; 46882657471SMarkus Pfeiffer } 46982657471SMarkus Pfeiffer 47082657471SMarkus Pfeiffer data = _hash_lookup(shmres, id); 47182657471SMarkus Pfeiffer if (!data) { 47282657471SMarkus Pfeiffer errno = EINVAL; 47382657471SMarkus Pfeiffer goto done; 47482657471SMarkus Pfeiffer } 47582657471SMarkus Pfeiffer 47682657471SMarkus Pfeiffer /* If segment was removed by another thread we can't use it. */ 47782657471SMarkus Pfeiffer if (data->removed) { 47882657471SMarkus Pfeiffer sysv_print("segment already removed\n"); 47982657471SMarkus Pfeiffer errno = EINVAL; 48082657471SMarkus Pfeiffer data = NULL; 48182657471SMarkus Pfeiffer goto done; 48282657471SMarkus Pfeiffer } 48382657471SMarkus Pfeiffer 48482657471SMarkus Pfeiffer /* Mark for removal. Inform the other threads from the 48582657471SMarkus Pfeiffer * same address space. */ 48682657471SMarkus Pfeiffer if (to_remove) { 48782657471SMarkus Pfeiffer sysv_print("segment is removed\n"); 48882657471SMarkus Pfeiffer data->removed = to_remove; /* 1 if it is removed by 48982657471SMarkus Pfeiffer the current process and 2 if it was removed by 49082657471SMarkus Pfeiffer another one. */ 49182657471SMarkus Pfeiffer 49282657471SMarkus Pfeiffer /* No need for any rights check because this is 49382657471SMarkus Pfeiffer * done by daemon if this is the process that removes 49482657471SMarkus Pfeiffer * the sem/msg. 49582657471SMarkus Pfeiffer * If not, there is no need for any right to clean 49682657471SMarkus Pfeiffer * internal resources. 49782657471SMarkus Pfeiffer */ 49882657471SMarkus Pfeiffer goto done2; 49982657471SMarkus Pfeiffer } 50082657471SMarkus Pfeiffer 50182657471SMarkus Pfeiffer /* Avoid segmentation fault if the memory zone 50282657471SMarkus Pfeiffer * is accessed without necessary permissions 50382657471SMarkus Pfeiffer * (it was mapped according to them). 50482657471SMarkus Pfeiffer */ 50582657471SMarkus Pfeiffer if (!(data->access & shm_access)) { 50682657471SMarkus Pfeiffer #if 0 50782657471SMarkus Pfeiffer sysv_print("no access rights has %o and wants %o\n", 50882657471SMarkus Pfeiffer data->access, shm_access); 50982657471SMarkus Pfeiffer errno = EACCES; 51082657471SMarkus Pfeiffer data = NULL; 51182657471SMarkus Pfeiffer goto done; 51282657471SMarkus Pfeiffer #endif 51382657471SMarkus Pfeiffer } 51482657471SMarkus Pfeiffer 51582657471SMarkus Pfeiffer done2: 51682657471SMarkus Pfeiffer data->used++; 51782657471SMarkus Pfeiffer done: 51882657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources); 51982657471SMarkus Pfeiffer return (data); 52082657471SMarkus Pfeiffer } 52182657471SMarkus Pfeiffer 52282657471SMarkus Pfeiffer /* Set the shm_access type (IPC_R, IPC_W) for sem/msg. */ 52382657471SMarkus Pfeiffer int 524ff86f401SSascha Wildner set_shmdata_access(int id, int shm_access) 525ff86f401SSascha Wildner { 52682657471SMarkus Pfeiffer struct shm_data *data; 52782657471SMarkus Pfeiffer int ret = -1; 52882657471SMarkus Pfeiffer 52982657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_resources); 53082657471SMarkus Pfeiffer if (!is_shm_started()) { 53182657471SMarkus Pfeiffer errno = EINVAL; 53282657471SMarkus Pfeiffer goto done; 53382657471SMarkus Pfeiffer } 53482657471SMarkus Pfeiffer 53582657471SMarkus Pfeiffer data = _hash_lookup(shmres, id); 53682657471SMarkus Pfeiffer if (!data) { 53782657471SMarkus Pfeiffer errno = EINVAL; 53882657471SMarkus Pfeiffer goto done; 53982657471SMarkus Pfeiffer } 54082657471SMarkus Pfeiffer 54182657471SMarkus Pfeiffer /* If segment was removed by another thread we can't use it. */ 54282657471SMarkus Pfeiffer if (data->removed) { 54382657471SMarkus Pfeiffer errno = EINVAL; 54482657471SMarkus Pfeiffer goto done; 54582657471SMarkus Pfeiffer } 54682657471SMarkus Pfeiffer 54782657471SMarkus Pfeiffer data->access = shm_access; 54882657471SMarkus Pfeiffer ret = 0; 54982657471SMarkus Pfeiffer done: 55082657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources); 55182657471SMarkus Pfeiffer 55282657471SMarkus Pfeiffer return (ret); 55382657471SMarkus Pfeiffer } 554