xref: /freebsd/usr.bin/ipcrm/ipcrm.c (revision 0957b409)
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 
57 static int	signaled;
58 static int	errflg;
59 static int	rmverbose = 0;
60 
61 static void
62 usage(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 
72 static int
73 msgrm(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 
113 static int
114 shmrm(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 
154 static int
155 semrm(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 
196 static void
197 not_configured(int signo __unused)
198 {
199 
200 	signaled++;
201 }
202 
203 int
204 main(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