]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
added POSIX IPC support to lsipc, ipcrm, ipcmk
authorPrasanna Paithankar <paithankarprasanna@gmail.com>
Wed, 22 Jan 2025 21:38:02 +0000 (03:08 +0530)
committerPrasanna Paithankar <paithankarprasanna@gmail.com>
Wed, 22 Jan 2025 21:38:02 +0000 (03:08 +0530)
sys-utils/ipcmk.1.adoc
sys-utils/ipcmk.c
sys-utils/ipcrm.1.adoc
sys-utils/ipcrm.c
sys-utils/ipcutils.c
sys-utils/ipcutils.h
sys-utils/lsipc.1.adoc
sys-utils/lsipc.c

index 605b9286ca725c8b32d380d97ec2e0cd5739ea63..a4871f438a4e9eb8731dfc7a8f82add4c3d87c52 100644 (file)
@@ -20,7 +20,7 @@ ipcmk - make various IPC resources
 
 == DESCRIPTION
 
-*ipcmk* allows you to create System V inter-process communication (IPC) objects: shared memory segments, message queues, and semaphore arrays.
+*ipcmk* allows you to create POSIX and System V inter-process communication (IPC) objects: shared memory segments, message queues, and semaphore (arrays for System V).
 
 == OPTIONS
 
@@ -29,12 +29,24 @@ Resources can be specified with these options:
 *-M*, *--shmem* _size_::
 Create a shared memory segment of _size_ bytes. The _size_ argument may be followed by the multiplicative suffixes KiB (=1024), MiB (=1024*1024), and so on for GiB, etc. (the "iB" is optional, e.g., "K" has the same meaning as "KiB") or the suffixes KB (=1000), MB (=1000*1000), and so on for GB, etc.
 
+*-m*, *--posix-shmem* _size_::
+Create a POSIX shared memory segment of _size_ bytes. The _size_ argument may be followed by the multiplicative suffixes KiB (=1024), MiB (=1024*1024), and so on for GiB, etc. (the "iB" is optional, e.g., "K" has the same meaning as "KiB") or the suffixes KB (=1000), MB (=1000*1000), and so on for GB, etc.
+
 *-Q*, *--queue*::
 Create a message queue.
 
+*-q*, *--posix-mqueue*::
+Create a POSIX message queue.
+
 *-S*, *--semaphore* _number_::
 Create a semaphore array with _number_ of elements.
 
+*-s*, *--posix-semaphore*::
+Create a POSIX named semaphore.
+
+*-n*, *--name* _name_::
+Name of the POSIX IPC object. This option is mandatory for POSIX IPC objects.
+
 Other options are:
 
 *-p*, *--mode* _mode_::
@@ -50,6 +62,7 @@ mailto:hayden.james@gmail.com[Hayden A. James]
 
 *ipcrm*(1),
 *ipcs*(1),
+*lsipc*(1),
 *sysvipc*(7)
 
 include::man-common/bugreports.adoc[]
index 67a7637f629ef4a7543b1465fb4acf2147f408d4..7e48b270ebb2fd775c5c50d5604f912d657b42c4 100644 (file)
 #include <stdlib.h>
 #include <sys/ipc.h>
 #include <sys/msg.h>
+#include <mqueue.h>
 #include <sys/sem.h>
+#include <semaphore.h>
 #include <sys/shm.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
 #include <sys/time.h>
 
 #include "c.h"
@@ -44,6 +48,23 @@ static int create_shm(size_t size, int permission)
        return shmget(key, size, permission | IPC_CREAT);
 }
 
+static int create_posix_shm(const char *name, size_t size, int permission)
+{
+       int shmfd;
+
+       if (-1 == (shmfd = shm_open(name, O_RDWR | O_CREAT, permission)))
+               return -1;
+       
+       if (-1 == ftruncate(shmfd, size)) {
+               close(shmfd);
+               return -1;
+       }
+
+       close(shmfd);
+       printf(_("POSIX shared memory name: %s\n"), name);
+       return 0;
+}
+
 static int create_msg(int permission)
 {
        key_t key;
@@ -52,6 +73,14 @@ static int create_msg(int permission)
        return msgget(key, permission | IPC_CREAT);
 }
 
+static int create_posix_msg(const char *name, int permission)
+{
+       if (-1 == mq_open(name, O_RDWR | O_CREAT, permission, NULL))
+               return -1;
+       printf(_("POSIX message queue name: %s\n"), name);
+       return 0;
+}
+
 static int create_sem(int nsems, int permission)
 {
        key_t key;
@@ -60,6 +89,18 @@ static int create_sem(int nsems, int permission)
        return semget(key, nsems, permission | IPC_CREAT);
 }
 
