From 4b685c75f348d04a7ecd1ec43903c571965d53cf Mon Sep 17 00:00:00 2001
From: Stathis Kamperis <ekamperi@gmail.com>
Date: Sat, 10 Nov 2012 13:06:09 +0200
Subject: [PATCH 1/1] Initial import of pipcs(1) utility

Thanks to swildner@ for the help with the mdoc markup
---
 sys/kern/sys_mqueue.c  |  20 ++++++
 usr.bin/pipcs/Makefile |   5 ++
 usr.bin/pipcs/pipcs.1  |  72 +++++++++++++++++++
 usr.bin/pipcs/pipcs.c  | 184 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 281 insertions(+)
 create mode 100644 usr.bin/pipcs/Makefile
 create mode 100644 usr.bin/pipcs/pipcs.1
 create mode 100644 usr.bin/pipcs/pipcs.c

diff --git a/sys/kern/sys_mqueue.c b/sys/kern/sys_mqueue.c
index 89aa990..d42122e 100644
--- a/sys/kern/sys_mqueue.c
+++ b/sys/kern/sys_mqueue.c
@@ -1178,4 +1178,24 @@ SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_max_maxmsg,
     CTLFLAG_RW, &mq_max_maxmsg, 0,
     "Maximal allowed message count");
 
+static int
+sysctl_mqueue_list_mqueues(SYSCTL_HANDLER_ARGS)
+{
+	struct mqueue *mq = NULL;
+	int error = 0;
+
+	lockmgr(&mqlist_mtx, LK_EXCLUSIVE);
+	LIST_FOREACH(mq, &mqueue_head, mq_list) {
+		error = sysctl_handle_opaque(oidp, mq, sizeof(*mq), req);
+		if (error)
+			break;
+	}
+	lockmgr(&mqlist_mtx, LK_RELEASE);
+
+	return error;
+}
+
+SYSCTL_PROC(_kern_mqueue, OID_AUTO, mqueue, CTLTYPE_OPAQUE|CTLFLAG_RD,
+    NULL, 0, sysctl_mqueue_list_mqueues, "A", "list of existing mqueues");
+
 SYSINIT(sys_mqueue_init, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, mqueue_sysinit, NULL);
