1/*-
2 * SPDX-License-Identifier: BSD-4-Clause
3 *
4 * Copyright (c) 1994 Adam Glass
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Adam Glass.
18 * 4. The name of the Author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL Adam Glass BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38#include <sys/param.h>
39#define	_WANT_SYSVMSG_INTERNALS
40#include <sys/msg.h>
41#define	_WANT_SYSVSEM_INTERNALS
42#define	_WANT_SEMUN
43#include <sys/sem.h>
44#define	_WANT_SYSVSHM_INTERNALS
45#include <sys/shm.h>
46
47#include <ctype.h>
48#include <err.h>
49#include <grp.h>
50#include <kvm.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <unistd.h>
54
55#include "ipc.h"
56
57static int	signaled;
58static int	errflg;
59static int	rmverbose = 0;
60
61static void
62usage(void)
63{
64
65	fprintf(stderr,
66	    "usage: ipcrm [-W] [-v[v]]\n"
67	    "             [-q msqid] [-m shmid] [-s semid]\n"
68	    "             [-Q msgkey] [-M shmkey] [-S semkey] ...\n");
69	exit(1);
70}
71
72static int
73msgrm(key_t key, int id)
74{
75
76	if (key == -1 || id == -1) {
77		struct msqid_kernel *kxmsqids;
78		size_t kxmsqids_len;
79		int num;
80
81		kget(X_MSGINFO, &msginfo, sizeof(msginfo));
82		kxmsqids_len = sizeof(struct msqid_kernel) * msginfo.msgmni;
83		kxmsqids = malloc(kxmsqids_len);
84		kget(X_MSQIDS, kxmsqids, kxmsqids_len);
85		num = msginfo.msgmni;
86		while (num-- && !signaled)
87			if (kxmsqids[num].u.msg_qbytes != 0) {
88				id = IXSEQ_TO_IPCID(num,
89					kxmsqids[num].u.msg_perm);
90				if (msgctl(id, IPC_RMID, NULL) < 0) {
91					if (rmverbose > 1)
92						warn("msqid(%d): ", id);
93					errflg++;
94				} else
95					if (rmverbose)
96						printf(
97						    "Removed %s %d\n",
98						    IPC_TO_STRING('Q'),
99						    id);
100			}
101		return signaled ? -1 : 0;       /* errors maybe handled above */
102	}
103
104	if (key) {
105		id = msgget(key, 0);
106		if (id == -1)
107			return -1;
108	}
109
110	return msgctl(id, IPC_RMID, NULL);
111}
112
113static int
114shmrm(key_t key, int id)
115{
116
117	if (key == -1 || id == -1) {
118		struct shmid_kernel *kxshmids;
119		size_t kxshmids_len;
120		int num;
121
122		kget(X_SHMINFO, &shminfo, sizeof(shminfo));
123		kxshmids_len = sizeof(struct shmid_kernel) * shminfo.shmmni;
124		kxshmids = malloc(kxshmids_len);
125		kget(X_SHMSEGS, kxshmids, kxshmids_len);
126		num = shminfo.shmmni;
127		while (num-- && !signaled)
128			if (kxshmids[num].u.shm_perm.mode & 0x0800) {
129				id = IXSEQ_TO_IPCID(num,
130					kxshmids[num].u.shm_perm);
131				if (shmctl(id, IPC_RMID, NULL) < 0) {
132					if (rmverbose > 1)
133						warn("shmid(%d): ", id);
134					errflg++;
135				} else
136					if (rmverbose)
137						printf(
138						    "Removed %s %d\n",
139						    IPC_TO_STRING('M'),
140						    id);
141			}
142		return signaled ? -1 : 0;       /* errors maybe handled above */
143	}
144
145	if (key) {
146		id = shmget(key, 0, 0);
147		if (id == -1)
148			return -1;
149	}
150
151	return shmctl(id, IPC_RMID, NULL);
152}
153
154static int
155semrm(key_t key, int id)
156{
157	union semun arg;
158
159	if (key == -1 || id == -1) {
160		struct semid_kernel *kxsema;
161		size_t kxsema_len;
162		int num;
163
164		kget(X_SEMINFO, &seminfo, sizeof(seminfo));
165		kxsema_len = sizeof(struct semid_kernel) * seminfo.semmni;
166		kxsema = malloc(kxsema_len);
167		kget(X_SEMA, kxsema, kxsema_len);
168		num = seminfo.semmni;
169		while (num-- && !signaled)
170			if ((kxsema[num].u.sem_perm.mode & SEM_ALLOC) != 0) {
171				id = IXSEQ_TO_IPCID(num,
172					kxsema[num].u.sem_perm);
173				if (semctl(id, 0, IPC_RMID, NULL) < 0) {
174					if (rmverbose > 1)
175						warn("semid(%d): ", id);
176					errflg++;
177				} else
178					if (rmverbose)
179						printf(
180						    "Removed %s %d\n",
181						    IPC_TO_STRING('S'),
182						    id);
183			}
184		return signaled ? -1 : 0;       /* errors maybe handled above */
185	}
186
187	if (key) {
188		id = semget(key, 0, 0);
189		if (id == -1)
190			return -1;
191	}
192
193	return semctl(id, 0, IPC_RMID, arg);
194}
195
196static void
197not_configured(int signo __unused)
198{
199
200	signaled++;
201}
202
203int
204main(int argc, char *argv[])
205{
206	int c, result, target_id;
207	key_t target_key;
208
209	while ((c = getopt(argc, argv, "q:m:s:Q:M:S:vWy")) != -1) {
210
211		signaled = 0;
212		switch (c) {
213		case 'v':
214			rmverbose++;
215			break;
216		case 'y':
217			use_sysctl = 0;
218			break;
219		}
220	}
221
222	optind = 1;
223	errflg = 0;
224	signal(SIGSYS, not_configured);
225	while ((c = getopt(argc, argv, "q:m:s:Q:M:S:vWy")) != -1) {
226
227		signaled = 0;
228		switch (c) {
229		case 'q':
230		case 'm':
231		case 's':
232			target_id = atoi(optarg);
233			if (c == 'q')
234				result = msgrm(0, target_id);
235			else if (c == 'm')
236				result = shmrm(0, target_id);
237			else
238				result = semrm(0, target_id);
239			if (result < 0) {
240				errflg++;
241				if (!signaled)
242					warn("%sid(%d): ",
243					    IPC_TO_STR(toupper(c)), target_id);
244				else
245					warnx(
246					    "%ss are not configured "
247					    "in the running kernel",
248					    IPC_TO_STRING(toupper(c)));
249			}
250			break;
251		case 'Q':
252		case 'M':
253		case 'S':
254			target_key = atol(optarg);
255			if (target_key == IPC_PRIVATE) {
256				warnx("can't remove private %ss",
257				    IPC_TO_STRING(c));
258				continue;
259			}
260			if (c == 'Q')
261				result = msgrm(target_key, 0);
262			else if (c == 'M')
263				result = shmrm(target_key, 0);
264			else
265				result = semrm(target_key, 0);
266			if (result < 0) {
267				errflg++;
268				if (!signaled)
269					warn("%ss(%ld): ",
270					    IPC_TO_STR(c), target_key);
271				else
272					warnx("%ss are not configured "
273					    "in the running kernel",
274					    IPC_TO_STRING(c));
275			}
276			break;
277		case 'v':
278		case 'y':
279			/* Handled in other getopt() loop */
280			break;
281		case 'W':
282			msgrm(-1, 0);
283			shmrm(-1, 0);
284			semrm(-1, 0);
285			break;
286		case ':':
287			fprintf(stderr,
288			    "option -%c requires an argument\n", optopt);
289			usage();
290		case '?':
291			fprintf(stderr, "unrecognized option: -%c\n", optopt);
292			usage();
293		}
294	}
295
296	if (optind != argc) {
297		fprintf(stderr, "unknown argument: %s\n", argv[optind]);
298		usage();
299	}
300	exit(errflg);
301}
302