+static int create_posix_sem(const char *name, int permission)
+{
+       sem_t *sem;
+
+       if (SEM_FAILED == (sem = sem_open(name, O_CREAT, permission, 0)))
+               return -1;
+
+       sem_close(sem);
+       printf(_("POSIX semaphore name: %s\n"), name);
+       return 0;
+}
+
 static void __attribute__((__noreturn__)) usage(void)
 {
        FILE *out = stdout;
@@ -71,9 +112,13 @@ static void __attribute__((__noreturn__)) usage(void)
 
        fputs(USAGE_OPTIONS, out);
        fputs(_(" -M, --shmem <size>       create shared memory segment of size <size>\n"), out);
+       fputs(_(" -m, --posix-shmem <size> create POSIX shared memory segment of size <size>\n"), out);
        fputs(_(" -S, --semaphore <number> create semaphore array with <number> elements\n"), out);
+       fputs(_(" -s, --posix-semaphore    create POSIX semaphore\n"), out);
        fputs(_(" -Q, --queue              create message queue\n"), out);
+       fputs(_(" -q, --posix-mqueue       create POSIX message queue\n"), out);
        fputs(_(" -p, --mode <mode>        permission for the resource (default is 0644)\n"), out);
+       fputs(_(" -n, --name <name>        name of the POSIX resource\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
        fprintf(out, USAGE_HELP_OPTIONS(26));
@@ -81,6 +126,9 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(USAGE_ARGUMENTS, out);
        fprintf(out, USAGE_ARG_SIZE(_("<size>")));
 
+       fputs(USAGE_SEPARATOR, out);
+       fputs(_(" -n, --name <name> option is required for POSIX IPC\n"), out);
+
        fprintf(out, USAGE_MAN_TAIL("ipcmk(1)"));
 
        exit(EXIT_SUCCESS);
@@ -89,15 +137,20 @@ static void __attribute__((__noreturn__)) usage(void)
 int main(int argc, char **argv)
 {
        int permission = 0644;
+       char *name = NULL;
        int opt;
        size_t size = 0;
        int nsems = 0;
-       int ask_shm = 0, ask_msg = 0, ask_sem = 0;
+       int ask_shm = 0, ask_msg = 0, ask_sem = 0, ask_pshm = 0, ask_pmsg = 0, ask_psem = 0;
        static const struct option longopts[] = {
                {"shmem", required_argument, NULL, 'M'},
+               {"posix-shmem", required_argument, NULL, 'm'},
                {"semaphore", required_argument, NULL, 'S'},
+               {"posix-semaphore", required_argument, NULL, 's'},
                {"queue", no_argument, NULL, 'Q'},
+               {"posix-mqueue", no_argument, NULL, 'q'},
                {"mode", required_argument, NULL, 'p'},
+               {"name", required_argument, NULL, 'n'},
                {"version", no_argument, NULL, 'V'},
                {"help", no_argument, NULL, 'h'},
                {NULL, 0, NULL, 0}
@@ -108,19 +161,29 @@ int main(int argc, char **argv)
        textdomain(PACKAGE);
        close_stdout_atexit();
 
-       while((opt = getopt_long(argc, argv, "hM:QS:p:Vh", longopts, NULL)) != -1) {
+       while((opt = getopt_long(argc, argv, "hM:m:QqS:sp:n:Vh", longopts, NULL)) != -1) {
                switch(opt) {
                case 'M':
                        size = strtosize_or_err(optarg, _("failed to parse size"));
                        ask_shm = 1;
                        break;
+               case 'm':
+                       size = strtosize_or_err(optarg, _("failed to parse size"));
+                       ask_pshm = 1;
+                       break;
                case 'Q':
                        ask_msg = 1;
                        break;
+               case 'q':
+                       ask_pmsg = 1;
+                       break;
                case 'S':
                        nsems = strtos32_or_err(optarg, _("failed to parse elements"));
                        ask_sem = 1;
                        break;
+               case 's':
+                       ask_psem = 1;
+                       break;
                case 'p':
                {
                        char *end = NULL;
@@ -130,6 +193,9 @@ int main(int argc, char **argv)
                                err(EXIT_FAILURE, _("failed to parse mode"));
                        break;
                }
+               case 'n':
+                       name = optarg;
+                       break;
                case 'h':
                        usage();
                case 'V':
@@ -139,10 +205,16 @@ int main(int argc, char **argv)
                }
        }
 
-       if(!ask_shm && !ask_msg && !ask_sem) {
+       if(!ask_shm && !ask_msg && !ask_sem && !ask_pshm && !ask_pmsg && !ask_psem) {
                warnx(_("bad usage"));
                errtryhelp(EXIT_FAILURE);
        }
+
+       if ((ask_pshm + ask_pmsg + ask_psem > 0) && name == NULL) {
+               warnx(_("name is required for POSIX IPC"));
+               errtryhelp(EXIT_FAILURE);
+       }
+
        if (ask_shm) {
                int shmid;
                if (-1 == (shmid = create_shm(size, permission)))
@@ -151,6 +223,11 @@ int main(int argc, char **argv)
                        printf(_("Shared memory id: %d\n"), shmid);
        }
 
+       if (ask_pshm) {
+               if (-1 == create_posix_shm(name, size, permission))
+                       err(EXIT_FAILURE, _("create POSIX shared memory failed"));
+       }
+
        if (ask_msg) {
                int msgid;
                if (-1 == (msgid = create_msg(permission)))
@@ -159,6 +236,11 @@ int main(int argc, char **argv)
                        printf(_("Message queue id: %d\n"), msgid);
        }
 
+       if (ask_pmsg) {
+               if (-1 == create_posix_msg(name, permission))
+                       err(EXIT_FAILURE, _("create POSIX message queue failed"));
+       }
+
        if (ask_sem) {
                int semid;
                if (-1 == (semid = create_sem(nsems, permission)))
@@ -167,5 +249,10 @@ int main(int argc, char **argv)
                        printf(_("Semaphore id: %d\n"), semid);
        }
 
+       if (ask_psem) {
+               if (-1 == create_posix_sem(name, permission))
+                       err(EXIT_FAILURE, _("create POSIX semaphore failed"));
+       }
+
        return EXIT_SUCCESS;
 }
index 98e3638921523065cfa08e3b608cfc12647ad5d7..f4a8b4546442825688fc3b5095ed10e2aa3439d2 100644 (file)
@@ -23,19 +23,19 @@ ipcrm - remove certain IPC resources
 
 == DESCRIPTION
 
-*ipcrm* removes System V inter-process communication (IPC) objects and associated data structures from the system. In order to delete such objects, you must be superuser, or the creator or owner of the object.
+*ipcrm* removes POSIX and System V inter-process communication (IPC) objects and associated data structures from the system. In order to delete such objects, you must be superuser, or the creator or owner of the object.
 
-System V IPC objects are of three types: shared memory, message queues, and semaphores. Deletion of a message queue or semaphore object is immediate (regardless of whether any process still holds an IPC identifier for the object). A shared memory object is only removed after all currently attached processes have detached (*shmdt*(2)) the object from their virtual address space.
+POSIX and System V IPC objects are of three types: shared memory, message queues, and semaphores. Deletion of a message queue or semaphore object is immediate (regardless of whether any process still holds an IPC identifier for the object). A shared memory object is only removed after all currently attached processes have detached (*shmdt*(2)) the object from their virtual address space.
 
 Two syntax styles are supported. The old Linux historical syntax specifies a three-letter keyword indicating which class of object is to be deleted, followed by one or more IPC identifiers for objects of this type.
 
 The SUS-compliant syntax allows the specification of zero or more objects of all three types in a single command line, with objects specified either by key or by identifier (see below). Both keys and identifiers may be specified in decimal, hexadecimal (specified with an initial '0x' or '0X'), or octal (specified with an initial '0').
 
-The details of the removes are described in *shmctl*(2), *msgctl*(2), and *semctl*(2). The identifiers and keys can be found by using *ipcs*(1).
+The details of the removes are described in *shmctl*(2), *shm_unlink*(3), *msgctl*(2), *mq_unlink*(3), *semctl*(2), and *sem_unlink*(3). The identifiers and keys can be found by using *lsipc*(1) or *ipcs*(1).
 
 == OPTIONS
 
-*-a*, *--all* [*shm*] [*msg*] [*sem*]::
+*-a*, *--all* [*shm*] [*pshm*] [*msg*] [*pmsg*] [*sem*] [*psem*]::
 Remove all resources. When an option argument is provided, the removal is performed only for the specified resource types.
 +
 _Warning!_ Do not use *-a* if you are unsure how the software using the resources might react to missing objects. Some programs create these resources at startup and may not have any code to deal with an unexpected disappearance.
@@ -46,18 +46,27 @@ Remove the shared memory segment created with _shmkey_ after the last detach is
 *-m*, *--shmem-id* _shmid_::
 Remove the shared memory segment identified by _shmid_ after the last detach is performed.
 
+*-x*, *--posix-shmem* _name_::
+Remove the POSIX shared memory segment created with _name_.
+
 *-Q*, *--queue-key* _msgkey_::
 Remove the message queue created with _msgkey_.
 
 *-q*, *--queue-id* _msgid_::
 Remove the message queue identified by _msgid_.
 
+*-y*, *--posix-mqueue* _name_::
+Remove the POSIX message queue created with _name_.
+
 *-S*, *--semaphore-key* _semkey_::
 Remove the semaphore created with _semkey_.
 
 *-s*, *--semaphore-id* _semid_::
 Remove the semaphore identified by _semid_.
 
+*-z*, *--posix-semaphore* _name_::
+Remove the POSIX named semaphore created with _name_.
+
 include::man-common/help-version.adoc[]
 
 == NOTES
@@ -69,13 +78,17 @@ In its first Linux implementation, *ipcrm* used the deprecated syntax shown in t
 
 *ipcmk*(1),
 *ipcs*(1),
+*lsipc*(1),
 *msgctl*(2),
+*mq_unlink*(3),
 *msgget*(2),
 *semctl*(2),
 *semget*(2),
+*sem_unlink*(3),
 *shmctl*(2),
 *shmdt*(2),
 *shmget*(2),
+*shm_unlink*(3),
 *ftok*(3),
 *sysvipc*(7)
 
index 26255c49452e522ee3131dfb54331761c543097d..2d080b007d322dc692ce509575bbd1f32762daa7 100644 (file)
@@ -20,6 +20,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
 #include "c.h"
 #include "nls.h"
 #include "strutils.h"
 
 typedef enum type_id {
        SHM,
+       PSHM,
        SEM,
+       PSEM,
        MSG,
+       PMSG,
        ALL
 } type_id;
 
@@ -48,14 +53,17 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_("Remove certain IPC resources.\n"), out);
 
        fputs(USAGE_OPTIONS, out);
-       fputs(_(" -m, --shmem-id <id>        remove shared memory segment by id\n"), out);
-       fputs(_(" -M, --shmem-key <key>      remove shared memory segment by key\n"), out);
-       fputs(_(" -q, --queue-id <id>        remove message queue by id\n"), out);
-       fputs(_(" -Q, --queue-key <key>      remove message queue by key\n"), out);
-       fputs(_(" -s, --semaphore-id <id>    remove semaphore by id\n"), out);
-       fputs(_(" -S, --semaphore-key <key>  remove semaphore by key\n"), out);
-       fputs(_(" -a, --all[=shm|msg|sem]    remove all (in the specified category)\n"), out);
-       fputs(_(" -v, --verbose              explain what is being done\n"), out);
+       fputs(_(" -m, --shmem-id <id>                                   remove shared memory segment by id\n"), out);
+       fputs(_(" -M, --shmem-key <key>                                 remove shared memory segment by key\n"), out);
+       fputs(_("     --posix-shmem <name>                              remove POSIX shared memory segment by name\n"), out);
+       fputs(_(" -q, --queue-id <id>                                   remove message queue by id\n"), out);
+       fputs(_(" -Q, --queue-key <key>                                 remove message queue by key\n"), out);
+       fputs(_("     --posix-mqueue <name>                             remove POSIX message queue by name\n"), out);
+       fputs(_(" -s, --semaphore-id <id>                               remove semaphore by id\n"), out);
+       fputs(_(" -S, --semaphore-key <key>                             remove semaphore by key\n"), out);
+       fputs(_("     --posix-semaphore <name>                          remove POSIX semaphore by name\n"), out);
+       fputs(_(" -a, --all[=shm|pshm|msg|pmsg|sem|psem]        remove all (in the specified category)\n"), out);
+       fputs(_(" -v, --verbose                                         explain what is being done\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
        fprintf(out, USAGE_HELP_OPTIONS(28));
@@ -229,6 +237,50 @@ static int key_to_id(type_id type, char *s)
        return id;
 }
 
+static int remove_name(type_id type, char *name)
+{
+       int ret;
+       
+       switch (type) {
+               case PSHM:
+                       if (verbose)
+                               printf(_("removing POSIX shared memory `%s'\n"), name);
+                       ret = shm_unlink(name);
+                       break;
+               case PMSG:
+                       if (verbose)
+                               printf(_("removing POSIX message queue `%s'\n"), name);
+                       ret = mq_unlink(name);
+                       break;
+               case PSEM:
+                       if (verbose)
+                               printf(_("removing POSIX semaphore `%s'\n"), name);
+                       ret = sem_unlink(name);
+                       break;
+               default:
+                       errx(EXIT_FAILURE, "impossible occurred");
+       }
+
+       if (ret < 0) {
+               switch (errno) {
+               case EACCES:
+               case EPERM:
+                       warnx(_("permission denied for name `%s'"), name);
+                       break;
+               case ENOENT:
+                       warnx(_("name `%s' not found"), name);
+                       break;
+               case ENAMETOOLONG:
+                       warnx(_("name `%s' too long"), name);
+                       break;
+               default:
+                       err(EXIT_FAILURE, _("name failed"));
+               }
+               return 1;
+       }
+       return 0;
+}              
+
 static int remove_all(type_id type)
 {
        int ret = 0;
@@ -236,13 +288,19 @@ static int remove_all(type_id type)
 
        struct shmid_ds shmseg;
 
+       struct posix_shm_data *shmds, *shmdsp;
+
        struct semid_ds semary;
        struct seminfo seminfo;
        union semun arg;
 
+       struct posix_sem_data *semds, *semdsp;
+
        struct msqid_ds msgque;
        struct msginfo msginfo;
 
+       struct posix_msg_data *msgds, *msgdsp;
+
        if (type == SHM || type == ALL) {
                maxid = shmctl(0, SHM_INFO, &shmseg);
                if (maxid < 0)
@@ -255,6 +313,16 @@ static int remove_all(type_id type)
                        ret |= remove_id(SHM, 0, rm_me);
                }
        }
+       if (type == PSHM || type == ALL) {
+               if (posix_ipc_shm_get_info(NULL, &shmds) > 0) {
+                       for (shmdsp = shmds; shmdsp->next != NULL; shmdsp = shmdsp->next) {
+                               if (verbose)
+                                       printf(_("removing POSIX shared memory `%s'\n"), shmdsp->name);
+                               ret |= remove_name(PSHM, shmdsp->name);
+                       }
+                       posix_ipc_shm_free_info(shmds);
+               }
+       }
        if (type == SEM || type == ALL) {
                arg.array = (ushort *) (void *)&seminfo;
                maxid = semctl(0, 0, SEM_INFO, arg);
@@ -269,6 +337,16 @@ static int remove_all(type_id type)
                        ret |= remove_id(SEM, 0, rm_me);
                }
        }
+       if (type == PSEM || type == ALL) {
+               if (posix_ipc_sem_get_info(NULL, &semds) > 0) {
+                       for (semdsp = semds; semdsp->next != NULL; semdsp = semdsp->next) {
+                               if (verbose)
+                                       printf(_("removing POSIX semaphore `%s'\n"), semdsp->sname);
+                               ret |= remove_name(PSEM, semdsp->sname);
+                       }
+                       posix_ipc_sem_free_info(semds);
+               }
+       }
        if (type == MSG || type == ALL) {
                maxid =
                    msgctl(0, MSG_INFO, (struct msqid_ds *)(void *)&msginfo);
@@ -282,6 +360,16 @@ static int remove_all(type_id type)
                        ret |= remove_id(MSG, 0, rm_me);
                }
        }
+       if (type == PMSG || type == ALL) {
+               if (posix_ipc_msg_get_info(NULL, &msgds) > 0) {
+                       for (msgdsp = msgds; msgdsp->next != NULL; msgdsp = msgdsp->next) {
+                               if (verbose)
+                                       printf(_("removing POSIX message queue `%s'\n"), msgdsp->mname);
+                               ret |= remove_name(PMSG, msgdsp->mname);
+                       }
+                       posix_ipc_msg_free_info(msgds);
+               }
+       }
        return ret;
 }
 
@@ -294,13 +382,22 @@ int main(int argc, char **argv)
        int rm_all = 0;
        type_id what_all = ALL;
 
+       enum {
+               OPT_PSHM = CHAR_MAX + 1,
+               OPT_PMSG,
+               OPT_PSEM
+       };
+
        static const struct option longopts[] = {
                {"shmem-id", required_argument, NULL, 'm'},
                {"shmem-key", required_argument, NULL, 'M'},
+               {"posix-shmem", required_argument, NULL, OPT_PSHM},
                {"queue-id", required_argument, NULL, 'q'},
                {"queue-key", required_argument, NULL, 'Q'},
+               {"posix-mqueue", required_argument, NULL, OPT_PMSG},
                {"semaphore-id", required_argument, NULL, 's'},
                {"semaphore-key", required_argument, NULL, 'S'},
+               {"posix-semaphore", required_argument, NULL, OPT_PSEM},
                {"all", optional_argument, NULL, 'a'},
                {"verbose", no_argument, NULL, 'v'},
                {"version", no_argument, NULL, 'V'},
@@ -309,8 +406,10 @@ int main(int argc, char **argv)
        };
 
        /* if the command is executed without parameters, do nothing */
-       if (argc == 1)
-               return 0;
+       if (argc == 1) {
+               warnx(_("bad usage"));
+               errtryhelp(EXIT_FAILURE);
+       }
 
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
@@ -368,15 +467,33 @@ int main(int argc, char **argv)
                        if (remove_id(SEM, iskey, id))
                                ret++;
                        break;
+               case OPT_PSHM:
+                       if (remove_name(PSHM, optarg))
+                               ret++;
+                       break;
+               case OPT_PMSG:
+                       if (remove_name(PMSG, optarg))
+                               ret++;
+                       break;
+               case OPT_PSEM:
+                       if (remove_name(PSEM, optarg))
+                               ret++;
+                       break;
                case 'a':
                        rm_all = 1;
                        if (optarg) {
                                if (!strcmp(optarg, "shm"))
                                        what_all = SHM;
+                               else if (!strcmp(optarg, "pshm"))
+                                       what_all = PSHM;
                                else if (!strcmp(optarg, "msg"))
                                        what_all = MSG;
+                               else if (!strcmp(optarg, "pmsg"))
+                                       what_all = PMSG;
                                else if (!strcmp(optarg, "sem"))
                                        what_all = SEM;
+                               else if (!strcmp(optarg, "psem"))
+                                       what_all = PSEM;
                                else
                                        errx(EXIT_FAILURE,
                                             _("unknown argument: %s"), optarg);
index 4d4bebb7479d487476e2e64536a9ff983137fdfc..7aeccbeca07902e972de29b0554089664f36b7a9 100644 (file)
@@ -51,6 +51,30 @@ int ipc_msg_get_limits(struct ipc_limits *lim)
                lim->msgmax = msginfo.msgmax;
        }
 
+       /* POSIX IPC */
+       FILE *f;
+
+       f = fopen(_PATH_PROC_POSIX_IPC_MSGMNI, "r");
+       if (f) {
+               if(fscanf(f, "%"SCNu64, &lim->msgmni_posix) != 1)
+                       lim->msgmni_posix = 0;
+               fclose(f);
+       }
+
+       f = fopen(_PATH_PROC_POSIX_IPC_MSGMNB, "r");
+       if (f) {
+               if(fscanf(f, "%"SCNu64, &lim->msgmnb_posix) != 1)
+                       lim->msgmnb_posix = 0;
+               fclose(f);
+       }
+
+       f = fopen(_PATH_PROC_POSIX_IPC_MSGMAX, "r");
+       if (f) {
+               if(fscanf(f, "%"SCNu64, &lim->msgmax_posix) != 1)
+                       lim->msgmax_posix = 0;
+               fclose(f);
+       }
+
        return 0;
 }
 
@@ -227,6 +251,75 @@ void ipc_shm_free_info(struct shm_data *shmds)
        }
 }
 
