summaryrefslogtreecommitdiffstats
path: root/usr.bin/ipcrm
diff options
context:
space:
mode:
authoredwin <edwin@FreeBSD.org>2007-12-25 00:52:24 +0000
committeredwin <edwin@FreeBSD.org>2007-12-25 00:52:24 +0000
commit3919ec2a104ff1b906ac9caa645afdabee1603f4 (patch)
treedf314cf1e2b139b48eb3dccaa2a77b25fa0d855f /usr.bin/ipcrm
parent75cfd086294c36db6dac8e29de531e727e07185d (diff)
downloadFreeBSD-src-3919ec2a104ff1b906ac9caa645afdabee1603f4.zip
FreeBSD-src-3919ec2a104ff1b906ac9caa645afdabee1603f4.tar.gz
Add the ability to clean up all shared memory segments which are
unused in one go. From the original PR: I've observed that linux apps running under the linuxulator have a habit of leaving behind shared memory segments which are unused, but which eventually cause the system to run out of free segments and these apps will stop working. ipcrm(1) currently only allows removal of unused message queues, shared memory segments and semaphores on an individual basis, or those having a matching (non-zero) key. However it would often be convenient to just do a complete cleanup of everything, usually as root. PR: bin/118292 Submitted by: Callum Gibson <callumgibson@optusnet.com.au> Not reviewed by: grog@ Approved by: grog@
Diffstat (limited to 'usr.bin/ipcrm')
-rw-r--r--usr.bin/ipcrm/Makefile5
-rw-r--r--usr.bin/ipcrm/ipcrm.137
-rw-r--r--usr.bin/ipcrm/ipcrm.c147
3 files changed, 172 insertions, 17 deletions
diff --git a/usr.bin/ipcrm/Makefile b/usr.bin/ipcrm/Makefile
index 9c0e45c..47e4ccc 100644
--- a/usr.bin/ipcrm/Makefile
+++ b/usr.bin/ipcrm/Makefile
@@ -1,5 +1,10 @@
# $FreeBSD$
PROG= ipcrm
+SRCS= ipcrm.c ipc.c
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+CFLAGS+=-I${.CURDIR}/../ipcs
+.PATH: ${.CURDIR}/../ipcs
.include <bsd.prog.mk>
diff --git a/usr.bin/ipcrm/ipcrm.1 b/usr.bin/ipcrm/ipcrm.1
index 9e2a470..30378f2 100644
--- a/usr.bin/ipcrm/ipcrm.1
+++ b/usr.bin/ipcrm/ipcrm.1
@@ -23,7 +23,7 @@
.\"
.\" $FreeBSD$
.\""
-.Dd August 8, 1994
+.Dd December 12, 2007
.Dt IPCRM 1
.Os
.Sh NAME
@@ -31,6 +31,8 @@
.Nd "remove the specified message queues, semaphore sets, and shared segments"
.Sh SYNOPSIS
.Nm
+.Op Fl W
+.Op Fl v
.Op Fl q Ar msqid
.Op Fl m Ar shmid
.Op Fl s Ar semid
@@ -46,6 +48,31 @@ segments.
These System V IPC objects can be specified by their
creation ID or any associated key.
.Pp
+The following options are generic:
+.Bl -tag -width indent
+.It Fl v
+If specified once with -W or with -1 for an object, it will show
+all removed objects.
+If specified twice with -W or with -1 for an objects, it will show
+all removed objects and all failed removals.
+.It Fl W
+Try to wipe all specified message queues, semaphores and shared
+memory segments.
+.It Fl y
+Use the
+.Xr kvm 3
+interface instead of the
+.Xr sysctl 3
+interface to extract the required information.
+If
+.Nm
+is to operate on the running system,
+using
+.Xr kvm 3
+will require read privileges to
+.Pa /dev/kmem .
+.El
+.Pp
The following options are used to specify which IPC objects will be removed.
Any number and combination of these options can be used:
.Bl -tag -width indent
@@ -80,5 +107,13 @@ from the system.
The identifiers and keys associated with these System V IPC objects can be
determined by using
.Xr ipcs 1 .
+If the identifier or the key is -1, it will remove all these objects.
.Sh SEE ALSO
.Xr ipcs 1
+.Sh HISTORY
+The wiping of all System V IPC objects was first implemented in
+.Fx 6.4 and 7.1.
+.Sh AUTHORS
+The original author was Adam Glass.
+The wiping of all System V IPC objects was thought up by Callum
+Gibson and extended and implemented by Edwin Groothuis.
diff --git a/usr.bin/ipcrm/ipcrm.c b/usr.bin/ipcrm/ipcrm.c
index 1ced896..32887e0 100644
--- a/usr.bin/ipcrm/ipcrm.c
+++ b/usr.bin/ipcrm/ipcrm.c
@@ -27,42 +27,47 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
+#include <sys/param.h>
+#define _KERNEL
#include <sys/sem.h>
#include <sys/shm.h>
+#include <sys/msg.h>
+#undef _KERNEL
#include <ctype.h>
#include <err.h>
-#include <signal.h>
+#include <grp.h>
+#include <kvm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#define IPC_TO_STR(x) (x == 'Q' ? "msq" : (x == 'M' ? "shm" : "sem"))
-#define IPC_TO_STRING(x) (x == 'Q' ? "message queue" : \
- (x == 'M' ? "shared memory segment" : "semaphore"))
+#include "ipc.h"
+
+int signaled;
+int errflg;
+int rmverbose = 0;
-int signaled;
+void usage(void);
-void usage(void);
-int msgrm(key_t, int);
-int shmrm(key_t, int);
-int semrm(key_t, int);
-void not_configured(int);
+int msgrm(key_t, int);
+int shmrm(key_t, int);
+int semrm(key_t, int);
+void not_configured(int);
void
usage(void)
{
fprintf(stderr,
- "usage: ipcrm [-q msqid] [-m shmid] [-s semid]\n"
+ "usage: ipcrm [-W] [-v[v]]\n"
+ " [-q msqid] [-m shmid] [-s semid]\n"
" [-Q msgkey] [-M shmkey] [-S semkey] ...\n");
exit(1);
}
@@ -71,11 +76,40 @@ int
msgrm(key_t key, int id)
{
+ if (key == -1 || id == -1) {
+ struct msqid_kernel *kxmsqids;
+ size_t kxmsqids_len;
+ int num;
+
+ kget(X_MSGINFO, &msginfo, sizeof(msginfo));
+ kxmsqids_len = sizeof(struct msqid_kernel) * msginfo.msgmni;
+ kxmsqids = malloc(kxmsqids_len);
+ kget(X_MSQIDS, kxmsqids, kxmsqids_len);
+ num = msginfo.msgmni;
+ while (num-- && !signaled)
+ if (kxmsqids[num].u.msg_qbytes != 0) {
+ id = IXSEQ_TO_IPCID(num,
+ kxmsqids[num].u.msg_perm);
+ if (msgctl(id, IPC_RMID, NULL) < 0) {
+ if (rmverbose > 1)
+ warn("msqid(%d): ", id);
+ errflg++;
+ } else
+ if (rmverbose)
+ printf(
+ "Removed %s %d\n",
+ IPC_TO_STRING('Q'),
+ id);
+ }
+ return signaled ? -1 : 0; /* errors maybe handled above */
+ }
+
if (key) {
id = msgget(key, 0);
if (id == -1)
return -1;
}
+
return msgctl(id, IPC_RMID, NULL);
}
@@ -83,11 +117,40 @@ int
shmrm(key_t key, int id)
{
+ if (key == -1 || id == -1) {
+ struct shmid_kernel *kxshmids;
+ size_t kxshmids_len;
+ int num;
+
+ kget(X_SHMINFO, &shminfo, sizeof(shminfo));
+ kxshmids_len = sizeof(struct shmid_kernel) * shminfo.shmmni;
+ kxshmids = malloc(kxshmids_len);
+ kget(X_SHMSEGS, kxshmids, kxshmids_len);
+ num = shminfo.shmmni;
+ while (num-- && !signaled)
+ if (kxshmids[num].u.shm_perm.mode & 0x0800) {
+ id = IXSEQ_TO_IPCID(num,
+ kxshmids[num].u.shm_perm);
+ if (shmctl(id, IPC_RMID, NULL) < 0) {
+ if (rmverbose > 1)
+ warn("shmid(%d): ", id);
+ errflg++;
+ } else
+ if (rmverbose)
+ printf(
+ "Removed %s %d\n",
+ IPC_TO_STRING('M'),
+ id);
+ }
+ return signaled ? -1 : 0; /* errors maybe handled above */
+ }
+
if (key) {
id = shmget(key, 0, 0);
if (id == -1)
return -1;
}
+
return shmctl(id, IPC_RMID, NULL);
}
@@ -96,11 +159,40 @@ semrm(key_t key, int id)
{
union semun arg;
+ if (key == -1 || id == -1) {
+ struct semid_kernel *kxsema;
+ size_t kxsema_len;
+ int num;
+
+ kget(X_SEMINFO, &seminfo, sizeof(seminfo));
+ kxsema_len = sizeof(struct semid_kernel) * seminfo.semmni;
+ kxsema = malloc(kxsema_len);
+ kget(X_SEMA, kxsema, kxsema_len);
+ num = seminfo.semmni;
+ while (num-- && !signaled)
+ if ((kxsema[num].u.sem_perm.mode & SEM_ALLOC) != 0) {
+ id = IXSEQ_TO_IPCID(num,
+ kxsema[num].u.sem_perm);
+ if (semctl(id, IPC_RMID, NULL) < 0) {
+ if (rmverbose > 1)
+ warn("semid(%d): ", id);
+ errflg++;
+ } else
+ if (rmverbose)
+ printf(
+ "Removed %s %d\n",
+ IPC_TO_STRING('S'),
+ id);
+ }
+ return signaled ? -1 : 0; /* errors maybe handled above */
+ }
+
if (key) {
id = semget(key, 0, 0);
if (id == -1)
return -1;
}
+
return semctl(id, 0, IPC_RMID, arg);
}
@@ -114,12 +206,26 @@ not_configured(int signo __unused)
int
main(int argc, char *argv[])
{
- int c, result, errflg, target_id;
+ int c, result, target_id;
key_t target_key;
+ while ((c = getopt(argc, argv, "q:m:s:Q:M:S:vWy")) != -1) {
+
+ signaled = 0;
+ switch (c) {
+ case 'v':
+ rmverbose++;
+ break;
+ case 'y':
+ use_sysctl = 0;
+ break;
+ }
+ }
+
+ optind = 1;
errflg = 0;
signal(SIGSYS, not_configured);
- while ((c = getopt(argc, argv, ":q:m:s:Q:M:S:")) != -1) {
+ while ((c = getopt(argc, argv, "q:m:s:Q:M:S:vWy")) != -1) {
signaled = 0;
switch (c) {
@@ -171,6 +277,15 @@ main(int argc, char *argv[])
IPC_TO_STRING(c));
}
break;
+ case 'v':
+ case 'y':
+ /* Handled in other getopt() loop */
+ break;
+ case 'W':
+ msgrm(-1, 0);
+ shmrm(-1, 0);
+ semrm(-1, 0);
+ break;
case ':':
fprintf(stderr,
"option -%c requires an argument\n", optopt);
OpenPOWER on IntegriCloud