xref: /dflybsd-src/usr.sbin/sysvipcd/shmd.c (revision 1b11ea06a427d663e12e6a7a5083df6209e4cda2)
182657471SMarkus Pfeiffer /*
282657471SMarkus Pfeiffer  * Copyright (c) 1994 Adam Glass and Charles Hannum.  All rights reserved.
382657471SMarkus Pfeiffer  * Copyright (c) 2013 Larisa Grigore <larisagrigore@gmail.com>
482657471SMarkus Pfeiffer  *
582657471SMarkus Pfeiffer  * Redistribution and use in source and binary forms, with or without
682657471SMarkus Pfeiffer  * modification, are permitted provided that the following conditions
782657471SMarkus Pfeiffer  * are met:
882657471SMarkus Pfeiffer  * 1. Redistributions of source code must retain the above copyright
982657471SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer.
1082657471SMarkus Pfeiffer  * 2. Redistributions in binary form must reproduce the above copyright
1182657471SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer in the
1282657471SMarkus Pfeiffer  *    documentation and/or other materials provided with the distribution.
1382657471SMarkus Pfeiffer  * 3. All advertising materials mentioning features or use of this software
1482657471SMarkus Pfeiffer  *    must display the following acknowledgement:
1582657471SMarkus Pfeiffer  *	This product includes software developed by Adam Glass and Charles
1682657471SMarkus Pfeiffer  *	Hannum.
1782657471SMarkus Pfeiffer  * 4. The names of the authors may not be used to endorse or promote products
1882657471SMarkus Pfeiffer  *    derived from this software without specific prior written permission.
1982657471SMarkus Pfeiffer  *
2082657471SMarkus Pfeiffer  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
2182657471SMarkus Pfeiffer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2282657471SMarkus Pfeiffer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2382657471SMarkus Pfeiffer  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2482657471SMarkus Pfeiffer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2582657471SMarkus Pfeiffer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2682657471SMarkus Pfeiffer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2782657471SMarkus Pfeiffer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2882657471SMarkus Pfeiffer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2982657471SMarkus Pfeiffer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3082657471SMarkus Pfeiffer  */
3182657471SMarkus Pfeiffer 
3282657471SMarkus Pfeiffer #include <sys/types.h>
3382657471SMarkus Pfeiffer #include <sys/stat.h>
3482657471SMarkus Pfeiffer #include <sys/param.h>
3582657471SMarkus Pfeiffer #include <sys/vmmeter.h>
3682657471SMarkus Pfeiffer #include <sys/wait.h>
3782657471SMarkus Pfeiffer #include <sys/queue.h>
3882657471SMarkus Pfeiffer #include <sys/mman.h>
3982657471SMarkus Pfeiffer 
4082657471SMarkus Pfeiffer #include <err.h>
4182657471SMarkus Pfeiffer #include <errno.h>
4282657471SMarkus Pfeiffer #include <stdio.h>
4382657471SMarkus Pfeiffer #include <stdlib.h>
4482657471SMarkus Pfeiffer #include <string.h>
4582657471SMarkus Pfeiffer #include <unistd.h>
4682657471SMarkus Pfeiffer #include <fcntl.h>
4782657471SMarkus Pfeiffer #include <time.h>
4882657471SMarkus Pfeiffer 
4982657471SMarkus Pfeiffer #include "limits.h"
5082657471SMarkus Pfeiffer #include "perm.h"
5182657471SMarkus Pfeiffer #include "utilsd.h"
5282657471SMarkus Pfeiffer 
5382657471SMarkus Pfeiffer #include "shmd.h"
5482657471SMarkus Pfeiffer #include "sysvipc_hash.h"
5582657471SMarkus Pfeiffer #include "sysvipc_sockets.h"
5682657471SMarkus Pfeiffer 
5782657471SMarkus Pfeiffer static struct	shminfo shminfo = {
5882657471SMarkus Pfeiffer //	0,
5982657471SMarkus Pfeiffer 	SHMMIN,
6082657471SMarkus Pfeiffer 	SHMMNI,
6182657471SMarkus Pfeiffer 	SHMSEG
6282657471SMarkus Pfeiffer //	0
6382657471SMarkus Pfeiffer };
6482657471SMarkus Pfeiffer 
6582657471SMarkus Pfeiffer /* Shared memory.*/
6682657471SMarkus Pfeiffer static int shm_last_free, shm_committed, shmalloced;
6782657471SMarkus Pfeiffer int shm_nused;
6882657471SMarkus Pfeiffer static struct shmid_ds	*shmsegs;
6982657471SMarkus Pfeiffer 
7082657471SMarkus Pfeiffer /* Message queues.*/
7182657471SMarkus Pfeiffer extern struct msginfo msginfo;
7282657471SMarkus Pfeiffer 
7382657471SMarkus Pfeiffer extern struct hashtable *clientshash;
7482657471SMarkus Pfeiffer 
7582657471SMarkus Pfeiffer static int
create_sysv_file(struct shmget_msg * msg,size_t size,struct shmid_ds * shmseg)7682657471SMarkus Pfeiffer create_sysv_file(struct shmget_msg *msg, size_t size,
7782657471SMarkus Pfeiffer 		struct shmid_ds *shmseg) {
7882657471SMarkus Pfeiffer 	char filename[FILENAME_MAX];
7982657471SMarkus Pfeiffer 	int fd;
8082657471SMarkus Pfeiffer 	void *addr;
8182657471SMarkus Pfeiffer 	int nsems;
8282657471SMarkus Pfeiffer 	struct semid_pool *sems;
8382657471SMarkus Pfeiffer 	struct msqid_pool *msgq;
8482657471SMarkus Pfeiffer 	key_t key = msg->key;
8582657471SMarkus Pfeiffer 	int i;
8682657471SMarkus Pfeiffer 
8782657471SMarkus Pfeiffer 	errno = 0;
8882657471SMarkus Pfeiffer 
8982657471SMarkus Pfeiffer 	switch(msg->type) {
9082657471SMarkus Pfeiffer 		case SHMGET:
9182657471SMarkus Pfeiffer 			sprintf(filename, "%s/%s_%ld", DIRPATH, SHM_NAME, key);
9282657471SMarkus Pfeiffer 			break;
9382657471SMarkus Pfeiffer 		case SEMGET:
9482657471SMarkus Pfeiffer 			sprintf(filename, "%s/%s_%ld", DIRPATH, SEM_NAME, key);
9582657471SMarkus Pfeiffer 			break;
9682657471SMarkus Pfeiffer 		case MSGGET:
9782657471SMarkus Pfeiffer 			sprintf(filename, "%s/%s_%ld", DIRPATH, MSG_NAME, key);
9882657471SMarkus Pfeiffer 			break;
9982657471SMarkus Pfeiffer 		case UNDOGET:
10082657471SMarkus Pfeiffer 			sprintf(filename, "%s/%s_%ld", DIRPATH, UNDO_NAME, key);
10182657471SMarkus Pfeiffer 			break;
10282657471SMarkus Pfeiffer 		default:
10382657471SMarkus Pfeiffer 			return (-EINVAL);
10482657471SMarkus Pfeiffer 	}
10582657471SMarkus Pfeiffer 
10682657471SMarkus Pfeiffer 	fd = open(filename, O_RDWR | O_CREAT, 0666);
10782657471SMarkus Pfeiffer 	if (fd < 0) {
10882657471SMarkus Pfeiffer 		sysvd_print_err("create sysv file: open\n");
10982657471SMarkus Pfeiffer 		goto out;
11082657471SMarkus Pfeiffer 	}
11182657471SMarkus Pfeiffer 
11282657471SMarkus Pfeiffer 	ftruncate(fd, size);
11382657471SMarkus Pfeiffer 
11482657471SMarkus Pfeiffer 	switch(msg->type) {
11582657471SMarkus Pfeiffer 		case SEMGET:
11682657471SMarkus Pfeiffer 			/* Map the semaphore to initialize it. */
11782657471SMarkus Pfeiffer 			addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
11882657471SMarkus Pfeiffer 			//TODO modify 0 for more sems on a page
11982657471SMarkus Pfeiffer 			if (!addr) {
12082657471SMarkus Pfeiffer 				sysvd_print_err("create sysv file: mmap");
12182657471SMarkus Pfeiffer 				goto error;
12282657471SMarkus Pfeiffer 			}
12382657471SMarkus Pfeiffer 
12482657471SMarkus Pfeiffer 			/* There is no need for any lock because all clients
12582657471SMarkus Pfeiffer 			 * that try to access this segment are blocked until
12682657471SMarkus Pfeiffer 			 * it becames ~SHMSEG_REMOVED. */
12782657471SMarkus Pfeiffer 			sems = (struct semid_pool*)addr;
12882657471SMarkus Pfeiffer 			nsems = (msg->size - sizeof(struct semid_pool)) /
12982657471SMarkus Pfeiffer 				sizeof(struct sem);
130*34bf0d2dSSascha Wildner 			sysvd_print("allocate %d sems\n", nsems);
13182657471SMarkus Pfeiffer 
13282657471SMarkus Pfeiffer 			/* Init lock. */
13382657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
13482657471SMarkus Pfeiffer 			sysv_rwlock_init(&sems->rwlock);
13582657471SMarkus Pfeiffer #else
13682657471SMarkus Pfeiffer 			sysv_mutex_init(&sems->mutex);
13782657471SMarkus Pfeiffer #endif
13882657471SMarkus Pfeiffer 			/* Credentials are kept in shmid_ds structure. */
13982657471SMarkus Pfeiffer 			sems->ds.sem_perm.seq = shmseg->shm_perm.seq;
14082657471SMarkus Pfeiffer 			sems->ds.sem_nsems = nsems;
14182657471SMarkus Pfeiffer 			sems->ds.sem_otime = 0;
14282657471SMarkus Pfeiffer 			//sems->ds.sem_ctime = time(NULL);
14382657471SMarkus Pfeiffer 			//semtot += nsems;
1440fdb7d01SSascha Wildner 			sems->gen = 0;
14582657471SMarkus Pfeiffer 
14682657471SMarkus Pfeiffer 			/* Initialize each sem. */
14782657471SMarkus Pfeiffer 			memset(sems->ds.sem_base, 0, nsems + sizeof(struct sem));
14882657471SMarkus Pfeiffer 
14982657471SMarkus Pfeiffer #ifdef SYSV_SEMS
15082657471SMarkus Pfeiffer 			int l;
15182657471SMarkus Pfeiffer 			for (l=0; l < nsems; l++)
15282657471SMarkus Pfeiffer 				sysv_mutex_init(&sems->ds.sem_base[l].sem_mutex);
15382657471SMarkus Pfeiffer #endif
15482657471SMarkus Pfeiffer 
15582657471SMarkus Pfeiffer 			munmap(addr, size);
15682657471SMarkus Pfeiffer 
15782657471SMarkus Pfeiffer 			break;
15882657471SMarkus Pfeiffer 		case MSGGET:
15982657471SMarkus Pfeiffer 			/* Map the message queue to initialize it. */
16082657471SMarkus Pfeiffer 			addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
16182657471SMarkus Pfeiffer 			if (!addr) {
16282657471SMarkus Pfeiffer 				sysvd_print_err("create sysv file: mmap");
16382657471SMarkus Pfeiffer 				goto error;
16482657471SMarkus Pfeiffer 			}
16582657471SMarkus Pfeiffer 
16682657471SMarkus Pfeiffer 			/* There is no need for any lock because all clients
16782657471SMarkus Pfeiffer 			 * that try to access this segment are blocked until
16882657471SMarkus Pfeiffer 			 * it becames ~SHMSEG_REMOVED. */
16982657471SMarkus Pfeiffer 			msgq = (struct msqid_pool*)addr; //TODO
17082657471SMarkus Pfeiffer 			/*sysvd_print("Attention!!! : %ld %ld %ld %ld\n",
17182657471SMarkus Pfeiffer 					sizeof(struct msqid_pool),
17282657471SMarkus Pfeiffer 					sizeof(msgq->msghdrs),
17382657471SMarkus Pfeiffer 					sizeof(msgq->msgmaps),
17482657471SMarkus Pfeiffer 					sizeof(msgq->msgpool));*/
17582657471SMarkus Pfeiffer 
17682657471SMarkus Pfeiffer 			/* Init lock. */
17782657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
17882657471SMarkus Pfeiffer 			sysv_rwlock_init(&msgq->rwlock);
17982657471SMarkus Pfeiffer #else
18082657471SMarkus Pfeiffer 			sysv_mutex_init(&msgq->mutex);
18182657471SMarkus Pfeiffer #endif
18282657471SMarkus Pfeiffer 			/* In kernel implementation, this was done globally. */
18382657471SMarkus Pfeiffer 			for (i = 0; i < msginfo.msgseg; i++) {
18482657471SMarkus Pfeiffer 				if (i > 0)
18582657471SMarkus Pfeiffer 					msgq->msgmaps[i-1].next = i;
18682657471SMarkus Pfeiffer 				msgq->msgmaps[i].next = -1;	/* implies entry is available */
18782657471SMarkus Pfeiffer 			}
18882657471SMarkus Pfeiffer 			msgq->free_msgmaps = 0;
18982657471SMarkus Pfeiffer 			msgq->nfree_msgmaps = msginfo.msgseg;
19082657471SMarkus Pfeiffer 
19182657471SMarkus Pfeiffer 			for (i = 0; i < msginfo.msgtql; i++) {
19282657471SMarkus Pfeiffer 				msgq->msghdrs[i].msg_type = 0;
19382657471SMarkus Pfeiffer 				if (i > 0)
19482657471SMarkus Pfeiffer 					msgq->msghdrs[i-1].msg_next = i;
19582657471SMarkus Pfeiffer 				msgq->msghdrs[i].msg_next = -1;
19682657471SMarkus Pfeiffer 			}
19782657471SMarkus Pfeiffer 			msgq->free_msghdrs = 0;
19882657471SMarkus Pfeiffer 
19982657471SMarkus Pfeiffer 			/* Credentials are kept in shmid_ds structure. */
20082657471SMarkus Pfeiffer 			msgq->ds.msg_perm.seq = shmseg->shm_perm.seq;
20182657471SMarkus Pfeiffer 			msgq->ds.first.msg_first_index = -1;
20282657471SMarkus Pfeiffer 			msgq->ds.last.msg_last_index = -1;
20382657471SMarkus Pfeiffer 			msgq->ds.msg_cbytes = 0;
20482657471SMarkus Pfeiffer 			msgq->ds.msg_qnum = 0;
20582657471SMarkus Pfeiffer 			msgq->ds.msg_qbytes = msginfo.msgmnb;
20682657471SMarkus Pfeiffer 			msgq->ds.msg_lspid = 0;
20782657471SMarkus Pfeiffer 			msgq->ds.msg_lrpid = 0;
20882657471SMarkus Pfeiffer 			msgq->ds.msg_stime = 0;
20982657471SMarkus Pfeiffer 			msgq->ds.msg_rtime = 0;
21082657471SMarkus Pfeiffer 
21182657471SMarkus Pfeiffer 			munmap(addr, size);
21282657471SMarkus Pfeiffer 
21382657471SMarkus Pfeiffer 			break;
21482657471SMarkus Pfeiffer 		default:
21582657471SMarkus Pfeiffer 			break;
21682657471SMarkus Pfeiffer 	}
21782657471SMarkus Pfeiffer 
21882657471SMarkus Pfeiffer 	unlink(filename);
21982657471SMarkus Pfeiffer out:
22082657471SMarkus Pfeiffer 	return (fd);
22182657471SMarkus Pfeiffer error:
22282657471SMarkus Pfeiffer 	close(fd);
22382657471SMarkus Pfeiffer 	return (-1);
22482657471SMarkus Pfeiffer }
22582657471SMarkus Pfeiffer 
22682657471SMarkus Pfeiffer /* Install for the client the file corresponding to fd. */
22782657471SMarkus Pfeiffer static int
install_fd_client(pid_t pid,int fd)22882657471SMarkus Pfeiffer install_fd_client(pid_t pid, int fd) {
22982657471SMarkus Pfeiffer 	int ret;
23082657471SMarkus Pfeiffer 	struct client *cl = _hash_lookup(clientshash, pid);
23182657471SMarkus Pfeiffer 	if (!cl) {
23282657471SMarkus Pfeiffer 		sysvd_print_err("no client entry for pid = %d\n", pid);
23382657471SMarkus Pfeiffer 		return (-1);
23482657471SMarkus Pfeiffer 	}
23582657471SMarkus Pfeiffer 
23682657471SMarkus Pfeiffer 	ret = send_fd(cl->sock, fd);
23782657471SMarkus Pfeiffer 	if (ret < 0) {
23882657471SMarkus Pfeiffer 		sysvd_print_err("can not send fd to client %d\n", pid);
23982657471SMarkus Pfeiffer 		return (-1);
24082657471SMarkus Pfeiffer 	}
24182657471SMarkus Pfeiffer 
24282657471SMarkus Pfeiffer 	return (0);
24382657471SMarkus Pfeiffer }
24482657471SMarkus Pfeiffer 
24582657471SMarkus Pfeiffer static int
shm_find_segment_by_key(key_t key)24682657471SMarkus Pfeiffer shm_find_segment_by_key(key_t key)
24782657471SMarkus Pfeiffer {
24882657471SMarkus Pfeiffer 	int i;
24982657471SMarkus Pfeiffer 
25082657471SMarkus Pfeiffer 	for (i = 0; i < shmalloced; i++) {
25182657471SMarkus Pfeiffer 		if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) &&
25282657471SMarkus Pfeiffer 				shmsegs[i].shm_perm.key == key)
25382657471SMarkus Pfeiffer 			return (i);
25482657471SMarkus Pfeiffer 	}
25582657471SMarkus Pfeiffer 	return (-1);
25682657471SMarkus Pfeiffer }
25782657471SMarkus Pfeiffer 
25882657471SMarkus Pfeiffer static struct shmid_ds *
shm_find_segment_by_shmid(int shmid)25982657471SMarkus Pfeiffer shm_find_segment_by_shmid(int shmid)
26082657471SMarkus Pfeiffer {
26182657471SMarkus Pfeiffer 	int segnum;
26282657471SMarkus Pfeiffer 	struct shmid_ds *shmseg;
26382657471SMarkus Pfeiffer 
26482657471SMarkus Pfeiffer 	segnum = IPCID_TO_IX(shmid);
26582657471SMarkus Pfeiffer 	if (segnum < 0 || segnum >= shmalloced) {
26682657471SMarkus Pfeiffer 		sysvd_print_err("segnum out of range\n");
26782657471SMarkus Pfeiffer 		return (NULL);
26882657471SMarkus Pfeiffer 	}
26982657471SMarkus Pfeiffer 
27082657471SMarkus Pfeiffer 	shmseg = &shmsegs[segnum];
27182657471SMarkus Pfeiffer 	if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED))
27282657471SMarkus Pfeiffer 			!= SHMSEG_ALLOCATED ||
27382657471SMarkus Pfeiffer 			shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid)) {
27482657471SMarkus Pfeiffer 		sysvd_print("segment most probably removed\n");
27582657471SMarkus Pfeiffer 		return (NULL);
27682657471SMarkus Pfeiffer 	}
27782657471SMarkus Pfeiffer 	return (shmseg);
27882657471SMarkus Pfeiffer }
27982657471SMarkus Pfeiffer 
28082657471SMarkus Pfeiffer /* Remove a shared memory segment. */
28182657471SMarkus Pfeiffer static void
shm_deallocate_segment(int segnum)28282657471SMarkus Pfeiffer shm_deallocate_segment(int segnum)
28382657471SMarkus Pfeiffer {
28482657471SMarkus Pfeiffer 	size_t size;
28582657471SMarkus Pfeiffer 	struct shmid_ds *shmseg = &shmsegs[segnum];
28682657471SMarkus Pfeiffer 	struct shm_handle *internal =
28782657471SMarkus Pfeiffer 		(struct shm_handle *)shmseg->shm_internal;
28882657471SMarkus Pfeiffer //	int nsems;
28982657471SMarkus Pfeiffer 
29082657471SMarkus Pfeiffer 	sysvd_print("deallocate segment %d\n", segnum);
29182657471SMarkus Pfeiffer 
29282657471SMarkus Pfeiffer 	size = round_page(shmseg->shm_segsz);
29382657471SMarkus Pfeiffer 
29482657471SMarkus Pfeiffer #if 0
29582657471SMarkus Pfeiffer 	if (internal->type == SEMGET) {
29682657471SMarkus Pfeiffer 			nsems = (shmseg->shm_segsz - sizeof(struct semid_pool)) /
29782657471SMarkus Pfeiffer 				sizeof(struct sem);
29882657471SMarkus Pfeiffer 			semtot -= nsems;
29982657471SMarkus Pfeiffer 			sysvd_print("freed %d sems\n", nsems);
30082657471SMarkus Pfeiffer 	}
30182657471SMarkus Pfeiffer #endif
30282657471SMarkus Pfeiffer 
30382657471SMarkus Pfeiffer 	/* Close the corresponding file. */
30482657471SMarkus Pfeiffer 	close(internal->fd);
30582657471SMarkus Pfeiffer 
30682657471SMarkus Pfeiffer 	/* Free other resources. */
30782657471SMarkus Pfeiffer 	free(shmseg->shm_internal);
30882657471SMarkus Pfeiffer 	shmseg->shm_internal = NULL;
30982657471SMarkus Pfeiffer 	shm_committed -= btoc(size);
31082657471SMarkus Pfeiffer 	shm_nused--;
31182657471SMarkus Pfeiffer 
31282657471SMarkus Pfeiffer 	shmseg->shm_perm.mode = SHMSEG_FREE;
31382657471SMarkus Pfeiffer }
31482657471SMarkus Pfeiffer 
31582657471SMarkus Pfeiffer static void *map_seg(int);
31682657471SMarkus Pfeiffer static int munmap_seg(int, void *);
31782657471SMarkus Pfeiffer 
31882657471SMarkus Pfeiffer /* In sem and msg case notify the other processes that use it. */
31982657471SMarkus Pfeiffer static void
mark_segment_removed(int shmid,int type)32082657471SMarkus Pfeiffer mark_segment_removed(int shmid, int type) {
32182657471SMarkus Pfeiffer 	struct semid_pool *semaptr;
32282657471SMarkus Pfeiffer 	struct msqid_pool *msgq;
32382657471SMarkus Pfeiffer 
32482657471SMarkus Pfeiffer 	switch (type) {
32582657471SMarkus Pfeiffer 		case SEMGET:
32682657471SMarkus Pfeiffer 			semaptr = (struct semid_pool *)map_seg(shmid);
32782657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
32882657471SMarkus Pfeiffer 			sysv_rwlock_wrlock(&semaptr->rwlock);
32982657471SMarkus Pfeiffer #else
33082657471SMarkus Pfeiffer 			sysv_mutex_lock(&semaptr->mutex);
33182657471SMarkus Pfeiffer #endif
33282657471SMarkus Pfeiffer 			semaptr->gen = -1;
33382657471SMarkus Pfeiffer 
33482657471SMarkus Pfeiffer 			/* It is not necessary to wake waiting threads because
33582657471SMarkus Pfeiffer 			 * if the group of semaphores is acquired by a thread,
33682657471SMarkus Pfeiffer 			 * the smaptr lock is held, so it is impossible to
33782657471SMarkus Pfeiffer 			 * reach this point.
33882657471SMarkus Pfeiffer 			 */
33982657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
34082657471SMarkus Pfeiffer 			sysv_rwlock_unlock(&semaptr->rwlock);
34182657471SMarkus Pfeiffer #else
34282657471SMarkus Pfeiffer 			sysv_mutex_unlock(&semaptr->mutex);
34382657471SMarkus Pfeiffer #endif
34482657471SMarkus Pfeiffer 			munmap_seg(shmid, semaptr);
34582657471SMarkus Pfeiffer 			break;
34682657471SMarkus Pfeiffer 		case MSGGET :
34782657471SMarkus Pfeiffer 			msgq = (struct msqid_pool*)map_seg(shmid);
34882657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
34982657471SMarkus Pfeiffer 			sysv_rwlock_wrlock(&msgq->rwlock);
35082657471SMarkus Pfeiffer #else
35182657471SMarkus Pfeiffer 			sysv_mutex_lock(&msgq->mutex);
35282657471SMarkus Pfeiffer #endif
35382657471SMarkus Pfeiffer 			msgq->gen = -1;
35482657471SMarkus Pfeiffer 
35582657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
35682657471SMarkus Pfeiffer 			sysv_rwlock_unlock(&msgq->rwlock);
35782657471SMarkus Pfeiffer #else
35882657471SMarkus Pfeiffer 			sysv_mutex_unlock(&msgq->mutex);
35982657471SMarkus Pfeiffer #endif
36082657471SMarkus Pfeiffer 			munmap_seg(shmid, msgq);
36182657471SMarkus Pfeiffer 			break;
36282657471SMarkus Pfeiffer 		default:
36382657471SMarkus Pfeiffer 			break;
36482657471SMarkus Pfeiffer 	}
36582657471SMarkus Pfeiffer }
36682657471SMarkus Pfeiffer 
36782657471SMarkus Pfeiffer /* Get the id of an existing shared memory segment. */
36882657471SMarkus Pfeiffer static int
shmget_existing(struct shmget_msg * shmget_msg,int mode,int segnum,struct cmsgcred * cred)36982657471SMarkus Pfeiffer shmget_existing(struct shmget_msg *shmget_msg, int mode,
37082657471SMarkus Pfeiffer 		int segnum, struct cmsgcred *cred)
37182657471SMarkus Pfeiffer {
37282657471SMarkus Pfeiffer 	struct shmid_ds *shmseg;
37382657471SMarkus Pfeiffer 	int error;
37482657471SMarkus Pfeiffer 
37582657471SMarkus Pfeiffer 	shmseg = &shmsegs[segnum];
37682657471SMarkus Pfeiffer 	if (shmseg->shm_perm.mode & SHMSEG_REMOVED) {
37782657471SMarkus Pfeiffer 		/*
37882657471SMarkus Pfeiffer 		 * This segment is in the process of being allocated.  Wait
37982657471SMarkus Pfeiffer 		 * until it's done, and look the key up again (in case the
38082657471SMarkus Pfeiffer 		 * allocation failed or it was freed).
38182657471SMarkus Pfeiffer 		 */
38282657471SMarkus Pfeiffer 		//TODO Maybe it will be necessary if the daemon is multithreading
38382657471SMarkus Pfeiffer 		/*shmseg->shm_perm.mode |= SHMSEG_WANTED;
38482657471SMarkus Pfeiffer 		  error = tsleep((caddr_t)shmseg, PCATCH, "shmget", 0);
38582657471SMarkus Pfeiffer 		  if (error)
38682657471SMarkus Pfeiffer 		  return error;
38782657471SMarkus Pfeiffer 		  return EAGAIN;*/
38882657471SMarkus Pfeiffer 	}
38982657471SMarkus Pfeiffer 	if ((shmget_msg->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL))
39082657471SMarkus Pfeiffer 		return (-EEXIST);
39182657471SMarkus Pfeiffer 	error = ipcperm(cred, &shmseg->shm_perm, mode);
39282657471SMarkus Pfeiffer 	if (error)
39382657471SMarkus Pfeiffer 		return (-error);
39482657471SMarkus Pfeiffer 	if (shmget_msg->size && (shmget_msg->size > shmseg->shm_segsz))
39582657471SMarkus Pfeiffer 		return (-EINVAL);
39682657471SMarkus Pfeiffer 	return (IXSEQ_TO_IPCID(segnum, shmseg->shm_perm));
39782657471SMarkus Pfeiffer }
39882657471SMarkus Pfeiffer 
39982657471SMarkus Pfeiffer /* Create a shared memory segment and return the id. */
40082657471SMarkus Pfeiffer static int
shmget_allocate_segment(pid_t pid,struct shmget_msg * shmget_msg,int mode,struct cmsgcred * cred)40182657471SMarkus Pfeiffer shmget_allocate_segment(pid_t pid, struct shmget_msg *shmget_msg,
40282657471SMarkus Pfeiffer 		int mode, struct cmsgcred *cred)
40382657471SMarkus Pfeiffer {
40482657471SMarkus Pfeiffer 	int i, segnum, shmid;
40582657471SMarkus Pfeiffer 	size_t size;
40682657471SMarkus Pfeiffer 	struct shmid_ds *shmseg;
40782657471SMarkus Pfeiffer 	struct shm_handle *handle;
40882657471SMarkus Pfeiffer #if 0
40982657471SMarkus Pfeiffer 	/* It is possible after a process calls exec().
41082657471SMarkus Pfeiffer 	 * We don't create another segment but return the old one
41182657471SMarkus Pfeiffer 	 * with all information.
41282657471SMarkus Pfeiffer 	 * This segment is destroyed only when process dies.
41382657471SMarkus Pfeiffer 	 * */
41482657471SMarkus Pfeiffer 	if (shmget_msg->type == UNDOGET) {
41582657471SMarkus Pfeiffer 		struct client *cl= _hash_lookup(clientshash, pid);
41682657471SMarkus Pfeiffer 		if (cl->undoid != -1)
41782657471SMarkus Pfeiffer 			return cl->undoid;
41882657471SMarkus Pfeiffer 	}
41982657471SMarkus Pfeiffer #endif
42082657471SMarkus Pfeiffer 	if ((long)shmget_msg->size < shminfo.shmmin)
42182657471SMarkus Pfeiffer 			//|| (long)shmget_msg->size > shminfo.shmmax)
42282657471SMarkus Pfeiffer 			/* There is no need to check the max limit,
42382657471SMarkus Pfeiffer 			 * the operating system do this for us.
42482657471SMarkus Pfeiffer 			 */
42582657471SMarkus Pfeiffer 		return (-EINVAL);
42682657471SMarkus Pfeiffer 	if (shm_nused >= shminfo.shmmni) /* any shmids left? */
42782657471SMarkus Pfeiffer 		return (-ENOSPC);
42882657471SMarkus Pfeiffer 
42982657471SMarkus Pfeiffer 	/* Compute the size of the segment. */
43082657471SMarkus Pfeiffer 	size = round_page(shmget_msg->size);
43182657471SMarkus Pfeiffer 
43282657471SMarkus Pfeiffer 	/* Find a free entry in the shmsegs vector. */
43382657471SMarkus Pfeiffer 	if (shm_last_free < 0) {
43482657471SMarkus Pfeiffer 		//	shmrealloc();	/* maybe expand the shmsegs[] array */
43582657471SMarkus Pfeiffer 		for (i = 0; i < shmalloced; i++) {
43682657471SMarkus Pfeiffer 			if (shmsegs[i].shm_perm.mode & SHMSEG_FREE)
43782657471SMarkus Pfeiffer 				break;
43882657471SMarkus Pfeiffer 		}
43982657471SMarkus Pfeiffer 		if (i == shmalloced) {
44082657471SMarkus Pfeiffer 			sysvd_print("i == shmalloced\n");
44182657471SMarkus Pfeiffer 			return (-ENOSPC);
44282657471SMarkus Pfeiffer 		}
44382657471SMarkus Pfeiffer 		segnum = i;
44482657471SMarkus Pfeiffer 	} else  {
44582657471SMarkus Pfeiffer 		segnum = shm_last_free;
44682657471SMarkus Pfeiffer 		shm_last_free = -1;
44782657471SMarkus Pfeiffer 	}
44882657471SMarkus Pfeiffer 	shmseg = &shmsegs[segnum];
44982657471SMarkus Pfeiffer 	/*
45082657471SMarkus Pfeiffer 	 * In case we sleep in malloc(), mark the segment present but deleted
45182657471SMarkus Pfeiffer 	 * so that noone else tries to create the same key.
45282657471SMarkus Pfeiffer 	 */
45382657471SMarkus Pfeiffer 	shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
45482657471SMarkus Pfeiffer 	shmseg->shm_perm.key = shmget_msg->key;
45582657471SMarkus Pfeiffer 	shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;
45682657471SMarkus Pfeiffer 
45782657471SMarkus Pfeiffer 	/* Create the file for the shared memory segment. */
45882657471SMarkus Pfeiffer 	handle = shmseg->shm_internal = malloc(sizeof(struct shm_handle));
45982657471SMarkus Pfeiffer 	handle->type = shmget_msg->type;
46082657471SMarkus Pfeiffer 	handle->fd = create_sysv_file(shmget_msg, size, shmseg);
46182657471SMarkus Pfeiffer 	if (handle->fd == -1) {
46282657471SMarkus Pfeiffer 		free(handle);
46382657471SMarkus Pfeiffer 		handle = NULL;
46482657471SMarkus Pfeiffer 		shmseg->shm_perm.mode = SHMSEG_FREE;
46582657471SMarkus Pfeiffer 		shm_last_free = segnum;
46682657471SMarkus Pfeiffer 		errno = -ENFILE;
46782657471SMarkus Pfeiffer 		return (-1);
46882657471SMarkus Pfeiffer 	}
46982657471SMarkus Pfeiffer 
47082657471SMarkus Pfeiffer 	LIST_INIT(&handle->attached_list);
47182657471SMarkus Pfeiffer 
47282657471SMarkus Pfeiffer 	if (handle->fd < 0) {
47382657471SMarkus Pfeiffer 		free(shmseg->shm_internal);
47482657471SMarkus Pfeiffer 		shmseg->shm_internal = NULL;
47582657471SMarkus Pfeiffer 		shm_last_free = segnum;
47682657471SMarkus Pfeiffer 		shmseg->shm_perm.mode = SHMSEG_FREE;
47782657471SMarkus Pfeiffer 		return (-errno);
47882657471SMarkus Pfeiffer 	}
47982657471SMarkus Pfeiffer 
48082657471SMarkus Pfeiffer 	/* Get the id. */
48182657471SMarkus Pfeiffer 	shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
48282657471SMarkus Pfeiffer 
48382657471SMarkus Pfeiffer 	shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cmcred_euid;
48482657471SMarkus Pfeiffer 	shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cmcred_gid;
48582657471SMarkus Pfeiffer 	shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) |
48682657471SMarkus Pfeiffer 		(mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
48782657471SMarkus Pfeiffer 
48882657471SMarkus Pfeiffer 	shmseg->shm_cpid = pid;
48982657471SMarkus Pfeiffer 	shmseg->shm_lpid = shmseg->shm_nattch = 0;
49082657471SMarkus Pfeiffer 	shmseg->shm_atime = shmseg->shm_dtime = 0;
49182657471SMarkus Pfeiffer 	shmseg->shm_ctime = time(NULL);
49282657471SMarkus Pfeiffer 
49382657471SMarkus Pfeiffer 	shmseg->shm_segsz = shmget_msg->size;
49482657471SMarkus Pfeiffer 	shm_committed += btoc(size);
49582657471SMarkus Pfeiffer 	shm_nused++;
49682657471SMarkus Pfeiffer 
49782657471SMarkus Pfeiffer 	if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
49882657471SMarkus Pfeiffer 		/*
49982657471SMarkus Pfeiffer 		 * Somebody else wanted this key while we were asleep.  Wake
50082657471SMarkus Pfeiffer 		 * them up now.
50182657471SMarkus Pfeiffer 		 */
50282657471SMarkus Pfeiffer 		shmseg->shm_perm.mode &= ~SHMSEG_WANTED;
50382657471SMarkus Pfeiffer 		//TODO multithreading
50482657471SMarkus Pfeiffer 		//wakeup((caddr_t)shmseg);
50582657471SMarkus Pfeiffer 	}
50682657471SMarkus Pfeiffer 	shmseg->shm_perm.mode &= ~SHMSEG_REMOVED;
50782657471SMarkus Pfeiffer 
50882657471SMarkus Pfeiffer 	if (shmget_msg->type == UNDOGET) {
50982657471SMarkus Pfeiffer 		/* The file is used by daemon when clients terminates
51082657471SMarkus Pfeiffer 		 * and sem_undo resources must be cleaned.
51182657471SMarkus Pfeiffer 		 */
51282657471SMarkus Pfeiffer 		struct client *cl= _hash_lookup(clientshash, pid);
51382657471SMarkus Pfeiffer 		cl->undoid = shmid;
51482657471SMarkus Pfeiffer 	}
51582657471SMarkus Pfeiffer 
51682657471SMarkus Pfeiffer 	return (shmid);
51782657471SMarkus Pfeiffer }
51882657471SMarkus Pfeiffer 
51982657471SMarkus Pfeiffer /* Handle a shmget() request. */
52082657471SMarkus Pfeiffer int
handle_shmget(pid_t pid,struct shmget_msg * shmget_msg,struct cmsgcred * cred)52182657471SMarkus Pfeiffer handle_shmget(pid_t pid, struct shmget_msg *shmget_msg,
52282657471SMarkus Pfeiffer 		struct cmsgcred *cred ) {
52382657471SMarkus Pfeiffer 	int segnum, mode, error;
52482657471SMarkus Pfeiffer 	struct shmid_ds *shmseg;
52582657471SMarkus Pfeiffer 	struct shm_handle *handle;
52682657471SMarkus Pfeiffer 
52782657471SMarkus Pfeiffer 	//if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL)
52882657471SMarkus Pfeiffer 	//	return (ENOSYS);
52982657471SMarkus Pfeiffer 	mode = shmget_msg->shmflg & ACCESSPERMS;
53082657471SMarkus Pfeiffer 
53182657471SMarkus Pfeiffer 	sysvd_print("ask for key = %ld\n", shmget_msg->key);
53282657471SMarkus Pfeiffer 	shmget_msg->key = (shmget_msg->key & 0x3FFF) |
53382657471SMarkus Pfeiffer 		(shmget_msg->type << 30);
53482657471SMarkus Pfeiffer 	sysvd_print("ask for key = %ld\n", shmget_msg->key);
53582657471SMarkus Pfeiffer 
53682657471SMarkus Pfeiffer 	if (shmget_msg->key != IPC_PRIVATE) {
53782657471SMarkus Pfeiffer 		//again:
53882657471SMarkus Pfeiffer 		segnum = shm_find_segment_by_key(shmget_msg->key);
53982657471SMarkus Pfeiffer 		if (segnum >= 0) {
54082657471SMarkus Pfeiffer 			error = shmget_existing(shmget_msg, mode, segnum, cred);
54182657471SMarkus Pfeiffer 			//TODO if daemon is multithreading
54282657471SMarkus Pfeiffer 			//if (error == EAGAIN)
54382657471SMarkus Pfeiffer 			//	goto again;
54482657471SMarkus Pfeiffer 			goto done;
54582657471SMarkus Pfeiffer 		}
54682657471SMarkus Pfeiffer 		if ((shmget_msg->shmflg & IPC_CREAT) == 0) {
54782657471SMarkus Pfeiffer 			error = -ENOENT;
54882657471SMarkus Pfeiffer 			goto done_err;
54982657471SMarkus Pfeiffer 		}
55082657471SMarkus Pfeiffer 	}
55182657471SMarkus Pfeiffer 	error = shmget_allocate_segment(pid, shmget_msg, mode, cred);
55282657471SMarkus Pfeiffer 	sysvd_print("allocate segment = %d\n", error);
55382657471SMarkus Pfeiffer done:
55482657471SMarkus Pfeiffer 	/*
55582657471SMarkus Pfeiffer 	 * Install to th client the file corresponding to the
55682657471SMarkus Pfeiffer 	 * shared memory segment.
55782657471SMarkus Pfeiffer 	 * client_fd is the file descriptor added in the client
55882657471SMarkus Pfeiffer 	 * files table.
55982657471SMarkus Pfeiffer 	 */
56082657471SMarkus Pfeiffer 	shmseg = shm_find_segment_by_shmid(error);
56182657471SMarkus Pfeiffer 	if (shmseg == NULL) {
56282657471SMarkus Pfeiffer 		sysvd_print_err("can not find segment by shmid\n");
56382657471SMarkus Pfeiffer 		return (-1);
56482657471SMarkus Pfeiffer 	}
56582657471SMarkus Pfeiffer 
56682657471SMarkus Pfeiffer 	handle = (struct shm_handle *)shmseg->shm_internal;
56782657471SMarkus Pfeiffer 	if (install_fd_client(pid, handle->fd) != 0)
56882657471SMarkus Pfeiffer 		error = errno;
56982657471SMarkus Pfeiffer done_err:
57082657471SMarkus Pfeiffer 	return (error);
57182657471SMarkus Pfeiffer 
57282657471SMarkus Pfeiffer }
57382657471SMarkus Pfeiffer 
57482657471SMarkus Pfeiffer /* Handle a shmat() request. */
57582657471SMarkus Pfeiffer int
handle_shmat(pid_t pid,struct shmat_msg * shmat_msg,struct cmsgcred * cred)57682657471SMarkus Pfeiffer handle_shmat(pid_t pid, struct shmat_msg *shmat_msg,
57782657471SMarkus Pfeiffer 		struct cmsgcred *cred ) {
57882657471SMarkus Pfeiffer 	int error;
57982657471SMarkus Pfeiffer 	int fd;
58082657471SMarkus Pfeiffer 	struct shmid_ds *shmseg;
58182657471SMarkus Pfeiffer 	struct pid_attached *pidatt;
58282657471SMarkus Pfeiffer 	struct shm_handle *handle;
58382657471SMarkus Pfeiffer 	size_t new_size = shmat_msg->size;
58482657471SMarkus Pfeiffer 	struct client *cl;
58582657471SMarkus Pfeiffer 	struct id_attached *idatt;
58682657471SMarkus Pfeiffer 
58782657471SMarkus Pfeiffer 	/*if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL)
58882657471SMarkus Pfeiffer 	  return (ENOSYS);
58982657471SMarkus Pfeiffer 
59082657471SMarkus Pfeiffer again:*/
59182657471SMarkus Pfeiffer 	shmseg = shm_find_segment_by_shmid(shmat_msg->shmid);
59282657471SMarkus Pfeiffer 	if (shmseg == NULL) {
59382657471SMarkus Pfeiffer 		sysvd_print_err("shmat error: segment was not found\n");
59482657471SMarkus Pfeiffer 		error = EINVAL;
59582657471SMarkus Pfeiffer 		goto done;
59682657471SMarkus Pfeiffer 	}
59782657471SMarkus Pfeiffer 	error = ipcperm(cred, &shmseg->shm_perm,
59882657471SMarkus Pfeiffer 			(shmat_msg->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
59982657471SMarkus Pfeiffer 	if (error)
60082657471SMarkus Pfeiffer 		goto done;
60182657471SMarkus Pfeiffer 
60282657471SMarkus Pfeiffer 	handle = shmseg->shm_internal;
60382657471SMarkus Pfeiffer 
60482657471SMarkus Pfeiffer 	if (shmat_msg->size > shmseg->shm_segsz) {
60582657471SMarkus Pfeiffer 		if (handle->type != UNDOGET) {
60682657471SMarkus Pfeiffer 			error = EINVAL;
60782657471SMarkus Pfeiffer 			goto done;
60882657471SMarkus Pfeiffer 		}
60982657471SMarkus Pfeiffer 
61082657471SMarkus Pfeiffer 		fd = ((struct shm_handle*)shmseg->shm_internal)->fd;
61182657471SMarkus Pfeiffer 		ftruncate(fd, round_page(new_size));
61282657471SMarkus Pfeiffer 		shmseg->shm_segsz = new_size;
61382657471SMarkus Pfeiffer 	}
61482657471SMarkus Pfeiffer 
61582657471SMarkus Pfeiffer 	shmseg->shm_lpid = pid;
61682657471SMarkus Pfeiffer 	shmseg->shm_atime = time(NULL);
61782657471SMarkus Pfeiffer 
61882657471SMarkus Pfeiffer 	if (handle->type != UNDOGET)
61982657471SMarkus Pfeiffer 		shmseg->shm_nattch++;
62082657471SMarkus Pfeiffer 	else
62182657471SMarkus Pfeiffer 		shmseg->shm_nattch = 1; /* Only a process calls shmat and
62282657471SMarkus Pfeiffer 		only once. If it does it for more than once that is because
62382657471SMarkus Pfeiffer 		it called exec() and reinitialized the undo segment. */
62482657471SMarkus Pfeiffer 
62582657471SMarkus Pfeiffer 	/* Insert the pid in the segment list of attaced pids.
62682657471SMarkus Pfeiffer 	 * The list is checked in handle_shmdt so that only
62782657471SMarkus Pfeiffer 	 * attached pids can dettached from this segment.
62882657471SMarkus Pfeiffer 	 */
62982657471SMarkus Pfeiffer 	sysvd_print("nattch = %d pid = %d\n",
63082657471SMarkus Pfeiffer 			shmseg->shm_nattch, pid);
63182657471SMarkus Pfeiffer 
63282657471SMarkus Pfeiffer 	pidatt = malloc(sizeof(*pidatt));
63382657471SMarkus Pfeiffer 	pidatt->pid = pid;
63482657471SMarkus Pfeiffer 	LIST_INSERT_HEAD(&handle->attached_list, pidatt, link);
63582657471SMarkus Pfeiffer 
63682657471SMarkus Pfeiffer 	/* Add the segment at the list of attached segments of the client.
63782657471SMarkus Pfeiffer 	 * It is used when the process finishes its execution. The daemon
63882657471SMarkus Pfeiffer 	 * walks through the list to dettach the segments.
63982657471SMarkus Pfeiffer 	 */
64082657471SMarkus Pfeiffer 	idatt = malloc(sizeof(*idatt));
64182657471SMarkus Pfeiffer 	idatt->shmid = shmat_msg->shmid;
64282657471SMarkus Pfeiffer 	cl = _hash_lookup(clientshash, pid);
64382657471SMarkus Pfeiffer 	LIST_INSERT_HEAD(&cl->ids_attached, idatt, link);
64482657471SMarkus Pfeiffer 
64582657471SMarkus Pfeiffer 	return (0);
64682657471SMarkus Pfeiffer done:
64782657471SMarkus Pfeiffer 	return (error);
64882657471SMarkus Pfeiffer }
64982657471SMarkus Pfeiffer 
65082657471SMarkus Pfeiffer /* Handle a shmdt() request. */
65182657471SMarkus Pfeiffer int
handle_shmdt(pid_t pid,int shmid)65282657471SMarkus Pfeiffer handle_shmdt(pid_t pid, int shmid) {
65382657471SMarkus Pfeiffer 	struct shmid_ds *shmseg;
65482657471SMarkus Pfeiffer 	int segnum;
65582657471SMarkus Pfeiffer 	struct shm_handle *handle;
65682657471SMarkus Pfeiffer 	struct pid_attached *pidatt;
65782657471SMarkus Pfeiffer 	struct id_attached *idatt;
65882657471SMarkus Pfeiffer 	struct client *cl;
65982657471SMarkus Pfeiffer 
66082657471SMarkus Pfeiffer 	sysvd_print("shmdt pid %d shmid %d\n", pid, shmid);
66182657471SMarkus Pfeiffer 	/*if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL)
66282657471SMarkus Pfeiffer 	  return (ENOSYS);
66382657471SMarkus Pfeiffer 	*/
66482657471SMarkus Pfeiffer 
66582657471SMarkus Pfeiffer 	segnum = IPCID_TO_IX(shmid);
66682657471SMarkus Pfeiffer 	shmseg = &shmsegs[segnum];
66782657471SMarkus Pfeiffer 	handle = shmseg->shm_internal;
66882657471SMarkus Pfeiffer 
66982657471SMarkus Pfeiffer 	/* Check if pid is attached. */
67082657471SMarkus Pfeiffer 	LIST_FOREACH(pidatt, &handle->attached_list, link)
67182657471SMarkus Pfeiffer 		if (pidatt->pid == pid)
67282657471SMarkus Pfeiffer 			break;
67382657471SMarkus Pfeiffer 	if (!pidatt) {
67482657471SMarkus Pfeiffer 		sysvd_print_err("process %d is not attached to %d (1)\n",
67582657471SMarkus Pfeiffer 				pid, shmid);
67682657471SMarkus Pfeiffer 		return (EINVAL);
67782657471SMarkus Pfeiffer 	}
67882657471SMarkus Pfeiffer 	LIST_REMOVE(pidatt, link);
67982657471SMarkus Pfeiffer 
68082657471SMarkus Pfeiffer 	/* Remove the segment from the list of attached segments of the pid.*/
68182657471SMarkus Pfeiffer 	cl = _hash_lookup(clientshash, pid);
68282657471SMarkus Pfeiffer 	LIST_FOREACH(idatt, &cl->ids_attached, link)
68382657471SMarkus Pfeiffer 		if (idatt->shmid == shmid)
68482657471SMarkus Pfeiffer 			break;
68582657471SMarkus Pfeiffer 	if (!idatt) {
68682657471SMarkus Pfeiffer 		sysvd_print_err("process %d is not attached to %d (2)\n",
68782657471SMarkus Pfeiffer 				pid, shmid);
68882657471SMarkus Pfeiffer 		return (EINVAL);
68982657471SMarkus Pfeiffer 	}
69082657471SMarkus Pfeiffer 	LIST_REMOVE(idatt, link);
69182657471SMarkus Pfeiffer 
69282657471SMarkus Pfeiffer 	shmseg->shm_dtime = time(NULL);
69382657471SMarkus Pfeiffer 
69482657471SMarkus Pfeiffer 	/* If no other process attaced remove the segment. */
69582657471SMarkus Pfeiffer 	if ((--shmseg->shm_nattch <= 0) &&
69682657471SMarkus Pfeiffer 			(shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
69782657471SMarkus Pfeiffer 		shm_deallocate_segment(segnum);
69882657471SMarkus Pfeiffer 		shm_last_free = segnum;
69982657471SMarkus Pfeiffer 	}
70082657471SMarkus Pfeiffer 
70182657471SMarkus Pfeiffer 	return (0);
70282657471SMarkus Pfeiffer }
70382657471SMarkus Pfeiffer 
70482657471SMarkus Pfeiffer /* Handle a shmctl() request. */
70582657471SMarkus Pfeiffer int
handle_shmctl(struct shmctl_msg * shmctl_msg,struct cmsgcred * cred)70682657471SMarkus Pfeiffer handle_shmctl(struct shmctl_msg *shmctl_msg,
70782657471SMarkus Pfeiffer 		struct cmsgcred *cred ) {
70882657471SMarkus Pfeiffer 	int error = 0;
70982657471SMarkus Pfeiffer 	struct shmid_ds *shmseg, *inbuf;
71082657471SMarkus Pfeiffer 
71182657471SMarkus Pfeiffer 	/*	if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL)
71282657471SMarkus Pfeiffer 		return (ENOSYS);
71382657471SMarkus Pfeiffer 		*/
71482657471SMarkus Pfeiffer 	shmseg = shm_find_segment_by_shmid(shmctl_msg->shmid);
71582657471SMarkus Pfeiffer 
71682657471SMarkus Pfeiffer 	if (shmseg == NULL) {
71782657471SMarkus Pfeiffer 		error = EINVAL;
71882657471SMarkus Pfeiffer 		goto done;
71982657471SMarkus Pfeiffer 	}
72082657471SMarkus Pfeiffer 
72182657471SMarkus Pfeiffer 	switch (shmctl_msg->cmd) {
72282657471SMarkus Pfeiffer 		case IPC_STAT:
72382657471SMarkus Pfeiffer 			sysvd_print("IPC STAT\n");
72482657471SMarkus Pfeiffer 			error = ipcperm(cred, &shmseg->shm_perm, IPC_R);
72582657471SMarkus Pfeiffer 			if (error) {
72682657471SMarkus Pfeiffer 				sysvd_print("IPC_STAT not allowed\n");
72782657471SMarkus Pfeiffer 				break;
72882657471SMarkus Pfeiffer 			}
72982657471SMarkus Pfeiffer 			shmctl_msg->buf = *shmseg;
73082657471SMarkus Pfeiffer 			break;
73182657471SMarkus Pfeiffer 		case IPC_SET:
73282657471SMarkus Pfeiffer 			sysvd_print("IPC SET\n");
73382657471SMarkus Pfeiffer 			error = ipcperm(cred, &shmseg->shm_perm, IPC_M);
73482657471SMarkus Pfeiffer 			if (error) {
73582657471SMarkus Pfeiffer 				sysvd_print("IPC_SET not allowed\n");
73682657471SMarkus Pfeiffer 				break;
73782657471SMarkus Pfeiffer 			}
73882657471SMarkus Pfeiffer 			inbuf = &shmctl_msg->buf;
73982657471SMarkus Pfeiffer 
74082657471SMarkus Pfeiffer 			shmseg->shm_perm.uid = inbuf->shm_perm.uid;
74182657471SMarkus Pfeiffer 			shmseg->shm_perm.gid = inbuf->shm_perm.gid;
74282657471SMarkus Pfeiffer 			shmseg->shm_perm.mode =
74382657471SMarkus Pfeiffer 				(shmseg->shm_perm.mode & ~ACCESSPERMS) |
74482657471SMarkus Pfeiffer 				(inbuf->shm_perm.mode & ACCESSPERMS);
74582657471SMarkus Pfeiffer 			shmseg->shm_ctime = time(NULL);
74682657471SMarkus Pfeiffer 			break;
74782657471SMarkus Pfeiffer 		case IPC_RMID:
74882657471SMarkus Pfeiffer 			sysvd_print("IPC RMID shmid = %d\n",
74982657471SMarkus Pfeiffer 					shmctl_msg->shmid);
75082657471SMarkus Pfeiffer 			error = ipcperm(cred, &shmseg->shm_perm, IPC_M);
75182657471SMarkus Pfeiffer 			if (error) {
75282657471SMarkus Pfeiffer 				sysvd_print("IPC_RMID not allowed\n");
75382657471SMarkus Pfeiffer 				break;
75482657471SMarkus Pfeiffer 			}
75582657471SMarkus Pfeiffer 			shmseg->shm_perm.key = IPC_PRIVATE;
75682657471SMarkus Pfeiffer 			shmseg->shm_perm.mode |= SHMSEG_REMOVED;
75782657471SMarkus Pfeiffer 			if (shmseg->shm_nattch <= 0) {
75882657471SMarkus Pfeiffer 				shm_deallocate_segment(IPCID_TO_IX(shmctl_msg->shmid));
75982657471SMarkus Pfeiffer 				shm_last_free = IPCID_TO_IX(shmctl_msg->shmid);
76082657471SMarkus Pfeiffer 			}
76182657471SMarkus Pfeiffer 			else {
76282657471SMarkus Pfeiffer 				/* In sem and msg cases, other process must be
76382657471SMarkus Pfeiffer 				 * noticed about the removal. */
76482657471SMarkus Pfeiffer 				struct shm_handle *internal =
76582657471SMarkus Pfeiffer 					(struct shm_handle *)shmseg->shm_internal;
76682657471SMarkus Pfeiffer 				mark_segment_removed(shmctl_msg->shmid,
76782657471SMarkus Pfeiffer 						internal->type);
76882657471SMarkus Pfeiffer 			}
76982657471SMarkus Pfeiffer 			break;
77082657471SMarkus Pfeiffer #if 0
77182657471SMarkus Pfeiffer 		case SHM_LOCK:
77282657471SMarkus Pfeiffer 		case SHM_UNLOCK:
77382657471SMarkus Pfeiffer #endif
77482657471SMarkus Pfeiffer 		default:
77582657471SMarkus Pfeiffer 			error = EINVAL;
77682657471SMarkus Pfeiffer 			break;
77782657471SMarkus Pfeiffer 	}
77882657471SMarkus Pfeiffer done:
77982657471SMarkus Pfeiffer 	return (error);
78082657471SMarkus Pfeiffer 
78182657471SMarkus Pfeiffer }
78282657471SMarkus Pfeiffer 
78382657471SMarkus Pfeiffer /* Function used by daemon to map a sysv resource. */
78482657471SMarkus Pfeiffer static void *
map_seg(int shmid)78582657471SMarkus Pfeiffer map_seg(int shmid) {
78682657471SMarkus Pfeiffer 	struct shmid_ds *shmseg;
78782657471SMarkus Pfeiffer 	struct shm_handle *internal;
78882657471SMarkus Pfeiffer 
78982657471SMarkus Pfeiffer 	int fd;
79082657471SMarkus Pfeiffer 	size_t size;
79182657471SMarkus Pfeiffer 	void *addr;
79282657471SMarkus Pfeiffer 
79382657471SMarkus Pfeiffer 	shmseg = shm_find_segment_by_shmid(shmid);
79482657471SMarkus Pfeiffer 	if (!shmseg) {
79582657471SMarkus Pfeiffer 		sysvd_print_err("map_seg error:"
79682657471SMarkus Pfeiffer 				"semid %d not found\n", shmid);
79782657471SMarkus Pfeiffer 		return (NULL);
79882657471SMarkus Pfeiffer 	}
79982657471SMarkus Pfeiffer 
80082657471SMarkus Pfeiffer 	internal = (struct shm_handle *)shmseg->shm_internal;
80182657471SMarkus Pfeiffer 	if (!internal) {
80282657471SMarkus Pfeiffer 		sysvd_print_err("map_seg error: internal for"
80382657471SMarkus Pfeiffer 				"semid %d not found\n", shmid);
80482657471SMarkus Pfeiffer 		return (NULL);
80582657471SMarkus Pfeiffer 	}
80682657471SMarkus Pfeiffer 
80782657471SMarkus Pfeiffer 	fd = internal->fd;
80882657471SMarkus Pfeiffer 
80982657471SMarkus Pfeiffer 	size = round_page(shmseg->shm_segsz);
81082657471SMarkus Pfeiffer 
81182657471SMarkus Pfeiffer 	addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
81282657471SMarkus Pfeiffer 	if (!addr) {
81382657471SMarkus Pfeiffer 		sysvd_print_err("map_seg: error mmap semid = %d\n", shmid);
81482657471SMarkus Pfeiffer 		return (NULL);
81582657471SMarkus Pfeiffer 	}
81682657471SMarkus Pfeiffer 
81782657471SMarkus Pfeiffer 	return (addr);
81882657471SMarkus Pfeiffer }
81982657471SMarkus Pfeiffer 
82082657471SMarkus Pfeiffer /* Function used by daemon to munmap a sysv resource. */
82182657471SMarkus Pfeiffer static int
munmap_seg(int shmid,void * addr)82282657471SMarkus Pfeiffer munmap_seg(int shmid, void *addr) {
82382657471SMarkus Pfeiffer 	struct shmid_ds *shmseg;
82482657471SMarkus Pfeiffer 	struct shm_handle *internal;
82582657471SMarkus Pfeiffer 
82682657471SMarkus Pfeiffer 	size_t size;
82782657471SMarkus Pfeiffer 
82882657471SMarkus Pfeiffer 	shmseg = shm_find_segment_by_shmid(shmid);
82982657471SMarkus Pfeiffer 	if (!shmseg) {
83082657471SMarkus Pfeiffer 		sysvd_print_err("munmap_seg error:"
83182657471SMarkus Pfeiffer 				"semid %d not found\n", shmid);
83282657471SMarkus Pfeiffer 		return (-1);
83382657471SMarkus Pfeiffer 	}
83482657471SMarkus Pfeiffer 
83582657471SMarkus Pfeiffer 	internal = (struct shm_handle *)shmseg->shm_internal;
83682657471SMarkus Pfeiffer 	if (!internal) {
83782657471SMarkus Pfeiffer 		sysvd_print_err("munmap_seg error: internal for"
83882657471SMarkus Pfeiffer 				"semid %d not found\n", shmid);
83982657471SMarkus Pfeiffer 		return (-1);
84082657471SMarkus Pfeiffer 	}
84182657471SMarkus Pfeiffer 
84282657471SMarkus Pfeiffer 	size = round_page(shmseg->shm_segsz);
84382657471SMarkus Pfeiffer 	munmap(addr, size);
84482657471SMarkus Pfeiffer 
84582657471SMarkus Pfeiffer 	return (0);
84682657471SMarkus Pfeiffer }
84782657471SMarkus Pfeiffer 
84882657471SMarkus Pfeiffer void
shminit(void)84982657471SMarkus Pfeiffer shminit(void) {
85082657471SMarkus Pfeiffer 	int i;
85182657471SMarkus Pfeiffer 
85282657471SMarkus Pfeiffer 	shmalloced = shminfo.shmmni;
85382657471SMarkus Pfeiffer 	shmsegs = malloc(shmalloced * sizeof(shmsegs[0]));
85482657471SMarkus Pfeiffer 	for (i = 0; i < shmalloced; i++) {
85582657471SMarkus Pfeiffer 		shmsegs[i].shm_perm.mode = SHMSEG_FREE;
85682657471SMarkus Pfeiffer 		shmsegs[i].shm_perm.seq = 0;
85782657471SMarkus Pfeiffer 	}
85882657471SMarkus Pfeiffer 	shm_last_free = 0;
85982657471SMarkus Pfeiffer 	shm_nused = 0;
86082657471SMarkus Pfeiffer 	shm_committed = 0;
86182657471SMarkus Pfeiffer 
86282657471SMarkus Pfeiffer 	/*
86382657471SMarkus Pfeiffer 	 * msginfo.msgssz should be a power of two for efficiency reasons.
86482657471SMarkus Pfeiffer 	 * It is also pretty silly if msginfo.msgssz is less than 8
86582657471SMarkus Pfeiffer 	 * or greater than about 256 so ...
86682657471SMarkus Pfeiffer 	 */
86782657471SMarkus Pfeiffer 	i = 8;
86882657471SMarkus Pfeiffer 	while (i < 1024 && i != msginfo.msgssz)
86982657471SMarkus Pfeiffer 		i <<= 1;
87082657471SMarkus Pfeiffer 	if (i != msginfo.msgssz) {
87182657471SMarkus Pfeiffer 		sysvd_print_err("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
87282657471SMarkus Pfeiffer 		    msginfo.msgssz);
87382657471SMarkus Pfeiffer 		sysvd_print_err("msginfo.msgssz not a small power of 2");
87482657471SMarkus Pfeiffer 		exit(-1);
87582657471SMarkus Pfeiffer 	}
87682657471SMarkus Pfeiffer 	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
87782657471SMarkus Pfeiffer }
87882657471SMarkus Pfeiffer 
87982657471SMarkus Pfeiffer /*static void
88082657471SMarkus Pfeiffer shmfree(void) {
88182657471SMarkus Pfeiffer 	free(shmsegs);
88282657471SMarkus Pfeiffer }*/
88382657471SMarkus Pfeiffer 
88482657471SMarkus Pfeiffer int
semexit(int undoid)88582657471SMarkus Pfeiffer semexit(int undoid) {
88682657471SMarkus Pfeiffer 	struct sem_undo *suptr;
88782657471SMarkus Pfeiffer 	struct sem *semptr;
88882657471SMarkus Pfeiffer 	struct shmid_ds *undoseg;
88982657471SMarkus Pfeiffer 
89082657471SMarkus Pfeiffer 	if (undoid < 0) {
89182657471SMarkus Pfeiffer 		return (-1);
89282657471SMarkus Pfeiffer 	}
89382657471SMarkus Pfeiffer 
89482657471SMarkus Pfeiffer 	undoseg = shm_find_segment_by_shmid(undoid);
89582657471SMarkus Pfeiffer 	/* The UNDO segment must be mapped by only one segment. */
89682657471SMarkus Pfeiffer 	if (undoseg->shm_nattch != 1) {
89782657471SMarkus Pfeiffer 		sysvd_print_err("undo segment mapped by more"
89882657471SMarkus Pfeiffer 				"than one process\n");
89982657471SMarkus Pfeiffer 		exit(-1);
90082657471SMarkus Pfeiffer 	}
90182657471SMarkus Pfeiffer 
90282657471SMarkus Pfeiffer 	suptr = (struct sem_undo *)map_seg(undoid);
90382657471SMarkus Pfeiffer 	if (suptr == NULL) {
90482657471SMarkus Pfeiffer 		sysvd_print_err("no %d undo segment found\n", undoid);
90582657471SMarkus Pfeiffer 		return (-1);
90682657471SMarkus Pfeiffer 	}
90782657471SMarkus Pfeiffer 
90882657471SMarkus Pfeiffer 	/* No locking mechanism is required because only the
90982657471SMarkus Pfeiffer 	 * client and the daemon can access the UNDO segment.
91082657471SMarkus Pfeiffer 	 * At this moment the client is disconnected so only
91182657471SMarkus Pfeiffer 	 * the daemon can modify this segment.
91282657471SMarkus Pfeiffer 	 */
91382657471SMarkus Pfeiffer 	while (suptr->un_cnt) {
91482657471SMarkus Pfeiffer 		struct semid_pool *semaptr;
91582657471SMarkus Pfeiffer 		int semid;
91682657471SMarkus Pfeiffer 		int semnum;
91782657471SMarkus Pfeiffer 		int adjval;
91882657471SMarkus Pfeiffer 		int ix;
91982657471SMarkus Pfeiffer 
92082657471SMarkus Pfeiffer 		ix = suptr->un_cnt - 1;
92182657471SMarkus Pfeiffer 		semid = suptr->un_ent[ix].un_id;
92282657471SMarkus Pfeiffer 		semnum = suptr->un_ent[ix].un_num;
92382657471SMarkus Pfeiffer 		adjval = suptr->un_ent[ix].un_adjval;
92482657471SMarkus Pfeiffer 
92582657471SMarkus Pfeiffer 		semaptr = (struct semid_pool *)map_seg(semid);
92682657471SMarkus Pfeiffer 		if (!semaptr) {
92782657471SMarkus Pfeiffer 			return (-1);
92882657471SMarkus Pfeiffer 		}
92982657471SMarkus Pfeiffer 
93082657471SMarkus Pfeiffer 		/* Was it removed? */
93182657471SMarkus Pfeiffer 		if (semaptr->gen == -1 ||
93282657471SMarkus Pfeiffer 			semaptr->ds.sem_perm.seq != IPCID_TO_SEQ(semid) ||
93382657471SMarkus Pfeiffer 			(semaptr->ds.sem_perm.mode & SHMSEG_ALLOCATED) == 0) {
93482657471SMarkus Pfeiffer 			--suptr->un_cnt;
93582657471SMarkus Pfeiffer 			sysvd_print_err("semexit - semid not allocated\n");
93682657471SMarkus Pfeiffer 			continue;
93782657471SMarkus Pfeiffer 		}
93882657471SMarkus Pfeiffer 		if (semnum >= semaptr->ds.sem_nsems) {
93982657471SMarkus Pfeiffer 			--suptr->un_cnt;
94082657471SMarkus Pfeiffer 			sysvd_print_err("semexit - semnum out of range\n");
94182657471SMarkus Pfeiffer 			continue;
94282657471SMarkus Pfeiffer 		}
94382657471SMarkus Pfeiffer 
94482657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
94582657471SMarkus Pfeiffer #ifdef SYSV_SEMS
94682657471SMarkus Pfeiffer 		sysv_rwlock_rdlock(&semaptr->rwlock);
94782657471SMarkus Pfeiffer #else
94882657471SMarkus Pfeiffer 		sysv_rwlock_wrlock(&semaptr->rwlock);
94982657471SMarkus Pfeiffer #endif //SYSV_SEMS
95082657471SMarkus Pfeiffer #else
95182657471SMarkus Pfeiffer 		sysv_mutex_lock(&semaptr->mutex);
95282657471SMarkus Pfeiffer 		/* Nobody can remove the semaphore beteen the check and the
95382657471SMarkus Pfeiffer 		 * lock acquisition because it must first send a IPC_RMID
95482657471SMarkus Pfeiffer 		 * to me and I will process that after finishing this function.
95582657471SMarkus Pfeiffer 		 */
95682657471SMarkus Pfeiffer #endif //SYSV_RWLOCK
95782657471SMarkus Pfeiffer 		semptr = &semaptr->ds.sem_base[semnum];
95882657471SMarkus Pfeiffer #ifdef SYSV_SEMS
95982657471SMarkus Pfeiffer 		sysv_mutex_lock(&semptr->sem_mutex);
96082657471SMarkus Pfeiffer #endif
96182657471SMarkus Pfeiffer 		if (ix == suptr->un_cnt - 1 &&
96282657471SMarkus Pfeiffer 		    semid == suptr->un_ent[ix].un_id &&
96382657471SMarkus Pfeiffer 		    semnum == suptr->un_ent[ix].un_num &&
96482657471SMarkus Pfeiffer 		    adjval == suptr->un_ent[ix].un_adjval) {
96582657471SMarkus Pfeiffer 			--suptr->un_cnt;
96682657471SMarkus Pfeiffer 
96782657471SMarkus Pfeiffer 			if (adjval < 0) {
96882657471SMarkus Pfeiffer 				if (semptr->semval < -adjval)
96982657471SMarkus Pfeiffer 					semptr->semval = 0;
97082657471SMarkus Pfeiffer 				else
97182657471SMarkus Pfeiffer 					semptr->semval += adjval;
97282657471SMarkus Pfeiffer 			} else {
97382657471SMarkus Pfeiffer 				semptr->semval += adjval;
97482657471SMarkus Pfeiffer 			}
97582657471SMarkus Pfeiffer 			/* TODO multithreaded daemon:
97682657471SMarkus Pfeiffer 			 * Check again if the semaphore was removed and do
97782657471SMarkus Pfeiffer 			 * not wake anyone if it was.*/
97882657471SMarkus Pfeiffer 			umtx_wakeup((int *)&semptr->semval, 0);
97982657471SMarkus Pfeiffer 		}
98082657471SMarkus Pfeiffer #ifdef SYSV_SEMS
98182657471SMarkus Pfeiffer 		sysv_mutex_unlock(&semptr->sem_mutex);
98282657471SMarkus Pfeiffer #endif
98382657471SMarkus Pfeiffer 
98482657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
98582657471SMarkus Pfeiffer 		sysv_rwlock_unlock(&semaptr->rwlock);
98682657471SMarkus Pfeiffer #else
98782657471SMarkus Pfeiffer 		sysv_mutex_unlock(&semaptr->mutex);
98882657471SMarkus Pfeiffer #endif
98982657471SMarkus Pfeiffer 		munmap_seg(semid, semaptr);
99082657471SMarkus Pfeiffer 	}
99182657471SMarkus Pfeiffer 
99282657471SMarkus Pfeiffer 	munmap_seg(undoid, suptr);
99382657471SMarkus Pfeiffer 	return (0);
99482657471SMarkus Pfeiffer }
99582657471SMarkus Pfeiffer 
99682657471SMarkus Pfeiffer void
shmexit(struct client * cl)99782657471SMarkus Pfeiffer shmexit(struct client *cl) {
99882657471SMarkus Pfeiffer 	struct id_attached *idatt;
99982657471SMarkus Pfeiffer 
100082657471SMarkus Pfeiffer 	while (!LIST_EMPTY(&cl->ids_attached)) {
100182657471SMarkus Pfeiffer 		idatt = LIST_FIRST(&cl->ids_attached);
100282657471SMarkus Pfeiffer 		handle_shmdt(cl->pid, idatt->shmid);
100382657471SMarkus Pfeiffer 	}
100482657471SMarkus Pfeiffer }
1005