+int posix_ipc_shm_get_info(const char *name, struct posix_shm_data **shmds)
+{
+       DIR *d;
+       int i = 0;
+       struct posix_shm_data *p;
+       struct dirent *de;
+
+       p = *shmds = xcalloc(1, sizeof(struct posix_shm_data));
+       p->next = NULL;
+
+       d = opendir(_PATH_DEV_SHM);
+       if (!d)
+               err(EXIT_FAILURE, _("cannot open %s"), _PATH_DEV_SHM);
+
+       while ((de = readdir(d)) != NULL) {
+               if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
+                   (de->d_name[0] == '.' && de->d_name[1] == '.' &&
+                    de->d_name[2] == '\0'))
+                       continue;
+
+               if (strncmp(de->d_name, "sem.", 4) == 0)
+                       continue;
+
+               struct stat st;
+               char path[PATH_MAX];
+               snprintf(path, sizeof(path), "%s/%s", _PATH_DEV_SHM, de->d_name);
+               if (stat(path, &st) < 0)
+                       continue;
+               
+               memset(path, 0, sizeof(path));
+               path[0] = '/';
+               strcat(path, de->d_name);
+
+               p->name = xstrdup(path);
+               p->cuid = st.st_uid;
+               p->cgid = st.st_gid;
+               p->size = st.st_size;
+               p->mode = st.st_mode;
+               p->mtime = st.st_mtime;
+
+               if (name != NULL) {
+                       if (strcmp(name, path) == 0) {
+                               i = 1;
+                               break;
+                       }
+                       continue;
+               }
+
+               p->next = xcalloc(1, sizeof(struct posix_shm_data));
+               p = p->next;
+               p->next = NULL;
+               i++;
+       }
+
+       if (i == 0)
+               free(*shmds);
+       closedir(d);
+       return i;
+}
+
+void posix_ipc_shm_free_info(struct posix_shm_data *shmds)
+{
+       while (shmds) {
+               struct posix_shm_data *next = shmds->next;
+               free(shmds);
+               shmds = next;
+       }
+}
+
 static void get_sem_elements(struct sem_data *p)
 {
        size_t i;
@@ -366,6 +459,80 @@ void ipc_sem_free_info(struct sem_data *semds)
        }
 }
 
