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/param.h>
36#define	_WANT_SYSVMSG_INTERNALS
37#include <sys/msg.h>
38#define	_WANT_SYSVSEM_INTERNALS
39#define	_WANT_SEMUN
40#include <sys/sem.h>
41#define	_WANT_SYSVSHM_INTERNALS
42#include <sys/shm.h>
43
44#include <ctype.h>
45#include <err.h>
46#include <grp.h>
47#include <kvm.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <unistd.h>
51
52#include "ipc.h"
53
54static int	signaled;
55static int	errflg;
56static int	rmverbose = 0;
57
58static void
59usage(void)
60{
61
62	fprintf(stderr,
63	    "usage: ipcrm [-W] [-v[v]]\n"
64	    "             [-q msqid] [-m shmid] [-s semid]\n"
65	    "             [-Q msgkey] [-M shmkey] [-S semkey] ...\n");
66	exit(1);
67}
68
69static int
70msgrm(key_t key, int id)
71{
72
73	if (key == -1 || id == -1) {
74		struct msqid_kernel *kxmsqids;
75		size_t kxmsqids_len;
76		int num;
77
78		kget(X_MSGINFO, &msginfo, sizeof(msginfo));
79		kxmsqids_len = sizeof(struct msqid_kernel) * msginfo.msgmni;
80		kxmsqids = malloc(kxmsqids_len);
81		kget(X_MSQIDS, kxmsqids, kxmsqids_len);
82		num = msginfo.msgmni;
83		while (num-- && !signaled)
84			if (kxmsqids[num].u.msg_qbytes != 0) {
85				id = IXSEQ_TO_IPCID(num,
86					kxmsqids[num].u.msg_perm);
87				if (msgctl(id, IPC_RMID, NULL) < 0) {
88					if (rmverbose > 1)
89						warn("msqid(%d): ", id);
90					errflg++;
91				} else
92					if (rmverbose)
93						printf(
94						    "Removed %s %d\n",
95						    IPC_TO_STRING('Q'),
96						    id);
97			}
98		return signaled ? -1 : 0;       /* errors maybe handled above */
99	}
100
101	if (key) {
102		id = msgget(key, 0);
103		if (id == -1)
104			return -1;
105	}
106
107	return msgctl(id, IPC_RMID, NULL);
108}
109
110static int
111shmrm(key_t key, int id)
112{
113
114	if (key == -1 || id == -1) {
115		struct shmid_kernel *kxshmids;
116		size_t kxshmids_len;
117		int num;
118
119		kget(X_SHMINFO, &shminfo, sizeof(shminfo));
120		kxshmids_len = sizeof(struct shmid_kernel) * shminfo.shmmni;
121		kxshmids = malloc(kxshmids_len);
122		kget(X_SHMSEGS, kxshmids, kxshmids_len);
123		num = shminfo.shmmni;
124		while (num-- && !signaled)
125			if (kxshmids[num].u.shm_perm.mode & 0x0800) {
126				id = IXSEQ_TO_IPCID(num,
127					kxshmids[num].u.shm_perm);
128				if (shmctl(id, IPC_RMID, NULL) < 0) {
129					if (rmverbose > 1)
130						warn("shmid(%d): ", id);
131					errflg++;
132				} else
133					if (rmverbose)
134						printf(
135						    "Removed %s %d\n",
136						    IPC_TO_STRING('M'),
137						    id);
138			}
139		return signaled ? -1 : 0;       /* errors maybe handled above */
140	}
141
142	if (key) {
143		id = shmget(key, 0, 0);
144		if (id == -1)
145			return -1;
146	}
147
148	return shmctl(id, IPC_RMID, NULL);
149}
150
151static int
152semrm(key_t key, int id)
153{
154	union semun arg;
155
156	if (key == -1 || id == -1) {
157		struct semid_kernel *kxsema;
158		size_t kxsema_len;
159		int num;
160
161		kget(X_SEMINFO, &seminfo, sizeof(seminfo));
162		kxsema_len = sizeof(struct semid_kernel) * seminfo.semmni;
163		kxsema = malloc(kxsema_len);
164		kget(X_SEMA, kxsema, kxsema_len);
165		num = seminfo.semmni;
166		while (num-- && !signaled)
167			if ((kxsema[num].u.sem_perm.mode & SEM_ALLOC) != 0) {
168				id = IXSEQ_TO_IPCID(num,
169					kxsema[num].u.sem_perm);
170				if (semctl(id, 0, IPC_RMID, NULL) < 0) {
171					if (rmverbose > 1)
172						warn("semid(%d): ", id);
173					errflg++;
174				} else
175					if (rmverbose)
176						printf(
177						    "Removed %s %d\n",
178						    IPC_TO_STRING('S'),
179						    id);
180			}
181		return signaled ? -1 : 0;       /* errors maybe handled above */
182	}
183
184	if (key) {
185		id = semget(key, 0, 0);
186		if (id == -1)
187			return -1;
188	}
189
190	return semctl(id, 0, IPC_RMID, arg);
191}
192
193static void
194not_configured(int signo __unused)
195{
196
197	signaled++;
198}
199
200int
201main(int argc, char *argv[])
202{
203	int c, result, target_id;
204	key_t target_key;
205
206	while ((c = getopt(argc, argv, "q:m:s:Q:M:S:vWy")) != -1) {
207
208		signaled = 0;
209		switch (c) {
210		case 'v':
211			rmverbose++;
212			break;
213		case 'y':
214			use_sysctl = 0;
215			break;
216		}
217	}
218
219	optind = 1;
220	errflg = 0;
221	signal(SIGSYS, not_configured);
222	while ((c = getopt(argc, argv, "q:m:s:Q:M:S:vWy")) != -1) {
223
224		signaled = 0;
225		switch (c) {
226		case 'q':
227		case 'm':
228		case 's':
229			target_id = atoi(optarg);
230			if (c == 'q')
231				result = msgrm(0, target_id);
232			else if (c == 'm')
233				result = shmrm(0, target_id);
234			else
235				result = semrm(0, target_id);
236			if (result < 0) {
237				errflg++;
238				if (!signaled)
239					warn("%sid(%d): ",
240					    IPC_TO_STR(toupper(c)), target_id);
241				else
242					warnx(
243					    "%ss are not configured "
244					    "in the running kernel",
245					    IPC_TO_STRING(toupper(c)));
246			}
247			break;
248		case 'Q':
249		case 'M':
250		case 'S':
251			target_key = atol(optarg);
252			if (target_key == IPC_PRIVATE) {
253				warnx("can't remove private %ss",
254				    IPC_TO_STRING(c));
255				continue;
256			}
257			if (c == 'Q')
258				result = msgrm(target_key, 0);
259			else if (c == 'M')
260				result = shmrm(target_key, 0);
261			else
262				result = semrm(target_key, 0);
263			if (result < 0) {
264				errflg++;
265				if (!signaled)
266					warn("%ss(%ld): ",
267					    IPC_TO_STR(c), target_key);
268				else
269					warnx("%ss are not configured "
270					    "in the running kernel",
271					    IPC_TO_STRING(c));
272			}
273			break;
274		case 'v':
275		case 'y':
276			/* Handled in other getopt() loop */
277			break;
278		case 'W':
279			msgrm(-1, 0);
280			shmrm(-1, 0);
281			semrm(-1, 0);
282			break;
283		case ':':
284			fprintf(stderr,
285			    "option -%c requires an argument\n", optopt);
286			usage();
287		case '?':
288			fprintf(stderr, "unrecognized option: -%c\n", optopt);
289			usage();
290		}
291	}
292
293	if (optind != argc) {
294		fprintf(stderr, "unknown argument: %s\n", argv[optind]);
295		usage();
296	}
297	exit(errflg);
298}
299