diff --git a/usr.bin/pipcs/Makefile b/usr.bin/pipcs/Makefile
new file mode 100644
index 0000000..791d4ae
--- /dev/null
+++ b/usr.bin/pipcs/Makefile
@@ -0,0 +1,5 @@
+PROG=	pipcs
+BINGRP=	kmem
+BINMODE= 2555
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/pipcs/pipcs.1 b/usr.bin/pipcs/pipcs.1
new file mode 100644
index 0000000..7a50460
--- /dev/null
+++ b/usr.bin/pipcs/pipcs.1
@@ -0,0 +1,72 @@
+.\"
+.\" Copyright (c) 2012, Stathis Kamperis
+.\" All rights reserved.
+.\" 
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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.
+.\"
+.Dd November 10, 2012
+.Dt PIPCS 1
+.Os
+.Sh NAME
+.Nm pipcs
+.Nd report POSIX interprocess communication facilities status
+.Sh SYNOPSIS
+.Nm
+{list, unlink} {all, /mqueue1 /mqueue2 ...}
+.Sh DESCRIPTION
+The pipcs utility provides information on active POSIX interprocess communication
+(IPC) facilities on the system. Currently, it only supports POSIX message queues.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Display all the active POSIX message queues:
+.Bd -literal
+% pipcs list all | head -n3
+         Name          Ptr     Mode    Flags Ref MaxMsg MsgSze CurMsg
+   /mq_inf519 0x4000010000      1ed     2561   0     32    992      0
+   /mq_inf517 0x4000010418      1ed     2561   9     32    992     10
+.Ed
+.Pp
+Remove a dangling message queue (i.e., a message queue with zero
+references):
+.Bd -literal
+% pipcs unlink /mq_inf519
+.Ed
+.Sh SEE ALSO
+.Xr ipcs 1 ,
+.Xr mq_close 2 ,
+.Xr mq_open 2 ,
+.Xr mq_unlink 2
+.Sh STANDARDS
+This utility is an extention to the standard.
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Dx 3.3 .
+.Sh AUTHORS
+.An Stathis Kamperis Aq ekamperi@gmail.com
+.Sh CAVEATS
+This utility reports only an approximation of the current system status,
+since the latter may be constantly changing during the retrieval of the
+requested information.
diff --git a/usr.bin/pipcs/pipcs.c b/usr.bin/pipcs/pipcs.c
new file mode 100644
index 0000000..e7a7be3
--- /dev/null
+++ b/usr.bin/pipcs/pipcs.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2012, Stathis Kamperis
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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 <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define _KERNEL_STRUCTURES
+#include <mqueue.h>
+#undef _KERNEL_STRUCTURES
+
+#include <sys/types.h>
+#include <sys/mqueue.h>
+#include <sys/sysctl.h>
+
+static void
+usage(const char *name)
+{
+	fprintf(stderr,
+	    "usage: %s "
+	    "[list | unlink] [all | /mqueue1 /mqueue2 ...]\n",
+	    name);
+
+	exit(EXIT_FAILURE);
+}
+
+static const struct mqueue *
+findbyname(const struct mqueue *mq, size_t nmqueues, const char *name)
+{
+	size_t i;
+
+	for (i = 0; i < nmqueues; i++) {
+		if (!strcmp(mq[i].mq_name, name))
+			return &mq[i];
+	}
+
+	return NULL;
+}
+
+static void
+print_header(int line)
+{
+	if (line % 20 == 0) {
+		printf("%20s %10s %8s %8s %3s %4s %4s %4s\n",
+		    "Name", "Ptr", "Mode", "Flags",  "Ref",
+		    "MaxMsg", "MsgSze", "CurMsg");
+	}
+}
+
+static void
+print_mqueue(const struct mqueue *mq)
+{
+	/* Message queues are required to start with a leading slash */
+	if (mq && mq->mq_name[0] == '/')
+		printf("%20s %10p %8x %8ld %3u %6lu %6lu %6lu\n",
+		    mq->mq_name,
+		    (const void *)mq,
+		    mq->mq_mode,
+		    mq->mq_attrib.mq_flags,
+		    mq->mq_refcnt,
+		    mq->mq_attrib.mq_maxmsg,
+		    mq->mq_attrib.mq_msgsize,
+		    mq->mq_attrib.mq_curmsgs);
+}
+
+static void
+print_all(const struct mqueue *mq, size_t nmqueues, int argc, char *argv[])
+{
+	size_t i;
+
+	if (!strcmp(argv[0], "all")) {
+		for (i = 0; i < nmqueues; i++) {
+			print_header(i);
+			print_mqueue(&mq[i]);
+		}
+	} else {
+		for (i = 0; i < (size_t)argc; i++) {
+			print_header(i);
+			print_mqueue(findbyname(mq, nmqueues, argv[i]));
+		}
+	}
+}
+
+static void
+unlink_mqueue(const struct mqueue *mq)
+{
+	if (mq)
+		mq_unlink(mq->mq_name);
+}
+
+static void
+unlink_all(const struct mqueue *mq, size_t nmqueues, int argc, char *argv[])
+{
+	size_t i;
+
+	if (!strcmp(argv[0], "all")) {
+		for (i = 0; i < nmqueues; i++)
+			unlink_mqueue(&mq[i]);
+	} else {
+		for (i = 0; i < (size_t)argc; i++)
+			unlink_mqueue(findbyname(mq, nmqueues, argv[i]));
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct mqueue *mqbuf;
+	size_t bytes = 0, nmqueues = 0;
+	int list, unlink, rv;
+
+	/* Skip program name */
+	const char *progname = argv[0];
+	argv++; argc--;
+
+	/* Parse command line arguments */
+	list = 0;
+	unlink  = 0;
+	if (argc == 0) {
+		usage(progname);
+		/* never reached */
+	} else if (argc > 1 && !strcmp(argv[0], "list")) {
+		list = 1;
+		argv++; argc--;
+	} else if (argc > 1 && !strcmp(argv[0], "unlink")) {
+		unlink = 1;
+		argv++; argc--;
+	} else {
+		usage(progname);
+		/* never reached */
+	}
+
+	/* Retrieve data */
+	rv = sysctlbyname("kern.mqueue.mqueue", NULL, &bytes, NULL, 0);
+	if (rv < 0)
+		err(EXIT_FAILURE, "sysctlbyname()");
+
+	mqbuf = malloc(bytes);
+	if (mqbuf == NULL)
+		err(EXIT_FAILURE, "malloc()");
+
+	rv = sysctlbyname("kern.mqueue.mqueue", mqbuf, &bytes, NULL, 0);
+	if (rv < 0)
+		err(EXIT_FAILURE, "sysctlbyname()");
+
+	/* Calculate the number of message queues */
+	nmqueues = bytes / sizeof(struct mqueue);
+
+	/* Execute the actual commands */
+	if (list) {
+		print_all(mqbuf, nmqueues, argc, argv);
+	} else if (unlink) {
+		unlink_all(mqbuf, nmqueues, argc, argv);
+	}
+
+	free(mqbuf);
+
+	return EXIT_SUCCESS;
+}
-- 
1.7.12