+int posix_ipc_sem_get_info(const char *name, struct posix_sem_data **semds)
+{
+       DIR *d;
+       int i = 0;
+       struct posix_sem_data *p;
+       struct dirent *de;
+
+       p = *semds = xcalloc(1, sizeof(struct posix_sem_data));
+       p->next = NULL;
+
+       d = opendir(_PATH_DEV_SHM);
+       if (!d)
+               err(EXIT_FAILURE, _("cannot open %s"), _PATH_DEV_SHM);
+
+       while ((de = readdir(d)) != NULL) {
+               if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
+                   (de->d_name[0] == '.' && de->d_name[1] == '.' &&
+                    de->d_name[2] == '\0'))
+                       continue;
+
+               if (strncmp(de->d_name, "sem.", 4) != 0)
+                       continue;
+
+               struct stat st;
+               char path[PATH_MAX];
+               snprintf(path, sizeof(path), "%s/%s", _PATH_DEV_SHM, de->d_name);
+               if (stat(path, &st) < 0)
+                       continue;
+
+               sem_t *sem = sem_open(de->d_name + 4, 0);
+               if (sem == SEM_FAILED)
+                       continue;
+               sem_getvalue(sem, &p->sval);
+               sem_close(sem);
+               
+               memset(path, 0, sizeof(path));
+               path[0] = '/';
+               strcat(path, de->d_name + 4);
+
+               p->sname = xstrdup(path);
+               p->cuid = st.st_uid;
+               p->cgid = st.st_gid;
+               p->mode = st.st_mode;
+               p->mtime = st.st_mtime;
+
+               if (name != NULL) {
+                       if (strcmp(name, path) == 0) {
+                               i = 1;
+                               break;
+                       }
+                       continue;
+               }
+
+               p->next = xcalloc(1, sizeof(struct posix_sem_data));
+               p = p->next;
+               p->next = NULL;
+               i++;
+       }
+
+       if (i == 0)
+               free(*semds);
+       closedir(d);
+       return i;
+}
+
+void posix_ipc_sem_free_info(struct posix_sem_data *semds)
+{
+       while (semds) {
+               struct posix_sem_data *next = semds->next;
+               free(semds);
+               semds = next;
+       }
+}
+
 int ipc_msg_get_info(int id, struct msg_data **msgds)
 {
        FILE *f;
@@ -477,6 +644,124 @@ void ipc_msg_free_info(struct msg_data *msgds)
        }
 }
 
