You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2000 lines
54 KiB
2000 lines
54 KiB
From 9f643efe377d2a39929f19cc09e8890afc74d9a4 Mon Sep 17 00:00:00 2001 |
|
From: Karel Zak <kzak@redhat.com> |
|
Date: Fri, 24 Jun 2016 12:57:13 +0200 |
|
Subject: [PATCH 78/84] lsipc: backport new command |
|
|
|
Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1153770 |
|
Signed-off-by: Karel Zak <kzak@redhat.com> |
|
--- |
|
bash-completion/lsipc | 64 +++ |
|
configure.ac | 6 + |
|
include/xalloc.h | 7 + |
|
sys-utils/Makemodule.am | 10 + |
|
sys-utils/ipcs.c | 2 +- |
|
sys-utils/ipcutils.c | 116 ++--- |
|
sys-utils/ipcutils.h | 13 +- |
|
sys-utils/lsipc.1 | 133 +++++ |
|
sys-utils/lsipc.c | 1316 +++++++++++++++++++++++++++++++++++++++++++++++ |
|
tests/functions.sh | 16 +- |
|
tests/ts/ipcs/limits2 | 9 +- |
|
11 files changed, 1613 insertions(+), 79 deletions(-) |
|
create mode 100644 bash-completion/lsipc |
|
create mode 100644 sys-utils/lsipc.1 |
|
create mode 100644 sys-utils/lsipc.c |
|
|
|
diff --git a/bash-completion/lsipc b/bash-completion/lsipc |
|
new file mode 100644 |
|
index 0000000..6a87393 |
|
--- /dev/null |
|
+++ b/bash-completion/lsipc |
|
@@ -0,0 +1,64 @@ |
|
+_lsipc_module() |
|
+{ |
|
+ local cur prev OPTS ARG |
|
+ COMPREPLY=() |
|
+ cur="${COMP_WORDS[COMP_CWORD]}" |
|
+ prev="${COMP_WORDS[COMP_CWORD-1]}" |
|
+ case $prev in |
|
+ '-i'|'--id') |
|
+ COMPREPLY=( $(compgen -W "id" -- $cur) ) |
|
+ return 0 |
|
+ ;; |
|
+ '-h'|'--help'|'-V'|'--version') |
|
+ return 0 |
|
+ ;; |
|
+ '-o'|'--output') |
|
+ local prefix realcur OUTPUT_ALL OUTPUT |
|
+ realcur="${cur##*,}" |
|
+ prefix="${cur%$realcur}" |
|
+ OUTPUT_ALL="GENERAL KEY ID OWNER PERMS CUID |
|
+ CGID UID GID CHANGE MESSAGE USEDBYTES |
|
+ MSGS SEND RECV LSPID LRPID SHARED BYTES |
|
+ NATTCH STATUS ATTACH DETACH CPID LPID NSEMS |
|
+ LASTOP" |
|
+ for WORD in $OUTPUT_ALL; do |
|
+ if ! [[ $prefix == *"$WORD"* ]]; then |
|
+ OUTPUT="$WORD $OUTPUT" |
|
+ fi |
|
+ done |
|
+ compopt -o nospace |
|
+ COMPREPLY=( $(compgen -P "$prefix" -W "$OUTPUT" -S ',' -- $realcur) ) |
|
+ return 0 |
|
+ ;; |
|
+ esac |
|
+ case $cur in |
|
+ -*) |
|
+ OPTS="--id |
|
+ --help |
|
+ --version |
|
+ --shmems |
|
+ --queues |
|
+ --semaphores |
|
+ --colon-separate |
|
+ --creator |
|
+ --export |
|
+ --global |
|
+ --newline |
|
+ --noheadings |
|
+ --notruncate |
|
+ --output |
|
+ --pid |
|
+ --print0 |
|
+ --raw |
|
+ --time |
|
+ --time-format" |
|
+ COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) |
|
+ return 0 |
|
+ ;; |
|
+ esac |
|
+ local IFS=$'\n' |
|
+ compopt -o filenames |
|
+ COMPREPLY=( $(compgen -f -- $cur) ) |
|
+ return 0 |
|
+} |
|
+complete -F _lsipc_module lsipc |
|
diff --git a/configure.ac b/configure.ac |
|
index 5d9ea39..fe0a011 100644 |
|
--- a/configure.ac |
|
+++ b/configure.ac |
|
@@ -1038,6 +1038,12 @@ UL_REQUIRES_BUILD([lsns], [libsmartcols]) |
|
AM_CONDITIONAL([BUILD_LSNS], [test "x$build_lsns" = xyes]) |
|
|
|
|
|
+UL_BUILD_INIT([lsipc], [check]) |
|
+UL_REQUIRES_LINUX([lsipc]) |
|
+UL_REQUIRES_BUILD([lsipc], [libsmartcols]) |
|
+AM_CONDITIONAL([BUILD_LSIPC], [test "x$build_lsipc" = xyes]) |
|
+ |
|
+ |
|
UL_BUILD_INIT([chcpu], [check]) |
|
UL_REQUIRES_LINUX([chcpu]) |
|
UL_REQUIRES_HAVE([chcpu], [cpu_set_t], [cpu_set_t type]) |
|
diff --git a/include/xalloc.h b/include/xalloc.h |
|
index 6342793..1a1799a 100644 |
|
--- a/include/xalloc.h |
|
+++ b/include/xalloc.h |
|
@@ -19,6 +19,13 @@ |
|
# define XALLOC_EXIT_CODE EXIT_FAILURE |
|
#endif |
|
|
|
+static inline void __err_oom(const char *file, unsigned int line) |
|
+{ |
|
+ err(XALLOC_EXIT_CODE, "%s: %u: cannot allocate memory", file, line); |
|
+} |
|
+ |
|
+#define err_oom() __err_oom(__FILE__, __LINE__) |
|
+ |
|
static inline __ul_alloc_size(1) |
|
void *xmalloc(const size_t size) |
|
{ |
|
diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am |
|
index 9baf5a3..6badd17 100644 |
|
--- a/sys-utils/Makemodule.am |
|
+++ b/sys-utils/Makemodule.am |
|
@@ -22,6 +22,16 @@ ipcs_SOURCES = sys-utils/ipcs.c \ |
|
ipcs_LDADD = $(LDADD) libcommon.la |
|
|
|
|
|
+if BUILD_LSIPC |
|
+usrbin_exec_PROGRAMS += lsipc |
|
+dist_man_MANS += sys-utils/lsipc.1 |
|
+lsipc_SOURCES = sys-utils/lsipc.c \ |
|
+ sys-utils/ipcutils.c \ |
|
+ sys-utils/ipcutils.h |
|
+lsipc_LDADD = $(LDADD) libcommon.la libsmartcols.la |
|
+lsipc_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir) |
|
+endif |
|
+ |
|
usrbin_exec_PROGRAMS += renice |
|
dist_man_MANS += sys-utils/renice.1 |
|
renice_SOURCES = sys-utils/renice.c |
|
diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c |
|
index 14f5f0b..1843cd5 100644 |
|
--- a/sys-utils/ipcs.c |
|
+++ b/sys-utils/ipcs.c |
|
@@ -201,7 +201,7 @@ static void do_shm (char format, int unit) |
|
_("max seg size"), lim.shmmax, "\n", 0); |
|
ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_KB : unit, |
|
_("max total shared memory"), |
|
- lim.shmall * getpagesize(), "\n", 0); |
|
+ (uint64_t) lim.shmall * getpagesize(), "\n", 0); |
|
ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_BYTES : unit, |
|
_("min seg size"), lim.shmmin, "\n", 0); |
|
return; |
|
diff --git a/sys-utils/ipcutils.c b/sys-utils/ipcutils.c |
|
index 62d7428..51fce7b 100644 |
|
--- a/sys-utils/ipcutils.c |
|
+++ b/sys-utils/ipcutils.c |
|
@@ -1,4 +1,3 @@ |
|
- |
|
#include <inttypes.h> |
|
|
|
#include "c.h" |
|
@@ -54,8 +53,8 @@ int ipc_sem_get_limits(struct ipc_limits *lim) |
|
|
|
} |
|
|
|
- if (rc == 4) { |
|
- struct seminfo seminfo; |
|
+ if (rc != 4) { |
|
+ struct seminfo seminfo = { .semmni = 0 }; |
|
union semun arg = { .array = (ushort *) &seminfo }; |
|
|
|
if (semctl(0, 0, IPC_INFO, arg) < 0) |
|
@@ -82,12 +81,15 @@ int ipc_shm_get_limits(struct ipc_limits *lim) |
|
lim->shmmni = path_read_u64(_PATH_PROC_IPC_SHMMNI); |
|
|
|
} else { |
|
- struct shminfo shminfo; |
|
+ struct shminfo *shminfo; |
|
+ struct shmid_ds shmbuf; |
|
|
|
- if (shmctl(0, IPC_INFO, (struct shmid_ds *) &shminfo) < 0) |
|
+ if (shmctl(0, IPC_INFO, &shmbuf) < 0) |
|
return 1; |
|
- lim->shmmni = shminfo.shmmni; |
|
- lim->shmall = shminfo.shmall; |
|
+ shminfo = (struct shminfo *) &shmbuf; |
|
+ lim->shmmni = shminfo->shmmni; |
|
+ lim->shmall = shminfo->shmall; |
|
+ lim->shmmax = shminfo->shmmax; |
|
} |
|
|
|
return 0; |
|
@@ -97,20 +99,24 @@ int ipc_shm_get_info(int id, struct shm_data **shmds) |
|
{ |
|
FILE *f; |
|
int i = 0, maxid; |
|
+ char buf[BUFSIZ]; |
|
struct shm_data *p; |
|
- struct shm_info dummy; |
|
+ struct shmid_ds dummy; |
|
|
|
p = *shmds = xcalloc(1, sizeof(struct shm_data)); |
|
p->next = NULL; |
|
|
|
f = path_fopen("r", 0, _PATH_PROC_SYSV_SHM); |
|
if (!f) |
|
- goto fallback; |
|
+ goto shm_fallback; |
|
|
|
while (fgetc(f) != '\n'); /* skip header */ |
|
|
|
- while (feof(f) == 0) { |
|
- if (fscanf(f, |
|
+ while (fgets(buf, sizeof(buf), f) != NULL) { |
|
+ /* scan for the first 14-16 columns (e.g. Linux 2.6.32 has 14) */ |
|
+ p->shm_rss = 0xdead; |
|
+ p->shm_swp = 0xdead; |
|
+ if (sscanf(buf, |
|
"%d %d %o %"SCNu64 " %u %u " |
|
"%"SCNu64 " %u %u %u %u %"SCNi64 " %"SCNi64 " %"SCNi64 |
|
" %"SCNu64 " %"SCNu64 "\n", |
|
@@ -129,8 +135,8 @@ int ipc_shm_get_info(int id, struct shm_data **shmds) |
|
&p->shm_dtim, |
|
&p->shm_ctim, |
|
&p->shm_rss, |
|
- &p->shm_swp) != 16) |
|
- continue; |
|
+ &p->shm_swp) < 14) |
|
+ continue; /* invalid line, skipped */ |
|
|
|
if (id > -1) { |
|
/* ID specified */ |
|
@@ -153,28 +159,20 @@ int ipc_shm_get_info(int id, struct shm_data **shmds) |
|
return i; |
|
|
|
/* Fallback; /proc or /sys file(s) missing. */ |
|
-fallback: |
|
- i = id < 0 ? 0 : id; |
|
- |
|
- maxid = shmctl(0, SHM_INFO, (struct shmid_ds *) &dummy); |
|
- if (maxid < 0) |
|
- return 0; |
|
+shm_fallback: |
|
+ maxid = shmctl(0, SHM_INFO, &dummy); |
|
|
|
- while (i <= maxid) { |
|
+ for (int j = 0; j <= maxid; j++) { |
|
int shmid; |
|
struct shmid_ds shmseg; |
|
struct ipc_perm *ipcp = &shmseg.shm_perm; |
|
|
|
- shmid = shmctl(i, SHM_STAT, &shmseg); |
|
- if (shmid < 0) { |
|
- if (-1 < id) { |
|
- free(*shmds); |
|
- return 0; |
|
- } |
|
- i++; |
|
+ shmid = shmctl(j, SHM_STAT, &shmseg); |
|
+ if (shmid < 0 || (id > -1 && shmid != id)) { |
|
continue; |
|
} |
|
|
|
+ i++; |
|
p->shm_perm.key = ipcp->KEY; |
|
p->shm_perm.id = shmid; |
|
p->shm_perm.mode = ipcp->mode; |
|
@@ -196,11 +194,12 @@ fallback: |
|
p->next = xcalloc(1, sizeof(struct shm_data)); |
|
p = p->next; |
|
p->next = NULL; |
|
- i++; |
|
} else |
|
- return 1; |
|
+ break; |
|
} |
|
|
|
+ if (i == 0) |
|
+ free(*shmds); |
|
return i; |
|
} |
|
|
|
@@ -299,30 +298,22 @@ int ipc_sem_get_info(int id, struct sem_data **semds) |
|
return i; |
|
|
|
/* Fallback; /proc or /sys file(s) missing. */ |
|
- sem_fallback: |
|
- i = id < 0 ? 0 : id; |
|
- |
|
+sem_fallback: |
|
arg.array = (ushort *) (void *)&dummy; |
|
maxid = semctl(0, 0, SEM_INFO, arg); |
|
- if (maxid < 0) |
|
- return 0; |
|
|
|
- while (i <= maxid) { |
|
+ for (int j = 0; j <= maxid; j++) { |
|
int semid; |
|
struct semid_ds semseg; |
|
struct ipc_perm *ipcp = &semseg.sem_perm; |
|
arg.buf = (struct semid_ds *)&semseg; |
|
|
|
- semid = semctl(i, 0, SEM_STAT, arg); |
|
- if (semid < 0) { |
|
- if (-1 < id) { |
|
- free(*semds); |
|
- return 0; |
|
- } |
|
- i++; |
|
+ semid = semctl(j, 0, SEM_STAT, arg); |
|
+ if (semid < 0 || (id > -1 && semid != id)) { |
|
continue; |
|
} |
|
|
|
+ i++; |
|
p->sem_perm.key = ipcp->KEY; |
|
p->sem_perm.id = semid; |
|
p->sem_perm.mode = ipcp->mode; |
|
@@ -341,10 +332,12 @@ int ipc_sem_get_info(int id, struct sem_data **semds) |
|
i++; |
|
} else { |
|
get_sem_elements(p); |
|
- return 1; |
|
+ break; |
|
} |
|
} |
|
|
|
+ if (i == 0) |
|
+ free(*semds); |
|
return i; |
|
} |
|
|
|
@@ -398,10 +391,6 @@ int ipc_msg_get_info(int id, struct msg_data **msgds) |
|
if (id > -1) { |
|
/* ID specified */ |
|
if (id == p->msg_perm.id) { |
|
- /* |
|
- * FIXME: q_qbytes are not in /proc |
|
- * |
|
- */ |
|
if (msgctl(id, IPC_STAT, &msgseg) != -1) |
|
p->q_qbytes = msgseg.msg_qbytes; |
|
i = 1; |
|
@@ -422,27 +411,19 @@ int ipc_msg_get_info(int id, struct msg_data **msgds) |
|
return i; |
|
|
|
/* Fallback; /proc or /sys file(s) missing. */ |
|
- msg_fallback: |
|
- i = id < 0 ? 0 : id; |
|
- |
|
- maxid = msgctl(id, MSG_STAT, &dummy); |
|
- if (maxid < 0) |
|
- return 0; |
|
+msg_fallback: |
|
+ maxid = msgctl(0, MSG_INFO, &dummy); |
|
|
|
- while (i <= maxid) { |
|
+ for (int j = 0; j <= maxid; j++) { |
|
int msgid; |
|
struct ipc_perm *ipcp = &msgseg.msg_perm; |
|
|
|
- msgid = msgctl(i, MSG_STAT, &msgseg); |
|
- if (msgid < 0) { |
|
- if (-1 < id) { |
|
- free(*msgds); |
|
- return 0; |
|
- } |
|
- i++; |
|
+ msgid = msgctl(j, MSG_STAT, &msgseg); |
|
+ if (msgid < 0 || (id > -1 && msgid != id)) { |
|
continue; |
|
} |
|
|
|
+ i++; |
|
p->msg_perm.key = ipcp->KEY; |
|
p->msg_perm.id = msgid; |
|
p->msg_perm.mode = ipcp->mode; |
|
@@ -463,11 +444,12 @@ int ipc_msg_get_info(int id, struct msg_data **msgds) |
|
p->next = xcalloc(1, sizeof(struct msg_data)); |
|
p = p->next; |
|
p->next = NULL; |
|
- i++; |
|
} else |
|
- return 1; |
|
+ break; |
|
} |
|
|
|
+ if (i == 0) |
|
+ free(*msgds); |
|
return i; |
|
} |
|
|
|
@@ -508,10 +490,10 @@ void ipc_print_perms(FILE *f, struct ipc_stat *is) |
|
fprintf(f, " %-10u\n", is->gid); |
|
} |
|
|
|
-void ipc_print_size(int unit, char *msg, size_t size, const char *end, |
|
+void ipc_print_size(int unit, char *msg, uint64_t size, const char *end, |
|
int width) |
|
{ |
|
- char format[16]; |
|
+ char format[32]; |
|
|
|
if (!msg) |
|
/* NULL */ ; |
|
@@ -527,11 +509,11 @@ void ipc_print_size(int unit, char *msg, size_t size, const char *end, |
|
switch (unit) { |
|
case IPC_UNIT_DEFAULT: |
|
case IPC_UNIT_BYTES: |
|
- sprintf(format, "%%%dzu", width); |
|
+ sprintf(format, "%%%dju", width); |
|
printf(format, size); |
|
break; |
|
case IPC_UNIT_KB: |
|
- sprintf(format, "%%%dzu", width); |
|
+ sprintf(format, "%%%dju", width); |
|
printf(format, size / 1024); |
|
break; |
|
case IPC_UNIT_HUMAN: |
|
diff --git a/sys-utils/ipcutils.h b/sys-utils/ipcutils.h |
|
index d2e5972..444065a 100644 |
|
--- a/sys-utils/ipcutils.h |
|
+++ b/sys-utils/ipcutils.h |
|
@@ -12,6 +12,7 @@ |
|
#include <unistd.h> |
|
#include <grp.h> |
|
#include <pwd.h> |
|
+#include <stdint.h> |
|
|
|
/* |
|
* SHM_DEST and SHM_LOCKED are defined in kernel headers, but inside |
|
@@ -34,11 +35,11 @@ |
|
# define SHM_INFO 14 |
|
struct shm_info { |
|
int used_ids; |
|
- ulong shm_tot; /* total allocated shm */ |
|
- ulong shm_rss; /* total resident shm */ |
|
- ulong shm_swp; /* total swapped shm */ |
|
- ulong swap_attempts; |
|
- ulong swap_successes; |
|
+ unsigned long shm_tot; /* total allocated shm */ |
|
+ unsigned long shm_rss; /* total resident shm */ |
|
+ unsigned long shm_swp; /* total swapped shm */ |
|
+ unsigned long swap_attempts; |
|
+ unsigned long swap_successes; |
|
}; |
|
#endif |
|
|
|
@@ -118,7 +119,7 @@ struct ipc_stat { |
|
}; |
|
|
|
extern void ipc_print_perms(FILE *f, struct ipc_stat *is); |
|
-extern void ipc_print_size(int unit, char *msg, size_t size, const char *end, int width); |
|
+extern void ipc_print_size(int unit, char *msg, uint64_t size, const char *end, int width); |
|
|
|
/* See 'struct shmid_kernel' in kernel sources |
|
*/ |
|
diff --git a/sys-utils/lsipc.1 b/sys-utils/lsipc.1 |
|
new file mode 100644 |
|
index 0000000..98449cb |
|
--- /dev/null |
|
+++ b/sys-utils/lsipc.1 |
|
@@ -0,0 +1,133 @@ |
|
+.\" Copyright 2015 Ondrej Oprala(ooprala@redhat.com) |
|
+.\" May be distributed under the GNU General Public License |
|
+.TH LSIPC "1" "November 2015" "util-linux" "User Commands" |
|
+.SH NAME |
|
+lsipc \- show information on IPC facilities currently employed in the system |
|
+.SH SYNOPSIS |
|
+.B lsipc |
|
+[options] |
|
+.SH DESCRIPTION |
|
+.B lsipc |
|
+shows information on the inter-process communication facilities |
|
+for which the calling process has read access. |
|
+.SH OPTIONS |
|
+.TP |
|
+\fB\-i\fR, \fB\-\-id\fR \fIid\fR |
|
+Show full details on just the one resource element identified by |
|
+.IR id . |
|
+This option needs to be combined with one of the three resource options: |
|
+.BR \-m , |
|
+.BR \-q " or" |
|
+.BR \-s . |
|
+It is possible to override the default output format for this option with the |
|
+\fB\-\-list\fR, \fB\-\-raw\fR, \fB\-\-json\fR or \fB\-\-export\fR option. |
|
+.TP |
|
+\fB\-g\fR, \fB\-\-global\fR |
|
+Show system-wide usage and limits of IPC resources. |
|
+This option may be combined with one of the three resource options: |
|
+.BR \-m , |
|
+.BR \-q " or" |
|
+.BR \-s . |
|
+The default is to show information about all resources. |
|
+.TP |
|
+\fB\-h\fR, \fB\-\-help\fR |
|
+Display help text and exit. |
|
+.TP |
|
+\fB\-V\fR, \fB\-\-version\fR |
|
+Display version information and exit. |
|
+.SS "Resource options" |
|
+.TP |
|
+\fB\-m\fR, \fB\-\-shmems\fR |
|
+Write information about active shared memory segments. |
|
+.TP |
|
+\fB\-q\fR, \fB\-\-queues\fR |
|
+Write information about active message queues. |
|
+.TP |
|
+\fB\-s\fR, \fB\-\-semaphores\fR |
|
+Write information about active semaphore sets. |
|
+.SS "Output formatting" |
|
+.TP |
|
+\fB\-c\fR, \fB\-\-creator\fR |
|
+Show creator and owner. |
|
+.TP |
|
+\fB\-e\fR, \fB\-\-export\fR |
|
+Output data in the format of NAME=VALUE. |
|
+.TP |
|
+\fB\-l\fR, \fB\-\-list\fR |
|
+Use the list output format. This is the default, except when \fB\-\-id\fR |
|
+is used. |
|
+.TP |
|
+\fB\-n\fR, \fB\-\-newline\fR |
|
+Display each piece of information on a separate line. |
|
+.TP |
|
+\fB\-\-noheadings\fR |
|
+Do not print a header line. |
|
+.TP |
|
+\fB\-\-notruncate\fR |
|
+Don't truncate output. |
|
+.TP |
|
+\fB\-o\fR, \fB\-\-output \fIlist\fP |
|
+Specify which output columns to print. Use |
|
+.B \-\-help |
|
+to get a list of all supported columns. |
|
+.TP |
|
+\fB\-p\fR, \fB\-\-pid\fR |
|
+Show PIDs of creator and last operator. |
|
+.TP |
|
+\fB\-r\fR, \fB\-\-raw\fR |
|
+Raw output (no columnation). |
|
+.TP |
|
+\fB\-t\fR, \fB\-\-time\fR |
|
+Write time information. The time of the last control operation that changed |
|
+the access permissions for all facilities, the time of the last |
|
+.I msgsnd() |
|
+and |
|
+.I msgrcv() |
|
+operations on message queues, the time of the last |
|
+.I shmat() |
|
+and |
|
+.I shmdt() |
|
+operations on shared memory, and the time of the last |
|
+.I semop() |
|
+operation on semaphores. |
|
+.TP |
|
+\fB\-\-time\-format\fR \fItype\fP |
|
+Display dates in short, full or iso format. The default is short, this time |
|
+format is designed to be space efficient and human readable. |
|
+ |
|
+.SH EXIT STATUS |
|
+.TP |
|
+0 |
|
+if OK, |
|
+.TP |
|
+1 |
|
+if incorrect arguments specified, |
|
+.TP |
|
+2 |
|
+if a serious error occurs. |
|
+.SH SEE ALSO |
|
+.BR ipcrm (1), |
|
+.BR ipcmk (1), |
|
+.BR msgrcv (2), |
|
+.BR msgsnd (2), |
|
+.BR semget (2), |
|
+.BR semop (2), |
|
+.BR shmat (2), |
|
+.BR shmdt (2), |
|
+.BR shmget (2) |
|
+.SH HISTORY |
|
+The \fBlsipc\fP utility is inspired by the \fBipcs\fP utility. |
|
+.SH AUTHORS |
|
+.MT ooprala@redhat.com |
|
+Ondrej Oprala |
|
+.ME |
|
+.br |
|
+.MT kzak@redhat.com |
|
+Karel Zak |
|
+.ME |
|
+ |
|
+.SH AVAILABILITY |
|
+The lsipc command is part of the util-linux package and is available from |
|
+.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/ |
|
+Linux Kernel Archive |
|
+.UE . |
|
diff --git a/sys-utils/lsipc.c b/sys-utils/lsipc.c |
|
new file mode 100644 |
|
index 0000000..0be9d91 |
|
--- /dev/null |
|
+++ b/sys-utils/lsipc.c |
|
@@ -0,0 +1,1316 @@ |
|
+/* |
|
+ * lsipc - List information about IPC instances employed in the system |
|
+ * |
|
+ * Copyright (C) 2015 Ondrej Oprala <ooprala@redhat.com> |
|
+ * Copyright (C) 2015 Karel Zak <ooprala@redhat.com> |
|
+ * |
|
+ * This program is free software; you can redistribute it and/or modify |
|
+ * it under the terms of the GNU General Public License as published by |
|
+ * the Free Software Foundation; either version 2 of the License, or |
|
+ * (at your option) any later version. |
|
+ * |
|
+ * This program is distributed in the hope that it would be useful, |
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
+ * GNU General Public License for more details. |
|
+ * |
|
+ * You should have received a copy of the GNU General Public License along |
|
+ * with this program; if not, write to the Free Software Foundation, Inc., |
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|
+ * |
|
+ * |
|
+ * lsipc is inspired by the ipcs utility. The aim is to create |
|
+ * a utility unencumbered by a standard to provide more flexible |
|
+ * means of controlling the output. |
|
+ */ |
|
+ |
|
+#include <errno.h> |
|
+#include <getopt.h> |
|
+#include <sys/time.h> |
|
+#include <unistd.h> |
|
+ |
|
+#include <libsmartcols.h> |
|
+ |
|
+#include "c.h" |
|
+#include "nls.h" |
|
+#include "closestream.h" |
|
+#include "strutils.h" |
|
+#include "optutils.h" |
|
+#include "xalloc.h" |
|
+#include "procutils.h" |
|
+#include "ipcutils.h" |
|
+ |
|
+/* |
|
+ * time modes |
|
+ * */ |
|
+enum { |
|
+ TIME_INVALID = 0, |
|
+ TIME_SHORT, |
|
+ TIME_FULL, |
|
+ TIME_ISO |
|
+}; |
|
+ |
|
+/* |
|
+ * IDs |
|
+ */ |
|
+enum { |
|
+ /* generic */ |
|
+ 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, |
|
+ COL_UID, |
|
+ COL_USER, |
|
+ COL_GID, |
|
+ COL_GROUP, |
|
+ COL_CTIME, |
|
+ COLDESC_IDX_GEN_LAST = COL_CTIME, |
|
+ |
|
+ /* msgq-specific */ |
|
+ COLDESC_IDX_MSG_FIRST, |
|
+ COL_USEDBYTES = COLDESC_IDX_MSG_FIRST, |
|
+ COL_MSGS, |
|
+ COL_SEND, |
|
+ COL_RECV, |
|
+ COL_LSPID, |
|
+ COL_LRPID, |
|
+ COLDESC_IDX_MSG_LAST = COL_LRPID, |
|
+ |
|
+ /* shm-specific */ |
|
+ COLDESC_IDX_SHM_FIRST, |
|
+ COL_SIZE = COLDESC_IDX_SHM_FIRST, |
|
+ COL_NATTCH, |
|
+ COL_STATUS, |
|
+ COL_ATTACH, |
|
+ COL_DETACH, |
|
+ COL_COMMAND, |
|
+ COL_CPID, |
|
+ COL_LPID, |
|
+ COLDESC_IDX_SHM_LAST = COL_LPID, |
|
+ |
|
+ /* sem-specific */ |
|
+ COLDESC_IDX_SEM_FIRST, |
|
+ COL_NSEMS = COLDESC_IDX_SEM_FIRST, |
|
+ COL_OTIME, |
|
+ COLDESC_IDX_SEM_LAST = COL_OTIME, |
|
+ |
|
+ /* summary (--global) */ |
|
+ COLDESC_IDX_SUM_FIRST, |
|
+ COL_RESOURCE = COLDESC_IDX_SUM_FIRST, |
|
+ COL_DESC, |
|
+ COL_LIMIT, |
|
+ COL_USED, |
|
+ COL_USEPERC, |
|
+ COLDESC_IDX_SUM_LAST = COL_USEPERC |
|
+}; |
|
+ |
|
+/* not all columns apply to all options, so we specify a legal range for each */ |
|
+static size_t LOWER, UPPER; |
|
+ |
|
+/* |
|
+ * output modes |
|
+ */ |
|
+enum { |
|
+ OUT_EXPORT = 1, |
|
+ OUT_NEWLINE, |
|
+ OUT_RAW, |
|
+ OUT_PRETTY, |
|
+ OUT_LIST |
|
+}; |
|
+ |
|
+struct lsipc_control { |
|
+ int outmode; |
|
+ unsigned int noheadings : 1, /* don't print header line */ |
|
+ notrunc : 1, /* don't truncate columns */ |
|
+ bytes : 1, /* SIZE in bytes */ |
|
+ numperms : 1, /* numeric permissions */ |
|
+ time_mode : 2; |
|
+}; |
|
+ |
|
+struct lsipc_coldesc { |
|
+ const char *name; |
|
+ const char *help; |
|
+ const char *pretty_name; |
|
+ |
|
+ double whint; /* width hint */ |
|
+ long flag; |
|
+}; |
|
+ |
|
+static const struct lsipc_coldesc coldescs[] = |
|
+{ |
|
+ /* common */ |
|
+ [COL_KEY] = { "KEY", N_("Resource key"), N_("Key"), 1}, |
|
+ [COL_ID] = { "ID", N_("Resource ID"), N_("ID"), 1}, |
|
+ [COL_OWNER] = { "OWNER", N_("Owner's username or UID"), N_("Owner"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_PERMS] = { "PERMS", N_("Permissions"), N_("Permissions"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_CUID] = { "CUID", N_("Creator UID"), N_("Creator UID"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_CUSER] = { "CUSER", N_("Creator user"), N_("Creator user"), 1 }, |
|
+ [COL_CGID] = { "CGID", N_("Creator GID"), N_("Creator GID"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_CGROUP] = { "CGROUP", N_("Creator group"), N_("Creator group"), 1 }, |
|
+ [COL_UID] = { "UID", N_("User ID"), N_("UID"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_USER] = { "USER", N_("User name"), N_("User name"), 1}, |
|
+ [COL_GID] = { "GID", N_("Group ID"), N_("GID"), 1, SCOLS_FL_RIGHT}, |
|
+ [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}, |
|
+ |
|
+ /* 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}, |
|
+ [COL_SEND] = { "SEND", N_("Time of last msg sent"), N_("Msg sent"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_RECV] = { "RECV", N_("Time of last msg received"), N_("Msg received"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_LSPID] = { "LSPID", N_("PID of the last msg sender"), N_("Msg sender"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_LRPID] = { "LRPID", N_("PID of the last msg receiver"), N_("Msg receiver"), 1, SCOLS_FL_RIGHT}, |
|
+ |
|
+ /* shm-specific */ |
|
+ [COL_SIZE] = { "SIZE", N_("Segment size"), N_("Segment size"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_NATTCH] = { "NATTCH", N_("Number of attached processes"), N_("Attached processes"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_STATUS] = { "STATUS", N_("Status"), N_("Status"), 1, SCOLS_FL_NOEXTREMES}, |
|
+ [COL_ATTACH] = { "ATTACH", N_("Attach time"), N_("Attach time"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_DETACH] = { "DETACH", N_("Detach time"), N_("Detach time"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_COMMAND] = { "COMMAND", N_("Creator command line"), N_("Creator command"), 0, SCOLS_FL_TRUNC}, |
|
+ [COL_CPID] = { "CPID", N_("PID of the creator"), N_("Creator PID"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_LPID] = { "LPID", N_("PID of last user"), N_("Last user PID"), 1, SCOLS_FL_RIGHT}, |
|
+ |
|
+ /* sem-specific */ |
|
+ [COL_NSEMS] = { "NSEMS", N_("Number of semaphores"), N_("Semaphores"), 1, SCOLS_FL_RIGHT}, |
|
+ [COL_OTIME] = { "OTIME", N_("Time of the last operation"), N_("Last operation"), 1, SCOLS_FL_RIGHT}, |
|
+ |
|
+ /* cols for summarized information */ |
|
+ [COL_RESOURCE] = { "RESOURCE", N_("Resource name"), N_("Resource"), 1 }, |
|
+ [COL_DESC] = { "DESCRIPTION",N_("Resource description"), N_("Description"), 1 }, |
|
+ [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 }, |
|
+}; |
|
+ |
|
+ |
|
+/* columns[] array specifies all currently wanted output column. The columns |
|
+ * are defined by coldescs[] array and you can specify (on command line) each |
|
+ * column twice. That's enough, dynamically allocated array of the columns is |
|
+ * unnecessary overkill and over-engineering in this case */ |
|
+static int columns[ARRAY_SIZE(coldescs) * 2]; |
|
+static size_t ncolumns; |
|
+ |
|
+static inline size_t err_columns_index(size_t arysz, size_t idx) |
|
+{ |
|
+ if (idx >= arysz) |
|
+ errx(EXIT_FAILURE, _("too many columns specified, " |
|
+ "the limit is %zu columns"), |
|
+ arysz - 1); |
|
+ return idx; |
|
+} |
|
+ |
|
+#define add_column(ary, n, id) \ |
|
+ ((ary)[ err_columns_index(ARRAY_SIZE(ary), (n)) ] = (id)) |
|
+ |
|
+static int column_name_to_id(const char *name, size_t namesz) |
|
+{ |
|
+ size_t i; |
|
+ |
|
+ for (i = 0; i < ARRAY_SIZE(coldescs); i++) { |
|
+ const char *cn = coldescs[i].name; |
|
+ |
|
+ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) { |
|
+ if (i > COL_CTIME) { |
|
+ if (i >= LOWER && i <= UPPER) |
|
+ return i; |
|
+ else { |
|
+ warnx(_("column %s does not apply to the specified IPC"), name); |
|
+ return -1; |
|
+ } |
|
+ } else |
|
+ return i; |
|
+ } |
|
+ } |
|
+ warnx(_("unknown column: %s"), name); |
|
+ return -1; |
|
+} |
|
+ |
|
+static char *get_username(struct passwd **pw, uid_t id) |
|
+{ |
|
+ if (!*pw || (*pw)->pw_uid != id) |
|
+ *pw = getpwuid(id); |
|
+ |
|
+ return *pw ? xstrdup((*pw)->pw_name) : NULL; |
|
+} |
|
+ |
|
+static char *get_groupname(struct group **gr, gid_t id) |
|
+{ |
|
+ if (!*gr || (*gr)->gr_gid != id) |
|
+ *gr = getgrgid(id); |
|
+ |
|
+ return *gr ? xstrdup((*gr)->gr_name) : NULL; |
|
+} |
|
+ |
|
+static int parse_time_mode(const char *optarg) |
|
+{ |
|
+ struct lsipc_timefmt { |
|
+ const char *name; |
|
+ const int val; |
|
+ }; |
|
+ static const struct lsipc_timefmt timefmts[] = { |
|
+ {"iso", TIME_ISO}, |
|
+ {"full", TIME_FULL}, |
|
+ {"short", TIME_SHORT}, |
|
+ }; |
|
+ size_t i; |
|
+ |
|
+ for (i = 0; i < ARRAY_SIZE(timefmts); i++) { |
|
+ if (strcmp(timefmts[i].name, optarg) == 0) |
|
+ return timefmts[i].val; |
|
+ } |
|
+ errx(EXIT_FAILURE, _("unknown time format: %s"), optarg); |
|
+} |
|
+ |
|
+static void __attribute__ ((__noreturn__)) usage(FILE * out) |
|
+{ |
|
+ size_t i; |
|
+ |
|
+ fputs(USAGE_HEADER, out); |
|
+ fprintf(out, _(" %s [options]\n"), program_invocation_short_name); |
|
+ |
|
+ fputs(USAGE_SEPARATOR, out); |
|
+ fputs(_("Show information on IPC facilities.\n"), out); |
|
+ |
|
+ 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(USAGE_OPTIONS, out); |
|
+ fputs(_(" --noheadings don't print headings\n"), out); |
|
+ fputs(_(" --notruncate don't truncate output\n"), out); |
|
+ fputs(_(" --time-format=<type> display dates in short, full or iso format\n"), out); |
|
+ fputs(_(" -b, --bytes print SIZE in bytes rather than in human readable format\n"), out); |
|
+ fputs(_(" -c, --creator show creator and owner\n"), out); |
|
+ fputs(_(" -e, --export display in an export-able output format\n"), out); |
|
+ fputs(_(" -n, --newline display each piece of information on a new line\n"), out); |
|
+ fputs(_(" -l, --list force list output format (for example with --id)\n"), out); |
|
+ fputs(_(" -o, --output[=<list>] define the columns to output\n"), out); |
|
+ fputs(_(" -P, --numeric-perms print numeric permissions (PERMS column)\n"), out); |
|
+ fputs(_(" -r, --raw display in raw mode\n"), out); |
|
+ fputs(_(" -t, --time show attach, detach and change times\n"), out); |
|
+ |
|
+ fputs(USAGE_SEPARATOR, out); |
|
+ fputs(USAGE_HELP, out); |
|
+ fputs(USAGE_VERSION, out); |
|
+ |
|
+ fprintf(out, _("\nGeneric 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, _("\nShared-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")); |
|
+ 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")); |
|
+ 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, _("\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)); |
|
+ |
|
+ fprintf(out, USAGE_MAN_TAIL("lsipc(1)")); |
|
+ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); |
|
+} |
|
+ |
|
+static struct libscols_table *new_table(struct lsipc_control *ctl) |
|
+{ |
|
+ struct libscols_table *table = scols_new_table(); |
|
+ |
|
+ if (!table) |
|
+ errx(EXIT_FAILURE, _("failed to initialize output table")); |
|
+ if (ctl->noheadings) |
|
+ scols_table_enable_noheadings(table, 1); |
|
+ |
|
+ switch(ctl->outmode) { |
|
+ case OUT_NEWLINE: |
|
+ scols_table_set_column_separator(table, "\n"); |
|
+ /* fallthrough */ |
|
+ case OUT_EXPORT: |
|
+ scols_table_enable_export(table, 1); |
|
+ break; |
|
+ case OUT_RAW: |
|
+ scols_table_enable_raw(table, 1); |
|
+ break; |
|
+ case OUT_PRETTY: |
|
+ scols_table_enable_noheadings(table, 1); |
|
+ break; |
|
+ default: |
|
+ break; |
|
+ } |
|
+ return table; |
|
+} |
|
+ |
|
+static struct libscols_table *setup_table(struct lsipc_control *ctl) |
|
+{ |
|
+ struct libscols_table *table = new_table(ctl); |
|
+ size_t n; |
|
+ |
|
+ for (n = 0; n < ncolumns; n++) { |
|
+ int flags = coldescs[columns[n]].flag; |
|
+ |
|
+ if (ctl->notrunc) |
|
+ flags &= ~SCOLS_FL_TRUNC; |
|
+ |
|
+ if (!scols_table_new_column(table, |
|
+ coldescs[columns[n]].name, |
|
+ coldescs[columns[n]].whint, |
|
+ flags)) |
|
+ goto fail; |
|
+ } |
|
+ return table; |
|
+fail: |
|
+ scols_unref_table(table); |
|
+ return NULL; |
|
+} |
|
+ |
|
+static int print_pretty(struct libscols_table *table) |
|
+{ |
|
+ struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD); |
|
+ struct libscols_column *col; |
|
+ struct libscols_cell *data; |
|
+ struct libscols_line *ln; |
|
+ const char *hstr, *dstr; |
|
+ int n = 0; |
|
+ |
|
+ ln = scols_table_get_line(table, 0); |
|
+ while (!scols_table_next_column(table, itr, &col)) { |
|
+ |
|
+ data = scols_line_get_cell(ln, n); |
|
+ |
|
+ hstr = N_(coldescs[columns[n]].pretty_name); |
|
+ dstr = scols_cell_get_data(data); |
|
+ |
|
+ if (dstr) |
|
+ printf("%s:%*c%-36s\n", hstr, 35 - (int)strlen(hstr), ' ', dstr); |
|
+ ++n; |
|
+ } |
|
+ |
|
+ /* this is used to pretty-print detailed info about a semaphore array */ |
|
+ if (ln) { |
|
+ struct libscols_table *subtab = scols_line_get_userdata(ln); |
|
+ if (subtab) { |
|
+ printf(_("Elements:\n\n")); |
|
+ scols_print_table(subtab); |
|
+ } |
|
+ } |
|
+ |
|
+ scols_free_iter(itr); |
|
+ return 0; |
|
+ |
|
+} |
|
+ |
|
+static int print_table(struct lsipc_control *ctl, struct libscols_table *tb) |
|
+{ |
|
+ if (ctl->outmode == OUT_PRETTY) |
|
+ print_pretty(tb); |
|
+ else |
|
+ scols_print_table(tb); |
|
+ return 0; |
|
+} |
|
+static struct timeval now; |
|
+ |
|
+static int date_is_today(time_t t) |
|
+{ |
|
+ if (now.tv_sec == 0) |
|
+ gettimeofday(&now, NULL); |
|
+ return t / (3600 * 24) == now.tv_sec / (3600 * 24); |
|
+} |
|
+ |
|
+static int date_is_thisyear(time_t t) |
|
+{ |
|
+ if (now.tv_sec == 0) |
|
+ gettimeofday(&now, NULL); |
|
+ return t / (3600 * 24 * 365) == now.tv_sec / (3600 * 24 * 365); |
|
+} |
|
+ |
|
+static char *make_time(int mode, time_t time) |
|
+{ |
|
+ char *s; |
|
+ struct tm tm; |
|
+ char buf[64] = {0}; |
|
+ |
|
+ localtime_r(&time, &tm); |
|
+ |
|
+ switch(mode) { |
|
+ case TIME_FULL: |
|
+ asctime_r(&tm, buf); |
|
+ if (*(s = buf + strlen(buf) - 1) == '\n') |
|
+ *s = '\0'; |
|
+ break; |
|
+ case TIME_SHORT: |
|
+ if (date_is_today(time)) |
|
+ strftime(buf, sizeof(buf), "%H:%M", &tm); |
|
+ else if (date_is_thisyear(time)) |
|
+ strftime(buf, sizeof(buf), "%b%d", &tm); |
|
+ else |
|
+ strftime(buf, sizeof(buf), "%Y-%b%d", &tm); |
|
+ break; |
|
+ case TIME_ISO: |
|
+ strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm); |
|
+ break; |
|
+ default: |
|
+ errx(EXIT_FAILURE, _("unsupported time type")); |
|
+ } |
|
+ return xstrdup(buf); |
|
+} |
|
+ |
|
+static void global_set_data(struct libscols_table *tb, const char *resource, |
|
+ const char *desc, uintmax_t used, uintmax_t limit, int usage) |
|
+{ |
|
+ struct libscols_line *ln; |
|
+ size_t n; |
|
+ |
|
+ ln = scols_table_new_line(tb, NULL); |
|
+ if (!ln) |
|
+ err_oom(); |
|
+ |
|
+ for (n = 0; n < ncolumns; n++) { |
|
+ int rc = 0; |
|
+ char *arg = NULL; |
|
+ |
|
+ switch (columns[n]) { |
|
+ case COL_RESOURCE: |
|
+ rc = scols_line_set_data(ln, n, resource); |
|
+ break; |
|
+ case COL_DESC: |
|
+ rc = scols_line_set_data(ln, n, desc); |
|
+ break; |
|
+ case COL_USED: |
|
+ if (usage) { |
|
+ xasprintf(&arg, "%ju", used); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ } else |
|
+ rc = scols_line_set_data(ln, n, "-"); |
|
+ break; |
|
+ case COL_USEPERC: |
|
+ if (usage) { |
|
+ xasprintf(&arg, "%2.2f%%", (double) used / limit * 100); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ } else |
|
+ rc = scols_line_set_data(ln, n, "-"); |
|
+ break; |
|
+ case COL_LIMIT: |
|
+ xasprintf(&arg, "%ju", limit); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ } |
|
+ |
|
+ if (rc != 0) |
|
+ err(EXIT_FAILURE, _("failed to set data")); |
|
+ } |
|
+} |
|
+ |
|
+static void setup_sem_elements_columns(struct libscols_table *tb) |
|
+{ |
|
+ if (!scols_table_new_column(tb, "SEMNUM", 0, SCOLS_FL_RIGHT)) |
|
+ err_oom(); |
|
+ if (!scols_table_new_column(tb, "VALUE", 0, SCOLS_FL_RIGHT)) |
|
+ err_oom(); |
|
+ if (!scols_table_new_column(tb, "NCOUNT", 0, SCOLS_FL_RIGHT)) |
|
+ err_oom(); |
|
+ if (!scols_table_new_column(tb, "ZCOUNT", 0, SCOLS_FL_RIGHT)) |
|
+ err_oom(); |
|
+ if (!scols_table_new_column(tb, "PID", 0, SCOLS_FL_RIGHT)) |
|
+ err_oom(); |
|
+ if (!scols_table_new_column(tb, "COMMAND", 0, SCOLS_FL_RIGHT)) |
|
+ err_oom(); |
|
+} |
|
+ |
|
+static void do_sem(int id, struct lsipc_control *ctl, struct libscols_table *tb) |
|
+{ |
|
+ struct libscols_line *ln; |
|
+ struct passwd *pw = NULL, *cpw = NULL; |
|
+ struct group *gr = NULL, *cgr = NULL; |
|
+ struct sem_data *semds, *semdsp; |
|
+ char *arg = NULL; |
|
+ |
|
+ if (ipc_sem_get_info(id, &semds) < 1) { |
|
+ if (id > -1) |
|
+ warnx(_("id %d not found"), id); |
|
+ return; |
|
+ } |
|
+ for (semdsp = semds; semdsp->next != NULL || id > -1; semdsp = semdsp->next) { |
|
+ size_t n; |
|
+ ln = scols_table_new_line(tb, NULL); |
|
+ |
|
+ for (n = 0; n < ncolumns; n++) { |
|
+ int rc = 0; |
|
+ switch (columns[n]) { |
|
+ case COL_KEY: |
|
+ xasprintf(&arg, "0x%08x",semdsp->sem_perm.key); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_ID: |
|
+ xasprintf(&arg, "%d",semdsp->sem_perm.id); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_OWNER: |
|
+ arg = get_username(&pw, semdsp->sem_perm.uid); |
|
+ if (!arg) |
|
+ xasprintf(&arg, "%u", semdsp->sem_perm.uid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_PERMS: |
|
+ if (ctl->numperms) |
|
+ xasprintf(&arg, "%#o", semdsp->sem_perm.mode & 0777); |
|
+ else { |
|
+ arg = xmalloc(11); |
|
+ strmode(semdsp->sem_perm.mode & 0777, arg); |
|
+ } |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CUID: |
|
+ xasprintf(&arg, "%u", semdsp->sem_perm.cuid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CUSER: |
|
+ arg = get_username(&cpw, semdsp->sem_perm.cuid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CGID: |
|
+ xasprintf(&arg, "%u", semdsp->sem_perm.cgid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CGROUP: |
|
+ arg = get_groupname(&cgr, semdsp->sem_perm.cgid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_UID: |
|
+ xasprintf(&arg, "%u", semdsp->sem_perm.uid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_USER: |
|
+ arg = get_username(&pw, semdsp->sem_perm.uid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_GID: |
|
+ xasprintf(&arg, "%u", semdsp->sem_perm.gid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_GROUP: |
|
+ arg = get_groupname(&gr, semdsp->sem_perm.gid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CTIME: |
|
+ if (semdsp->sem_ctime != 0) { |
|
+ rc = scols_line_refer_data(ln, n, |
|
+ make_time(ctl->time_mode, |
|
+ (time_t)semdsp->sem_ctime)); |
|
+ } |
|
+ break; |
|
+ case COL_NSEMS: |
|
+ xasprintf(&arg, "%ju", semdsp->sem_nsems); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_OTIME: |
|
+ if (semdsp->sem_otime != 0) { |
|
+ rc = scols_line_refer_data(ln, n, |
|
+ make_time(ctl->time_mode, |
|
+ (time_t)semdsp->sem_otime)); |
|
+ } |
|
+ break; |
|
+ } |
|
+ if (rc != 0) |
|
+ err(EXIT_FAILURE, _("failed to set data")); |
|
+ arg = NULL; |
|
+ } |
|
+ |
|
+ if (id > -1 && semds->sem_nsems) { |
|
+ /* Create extra table with ID specific semaphore elements */ |
|
+ struct libscols_table *sub = new_table(ctl); |
|
+ size_t i; |
|
+ int rc = 0; |
|
+ |
|
+ scols_table_enable_noheadings(sub, 0); |
|
+ setup_sem_elements_columns(sub); |
|
+ |
|
+ for (i = 0; i < semds->sem_nsems; i++) { |
|
+ struct sem_elem *e = &semds->elements[i]; |
|
+ struct libscols_line *sln = scols_table_new_line(sub, NULL); |
|
+ |
|
+ /* SEMNUM */ |
|
+ xasprintf(&arg, "%zu", i); |
|
+ rc = scols_line_refer_data(sln, 0, arg); |
|
+ if (rc) |
|
+ break; |
|
+ |
|
+ /* VALUE */ |
|
+ xasprintf(&arg, "%d", e->semval); |
|
+ rc = scols_line_refer_data(sln, 1, arg); |
|
+ if (rc) |
|
+ break; |
|
+ |
|
+ /* NCOUNT */ |
|
+ xasprintf(&arg, "%d", e->ncount); |
|
+ rc = scols_line_refer_data(sln, 2, arg); |
|
+ if (rc) |
|
+ break; |
|
+ |
|
+ /* ZCOUNT */ |
|
+ xasprintf(&arg, "%d", e->zcount); |
|
+ rc = scols_line_refer_data(sln, 3, arg); |
|
+ if (rc) |
|
+ break; |
|
+ |
|
+ /* PID */ |
|
+ xasprintf(&arg, "%d", e->pid); |
|
+ rc = scols_line_refer_data(sln, 4, arg); |
|
+ if (rc) |
|
+ break; |
|
+ |
|
+ /* COMMAND */ |
|
+ arg = proc_get_command(e->pid); |
|
+ rc = scols_line_refer_data(sln, 5, arg); |
|
+ if (rc) |
|
+ break; |
|
+ } |
|
+ |
|
+ if (rc != 0) |
|
+ err(EXIT_FAILURE, _("failed to set data")); |
|
+ |
|
+ scols_line_set_userdata(ln, (void *)sub); |
|
+ break; |
|
+ } |
|
+ } |
|
+ ipc_sem_free_info(semds); |
|
+} |
|
+ |
|
+static void do_sem_global(struct libscols_table *tb) |
|
+{ |
|
+ struct sem_data *semds, *semdsp; |
|
+ struct ipc_limits lim; |
|
+ int nsems = 0, nsets = 0; |
|
+ |
|
+ ipc_sem_get_limits(&lim); |
|
+ |
|
+ if (ipc_sem_get_info(-1, &semds) > 0) { |
|
+ for (semdsp = semds; semdsp->next != NULL; semdsp = semdsp->next) { |
|
+ ++nsets; |
|
+ nsems += semds->sem_nsems; |
|
+ } |
|
+ ipc_sem_free_info(semds); |
|
+ } |
|
+ |
|
+ global_set_data(tb, "SEMMNI", _("Number of semaphore identifiers"), nsets, lim.semmni, 1); |
|
+ global_set_data(tb, "SEMMNS", _("Total number of semaphores"), nsems, lim.semmns, 1); |
|
+ global_set_data(tb, "SEMMSL", _("Max semaphores per semaphore set."), 0, lim.semmsl, 0); |
|
+ global_set_data(tb, "SEMOPM", _("Max number of operations per semop(2)"), 0, lim.semopm, 0); |
|
+ global_set_data(tb, "SEMVMX", _("Semaphore max value"), 0, lim.semvmx, 0); |
|
+} |
|
+ |
|
+static void do_msg(int id, struct lsipc_control *ctl, struct libscols_table *tb) |
|
+{ |
|
+ struct libscols_line *ln; |
|
+ struct passwd *pw = NULL; |
|
+ struct group *gr = NULL; |
|
+ struct msg_data *msgds, *msgdsp; |
|
+ char *arg = NULL; |
|
+ |
|
+ if (ipc_msg_get_info(id, &msgds) < 1) { |
|
+ if (id > -1) |
|
+ warnx(_("id %d not found"), id); |
|
+ return; |
|
+ } |
|
+ |
|
+ for (msgdsp = msgds; msgdsp->next != NULL || id > -1 ; msgdsp = msgdsp->next) { |
|
+ size_t n; |
|
+ ln = scols_table_new_line(tb, NULL); |
|
+ |
|
+ /* no need to call getpwuid() for the same user */ |
|
+ if (!(pw && pw->pw_uid == msgdsp->msg_perm.uid)) |
|
+ pw = getpwuid(msgdsp->msg_perm.uid); |
|
+ |
|
+ /* no need to call getgrgid() for the same user */ |
|
+ if (!(gr && gr->gr_gid == msgdsp->msg_perm.gid)) |
|
+ gr = getgrgid(msgdsp->msg_perm.gid); |
|
+ |
|
+ for (n = 0; n < ncolumns; n++) { |
|
+ int rc = 0; |
|
+ |
|
+ switch (columns[n]) { |
|
+ case COL_KEY: |
|
+ xasprintf(&arg, "0x%08x",msgdsp->msg_perm.key); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_ID: |
|
+ xasprintf(&arg, "%d",msgdsp->msg_perm.id); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_OWNER: |
|
+ arg = get_username(&pw, msgdsp->msg_perm.uid); |
|
+ if (!arg) |
|
+ xasprintf(&arg, "%u", msgdsp->msg_perm.uid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_PERMS: |
|
+ if (ctl->numperms) |
|
+ xasprintf(&arg, "%#o", msgdsp->msg_perm.mode & 0777); |
|
+ else { |
|
+ arg = xmalloc(11); |
|
+ strmode(msgdsp->msg_perm.mode & 0777, arg); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ } |
|
+ break; |
|
+ case COL_CUID: |
|
+ xasprintf(&arg, "%u", msgdsp->msg_perm.cuid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CUSER: |
|
+ arg = get_username(&pw, msgdsp->msg_perm.cuid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CGID: |
|
+ xasprintf(&arg, "%u", msgdsp->msg_perm.cuid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CGROUP: |
|
+ arg = get_groupname(&gr, msgdsp->msg_perm.cgid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_UID: |
|
+ xasprintf(&arg, "%u", msgdsp->msg_perm.uid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_USER: |
|
+ arg = get_username(&pw, msgdsp->msg_perm.uid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_GID: |
|
+ xasprintf(&arg, "%u", msgdsp->msg_perm.gid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_GROUP: |
|
+ arg = get_groupname(&gr,msgdsp->msg_perm.gid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CTIME: |
|
+ if (msgdsp->q_ctime != 0) |
|
+ rc = scols_line_refer_data(ln, n, |
|
+ make_time(ctl->time_mode, |
|
+ (time_t)msgdsp->q_ctime)); |
|
+ break; |
|
+ case COL_USEDBYTES: |
|
+ xasprintf(&arg, "%ju", msgdsp->q_cbytes); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_MSGS: |
|
+ xasprintf(&arg, "%ju", msgdsp->q_qnum); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_SEND: |
|
+ if (msgdsp->q_stime != 0) |
|
+ rc = scols_line_refer_data(ln, n, |
|
+ make_time(ctl->time_mode, |
|
+ (time_t)msgdsp->q_stime)); |
|
+ break; |
|
+ case COL_RECV: |
|
+ if (msgdsp->q_rtime != 0) |
|
+ rc = scols_line_refer_data(ln, n, |
|
+ make_time(ctl->time_mode, |
|
+ (time_t)msgdsp->q_rtime)); |
|
+ break; |
|
+ case COL_LSPID: |
|
+ xasprintf(&arg, "%u", msgdsp->q_lspid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_LRPID: |
|
+ xasprintf(&arg, "%u", msgdsp->q_lrpid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ } |
|
+ if (rc != 0) |
|
+ err(EXIT_FAILURE, _("failed to set data")); |
|
+ arg = NULL; |
|
+ } |
|
+ if (id > -1) |
|
+ break; |
|
+ } |
|
+ ipc_msg_free_info(msgds); |
|
+} |
|
+ |
|
+ |
|
+static void do_msg_global(struct libscols_table *tb) |
|
+{ |
|
+ struct msg_data *msgds, *msgdsp; |
|
+ struct ipc_limits lim; |
|
+ int msgqs = 0; |
|
+ |
|
+ ipc_msg_get_limits(&lim); |
|
+ |
|
+ /* count number of used queues */ |
|
+ if (ipc_msg_get_info(-1, &msgds) > 0) { |
|
+ for (msgdsp = msgds; msgdsp->next != NULL; msgdsp = msgdsp->next) |
|
+ ++msgqs; |
|
+ ipc_msg_free_info(msgds); |
|
+ } |
|
+ |
|
+ global_set_data(tb, "MSGMNI", _("Number of message queues"), msgqs, lim.msgmni, 1); |
|
+ global_set_data(tb, "MSGMAX", _("Max size of message (bytes)"), 0, lim.msgmax, 0); |
|
+ global_set_data(tb, "MSGMNB", _("Default max size of queue (bytes)"), 0, lim.msgmnb, 0); |
|
+} |
|
+ |
|
+ |
|
+static void do_shm(int id, struct lsipc_control *ctl, struct libscols_table *tb) |
|
+{ |
|
+ struct libscols_line *ln; |
|
+ struct passwd *pw = NULL; |
|
+ struct group *gr = NULL; |
|
+ struct shm_data *shmds, *shmdsp; |
|
+ char *arg = NULL; |
|
+ |
|
+ if (ipc_shm_get_info(id, &shmds) < 1) { |
|
+ if (id > -1) |
|
+ warnx(_("id %d not found"), id); |
|
+ return; |
|
+ } |
|
+ |
|
+ for (shmdsp = shmds; shmdsp->next != NULL || id > -1 ; shmdsp = shmdsp->next) { |
|
+ size_t n; |
|
+ ln = scols_table_new_line(tb, NULL); |
|
+ if (!ln) |
|
+ err_oom(); |
|
+ |
|
+ for (n = 0; n < ncolumns; n++) { |
|
+ int rc = 0; |
|
+ |
|
+ switch (columns[n]) { |
|
+ case COL_KEY: |
|
+ xasprintf(&arg, "0x%08x",shmdsp->shm_perm.key); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_ID: |
|
+ xasprintf(&arg, "%d",shmdsp->shm_perm.id); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_OWNER: |
|
+ arg = get_username(&pw, shmdsp->shm_perm.uid); |
|
+ if (!arg) |
|
+ xasprintf(&arg, "%u", shmdsp->shm_perm.uid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_PERMS: |
|
+ if (ctl->numperms) |
|
+ xasprintf(&arg, "%#o", shmdsp->shm_perm.mode & 0777); |
|
+ else { |
|
+ arg = xmalloc(11); |
|
+ strmode(shmdsp->shm_perm.mode & 0777, arg); |
|
+ } |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CUID: |
|
+ xasprintf(&arg, "%u", shmdsp->shm_perm.cuid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CUSER: |
|
+ arg = get_username(&pw, shmdsp->shm_perm.cuid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CGID: |
|
+ xasprintf(&arg, "%u", shmdsp->shm_perm.cuid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CGROUP: |
|
+ arg = get_groupname(&gr, shmdsp->shm_perm.cgid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_UID: |
|
+ xasprintf(&arg, "%u", shmdsp->shm_perm.uid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_USER: |
|
+ arg = get_username(&pw, shmdsp->shm_perm.uid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_GID: |
|
+ xasprintf(&arg, "%u", shmdsp->shm_perm.gid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_GROUP: |
|
+ arg = get_groupname(&gr, shmdsp->shm_perm.gid); |
|
+ if (arg) |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_CTIME: |
|
+ if (shmdsp->shm_ctim != 0) |
|
+ rc = scols_line_refer_data(ln, n, |
|
+ make_time(ctl->time_mode, |
|
+ (time_t)shmdsp->shm_ctim)); |
|
+ break; |
|
+ case COL_SIZE: |
|
+ if (ctl->bytes) |
|
+ xasprintf(&arg, "%ju", shmdsp->shm_segsz); |
|
+ else |
|
+ arg = size_to_human_string(SIZE_SUFFIX_1LETTER, shmdsp->shm_segsz); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_NATTCH: |
|
+ xasprintf(&arg, "%ju", shmdsp->shm_nattch); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_STATUS: { |
|
+ int comma = 0; |
|
+ size_t offt = 0; |
|
+ |
|
+ free(arg); |
|
+ arg = xcalloc(1, sizeof(char) * strlen(_("dest")) |
|
+ + strlen(_("locked")) |
|
+ + strlen(_("hugetlb")) |
|
+ + strlen(_("noreserve")) + 4); |
|
+#ifdef SHM_DEST |
|
+ if (shmdsp->shm_perm.mode & SHM_DEST) { |
|
+ offt += sprintf(arg, "%s", _("dest")); |
|
+ comma++; |
|
+ } |
|
+#endif |
|
+#ifdef SHM_LOCKED |
|
+ if (shmdsp->shm_perm.mode & SHM_LOCKED) { |
|
+ if (comma) |
|
+ arg[offt++] = ','; |
|
+ offt += sprintf(arg + offt, "%s", _("locked")); |
|
+ } |
|
+#endif |
|
+#ifdef SHM_HUGETLB |
|
+ if (shmdsp->shm_perm.mode & SHM_HUGETLB) { |
|
+ if (comma) |
|
+ arg[offt++] = ','; |
|
+ offt += sprintf(arg + offt, "%s", _("hugetlb")); |
|
+ } |
|
+#endif |
|
+#ifdef SHM_NORESERVE |
|
+ if (shmdsp->shm_perm.mode & SHM_NORESERVE) { |
|
+ if (comma) |
|
+ arg[offt++] = ','; |
|
+ sprintf(arg + offt, "%s", _("noreserve")); |
|
+ } |
|
+#endif |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ } |
|
+ break; |
|
+ case COL_ATTACH: |
|
+ if (shmdsp->shm_atim != 0) |
|
+ rc = scols_line_refer_data(ln, n, |
|
+ make_time(ctl->time_mode, |
|
+ (time_t)shmdsp->shm_atim)); |
|
+ break; |
|
+ case COL_DETACH: |
|
+ if (shmdsp->shm_dtim != 0) |
|
+ rc = scols_line_refer_data(ln, n, |
|
+ make_time(ctl->time_mode, |
|
+ (time_t)shmdsp->shm_dtim)); |
|
+ break; |
|
+ case COL_CPID: |
|
+ xasprintf(&arg, "%u", shmdsp->shm_cprid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_LPID: |
|
+ xasprintf(&arg, "%u", shmdsp->shm_lprid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ case COL_COMMAND: |
|
+ arg = proc_get_command(shmdsp->shm_cprid); |
|
+ rc = scols_line_refer_data(ln, n, arg); |
|
+ break; |
|
+ } |
|
+ if (rc != 0) |
|
+ err(EXIT_FAILURE, _("failed to set data")); |
|
+ arg = NULL; |
|
+ } |
|
+ if (id > -1) |
|
+ break; |
|
+ } |
|
+ ipc_shm_free_info(shmds); |
|
+} |
|
+ |
|
+static void do_shm_global(struct libscols_table *tb) |
|
+{ |
|
+ struct shm_data *shmds, *shmdsp; |
|
+ uint64_t nsegs = 0, sum_segsz = 0; |
|
+ struct ipc_limits lim; |
|
+ |
|
+ ipc_shm_get_limits(&lim); |
|
+ |
|
+ if (ipc_shm_get_info(-1, &shmds) > 0) { |
|
+ for (shmdsp = shmds; shmdsp->next != NULL; shmdsp = shmdsp->next) { |
|
+ ++nsegs; |
|
+ sum_segsz += shmdsp->shm_segsz; |
|
+ } |
|
+ ipc_shm_free_info(shmds); |
|
+ } |
|
+ |
|
+ global_set_data(tb, "SHMMNI", _("Shared memory segments"), nsegs, lim.shmmni, 1); |
|
+ global_set_data(tb, "SHMALL", _("Shared memory pages"), sum_segsz / getpagesize(), lim.shmall, 1); |
|
+ global_set_data(tb, "SHMMAX", _("Max size of shared memory segment (bytes)"), 0, lim.shmmax, 0); |
|
+ global_set_data(tb, "SHMMIN", _("Min size of shared memory segment (bytes)"), 0, lim.shmmin, 0); |
|
+} |
|
+ |
|
+int main(int argc, char *argv[]) |
|
+{ |
|
+ int opt, msg = 0, sem = 0, shm = 0, id = -1; |
|
+ 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; |
|
+ |
|
+ /* long only options. */ |
|
+ enum { |
|
+ OPT_NOTRUNC = CHAR_MAX + 1, |
|
+ OPT_NOHEAD, |
|
+ OPT_TIME_FMT |
|
+ }; |
|
+ |
|
+ static const struct option longopts[] = { |
|
+ { "bytes", no_argument, 0, 'b' }, |
|
+ { "creator", no_argument, 0, 'c' }, |
|
+ { "export", no_argument, 0, 'e' }, |
|
+ { "global", no_argument, 0, 'g' }, |
|
+ { "help", no_argument, 0, 'h' }, |
|
+ { "id", required_argument, 0, 'i' }, |
|
+ { "list", no_argument, 0, 'l' }, |
|
+ { "newline", no_argument, 0, 'n' }, |
|
+ { "noheadings", no_argument, 0, OPT_NOHEAD }, |
|
+ { "notruncate", no_argument, 0, OPT_NOTRUNC }, |
|
+ { "numeric-perms", no_argument, 0, 'P' }, |
|
+ { "output", required_argument, 0, 'o' }, |
|
+ { "pid", no_argument, 0, 'p' }, |
|
+ { "queues", no_argument, 0, 'q' }, |
|
+ { "raw", no_argument, 0, 'r' }, |
|
+ { "semaphores", no_argument, 0, 's' }, |
|
+ { "shmems", no_argument, 0, 'm' }, |
|
+ { "time", no_argument, 0, 't' }, |
|
+ { "time-format", required_argument, 0, OPT_TIME_FMT }, |
|
+ { "version", no_argument, 0, 'V' }, |
|
+ {NULL, 0, NULL, 0} |
|
+ }; |
|
+ |
|
+ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ |
|
+ { 'J', 'e', 'l', 'n', 'r' }, |
|
+ { 'g', 'i' }, |
|
+ { 'c', 'o', 't' }, |
|
+ { 'm', 'q', 's' }, |
|
+ { 0 } |
|
+ }; |
|
+ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; |
|
+ |
|
+ setlocale(LC_ALL, ""); |
|
+ bindtextdomain(PACKAGE, LOCALEDIR); |
|
+ textdomain(PACKAGE); |
|
+ atexit(close_stdout); |
|
+ |
|
+ ctl->time_mode = 0; |
|
+ |
|
+ scols_init_debug(0); |
|
+ |
|
+ while ((opt = getopt_long(argc, argv, "bceghi:lmno:PqrstuV", longopts, NULL)) != -1) { |
|
+ |
|
+ err_exclusive_options(opt, longopts, excl, excl_st); |
|
+ |
|
+ switch (opt) { |
|
+ case 'b': |
|
+ ctl->bytes = 1; |
|
+ break; |
|
+ case 'i': |
|
+ id = strtos32_or_err(optarg, _("failed to parse IPC identifier")); |
|
+ break; |
|
+ case 'e': |
|
+ ctl->outmode = OUT_EXPORT; |
|
+ break; |
|
+ case 'r': |
|
+ ctl->outmode = OUT_RAW; |
|
+ break; |
|
+ case 'o': |
|
+ outarg = optarg; |
|
+ break; |
|
+ case 'g': |
|
+ global = 1; |
|
+ break; |
|
+ case 'q': |
|
+ msg = 1; |
|
+ add_column(columns, ncolumns++, COL_KEY); |
|
+ add_column(columns, ncolumns++, COL_ID); |
|
+ add_column(columns, ncolumns++, COL_PERMS); |
|
+ add_column(columns, ncolumns++, COL_OWNER); |
|
+ add_column(columns, ncolumns++, COL_USEDBYTES); |
|
+ add_column(columns, ncolumns++, COL_MSGS); |
|
+ add_column(columns, ncolumns++, COL_LSPID); |
|
+ add_column(columns, ncolumns++, COL_LRPID); |
|
+ LOWER = COLDESC_IDX_MSG_FIRST; |
|
+ UPPER = COLDESC_IDX_MSG_LAST; |
|
+ break; |
|
+ case 'l': |
|
+ ctl->outmode = OUT_LIST; |
|
+ break; |
|
+ case 'm': |
|
+ shm = 1; |
|
+ add_column(columns, ncolumns++, COL_KEY); |
|
+ add_column(columns, ncolumns++, COL_ID); |
|
+ add_column(columns, ncolumns++, COL_PERMS); |
|
+ add_column(columns, ncolumns++, COL_OWNER); |
|
+ add_column(columns, ncolumns++, COL_SIZE); |
|
+ add_column(columns, ncolumns++, COL_NATTCH); |
|
+ add_column(columns, ncolumns++, COL_STATUS); |
|
+ add_column(columns, ncolumns++, COL_CTIME); |
|
+ add_column(columns, ncolumns++, COL_CPID); |
|
+ add_column(columns, ncolumns++, COL_LPID); |
|
+ add_column(columns, ncolumns++, COL_COMMAND); |
|
+ LOWER = COLDESC_IDX_SHM_FIRST; |
|
+ UPPER = COLDESC_IDX_SHM_LAST; |
|
+ break; |
|
+ case 'n': |
|
+ ctl->outmode = OUT_NEWLINE; |
|
+ break; |
|
+ case 'P': |
|
+ ctl->numperms = 1; |
|
+ break; |
|
+ case 's': |
|
+ sem = 1; |
|
+ add_column(columns, ncolumns++, COL_KEY); |
|
+ add_column(columns, ncolumns++, COL_ID); |
|
+ add_column(columns, ncolumns++, COL_PERMS); |
|
+ add_column(columns, ncolumns++, COL_OWNER); |
|
+ add_column(columns, ncolumns++, COL_NSEMS); |
|
+ LOWER = COLDESC_IDX_SEM_FIRST; |
|
+ UPPER = COLDESC_IDX_SEM_LAST; |
|
+ break; |
|
+ case OPT_NOTRUNC: |
|
+ ctl->notrunc = 1; |
|
+ break; |
|
+ case OPT_NOHEAD: |
|
+ ctl->noheadings = 1; |
|
+ break; |
|
+ case OPT_TIME_FMT: |
|
+ ctl->time_mode = parse_time_mode(optarg); |
|
+ break; |
|
+ case 't': |
|
+ show_time = 1; |
|
+ break; |
|
+ case 'c': |
|
+ show_creat = 1; |
|
+ break; |
|
+ case 'h': |
|
+ usage(stdout); |
|
+ case 'V': |
|
+ printf(UTIL_LINUX_VERSION); |
|
+ return EXIT_SUCCESS; |
|
+ default: |
|
+ usage(stderr); |
|
+ } |
|
+ } |
|
+ |
|
+ /* 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 (global) { |
|
+ add_column(columns, ncolumns++, COL_RESOURCE); |
|
+ add_column(columns, ncolumns++, COL_DESC); |
|
+ add_column(columns, ncolumns++, COL_LIMIT); |
|
+ add_column(columns, ncolumns++, COL_USED); |
|
+ add_column(columns, ncolumns++, COL_USEPERC); |
|
+ LOWER = COLDESC_IDX_SUM_FIRST; |
|
+ UPPER = COLDESC_IDX_SUM_LAST; |
|
+ } |
|
+ |
|
+ /* default to pretty-print if --id specified */ |
|
+ if (id != -1 && !ctl->outmode) |
|
+ ctl->outmode = OUT_PRETTY; |
|
+ |
|
+ if (!ctl->time_mode) |
|
+ ctl->time_mode = ctl->outmode == OUT_PRETTY ? TIME_FULL : TIME_SHORT; |
|
+ |
|
+ if (ctl->outmode == OUT_PRETTY && !(optarg || show_creat || show_time)) { |
|
+ /* all columns for lsipc --<RESOURCE> --id <ID> */ |
|
+ for (ncolumns = 0, i = 0; i < ARRAY_SIZE(coldescs); i++) |
|
+ columns[ncolumns++] = i; |
|
+ } else { |
|
+ 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 (msg && show_time) { |
|
+ add_column(columns, ncolumns++, COL_SEND); |
|
+ add_column(columns, ncolumns++, COL_RECV); |
|
+ add_column(columns, ncolumns++, COL_CTIME); |
|
+ } |
|
+ if (shm && show_time) { |
|
+ /* keep "COMMAND" as last column */ |
|
+ size_t cmd = columns[ncolumns - 1] == COL_COMMAND; |
|
+ |
|
+ if (cmd) |
|
+ ncolumns--; |
|
+ add_column(columns, ncolumns++, COL_ATTACH); |
|
+ add_column(columns, ncolumns++, COL_DETACH); |
|
+ if (cmd) |
|
+ add_column(columns, ncolumns++, COL_COMMAND); |
|
+ } |
|
+ if (sem && show_time) { |
|
+ add_column(columns, ncolumns++, COL_OTIME); |
|
+ add_column(columns, ncolumns++, COL_CTIME); |
|
+ } |
|
+ } |
|
+ |
|
+ if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns), |
|
+ (int *) &ncolumns, column_name_to_id) < 0) |
|
+ return EXIT_FAILURE; |
|
+ |
|
+ tb = setup_table(ctl); |
|
+ if (!tb) |
|
+ return EXIT_FAILURE; |
|
+ |
|
+ if (msg) { |
|
+ if (global) |
|
+ do_msg_global(tb); |
|
+ else |
|
+ do_msg(id, ctl, tb); |
|
+ } |
|
+ if (shm) { |
|
+ if (global) |
|
+ do_shm_global(tb); |
|
+ else |
|
+ do_shm(id, ctl, tb); |
|
+ } |
|
+ if (sem) { |
|
+ if (global) |
|
+ do_sem_global(tb); |
|
+ else |
|
+ do_sem(id, ctl, tb); |
|
+ } |
|
+ |
|
+ print_table(ctl, tb); |
|
+ |
|
+ scols_unref_table(tb); |
|
+ free(ctl); |
|
+ |
|
+ return EXIT_SUCCESS; |
|
+} |
|
+ |
|
diff --git a/tests/functions.sh b/tests/functions.sh |
|
index 123f6c3..b2d493c 100644 |
|
--- a/tests/functions.sh |
|
+++ b/tests/functions.sh |
|
@@ -50,16 +50,25 @@ function ts_skip_nonroot { |
|
} |
|
|
|
function ts_failed_subtest { |
|
+ local msg="FAILED" |
|
+ local ret=1 |
|
+ if [ "$TS_KNOWN_FAIL" = "yes" ]; then |
|
+ msg="KNOWN FAILED" |
|
+ ret=0 |
|
+ fi |
|
+ |
|
if [ x"$1" == x"" ]; then |
|
- echo " FAILED ($TS_NS)" |
|
+ echo " $msg ($TS_NS)" |
|
else |
|
- echo " FAILED ($1)" |
|
+ echo " $msg ($1)" |
|
fi |
|
+ |
|
+ return $ret |
|
} |
|
|
|
function ts_failed { |
|
ts_failed_subtest "$1" |
|
- exit 1 |
|
+ exit $? |
|
} |
|
|
|
function ts_ok_subtest { |
|
@@ -150,6 +159,7 @@ function ts_init_env { |
|
TS_SUBDIR=$(dirname $TS_SCRIPT) |
|
TS_TESTNAME=$(basename $TS_SCRIPT) |
|
TS_COMPONENT=$(basename $TS_SUBDIR) |
|
+ TS_KNOWN_FAIL="no" |
|
|
|
TS_NSUBTESTS=0 |
|
TS_NSUBFAILED=0 |
|
diff --git a/tests/ts/ipcs/limits2 b/tests/ts/ipcs/limits2 |
|
index f99a354..63f834d 100755 |
|
--- a/tests/ts/ipcs/limits2 |
|
+++ b/tests/ts/ipcs/limits2 |
|
@@ -16,15 +16,20 @@ |
|
# GNU General Public License for more details. |
|
# |
|
|
|
-TS_TOPDIR="$(dirname $0)/../.." |
|
+TS_TOPDIR="${0%/*}/../.." |
|
TS_DESC="basic limits" |
|
|
|
. $TS_TOPDIR/functions.sh |
|
ts_init "$*" |
|
-type bc >/dev/null 2>&1 || ts_skip "cannot find bc command" |
|
|
|
. $TS_SELF/functions.sh |
|
|
|
+# TODO https://github.com/karelzak/util-linux/issues/51 |
|
+SHMALL=$(</proc/sys/kernel/shmall) |
|
+if [ $(bc <<<"(2^64 / $PAGE_SIZE) <= $SHMALL") -eq 1 ]; then |
|
+ TS_KNOWN_FAIL="yes" |
|
+fi |
|
+ |
|
ts_log "check for difference between kernel and IPC" |
|
ipcs_limits_check >> $TS_OUTPUT |
|
|
|
-- |
|
2.7.4 |
|
|
|
|