+int posix_ipc_msg_get_info(const char *name, struct posix_msg_data **msgds)
+{
+       FILE *f;
+       DIR *d;
+       int i = 0, mounted = 0;
+       struct posix_msg_data *p;
+       struct dirent *de;
+
+       p = *msgds = xcalloc(1, sizeof(struct msg_data));
+       p->next = NULL;
+
+       d = opendir(_PATH_DEV_MQUEUE);
+       if (!d) {
+               if (errno == ENOENT) {
+                       struct libmnt_context *ctx;
+
+                       ctx = mnt_new_context();
+                       if (!ctx)
+                               err(EXIT_FAILURE, _("cannot create libmount context"));
+
+                       if (mnt_context_set_source(ctx, "none") < 0)
+                               err(EXIT_FAILURE, _("cannot set source"));
+
+                       if (mnt_context_set_target(ctx, _PATH_DEV_MQUEUE) < 0)
+                               err(EXIT_FAILURE, _("cannot set target"));
+
+                       if (mnt_context_set_fstype(ctx, "mqueue") < 0)
+                               err(EXIT_FAILURE, _("cannot set filesystem type"));
+
+                       if (mnt_context_mount(ctx) < 0)
+                               err(EXIT_FAILURE, _("cannot mount %s"), _PATH_DEV_MQUEUE);
+
+                       mounted = 1;
+               } else err(EXIT_FAILURE, _("cannot open %s"), _PATH_DEV_MQUEUE);
+       }
+
+       while ((de = readdir(d)) != NULL) {
+               if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
+                   (de->d_name[0] == '.' && de->d_name[1] == '.' &&
+                    de->d_name[2] == '\0'))
+                       continue;
+
+               struct stat st;
+               char path[PATH_MAX];
+               snprintf(path, sizeof(path), "%s/%s", _PATH_DEV_MQUEUE, de->d_name);
+               if (stat(path, &st) < 0)
+                       continue;
+
+               f = fopen(path, "r");
+               if (!f)
+                       continue;
+               if (fscanf(f, "QSIZE:%"SCNu64, &p->q_cbytes) != 1) {
+                       fclose(f);
+                       continue;
+               }
+               fclose(f);
+               
+               memset(path, 0, sizeof(path));
+               path[0] = '/';
+               strcat(path, de->d_name);
+
+               p->mname = xstrdup(path);
+
+               mqd_t mq = mq_open(path, O_RDONLY);
+               struct mq_attr attr;
+               mq_getattr(mq, &attr);
+               p->q_qnum = attr.mq_curmsgs;
+               mq_close(mq);
+
+               p->cuid = st.st_uid;
+               p->cgid = st.st_gid;
+               p->mode = st.st_mode;
+               p->mtime = st.st_mtime;
+
+               if (name != NULL) {
+                       if (strcmp(name, path) == 0) {
+                               i = 1;
+                               break;
+                       }
+                       continue;
+               }
+
+               p->next = xcalloc(1, sizeof(struct posix_msg_data));
+               p = p->next;
+               p->next = NULL;
+               i++;
+       }
+
+       if (i == 0)
+               free(*msgds);
+       closedir(d);
+
+       if (mounted) {
+               struct libmnt_context *ctx;
+
+               ctx = mnt_new_context();
+               if (!ctx)
+                       err(EXIT_FAILURE, _("cannot create libmount context"));
+
+               if (mnt_context_set_target(ctx, _PATH_DEV_MQUEUE) < 0)
+                       err(EXIT_FAILURE, _("cannot set target"));
+
+               if (mnt_context_umount(ctx) < 0)
+                       err(EXIT_FAILURE, _("cannot umount %s"), _PATH_DEV_MQUEUE);
+       }
+
+       return i;
+}
+
+void posix_ipc_msg_free_info(struct posix_msg_data *msgds)
+{
+       while (msgds) {
+               struct posix_msg_data *next = msgds->next;
+               free(msgds);
+               msgds = next;
+       }
+}
+
 void ipc_print_perms(FILE *f, struct ipc_stat *is)
 {
        struct passwd *pw;
index 0234465d2b9241eb778957b60f20195899bff829..7c6963aa57d1afadd273f47cbe2434a5d7383607 100644 (file)
 #include <sys/msg.h>
 #include <sys/sem.h>
 #include <sys/shm.h>
+#include <mqueue.h>
+#include <semaphore.h>
 #include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
 #include <grp.h>
 #include <pwd.h>
 #include <stdint.h>
+#include <libmount.h>
 
 /*
  * SHM_DEST and SHM_LOCKED are defined in kernel headers, but inside
@@ -99,6 +102,7 @@ enum {
 };
 
 struct ipc_limits {
+       /* System V IPC */
        uint64_t        shmmni;         /* max number of segments */
        uint64_t        shmmax;         /* max segment size */
        uint64_t        shmall;         /* max total shared memory */
@@ -113,6 +117,11 @@ struct ipc_limits {
        int             msgmni;         /* max queues system wide */
        uint64_t        msgmax;         /* max size of message */
        int             msgmnb;         /* default max size of queue */
+
+       /* POSIX IPC */
+       uint64_t        msgmax_posix;   /* max size of message */
+       uint64_t        msgmni_posix;   /* max queues system wide */
+       uint64_t        msgmnb_posix;   /* default max number of messages in a queue */
 };
 
 extern int ipc_msg_get_limits(struct ipc_limits *lim);
@@ -153,6 +162,20 @@ struct shm_data {
 extern int ipc_shm_get_info(int id, struct shm_data **shmds);
 extern void ipc_shm_free_info(struct shm_data *shmds);
 
+struct posix_shm_data {
+       char                    *name;
+       int64_t                 mtime;  /* last change time */
+       uid_t                   cuid;
+       gid_t                   cgid;
+       off_t                   size;
+       unsigned int    mode;
+
+       struct posix_shm_data *next;
+};
+
+extern int posix_ipc_shm_get_info(const char *name, struct posix_shm_data **shmds);
+extern void posix_ipc_shm_free_info(struct posix_shm_data *shmds);
+
 /* See 'struct sem_array' in kernel sources
  */
 struct sem_elem {
@@ -175,6 +198,20 @@ struct sem_data {
 extern int ipc_sem_get_info(int id, struct sem_data **semds);
 extern void ipc_sem_free_info(struct sem_data *semds);
 
+struct posix_sem_data {
+       char                    *sname;
+       int64_t                 mtime;  /* last change time */
+       uid_t                   cuid;
+       gid_t                   cgid;
+       unsigned int    mode;
+       int                             sval;   /* semaphore value */
+
+       struct posix_sem_data *next;
+};
+
+extern int posix_ipc_sem_get_info(const char *name, struct posix_sem_data **semds);
+extern void posix_ipc_sem_free_info(struct posix_sem_data *semds);
+
 /* See 'struct msg_queue' in kernel sources
  */
 struct msg_data {
@@ -195,4 +232,19 @@ struct msg_data {
 extern int ipc_msg_get_info(int id, struct msg_data **msgds);
 extern void ipc_msg_free_info(struct msg_data *msgds);
 
+struct posix_msg_data {
+       char                    *mname;
+       int64_t                 mtime;
+       uid_t                   cuid;
+       gid_t                   cgid;
+       unsigned int    mode;
+       uint64_t                q_cbytes;       /* current number of bytes on the queue */
+       long                    q_qnum;         /* number of messages on the queue */
+
+       struct posix_msg_data *next;
+};
+
+extern int posix_ipc_msg_get_info(const char *name, struct posix_msg_data **msgds);
+extern void posix_ipc_msg_free_info(struct posix_msg_data *msgds);
+
 #endif /* UTIL_LINUX_IPCUTILS_H */
index 3ee790e2177652658ae680b515b0c9b4f4e323a2..01deaf95f6b5a2b6f53d305be452eac9b01ed17b 100644 (file)
@@ -16,12 +16,15 @@ lsipc - show information on IPC facilities currently employed in the system
 
 == DESCRIPTION
 
-*lsipc* shows information on the System V inter-process communication facilities for which the calling process has read access.
+*lsipc* shows information on the POSIX and System V inter-process communication facilities for which the calling process has read access.
 
 == OPTIONS
 
 *-i*, *--id* _id_::
-Show full details on just the one resource element identified by _id_. This option needs to be combined with one of the three resource options: *-m*, *-q* or *-s*. It is possible to override the default output format for this option with the *--list*, *--raw*, *--json* or *--export* option.
+Show full details on just the one resource element (System V) identified by _id_. This option needs to be combined with one of the three resource options: *-m*, *-q* or *-s*. It is possible to override the default output format for this option with the *--list*, *--raw*, *--json* or *--export* option.
+
+*-N*, *--name* _name_::
+Show full details on just the one resource element (POSIX) identified by _name_. This option needs to be combined with one of the three resource options: *-M*, *-Q* or *-S*. It is possible to override the default output format for this option with the *--list*, *--raw*, *--json* or *--export* option.
 
 *-g*, *--global*::
 Show system-wide usage and limits of IPC resources. This option may be combined with one of the three resource options: *-m*, *-q* or *-s*. The default is to show information about all resources.
@@ -31,13 +34,22 @@ include::man-common/help-version.adoc[]
 === Resource options
 
 *-m*, *--shmems*::
-Write information about active shared memory segments.
+Write information about active System V shared memory segments.
+
+*-M*, *--posix-shmems*::
+Write information about active POSIX shared memory segments.
 
 *-q*, *--queues*::
-Write information about active message queues.
+Write information about active System V message queues.
+
+*-Q*, *--posix-mqueues*::
+Write information about active POSIX message queues. Mounts /dev/mqueue if not already mounted.
 
 *-s*, *--semaphores*::
-Write information about active semaphore sets.
+Write information about active System V semaphore sets.
+
+*-S*, *--posix-semaphores*::
+Write information about active POSIX named semaphores.
 
 === Output formatting
 
index 85ebcafd3525626a0d5cdf33d9c31d090edbb073..c095f315c6a2f702352454f47da4181be1ed4e1e 100644 (file)
@@ -59,12 +59,17 @@ enum {
        COLDESC_IDX_GEN_FIRST = 0,
                COL_KEY = COLDESC_IDX_GEN_FIRST,
                COL_ID,
-               COL_OWNER,
-               COL_PERMS,
-               COL_CUID,
-               COL_CUSER,
-               COL_CGID,
-               COL_CGROUP,
+
+               /* generic and posix */
+               COLDESC_IDX_GEN_POSIX_FIRST,
+                       COL_OWNER = COLDESC_IDX_GEN_POSIX_FIRST,
+                       COL_PERMS,
+                       COL_CUID,
+                       COL_CUSER,
+                       COL_CGID,
+                       COL_CGROUP,
+               COLDSEC_IDX_GEN_POSIX_LAST = COL_CGROUP,
+
                COL_UID,
                COL_USER,
                COL_GID,
@@ -72,6 +77,12 @@ enum {
                COL_CTIME,
        COLDESC_IDX_GEN_LAST = COL_CTIME,
 
+       /* posix-specific */
+       COLDESC_IDX_POSIX_FIRST,
+               COL_NAME = COLDESC_IDX_POSIX_FIRST,
+               COL_MTIME,
+       COLDESC_IDX_POSIX_LAST = COL_MTIME,
+
        /* msgq-specific */
        COLDESC_IDX_MSG_FIRST,
                COL_USEDBYTES = COLDESC_IDX_MSG_FIRST,
@@ -107,7 +118,12 @@ enum {
                COL_LIMIT,
                COL_USED,
                COL_USEPERC,
-       COLDESC_IDX_SUM_LAST = COL_USEPERC
+       COLDESC_IDX_SUM_LAST = COL_USEPERC,
+
+       /* posix-sem-specific */
+       COLDESC_IDX_POSIX_SEM_FIRST,
+               COL_SVAL = COLDESC_IDX_POSIX_SEM_FIRST,
+       COLDESC_IDX_POSIX_SEM_LAST = COL_SVAL
 };
 
 /* not all columns apply to all options, so we specify a legal range for each */
@@ -161,6 +177,10 @@ static const struct lsipc_coldesc coldescs[] =
        [COL_GROUP]     = { "GROUP",    N_("Group name"), N_("Group name"), 1},
        [COL_CTIME]     = { "CTIME",    N_("Time of the last change"), N_("Last change"), 1, SCOLS_FL_RIGHT},
 
+       /* posix-common */
+       [COL_NAME]              = { "NAME",     N_("Resource name"), N_("Name"), 1 },
+       [COL_MTIME]     = { "MTIME",   N_("Time of last action"), N_("Last action"), 1, SCOLS_FL_RIGHT},
+
        /* msgq-specific */
        [COL_USEDBYTES] = { "USEDBYTES",N_("Bytes used"), N_("Bytes used"), 1, SCOLS_FL_RIGHT},
        [COL_MSGS]      = { "MSGS",     N_("Number of messages"), N_("Messages"), 1},
@@ -189,6 +209,9 @@ static const struct lsipc_coldesc coldescs[] =
        [COL_USED]      = { "USED",     N_("Currently used"), N_("Used"), 1, SCOLS_FL_RIGHT },
        [COL_USEPERC]   = { "USE%",     N_("Currently use percentage"), N_("Use"), 1, SCOLS_FL_RIGHT },
        [COL_LIMIT]     = { "LIMIT",    N_("System-wide limit"), N_("Limit"), 1, SCOLS_FL_RIGHT },
+
+       /* posix-sem-specific */
+       [COL_SVAL]      = { "SVAL",     N_("Semaphore value"), N_("Value"), 1, SCOLS_FL_RIGHT}
 };
 
 
@@ -296,11 +319,15 @@ static void __attribute__((__noreturn__)) usage(void)
 
        fputs(USAGE_SEPARATOR, out);
        fputs(_("Resource options:\n"), out);
-       fputs(_(" -m, --shmems      shared memory segments\n"), out);
-       fputs(_(" -q, --queues      message queues\n"), out);
-       fputs(_(" -s, --semaphores  semaphores\n"), out);
-       fputs(_(" -g, --global      info about system-wide usage (may be used with -m, -q and -s)\n"), out);
-       fputs(_(" -i, --id <id>     print details on resource identified by <id>\n"), out);
+       fputs(_(" -m, --shmems           shared memory segments\n"), out);
+       fputs(_(" -M, --posix-shmems     POSIX shared memory segments\n"), out);
+       fputs(_(" -q, --queues           message queues\n"), out);
+       fputs(_(" -Q, --posix-mqueues    POSIX message queues\n"), out);
+       fputs(_(" -s, --semaphores       semaphores\n"), out);
+       fputs(_(" -S, --posix-semaphores POSIX semaphores\n"), out);
+       fputs(_(" -g, --global           info about system-wide usage (may be used with -m, -q and -s)\n"), out);
+       fputs(_(" -i, --id <id>          print details on resource identified by <id>\n"), out);
+       fputs(_(" -N, --name <name>      print details on posix resource identified by <name>\n"), out);
 
        fputs(USAGE_OPTIONS, out);
        fputs(_("     --noheadings         don't print headings\n"), out);
@@ -322,22 +349,32 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(USAGE_SEPARATOR, out);
        fprintf(out, USAGE_HELP_OPTIONS(26));
 
-       fprintf(out, _("\nGeneric columns:\n"));
+       fprintf(out, _("\nGeneric System V columns:\n"));
        for (i = COLDESC_IDX_GEN_FIRST; i <= COLDESC_IDX_GEN_LAST; i++)
                fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
+       
+       fprintf(out, _("\nGeneric POSIX columns:\n"));
+       fprintf(out, " %14s  %s\n", coldescs[COL_NAME].name, _(coldescs[COL_NAME].help));
+       for (i = COLDESC_IDX_GEN_POSIX_FIRST; i <= COLDSEC_IDX_GEN_POSIX_LAST; i++)
+               fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
+       fprintf(out, " %14s  %s\n", coldescs[COL_MTIME].name, _(coldescs[COL_MTIME].help));
 
-       fprintf(out, _("\nShared-memory columns (--shmems):\n"));
+       fprintf(out, _("\nSystem V Shared-memory columns (--shmems):\n"));
        for (i = COLDESC_IDX_SHM_FIRST; i <= COLDESC_IDX_SHM_LAST; i++)
                fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
 
-       fprintf(out, _("\nMessage-queue columns (--queues):\n"));
+       fprintf(out, _("\nSystem V Message-queue columns (--queues):\n"));
        for (i = COLDESC_IDX_MSG_FIRST; i <= COLDESC_IDX_MSG_LAST; i++)
                fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
 
-       fprintf(out, _("\nSemaphore columns (--semaphores):\n"));
+       fprintf(out, _("\nSystem V Semaphore columns (--semaphores):\n"));
        for (i = COLDESC_IDX_SEM_FIRST; i <= COLDESC_IDX_SEM_LAST; i++)
                fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
 
+       fprintf(out, _("\nPOSIX Semaphore columns (--posix-semaphores):\n"));
+       for (i = COLDESC_IDX_POSIX_SEM_FIRST; i <= COLDESC_IDX_POSIX_SEM_LAST; i++)
+               fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
+
        fprintf(out, _("\nSummary columns (--global):\n"));
        for (i = COLDESC_IDX_SUM_FIRST; i <= COLDESC_IDX_SUM_LAST; i++)
                fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
@@ -728,6 +765,92 @@ static void do_sem_global(struct lsipc_control *ctl, struct libscols_table *tb)
        global_set_data(ctl, tb, "SEMVMX", _("Semaphore max value"), 0, lim.semvmx, 0, 0);
 }
 
+static void do_posix_sem(const char *name, struct lsipc_control *ctl, struct libscols_table *tb)
+{
+       struct libscols_line *ln;
+       struct passwd *pw = NULL;
+       struct group *gr = NULL;
+       struct posix_sem_data *semds, *p;
+       char *arg = NULL;
+
+       scols_table_set_name(tb, "posix-semaphores");
+       if (posix_ipc_sem_get_info(name, &semds) < 1) {
+               if (name)
+                       warnx(_("name %s not found"), name);
+               return;
+       }
+       for (p = semds; p->next != NULL || name != NULL; p = p->next) {
+               size_t n;
+
+               ln = scols_table_new_line(tb, NULL);
+               if (!ln)
+                       err(EXIT_FAILURE, _("failed to allocate output line"));
+
+               /* no need to call getpwuid() for the same user */
+               if (!(pw && pw->pw_uid == p->cuid))
+                       pw = getpwuid(p->cuid);
+
+               /* no need to call getgrgid() for the same user */
+               if (!(gr && gr->gr_gid == p->cgid))
+                       gr = getgrgid(p->cgid);
+
+               for (n = 0; n < ncolumns; n++) {
+                       int rc = 0;
+                       switch (get_column_id(n)) {
+                       case COL_NAME:
+                               rc = scols_line_set_data(ln, n, p->sname);
+                               break;
+                       case COL_OWNER:
+                               arg = get_username(&pw, p->cuid);
+                               if (!arg)
+                                       xasprintf(&arg, "%u", p->cuid);
+                               rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_PERMS:
+                               if (ctl->numperms)
+                                       xasprintf(&arg, "%#o", p->mode & 0777);
+                               else {
+                                       arg = xmalloc(11);
+                                       xstrmode(p->mode & 0777, arg);
+                               }
+                               rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_MTIME:
+                               if (p->mtime != 0)
+                                       rc = scols_line_refer_data(ln, n,
+                                               make_time(ctl->time_mode,
+                                                         (time_t) p->mtime));
+                               break;
+                       case COL_CUID:
+                               rc = scols_line_sprintf(ln, n, "%u", p->cuid);
+                               break;
+                       case COL_CUSER:
+                               arg = get_username(&pw, p->cuid);
+                               if (arg)
+                                       rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_CGID:
+                               rc = scols_line_sprintf(ln, n, "%u", p->cgid);
+                               break;
+                       case COL_CGROUP:
+                               arg = get_groupname(&gr, p->cgid);
+                               if (arg)
+                                       rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_SVAL:
+                               rc = scols_line_sprintf(ln, n, "%d", p->sval);
+                               break;
+                       }
+                       if (rc != 0)
+                               err(EXIT_FAILURE, _("failed to add output data"));
+                       arg = NULL;
+               }
+               if (name != NULL)
+                       break;          
+       }
+       posix_ipc_sem_free_info(semds);
+}
+
 static void do_msg(int id, struct lsipc_control *ctl, struct libscols_table *tb)
 {
        struct libscols_line *ln;
@@ -861,6 +984,101 @@ static void do_msg(int id, struct lsipc_control *ctl, struct libscols_table *tb)
        ipc_msg_free_info(msgds);
 }
 
+static void do_posix_msg(const char *name, struct lsipc_control *ctl, struct libscols_table *tb)
+{
+    struct libscols_line *ln;
+       struct passwd *pw = NULL;
+       struct group *gr = NULL;
+       struct posix_msg_data *msgds, *p;
+       char *arg = NULL;
+
+       if (posix_ipc_msg_get_info(name, &msgds) < 1) {
+               if (name != NULL)
+                       warnx(_("mqueue %s not found"), name);
+               return;
+       }
+       scols_table_set_name(tb, "posix-messages");
+
+       for (p = msgds; p->next != NULL || name != NULL; p = p->next) {
+               size_t n;
+               ln = scols_table_new_line(tb, NULL);
+
+               if (!ln)
+                       err(EXIT_FAILURE, _("failed to allocate output line"));
+
+               /* no need to call getpwuid() for the same user */
+               if (!(pw && pw->pw_uid == p->cuid))
+                       pw = getpwuid(p->cuid);
+
+               /* no need to call getgrgid() for the same user */
+               if (!(gr && gr->gr_gid == p->cgid))
+                       gr = getgrgid(p->cgid);
+
+               for (n = 0; n < ncolumns; n++) {
+                       int rc = 0;
+
+                       switch (get_column_id(n)) {
+                       case COL_NAME:
+                               rc = scols_line_refer_data(ln, n, p->mname);
+                               break;
+                       case COL_OWNER:
+                               arg = get_username(&pw, p->cuid);
+                               if (!arg)
+                                       xasprintf(&arg, "%u", p->cuid);
+                               rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_PERMS:
+                               if (ctl->numperms)
+                                       xasprintf(&arg, "%#o", p->mode & 0777);
+                               else {
+                                       arg = xmalloc(11);
+                                       xstrmode(p->mode & 0777, arg);
+                                       rc = scols_line_refer_data(ln, n, arg);
+                               }
+                               break;
+                       case COL_CUID:
+                               rc = scols_line_sprintf(ln, n, "%u", p->cuid);
+                               break;
+                       case COL_CUSER:
+                               arg = get_username(&pw, p->cuid);
+                               if (arg)
+                                       rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_CGID:
+                               rc = scols_line_sprintf(ln, n, "%u", p->cgid);
+                               break;
+                       case COL_CGROUP:
+                               arg = get_groupname(&gr, p->cgid);
+                               if (arg)
+                                       rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_MTIME:
+                               if (p->mtime != 0)
+                                       rc = scols_line_refer_data(ln, n,
+                                               make_time(ctl->time_mode,
+                                                         (time_t) p->mtime));
+                               break;
+                       case COL_USEDBYTES:
+                               if (ctl->bytes)
+                                       xasprintf(&arg, "%ju", p->q_cbytes);
+                               else
+                                       arg = size_to_human_string(SIZE_SUFFIX_1LETTER,
+                                                       p->q_cbytes);
+                               rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_MSGS:
+                               rc = scols_line_sprintf(ln, n, "%ju", p->q_qnum);
+                               break;
+                       }
+                       if (rc != 0)
+                               err(EXIT_FAILURE, _("failed to set data"));
+                       arg = NULL;
+               }
+               if (name != NULL)
+                       break;
+       }
+       posix_ipc_msg_free_info(msgds);
+} 
 
 static void do_msg_global(struct lsipc_control *ctl, struct libscols_table *tb)
 {
@@ -879,9 +1097,31 @@ static void do_msg_global(struct lsipc_control *ctl, struct libscols_table *tb)
                ipc_msg_free_info(msgds);
        }
 
-       global_set_data(ctl, tb, "MSGMNI", _("Number of message queues"), msgqs, lim.msgmni, 1, 0);
-       global_set_data(ctl, tb, "MSGMAX", _("Max size of message (bytes)"),    0, lim.msgmax, 0, 1);
-       global_set_data(ctl, tb, "MSGMNB", _("Default max size of queue (bytes)"), 0, lim.msgmnb, 0, 1);
+       global_set_data(ctl, tb, "MSGMNI", _("Number of System V message queues"), msgqs, lim.msgmni, 1, 0);
+       global_set_data(ctl, tb, "MSGMAX", _("Max size of System V message (bytes)"),   0, lim.msgmax, 0, 1);
+       global_set_data(ctl, tb, "MSGMNB", _("Default max size of System V queue (bytes)"), 0, lim.msgmnb, 0, 1);
+}
+
+static void do_posix_msg_global(struct lsipc_control *ctl, struct libscols_table *tb)
+{
+       struct posix_msg_data *pmsgds;
+       struct ipc_limits lim;
+       int pmsgqs = 0;
+
+       ipc_msg_get_limits(&lim);
+
+       /* count number of used posix queues */
+       if (posix_ipc_msg_get_info(NULL, &pmsgds) > 0) {
+               struct posix_msg_data *p;
+
+               for (p = pmsgds; p->next != NULL; p = p->next)
+                       ++pmsgqs;
+               posix_ipc_msg_free_info(pmsgds);
+       }
+
+       global_set_data(ctl, tb, "MQUMNI", _("Number of POSIX message queues"), pmsgqs, lim.msgmni_posix, 1, 0);
+       global_set_data(ctl, tb, "MQUMAX", _("Max size of POSIX message (bytes)"), 0, lim.msgmax_posix, 0, 1);
+       global_set_data(ctl, tb, "MQUMNB", _("Number of messages in POSIX message queue"), 0, lim.msgmnb_posix, 0, 0);
 }
 
 
@@ -1054,6 +1294,100 @@ static void do_shm(int id, struct lsipc_control *ctl, struct libscols_table *tb)
        ipc_shm_free_info(shmds);
 }
 
+static void do_posix_shm(const char *name, struct lsipc_control *ctl, struct libscols_table *tb)
+{
+       struct libscols_line *ln;
+       struct passwd *pw = NULL;
+       struct group *gr = NULL;
+       struct posix_shm_data *shmds, *p;
+       char *arg = NULL;
+
+       if (posix_ipc_shm_get_info(name, &shmds) < 1) {
+               if (name != NULL)
+                       warnx(_("shm %s not found"), name);
+               return;
+       }
+
+       scols_table_set_name(tb, "posix-sharedmemory");
+
+       for (p = shmds; p->next != NULL || name != NULL ; p = p->next) {
+               size_t n;
+               ln = scols_table_new_line(tb, NULL);
+
+               if (!ln)
+                       err(EXIT_FAILURE, _("failed to allocate output line"));
+
+               /* no need to call getpwuid() for the same user */
+               if (!(pw && pw->pw_uid == p->cuid))
+                       pw = getpwuid(p->cuid);
+
+               /* no need to call getgrgid() for the same user */
+               if (!(gr && gr->gr_gid == p->cgid))
+                       gr = getgrgid(p->cgid);
+
+               for (n = 0; n < ncolumns; n++) {
+                       int rc = 0;
+
+                       switch (get_column_id(n)) {
+                       case COL_NAME:
+                               rc = scols_line_refer_data(ln, n, p->name);
+                               break;
+                       case COL_OWNER:
+                               arg = get_username(&pw, p->cuid);
+                               if (!arg)
+                                       xasprintf(&arg, "%u", p->cuid);
+                               rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_PERMS:
+                               if (ctl->numperms)
+                                       xasprintf(&arg, "%#o", p->mode & 0777);
+                               else {
+                                       arg = xmalloc(11);
+                                       xstrmode(p->mode & 0777, arg);
+                               }
+                               rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_CUID:
+                               rc = scols_line_sprintf(ln, n, "%u", p->cuid);
+                               break;
+                       case COL_CUSER:
+                               arg = get_username(&pw, p->cuid);
+                               if (arg)
+                                       rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_CGID:
+                               rc = scols_line_sprintf(ln, n, "%u", p->cgid);
+                               break;
+                       case COL_CGROUP:
+                               arg = get_groupname(&gr, p->cgid);
+                               if (arg)
+                                       rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_SIZE:
+                               if (ctl->bytes)
+                                       xasprintf(&arg, "%ju", p->size);
+                               else
+                                       arg = size_to_human_string(SIZE_SUFFIX_1LETTER,
+                                                       p->size);
+                               rc = scols_line_refer_data(ln, n, arg);
+                               break;
+                       case COL_MTIME:
+                               if (p->mtime != 0)
+                                       rc = scols_line_refer_data(ln, n,
+                                               make_time(ctl->time_mode,
+                                                         (time_t) p->mtime));
+                               break;
+                       }
+                       if (rc != 0)
+                               err(EXIT_FAILURE, _("failed to set data"));
+                       arg = NULL;
+               }
+               if (name != NULL)
+                       break;
+       }
+       posix_ipc_shm_free_info(shmds);
+}
+
 static void do_shm_global(struct lsipc_control *ctl, struct libscols_table *tb)
 {
        struct shm_data *shmds;
@@ -1081,11 +1415,13 @@ static void do_shm_global(struct lsipc_control *ctl, struct libscols_table *tb)
 int main(int argc, char *argv[])
 {
        int opt, msg = 0, sem = 0, shm = 0, id = -1;
+       int pmsg = 0, pshm = 0, psem = 0;
        int show_time = 0, show_creat = 0, global = 0;
        size_t i;
        struct lsipc_control *ctl = xcalloc(1, sizeof(struct lsipc_control));
        static struct libscols_table *tb;
        char *outarg = NULL;
+       char *name = NULL;
 
        /* long only options. */
        enum {
@@ -1103,11 +1439,15 @@ int main(int argc, char *argv[])
                { "id",             required_argument,  NULL, 'i' },
                { "json",           no_argument,        NULL, 'J' },
                { "list",           no_argument,        NULL, 'l' },
+               { "name",           required_argument,  NULL, 'N' },
                { "newline",        no_argument,        NULL, 'n' },
                { "noheadings",     no_argument,        NULL, OPT_NOHEAD },
                { "notruncate",     no_argument,        NULL, OPT_NOTRUNC },
                { "numeric-perms",  no_argument,        NULL, 'P' },
                { "output",         required_argument,  NULL, 'o' },
+               { "posix-mqueues",  no_argument,        NULL, 'Q' },
+               { "posix-semaphores", no_argument,      NULL, 'S' },
+               { "posix-shmems",   no_argument,        NULL, 'M' },
                { "queues",         no_argument,        NULL, 'q' },
                { "raw",            no_argument,        NULL, 'r' },
                { "semaphores",     no_argument,        NULL, 's' },
@@ -1121,9 +1461,9 @@ int main(int argc, char *argv[])
 
        static const ul_excl_t excl[] = {       /* rows and cols in ASCII order */
                { 'J', 'e', 'l', 'n', 'r' },
-               { 'g', 'i' },
+               { 'N', 'g', 'i' },
                { 'c', 'o', 't' },
-               { 'm', 'q', 's' },
+               { 'M', 'Q', 'S', 'm', 'q', 's' },       
                { 0 }
        };
        int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
@@ -1137,7 +1477,7 @@ int main(int argc, char *argv[])
 
        scols_init_debug(0);
 
-       while ((opt = getopt_long(argc, argv, "bceghi:Jlmno:PqrstVy", longopts, NULL)) != -1) {
+       while ((opt = getopt_long(argc, argv, "bceghi:JlMmN:no:PQqrSstVy", longopts, NULL)) != -1) {
 
                err_exclusive_options(opt, longopts, excl, excl_st);
 
@@ -1148,6 +1488,9 @@ int main(int argc, char *argv[])
                case 'i':
                        id = strtos32_or_err(optarg, _("failed to parse IPC identifier"));
                        break;
+               case 'N':
+                       name = optarg;
+                       break;
                case 'e':
                        ctl->outmode = OUT_EXPORT;
                        break;
@@ -1173,6 +1516,17 @@ int main(int argc, char *argv[])
                        LOWER = COLDESC_IDX_MSG_FIRST;
                        UPPER = COLDESC_IDX_MSG_LAST;
                        break;
+               case 'Q':
+                       pmsg = 1;
+                       add_column(columns, ncolumns++, COL_NAME);
+                       add_column(columns, ncolumns++, COL_PERMS);
+                       add_column(columns, ncolumns++, COL_OWNER);
+                       add_column(columns, ncolumns++, COL_MTIME);
+                       add_column(columns, ncolumns++, COL_USEDBYTES);
+                       add_column(columns, ncolumns++, COL_MSGS);
+                       LOWER = COLDESC_IDX_POSIX_FIRST;
+                       UPPER = COLDESC_IDX_POSIX_LAST;
+                       break;
                case 'l':
                        ctl->outmode = OUT_LIST;
                        break;
@@ -1192,6 +1546,16 @@ int main(int argc, char *argv[])
                        LOWER = COLDESC_IDX_SHM_FIRST;
                        UPPER = COLDESC_IDX_SHM_LAST;
                        break;
+               case 'M':
+                       pshm = 1;
+                       add_column(columns, ncolumns++, COL_NAME);
+                       add_column(columns, ncolumns++, COL_PERMS);
+                       add_column(columns, ncolumns++, COL_OWNER);
+                       add_column(columns, ncolumns++, COL_SIZE);
+                       add_column(columns, ncolumns++, COL_MTIME);
+                       LOWER = COLDESC_IDX_POSIX_FIRST;
+                       UPPER = COLDESC_IDX_POSIX_LAST;
+                       break;
                case 'n':
                        ctl->outmode = OUT_NEWLINE;
                        break;
@@ -1208,6 +1572,16 @@ int main(int argc, char *argv[])
                        LOWER = COLDESC_IDX_SEM_FIRST;
                        UPPER = COLDESC_IDX_SEM_LAST;
                        break;
+               case 'S':
+                       psem = 1;
+                       add_column(columns, ncolumns++, COL_NAME);
+                       add_column(columns, ncolumns++, COL_PERMS);
+                       add_column(columns, ncolumns++, COL_OWNER);
+                       add_column(columns, ncolumns++, COL_MTIME);
+                       add_column(columns, ncolumns++, COL_SVAL);
+                       LOWER = COLDESC_IDX_POSIX_FIRST;
+                       UPPER = COLDESC_IDX_POSIX_LAST;
+                       break;
                case OPT_NOTRUNC:
                        ctl->notrunc = 1;
                        break;
@@ -1240,10 +1614,10 @@ int main(int argc, char *argv[])
        }
 
        /* default is global */
-       if (msg + shm + sem == 0) {
-               msg = shm = sem = global = 1;
-               if (show_time || show_creat || id != -1)
-                       errx(EXIT_FAILURE, _("--global is mutually exclusive with --creator, --id and --time"));
+       if (msg + shm + sem + pmsg + pshm + psem == 0) {
+               msg = shm = sem = pmsg = pshm = psem = global = 1;
+               if (show_time || show_creat || id != -1 || name != NULL)
+                       errx(EXIT_FAILURE, _("--global is mutually exclusive with --creator, --id, --name and --time"));
        }
        if (global) {
                add_column(columns, ncolumns++, COL_RESOURCE);
@@ -1256,7 +1630,7 @@ int main(int argc, char *argv[])
        }
 
        /* default to pretty-print if --id specified */
-       if (id != -1 && !ctl->outmode)
+       if ((id != -1 || name != NULL) && !ctl->outmode)
                ctl->outmode = OUT_PRETTY;
 
        if (!ctl->time_mode)
@@ -1270,8 +1644,10 @@ int main(int argc, char *argv[])
                if (show_creat) {
                        add_column(columns, ncolumns++, COL_CUID);
                        add_column(columns, ncolumns++, COL_CGID);
-                       add_column(columns, ncolumns++, COL_UID);
-                       add_column(columns, ncolumns++, COL_GID);
+                       if (!(pmsg || pshm || psem)) {
+                               add_column(columns, ncolumns++, COL_UID);
+                               add_column(columns, ncolumns++, COL_GID);
+                       }
                }
                if (msg && show_time) {
                        add_column(columns, ncolumns++, COL_SEND);
@@ -1312,18 +1688,32 @@ int main(int argc, char *argv[])
                else
                        do_msg(id, ctl, tb);
        }
+       if (pmsg) {
+               if (global)
+                       do_posix_msg_global(ctl, tb);
+               else
+                       do_posix_msg(name, ctl, tb);
+       }
        if (shm) {
                if (global)
                        do_shm_global(ctl ,tb);
                else
                        do_shm(id, ctl, tb);
        }
+       if (pshm) {
+               if (!global)
+                       do_posix_shm(name, ctl, tb);
+       }
        if (sem) {
                if (global)
                        do_sem_global(ctl, tb);
                else
                        do_sem(id, ctl, tb);
        }
+       if (psem) {
+               if (!global)
+                       do_posix_sem(name, ctl, tb);
+       }
 
        print_table(ctl, tb);