]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/lsipc.c
Merge branch 'libeconf' of https://github.com/thkukuk/util-linux
[thirdparty/util-linux.git] / sys-utils / lsipc.c
CommitLineData
9d20ffda
KZ
1/*
2 * lsipc - List information about IPC instances employed in the system
3 *
4 * Copyright (C) 2015 Ondrej Oprala <ooprala@redhat.com>
5 * Copyright (C) 2015 Karel Zak <ooprala@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 *
22 * lsipc is inspired by the ipcs utility. The aim is to create
23 * a utility unencumbered by a standard to provide more flexible
24 * means of controlling the output.
25 */
26
27#include <errno.h>
9d20ffda
KZ
28#include <getopt.h>
29#include <sys/time.h>
30#include <unistd.h>
31
32#include <libsmartcols.h>
33
34#include "c.h"
35#include "nls.h"
36#include "closestream.h"
37#include "strutils.h"
38#include "optutils.h"
39#include "xalloc.h"
be475287 40#include "procutils.h"
9d20ffda 41#include "ipcutils.h"
bbdfcbe9 42#include "timeutils.h"
9d20ffda
KZ
43
44/*
45 * time modes
46 * */
47enum {
48 TIME_INVALID = 0,
49 TIME_SHORT,
50 TIME_FULL,
c8b47062 51 TIME_ISO
9d20ffda
KZ
52};
53
54/*
55 * IDs
56 */
57enum {
470a7332
KZ
58 /* generic */
59 COLDESC_IDX_GEN_FIRST = 0,
60 COL_KEY = COLDESC_IDX_GEN_FIRST,
61 COL_ID,
62 COL_OWNER,
63 COL_PERMS,
64 COL_CUID,
7458c061 65 COL_CUSER,
470a7332 66 COL_CGID,
7458c061 67 COL_CGROUP,
470a7332 68 COL_UID,
7458c061 69 COL_USER,
470a7332 70 COL_GID,
7458c061 71 COL_GROUP,
470a7332
KZ
72 COL_CTIME,
73 COLDESC_IDX_GEN_LAST = COL_CTIME,
74
9d20ffda 75 /* msgq-specific */
470a7332
KZ
76 COLDESC_IDX_MSG_FIRST,
77 COL_USEDBYTES = COLDESC_IDX_MSG_FIRST,
78 COL_MSGS,
79 COL_SEND,
80 COL_RECV,
81 COL_LSPID,
82 COL_LRPID,
83 COLDESC_IDX_MSG_LAST = COL_LRPID,
84
9d20ffda 85 /* shm-specific */
470a7332
KZ
86 COLDESC_IDX_SHM_FIRST,
87 COL_SIZE = COLDESC_IDX_SHM_FIRST,
88 COL_NATTCH,
89 COL_STATUS,
90 COL_ATTACH,
91 COL_DETACH,
92 COL_COMMAND,
93 COL_CPID,
94 COL_LPID,
95 COLDESC_IDX_SHM_LAST = COL_LPID,
96
9d20ffda 97 /* sem-specific */
470a7332
KZ
98 COLDESC_IDX_SEM_FIRST,
99 COL_NSEMS = COLDESC_IDX_SEM_FIRST,
100 COL_OTIME,
101 COLDESC_IDX_SEM_LAST = COL_OTIME,
102
103 /* summary (--global) */
104 COLDESC_IDX_SUM_FIRST,
32cfe498 105 COL_RESOURCE = COLDESC_IDX_SUM_FIRST,
470a7332 106 COL_DESC,
470a7332 107 COL_LIMIT,
1a311071
KZ
108 COL_USED,
109 COL_USEPERC,
110 COLDESC_IDX_SUM_LAST = COL_USEPERC
9d20ffda
KZ
111};
112
9d20ffda
KZ
113/* not all columns apply to all options, so we specify a legal range for each */
114static size_t LOWER, UPPER;
115
116/*
117 * output modes
118 */
119enum {
2a7150ac 120 OUT_EXPORT = 1,
9d20ffda
KZ
121 OUT_NEWLINE,
122 OUT_RAW,
5de8fcfd 123 OUT_JSON,
2916afa3
KZ
124 OUT_PRETTY,
125 OUT_LIST
9d20ffda
KZ
126};
127
128struct lsipc_control {
d7500c6a 129 int outmode;
9d20ffda
KZ
130 unsigned int noheadings : 1, /* don't print header line */
131 notrunc : 1, /* don't truncate columns */
9d20ffda
KZ
132 bytes : 1, /* SIZE in bytes */
133 numperms : 1, /* numeric permissions */
134 time_mode : 2;
135};
136
137struct lsipc_coldesc {
138 const char *name;
139 const char *help;
140 const char *pretty_name;
141
142 double whint; /* width hint */
143 long flag;
144};
145
146static const struct lsipc_coldesc coldescs[] =
147{
148 /* common */
149 [COL_KEY] = { "KEY", N_("Resource key"), N_("Key"), 1},
150 [COL_ID] = { "ID", N_("Resource ID"), N_("ID"), 1},
d8461c4e 151 [COL_OWNER] = { "OWNER", N_("Owner's username or UID"), N_("Owner"), 1, SCOLS_FL_RIGHT},
9d20ffda 152 [COL_PERMS] = { "PERMS", N_("Permissions"), N_("Permissions"), 1, SCOLS_FL_RIGHT},
7458c061
KZ
153 [COL_CUID] = { "CUID", N_("Creator UID"), N_("Creator UID"), 1, SCOLS_FL_RIGHT},
154 [COL_CUSER] = { "CUSER", N_("Creator user"), N_("Creator user"), 1 },
155 [COL_CGID] = { "CGID", N_("Creator GID"), N_("Creator GID"), 1, SCOLS_FL_RIGHT},
156 [COL_CGROUP] = { "CGROUP", N_("Creator group"), N_("Creator group"), 1 },
9d20ffda 157 [COL_UID] = { "UID", N_("User ID"), N_("UID"), 1, SCOLS_FL_RIGHT},
7458c061 158 [COL_USER] = { "USER", N_("User name"), N_("User name"), 1},
9d20ffda 159 [COL_GID] = { "GID", N_("Group ID"), N_("GID"), 1, SCOLS_FL_RIGHT},
7458c061 160 [COL_GROUP] = { "GROUP", N_("Group name"), N_("Group name"), 1},
9d20ffda
KZ
161 [COL_CTIME] = { "CTIME", N_("Time of the last change"), N_("Last change"), 1, SCOLS_FL_RIGHT},
162
163 /* msgq-specific */
164 [COL_USEDBYTES] = { "USEDBYTES",N_("Bytes used"), N_("Bytes used"), 1, SCOLS_FL_RIGHT},
165 [COL_MSGS] = { "MSGS", N_("Number of messages"), N_("Messages"), 1},
166 [COL_SEND] = { "SEND", N_("Time of last msg sent"), N_("Msg sent"), 1, SCOLS_FL_RIGHT},
167 [COL_RECV] = { "RECV", N_("Time of last msg received"), N_("Msg received"), 1, SCOLS_FL_RIGHT},
168 [COL_LSPID] = { "LSPID", N_("PID of the last msg sender"), N_("Msg sender"), 1, SCOLS_FL_RIGHT},
169 [COL_LRPID] = { "LRPID", N_("PID of the last msg receiver"), N_("Msg receiver"), 1, SCOLS_FL_RIGHT},
170
171 /* shm-specific */
172 [COL_SIZE] = { "SIZE", N_("Segment size"), N_("Segment size"), 1, SCOLS_FL_RIGHT},
173 [COL_NATTCH] = { "NATTCH", N_("Number of attached processes"), N_("Attached processes"), 1, SCOLS_FL_RIGHT},
174 [COL_STATUS] = { "STATUS", N_("Status"), N_("Status"), 1, SCOLS_FL_NOEXTREMES},
175 [COL_ATTACH] = { "ATTACH", N_("Attach time"), N_("Attach time"), 1, SCOLS_FL_RIGHT},
176 [COL_DETACH] = { "DETACH", N_("Detach time"), N_("Detach time"), 1, SCOLS_FL_RIGHT},
be475287 177 [COL_COMMAND] = { "COMMAND", N_("Creator command line"), N_("Creator command"), 0, SCOLS_FL_TRUNC},
9d20ffda
KZ
178 [COL_CPID] = { "CPID", N_("PID of the creator"), N_("Creator PID"), 1, SCOLS_FL_RIGHT},
179 [COL_LPID] = { "LPID", N_("PID of last user"), N_("Last user PID"), 1, SCOLS_FL_RIGHT},
180
181 /* sem-specific */
182 [COL_NSEMS] = { "NSEMS", N_("Number of semaphores"), N_("Semaphores"), 1, SCOLS_FL_RIGHT},
183 [COL_OTIME] = { "OTIME", N_("Time of the last operation"), N_("Last operation"), 1, SCOLS_FL_RIGHT},
184
185 /* cols for summarized information */
186 [COL_RESOURCE] = { "RESOURCE", N_("Resource name"), N_("Resource"), 1 },
187 [COL_DESC] = { "DESCRIPTION",N_("Resource description"), N_("Description"), 1 },
32cfe498 188 [COL_USED] = { "USED", N_("Currently used"), N_("Used"), 1, SCOLS_FL_RIGHT },
1a311071 189 [COL_USEPERC] = { "USE%", N_("Currently use percentage"), N_("Use"), 1, SCOLS_FL_RIGHT },
9d20ffda
KZ
190 [COL_LIMIT] = { "LIMIT", N_("System-wide limit"), N_("Limit"), 1, SCOLS_FL_RIGHT },
191};
192
193
194/* columns[] array specifies all currently wanted output column. The columns
195 * are defined by coldescs[] array and you can specify (on command line) each
196 * column twice. That's enough, dynamically allocated array of the columns is
197 * unnecessary overkill and over-engineering in this case */
198static int columns[ARRAY_SIZE(coldescs) * 2];
e0154173 199static size_t ncolumns;
9d20ffda
KZ
200
201static inline size_t err_columns_index(size_t arysz, size_t idx)
202{
203 if (idx >= arysz)
204 errx(EXIT_FAILURE, _("too many columns specified, "
205 "the limit is %zu columns"),
206 arysz - 1);
207 return idx;
208}
209
210#define add_column(ary, n, id) \
211 ((ary)[ err_columns_index(ARRAY_SIZE(ary), (n)) ] = (id))
212
213static int column_name_to_id(const char *name, size_t namesz)
214{
215 size_t i;
216
217 for (i = 0; i < ARRAY_SIZE(coldescs); i++) {
218 const char *cn = coldescs[i].name;
219
220 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) {
221 if (i > COL_CTIME) {
222 if (i >= LOWER && i <= UPPER)
223 return i;
042f62df
RP
224
225 warnx(_("column %s does not apply to the specified IPC"), name);
226 return -1;
227 }
228
229 return i;
9d20ffda
KZ
230 }
231 }
232 warnx(_("unknown column: %s"), name);
233 return -1;
234}
235
8941e5cb
KZ
236static int get_column_id(int num)
237{
238 assert(num >= 0);
239 assert((size_t) num < ncolumns);
240 assert((size_t) columns[num] < ARRAY_SIZE(coldescs));
241 return columns[num];
242}
243
244static const struct lsipc_coldesc *get_column_desc(int num)
245{
246 return &coldescs[ get_column_id(num) ];
247}
248
71b63dc1
KZ
249static char *get_username(struct passwd **pw, uid_t id)
250{
251 if (!*pw || (*pw)->pw_uid != id)
252 *pw = getpwuid(id);
253
254 return *pw ? xstrdup((*pw)->pw_name) : NULL;
255}
256
257static char *get_groupname(struct group **gr, gid_t id)
258{
259 if (!*gr || (*gr)->gr_gid != id)
260 *gr = getgrgid(id);
261
262 return *gr ? xstrdup((*gr)->gr_name) : NULL;
263}
264
eb2306e6 265static int parse_time_mode(const char *s)
9d20ffda
KZ
266{
267 struct lsipc_timefmt {
268 const char *name;
269 const int val;
270 };
271 static const struct lsipc_timefmt timefmts[] = {
272 {"iso", TIME_ISO},
273 {"full", TIME_FULL},
274 {"short", TIME_SHORT},
275 };
276 size_t i;
277
278 for (i = 0; i < ARRAY_SIZE(timefmts); i++) {
eb2306e6 279 if (strcmp(timefmts[i].name, s) == 0)
9d20ffda
KZ
280 return timefmts[i].val;
281 }
eb2306e6 282 errx(EXIT_FAILURE, _("unknown time format: %s"), s);
9d20ffda
KZ
283}
284
9325dbfd 285static void __attribute__((__noreturn__)) usage(void)
9d20ffda 286{
9325dbfd 287 FILE *out = stdout;
9d20ffda
KZ
288 size_t i;
289
290 fputs(USAGE_HEADER, out);
9d20ffda
KZ
291 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
292
293 fputs(USAGE_SEPARATOR, out);
294 fputs(_("Show information on IPC facilities.\n"), out);
295
9d20ffda
KZ
296 fputs(USAGE_SEPARATOR, out);
297 fputs(_("Resource options:\n"), out);
298 fputs(_(" -m, --shmems shared memory segments\n"), out);
299 fputs(_(" -q, --queues message queues\n"), out);
300 fputs(_(" -s, --semaphores semaphores\n"), out);
32cfe498 301 fputs(_(" -g, --global info about system-wide usage (may be used with -m, -q and -s)\n"), out);
9d20ffda
KZ
302 fputs(_(" -i, --id <id> print details on resource identified by <id>\n"), out);
303
470a7332 304 fputs(USAGE_OPTIONS, out);
9d20ffda
KZ
305 fputs(_(" --noheadings don't print headings\n"), out);
306 fputs(_(" --notruncate don't truncate output\n"), out);
307 fputs(_(" --time-format=<type> display dates in short, full or iso format\n"), out);
308 fputs(_(" -b, --bytes print SIZE in bytes rather than in human readable format\n"), out);
309 fputs(_(" -c, --creator show creator and owner\n"), out);
310 fputs(_(" -e, --export display in an export-able output format\n"), out);
9d20ffda
KZ
311 fputs(_(" -J, --json use the JSON output format\n"), out);
312 fputs(_(" -n, --newline display each piece of information on a new line\n"), out);
2916afa3 313 fputs(_(" -l, --list force list output format (for example with --id)\n"), out);
9d20ffda
KZ
314 fputs(_(" -o, --output[=<list>] define the columns to output\n"), out);
315 fputs(_(" -P, --numeric-perms print numeric permissions (PERMS column)\n"), out);
316 fputs(_(" -r, --raw display in raw mode\n"), out);
317 fputs(_(" -t, --time show attach, detach and change times\n"), out);
2a7150ac
KZ
318
319 fputs(USAGE_SEPARATOR, out);
f45f3ec3 320 printf(USAGE_HELP_OPTIONS(26));
9d20ffda 321
470a7332 322 fprintf(out, _("\nGeneric columns:\n"));
32cfe498 323 for (i = COLDESC_IDX_GEN_FIRST; i <= COLDESC_IDX_GEN_LAST; i++)
470a7332 324 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
9d20ffda 325
62eea9ce 326 fprintf(out, _("\nShared-memory columns (--shmems):\n"));
32cfe498 327 for (i = COLDESC_IDX_SHM_FIRST; i <= COLDESC_IDX_SHM_LAST; i++)
470a7332 328 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
9d20ffda 329
62eea9ce 330 fprintf(out, _("\nMessage-queue columns (--queues):\n"));
32cfe498 331 for (i = COLDESC_IDX_MSG_FIRST; i <= COLDESC_IDX_MSG_LAST; i++)
470a7332 332 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
9d20ffda 333
62eea9ce 334 fprintf(out, _("\nSemaphore columns (--semaphores):\n"));
32cfe498 335 for (i = COLDESC_IDX_SEM_FIRST; i <= COLDESC_IDX_SEM_LAST; i++)
470a7332
KZ
336 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
337
338 fprintf(out, _("\nSummary columns (--global):\n"));
32cfe498 339 for (i = COLDESC_IDX_SUM_FIRST; i <= COLDESC_IDX_SUM_LAST; i++)
470a7332
KZ
340 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
341
f45f3ec3 342 printf(USAGE_MAN_TAIL("lsipc(1)"));
9325dbfd 343 exit(EXIT_SUCCESS);
9d20ffda
KZ
344}
345
624de257 346static struct libscols_table *new_table(struct lsipc_control *ctl)
9d20ffda
KZ
347{
348 struct libscols_table *table = scols_new_table();
9d20ffda
KZ
349
350 if (!table)
780ce22c
KZ
351 err(EXIT_FAILURE, _("failed to allocate output table"));
352
9d20ffda
KZ
353 if (ctl->noheadings)
354 scols_table_enable_noheadings(table, 1);
9d20ffda 355
d7500c6a 356 switch(ctl->outmode) {
9d20ffda
KZ
357 case OUT_NEWLINE:
358 scols_table_set_column_separator(table, "\n");
359 /* fallthrough */
360 case OUT_EXPORT:
361 scols_table_enable_export(table, 1);
362 break;
9d20ffda
KZ
363 case OUT_RAW:
364 scols_table_enable_raw(table, 1);
365 break;
366 case OUT_PRETTY:
367 scols_table_enable_noheadings(table, 1);
5de8fcfd
KZ
368 break;
369 case OUT_JSON:
370 scols_table_enable_json(table, 1);
371 break;
9d20ffda
KZ
372 default:
373 break;
374 }
624de257
KZ
375 return table;
376}
377
378static struct libscols_table *setup_table(struct lsipc_control *ctl)
379{
380 struct libscols_table *table = new_table(ctl);
381 size_t n;
9d20ffda 382
e0154173 383 for (n = 0; n < ncolumns; n++) {
8941e5cb
KZ
384 const struct lsipc_coldesc *desc = get_column_desc(n);
385 int flags = desc->flag;
9d20ffda
KZ
386
387 if (ctl->notrunc)
388 flags &= ~SCOLS_FL_TRUNC;
8941e5cb 389 if (!scols_table_new_column(table, desc->name, desc->whint, flags))
9d20ffda 390 goto fail;
9d20ffda
KZ
391 }
392 return table;
393fail:
394 scols_unref_table(table);
395 return NULL;
396}
397
398static int print_pretty(struct libscols_table *table)
399{
400 struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
401 struct libscols_column *col;
402 struct libscols_cell *data;
403 struct libscols_line *ln;
624de257 404 const char *hstr, *dstr;
9d20ffda
KZ
405 int n = 0;
406
407 ln = scols_table_get_line(table, 0);
408 while (!scols_table_next_column(table, itr, &col)) {
409
410 data = scols_line_get_cell(ln, n);
411
8941e5cb 412 hstr = N_(get_column_desc(n)->pretty_name);
9d20ffda
KZ
413 dstr = scols_cell_get_data(data);
414
415 if (dstr)
416 printf("%s:%*c%-36s\n", hstr, 35 - (int)strlen(hstr), ' ', dstr);
417 ++n;
418 }
419
420 /* this is used to pretty-print detailed info about a semaphore array */
421 if (ln) {
624de257
KZ
422 struct libscols_table *subtab = scols_line_get_userdata(ln);
423 if (subtab) {
424 printf(_("Elements:\n\n"));
425 scols_print_table(subtab);
9d20ffda
KZ
426 }
427 }
428
429 scols_free_iter(itr);
430 return 0;
431
432}
433
d7500c6a 434static int print_table(struct lsipc_control *ctl, struct libscols_table *tb)
9d20ffda 435{
d7500c6a 436 if (ctl->outmode == OUT_PRETTY)
9d20ffda
KZ
437 print_pretty(tb);
438 else
439 scols_print_table(tb);
440 return 0;
441}
442static struct timeval now;
443
9d20ffda
KZ
444static char *make_time(int mode, time_t time)
445{
9d20ffda
KZ
446 char buf[64] = {0};
447
9d20ffda
KZ
448 switch(mode) {
449 case TIME_FULL:
bcf72069
KZ
450 {
451 struct tm tm;
452 char *s;
453
454 localtime_r(&time, &tm);
9d20ffda
KZ
455 asctime_r(&tm, buf);
456 if (*(s = buf + strlen(buf) - 1) == '\n')
457 *s = '\0';
458 break;
bcf72069 459 }
9d20ffda 460 case TIME_SHORT:
bcf72069 461 strtime_short(&time, &now, 0, buf, sizeof(buf));
9d20ffda
KZ
462 break;
463 case TIME_ISO:
4111bb3a 464 strtime_iso(&time, ISO_TIMESTAMP_T, buf, sizeof(buf));
9d20ffda
KZ
465 break;
466 default:
467 errx(EXIT_FAILURE, _("unsupported time type"));
468 }
469 return xstrdup(buf);
470}
471
32cfe498 472static void global_set_data(struct libscols_table *tb, const char *resource,
a4839bc7 473 const char *desc, uintmax_t used, uintmax_t limit, int usage)
32cfe498
KZ
474{
475 struct libscols_line *ln;
e0154173 476 size_t n;
32cfe498
KZ
477
478 ln = scols_table_new_line(tb, NULL);
479 if (!ln)
780ce22c 480 err(EXIT_FAILURE, _("failed to allocate output line"));
32cfe498
KZ
481
482 for (n = 0; n < ncolumns; n++) {
483 int rc = 0;
484 char *arg = NULL;
485
8941e5cb 486 switch (get_column_id(n)) {
32cfe498
KZ
487 case COL_RESOURCE:
488 rc = scols_line_set_data(ln, n, resource);
489 break;
490 case COL_DESC:
491 rc = scols_line_set_data(ln, n, desc);
492 break;
493 case COL_USED:
a4839bc7
KZ
494 if (usage) {
495 xasprintf(&arg, "%ju", used);
496 rc = scols_line_refer_data(ln, n, arg);
497 } else
498 rc = scols_line_set_data(ln, n, "-");
32cfe498 499 break;
1a311071 500 case COL_USEPERC:
a4839bc7
KZ
501 if (usage) {
502 xasprintf(&arg, "%2.2f%%", (double) used / limit * 100);
503 rc = scols_line_refer_data(ln, n, arg);
504 } else
505 rc = scols_line_set_data(ln, n, "-");
1a311071 506 break;
32cfe498
KZ
507 case COL_LIMIT:
508 xasprintf(&arg, "%ju", limit);
cdb4a946 509 rc = scols_line_refer_data(ln, n, arg);
32cfe498
KZ
510 break;
511 }
512
513 if (rc != 0)
780ce22c 514 err(EXIT_FAILURE, _("failed to add output data"));
32cfe498
KZ
515 }
516}
517
624de257
KZ
518static void setup_sem_elements_columns(struct libscols_table *tb)
519{
520 scols_table_set_name(tb, "elements");
521 if (!scols_table_new_column(tb, "SEMNUM", 0, SCOLS_FL_RIGHT))
522 err_oom();
523 if (!scols_table_new_column(tb, "VALUE", 0, SCOLS_FL_RIGHT))
524 err_oom();
525 if (!scols_table_new_column(tb, "NCOUNT", 0, SCOLS_FL_RIGHT))
526 err_oom();
527 if (!scols_table_new_column(tb, "ZCOUNT", 0, SCOLS_FL_RIGHT))
528 err_oom();
529 if (!scols_table_new_column(tb, "PID", 0, SCOLS_FL_RIGHT))
530 err_oom();
531 if (!scols_table_new_column(tb, "COMMAND", 0, SCOLS_FL_RIGHT))
532 err_oom();
533}
534
9d20ffda
KZ
535static void do_sem(int id, struct lsipc_control *ctl, struct libscols_table *tb)
536{
9d20ffda
KZ
537 struct libscols_line *ln;
538 struct passwd *pw = NULL, *cpw = NULL;
539 struct group *gr = NULL, *cgr = NULL;
540 struct sem_data *semds, *semdsp;
cdb4a946 541 char *arg = NULL;
9d20ffda 542
5de8fcfd
KZ
543 scols_table_set_name(tb, "semaphores");
544
9d20ffda
KZ
545 if (ipc_sem_get_info(id, &semds) < 1) {
546 if (id > -1)
547 warnx(_("id %d not found"), id);
548 return;
549 }
550 for (semdsp = semds; semdsp->next != NULL || id > -1; semdsp = semdsp->next) {
e0154173 551 size_t n;
780ce22c 552
9d20ffda 553 ln = scols_table_new_line(tb, NULL);
780ce22c
KZ
554 if (!ln)
555 err(EXIT_FAILURE, _("failed to allocate output line"));
9d20ffda 556
e0154173
KZ
557 for (n = 0; n < ncolumns; n++) {
558 int rc = 0;
8941e5cb 559 switch (get_column_id(n)) {
91c92cb5
KZ
560 case COL_KEY:
561 xasprintf(&arg, "0x%08x",semdsp->sem_perm.key);
cdb4a946 562 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
563 break;
564 case COL_ID:
565 xasprintf(&arg, "%d",semdsp->sem_perm.id);
cdb4a946 566 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
567 break;
568 case COL_OWNER:
71b63dc1
KZ
569 arg = get_username(&pw, semdsp->sem_perm.uid);
570 if (!arg)
91c92cb5 571 xasprintf(&arg, "%u", semdsp->sem_perm.uid);
cdb4a946 572 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
573 break;
574 case COL_PERMS:
575 if (ctl->numperms)
576 xasprintf(&arg, "%#o", semdsp->sem_perm.mode & 0777);
577 else {
578 arg = xmalloc(11);
b0b24b11 579 xstrmode(semdsp->sem_perm.mode & 0777, arg);
91c92cb5 580 }
cdb4a946 581 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
582 break;
583 case COL_CUID:
584 xasprintf(&arg, "%u", semdsp->sem_perm.cuid);
cdb4a946 585 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
586 break;
587 case COL_CUSER:
71b63dc1
KZ
588 arg = get_username(&cpw, semdsp->sem_perm.cuid);
589 if (arg)
cdb4a946 590 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
591 break;
592 case COL_CGID:
71b63dc1 593 xasprintf(&arg, "%u", semdsp->sem_perm.cgid);
cdb4a946 594 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
595 break;
596 case COL_CGROUP:
71b63dc1
KZ
597 arg = get_groupname(&cgr, semdsp->sem_perm.cgid);
598 if (arg)
cdb4a946 599 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
600 break;
601 case COL_UID:
602 xasprintf(&arg, "%u", semdsp->sem_perm.uid);
cdb4a946 603 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
604 break;
605 case COL_USER:
71b63dc1
KZ
606 arg = get_username(&pw, semdsp->sem_perm.uid);
607 if (arg)
cdb4a946 608 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
609 break;
610 case COL_GID:
71b63dc1 611 xasprintf(&arg, "%u", semdsp->sem_perm.gid);
cdb4a946 612 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
613 break;
614 case COL_GROUP:
71b63dc1
KZ
615 arg = get_groupname(&gr, semdsp->sem_perm.gid);
616 if (arg)
cdb4a946 617 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
618 break;
619 case COL_CTIME:
620 if (semdsp->sem_ctime != 0) {
cdb4a946
KZ
621 rc = scols_line_refer_data(ln, n,
622 make_time(ctl->time_mode,
91c92cb5 623 (time_t)semdsp->sem_ctime));
91c92cb5
KZ
624 }
625 break;
626 case COL_NSEMS:
627 xasprintf(&arg, "%ju", semdsp->sem_nsems);
cdb4a946 628 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
629 break;
630 case COL_OTIME:
631 if (semdsp->sem_otime != 0) {
cdb4a946
KZ
632 rc = scols_line_refer_data(ln, n,
633 make_time(ctl->time_mode,
91c92cb5 634 (time_t)semdsp->sem_otime));
91c92cb5
KZ
635 }
636 break;
9d20ffda
KZ
637 }
638 if (rc != 0)
780ce22c 639 err(EXIT_FAILURE, _("failed to add output data"));
9d20ffda
KZ
640 arg = NULL;
641 }
9d20ffda 642
624de257
KZ
643 if (id > -1 && semds->sem_nsems) {
644 /* Create extra table with ID specific semaphore elements */
645 struct libscols_table *sub = new_table(ctl);
646 size_t i;
fadf556a 647 int rc = 0;
624de257
KZ
648
649 scols_table_enable_noheadings(sub, 0);
650 setup_sem_elements_columns(sub);
9d20ffda
KZ
651
652 for (i = 0; i < semds->sem_nsems; i++) {
653 struct sem_elem *e = &semds->elements[i];
624de257
KZ
654 struct libscols_line *sln = scols_table_new_line(sub, NULL);
655
780ce22c
KZ
656 if (!sln)
657 err(EXIT_FAILURE, _("failed to allocate output line"));
658
624de257
KZ
659 /* SEMNUM */
660 xasprintf(&arg, "%zu", i);
fadf556a
KZ
661 rc = scols_line_refer_data(sln, 0, arg);
662 if (rc)
663 break;
624de257
KZ
664
665 /* VALUE */
666 xasprintf(&arg, "%d", e->semval);
fadf556a
KZ
667 rc = scols_line_refer_data(sln, 1, arg);
668 if (rc)
669 break;
624de257
KZ
670
671 /* NCOUNT */
672 xasprintf(&arg, "%d", e->ncount);
fadf556a
KZ
673 rc = scols_line_refer_data(sln, 2, arg);
674 if (rc)
675 break;
624de257
KZ
676
677 /* ZCOUNT */
678 xasprintf(&arg, "%d", e->zcount);
fadf556a
KZ
679 rc = scols_line_refer_data(sln, 3, arg);
680 if (rc)
681 break;
624de257
KZ
682
683 /* PID */
684 xasprintf(&arg, "%d", e->pid);
fadf556a
KZ
685 rc = scols_line_refer_data(sln, 4, arg);
686 if (rc)
687 break;
624de257
KZ
688
689 /* COMMAND */
690 arg = proc_get_command(e->pid);
fadf556a
KZ
691 rc = scols_line_refer_data(sln, 5, arg);
692 if (rc)
693 break;
9d20ffda 694 }
624de257 695
fadf556a
KZ
696 if (rc != 0)
697 err(EXIT_FAILURE, _("failed to set data"));
698
624de257 699 scols_line_set_userdata(ln, (void *)sub);
9d20ffda
KZ
700 break;
701 }
702 }
703 ipc_sem_free_info(semds);
704}
705
706static void do_sem_global(struct libscols_table *tb)
707{
708 struct sem_data *semds, *semdsp;
709 struct ipc_limits lim;
32cfe498 710 int nsems = 0, nsets = 0;
9d20ffda 711
9d20ffda
KZ
712 ipc_sem_get_limits(&lim);
713
32cfe498
KZ
714 if (ipc_sem_get_info(-1, &semds) > 0) {
715 for (semdsp = semds; semdsp->next != NULL; semdsp = semdsp->next) {
716 ++nsets;
717 nsems += semds->sem_nsems;
718 }
719 ipc_sem_free_info(semds);
9d20ffda 720 }
9d20ffda 721
a4839bc7
KZ
722 global_set_data(tb, "SEMMNI", _("Number of semaphore identifiers"), nsets, lim.semmni, 1);
723 global_set_data(tb, "SEMMNS", _("Total number of semaphores"), nsems, lim.semmns, 1);
724 global_set_data(tb, "SEMMSL", _("Max semaphores per semaphore set."), 0, lim.semmsl, 0);
725 global_set_data(tb, "SEMOPM", _("Max number of operations per semop(2)"), 0, lim.semopm, 0);
726 global_set_data(tb, "SEMVMX", _("Semaphore max value"), 0, lim.semvmx, 0);
9d20ffda
KZ
727}
728
729static void do_msg(int id, struct lsipc_control *ctl, struct libscols_table *tb)
730{
9d20ffda
KZ
731 struct libscols_line *ln;
732 struct passwd *pw = NULL;
733 struct group *gr = NULL;
734 struct msg_data *msgds, *msgdsp;
cdb4a946 735 char *arg = NULL;
9d20ffda
KZ
736
737 if (ipc_msg_get_info(id, &msgds) < 1) {
738 if (id > -1)
739 warnx(_("id %d not found"), id);
740 return;
741 }
5de8fcfd 742 scols_table_set_name(tb, "messages");
9d20ffda
KZ
743
744 for (msgdsp = msgds; msgdsp->next != NULL || id > -1 ; msgdsp = msgdsp->next) {
e0154173 745 size_t n;
9d20ffda
KZ
746 ln = scols_table_new_line(tb, NULL);
747
780ce22c
KZ
748 if (!ln)
749 err(EXIT_FAILURE, _("failed to allocate output line"));
750
9d20ffda
KZ
751 /* no need to call getpwuid() for the same user */
752 if (!(pw && pw->pw_uid == msgdsp->msg_perm.uid))
753 pw = getpwuid(msgdsp->msg_perm.uid);
754
755 /* no need to call getgrgid() for the same user */
756 if (!(gr && gr->gr_gid == msgdsp->msg_perm.gid))
757 gr = getgrgid(msgdsp->msg_perm.gid);
758
e0154173 759 for (n = 0; n < ncolumns; n++) {
9d20ffda
KZ
760 int rc = 0;
761
8941e5cb 762 switch (get_column_id(n)) {
91c92cb5
KZ
763 case COL_KEY:
764 xasprintf(&arg, "0x%08x",msgdsp->msg_perm.key);
cdb4a946 765 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
766 break;
767 case COL_ID:
768 xasprintf(&arg, "%d",msgdsp->msg_perm.id);
cdb4a946 769 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
770 break;
771 case COL_OWNER:
71b63dc1
KZ
772 arg = get_username(&pw, msgdsp->msg_perm.uid);
773 if (!arg)
91c92cb5 774 xasprintf(&arg, "%u", msgdsp->msg_perm.uid);
cdb4a946 775 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
776 break;
777 case COL_PERMS:
778 if (ctl->numperms)
779 xasprintf(&arg, "%#o", msgdsp->msg_perm.mode & 0777);
780 else {
781 arg = xmalloc(11);
b0b24b11 782 xstrmode(msgdsp->msg_perm.mode & 0777, arg);
cdb4a946 783 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
784 }
785 break;
786 case COL_CUID:
787 xasprintf(&arg, "%u", msgdsp->msg_perm.cuid);
cdb4a946 788 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
789 break;
790 case COL_CUSER:
71b63dc1
KZ
791 arg = get_username(&pw, msgdsp->msg_perm.cuid);
792 if (arg)
cdb4a946 793 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
794 break;
795 case COL_CGID:
796 xasprintf(&arg, "%u", msgdsp->msg_perm.cuid);
cdb4a946 797 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
798 break;
799 case COL_CGROUP:
71b63dc1
KZ
800 arg = get_groupname(&gr, msgdsp->msg_perm.cgid);
801 if (arg)
cdb4a946 802 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
803 break;
804 case COL_UID:
805 xasprintf(&arg, "%u", msgdsp->msg_perm.uid);
cdb4a946 806 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
807 break;
808 case COL_USER:
71b63dc1
KZ
809 arg = get_username(&pw, msgdsp->msg_perm.uid);
810 if (arg)
cdb4a946 811 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
812 break;
813 case COL_GID:
814 xasprintf(&arg, "%u", msgdsp->msg_perm.gid);
cdb4a946 815 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
816 break;
817 case COL_GROUP:
71b63dc1
KZ
818 arg = get_groupname(&gr,msgdsp->msg_perm.gid);
819 if (arg)
cdb4a946 820 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
821 break;
822 case COL_CTIME:
cdb4a946
KZ
823 if (msgdsp->q_ctime != 0)
824 rc = scols_line_refer_data(ln, n,
825 make_time(ctl->time_mode,
91c92cb5 826 (time_t)msgdsp->q_ctime));
91c92cb5
KZ
827 break;
828 case COL_USEDBYTES:
829 xasprintf(&arg, "%ju", msgdsp->q_cbytes);
cdb4a946 830 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
831 break;
832 case COL_MSGS:
833 xasprintf(&arg, "%ju", msgdsp->q_qnum);
cdb4a946 834 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
835 break;
836 case COL_SEND:
cdb4a946
KZ
837 if (msgdsp->q_stime != 0)
838 rc = scols_line_refer_data(ln, n,
839 make_time(ctl->time_mode,
91c92cb5 840 (time_t)msgdsp->q_stime));
91c92cb5
KZ
841 break;
842 case COL_RECV:
cdb4a946
KZ
843 if (msgdsp->q_rtime != 0)
844 rc = scols_line_refer_data(ln, n,
845 make_time(ctl->time_mode,
91c92cb5 846 (time_t)msgdsp->q_rtime));
91c92cb5
KZ
847 break;
848 case COL_LSPID:
849 xasprintf(&arg, "%u", msgdsp->q_lspid);
cdb4a946 850 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
851 break;
852 case COL_LRPID:
853 xasprintf(&arg, "%u", msgdsp->q_lrpid);
cdb4a946 854 rc = scols_line_refer_data(ln, n, arg);
91c92cb5 855 break;
9d20ffda
KZ
856 }
857 if (rc != 0)
858 err(EXIT_FAILURE, _("failed to set data"));
9d20ffda
KZ
859 arg = NULL;
860 }
861 if (id > -1)
862 break;
863 }
864 ipc_msg_free_info(msgds);
865}
866
32cfe498 867
9d20ffda
KZ
868static void do_msg_global(struct libscols_table *tb)
869{
870 struct msg_data *msgds, *msgdsp;
871 struct ipc_limits lim;
32cfe498 872 int msgqs = 0;
9d20ffda 873
9d20ffda
KZ
874 ipc_msg_get_limits(&lim);
875
32cfe498
KZ
876 /* count number of used queues */
877 if (ipc_msg_get_info(-1, &msgds) > 0) {
878 for (msgdsp = msgds; msgdsp->next != NULL; msgdsp = msgdsp->next)
879 ++msgqs;
880 ipc_msg_free_info(msgds);
9d20ffda
KZ
881 }
882
a4839bc7
KZ
883 global_set_data(tb, "MSGMNI", _("Number of message queues"), msgqs, lim.msgmni, 1);
884 global_set_data(tb, "MSGMAX", _("Max size of message (bytes)"), 0, lim.msgmax, 0);
885 global_set_data(tb, "MSGMNB", _("Default max size of queue (bytes)"), 0, lim.msgmnb, 0);
9d20ffda
KZ
886}
887
d8461c4e 888
9d20ffda
KZ
889static void do_shm(int id, struct lsipc_control *ctl, struct libscols_table *tb)
890{
9d20ffda
KZ
891 struct libscols_line *ln;
892 struct passwd *pw = NULL;
893 struct group *gr = NULL;
894 struct shm_data *shmds, *shmdsp;
cdb4a946 895 char *arg = NULL;
9d20ffda
KZ
896
897 if (ipc_shm_get_info(id, &shmds) < 1) {
898 if (id > -1)
899 warnx(_("id %d not found"), id);
900 return;
901 }
902
5de8fcfd
KZ
903 scols_table_set_name(tb, "sharedmemory");
904
9d20ffda 905 for (shmdsp = shmds; shmdsp->next != NULL || id > -1 ; shmdsp = shmdsp->next) {
e0154173 906 size_t n;
9d20ffda 907 ln = scols_table_new_line(tb, NULL);
780ce22c 908
32cfe498 909 if (!ln)
780ce22c 910 err(EXIT_FAILURE, _("failed to allocate output line"));
9d20ffda 911
e0154173 912 for (n = 0; n < ncolumns; n++) {
9d20ffda
KZ
913 int rc = 0;
914
8941e5cb 915 switch (get_column_id(n)) {
91c92cb5
KZ
916 case COL_KEY:
917 xasprintf(&arg, "0x%08x",shmdsp->shm_perm.key);
cdb4a946 918 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
919 break;
920 case COL_ID:
921 xasprintf(&arg, "%d",shmdsp->shm_perm.id);
cdb4a946 922 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
923 break;
924 case COL_OWNER:
d8461c4e
KZ
925 arg = get_username(&pw, shmdsp->shm_perm.uid);
926 if (!arg)
7458c061 927 xasprintf(&arg, "%u", shmdsp->shm_perm.uid);
cdb4a946 928 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
929 break;
930 case COL_PERMS:
931 if (ctl->numperms)
932 xasprintf(&arg, "%#o", shmdsp->shm_perm.mode & 0777);
933 else {
934 arg = xmalloc(11);
b0b24b11 935 xstrmode(shmdsp->shm_perm.mode & 0777, arg);
91c92cb5 936 }
cdb4a946 937 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
938 break;
939 case COL_CUID:
940 xasprintf(&arg, "%u", shmdsp->shm_perm.cuid);
cdb4a946 941 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
942 break;
943 case COL_CUSER:
d8461c4e
KZ
944 arg = get_username(&pw, shmdsp->shm_perm.cuid);
945 if (arg)
cdb4a946 946 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
947 break;
948 case COL_CGID:
949 xasprintf(&arg, "%u", shmdsp->shm_perm.cuid);
cdb4a946 950 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
951 break;
952 case COL_CGROUP:
d8461c4e
KZ
953 arg = get_groupname(&gr, shmdsp->shm_perm.cgid);
954 if (arg)
cdb4a946 955 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
956 break;
957 case COL_UID:
958 xasprintf(&arg, "%u", shmdsp->shm_perm.uid);
cdb4a946 959 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
960 break;
961 case COL_USER:
d8461c4e
KZ
962 arg = get_username(&pw, shmdsp->shm_perm.uid);
963 if (arg)
cdb4a946 964 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
965 break;
966 case COL_GID:
967 xasprintf(&arg, "%u", shmdsp->shm_perm.gid);
cdb4a946 968 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
969 break;
970 case COL_GROUP:
d8461c4e
KZ
971 arg = get_groupname(&gr, shmdsp->shm_perm.gid);
972 if (arg)
cdb4a946 973 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
974 break;
975 case COL_CTIME:
cdb4a946
KZ
976 if (shmdsp->shm_ctim != 0)
977 rc = scols_line_refer_data(ln, n,
978 make_time(ctl->time_mode,
91c92cb5 979 (time_t)shmdsp->shm_ctim));
91c92cb5
KZ
980 break;
981 case COL_SIZE:
982 if (ctl->bytes)
983 xasprintf(&arg, "%ju", shmdsp->shm_segsz);
984 else
985 arg = size_to_human_string(SIZE_SUFFIX_1LETTER, shmdsp->shm_segsz);
cdb4a946 986 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
987 break;
988 case COL_NATTCH:
989 xasprintf(&arg, "%ju", shmdsp->shm_nattch);
cdb4a946 990 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
991 break;
992 case COL_STATUS: {
993 int comma = 0;
994 size_t offt = 0;
9380fbef
KZ
995
996 free(arg);
91c92cb5
KZ
997 arg = xcalloc(1, sizeof(char) * strlen(_("dest"))
998 + strlen(_("locked"))
999 + strlen(_("hugetlb"))
1000 + strlen(_("noreserve")) + 4);
21ce5a5d 1001#ifdef SHM_DEST
91c92cb5
KZ
1002 if (shmdsp->shm_perm.mode & SHM_DEST) {
1003 offt += sprintf(arg, "%s", _("dest"));
1004 comma++;
9d20ffda 1005 }
21ce5a5d
KZ
1006#endif
1007#ifdef SHM_LOCKED
91c92cb5
KZ
1008 if (shmdsp->shm_perm.mode & SHM_LOCKED) {
1009 if (comma)
1010 arg[offt++] = ',';
1011 offt += sprintf(arg + offt, "%s", _("locked"));
9d20ffda 1012 }
21ce5a5d
KZ
1013#endif
1014#ifdef SHM_HUGETLB
91c92cb5
KZ
1015 if (shmdsp->shm_perm.mode & SHM_HUGETLB) {
1016 if (comma)
1017 arg[offt++] = ',';
1018 offt += sprintf(arg + offt, "%s", _("hugetlb"));
1019 }
21ce5a5d
KZ
1020#endif
1021#ifdef SHM_NORESERVE
91c92cb5
KZ
1022 if (shmdsp->shm_perm.mode & SHM_NORESERVE) {
1023 if (comma)
1024 arg[offt++] = ',';
9380fbef 1025 sprintf(arg + offt, "%s", _("noreserve"));
9d20ffda 1026 }
21ce5a5d 1027#endif
cdb4a946 1028 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
1029 }
1030 break;
1031 case COL_ATTACH:
cdb4a946
KZ
1032 if (shmdsp->shm_atim != 0)
1033 rc = scols_line_refer_data(ln, n,
1034 make_time(ctl->time_mode,
91c92cb5 1035 (time_t)shmdsp->shm_atim));
91c92cb5
KZ
1036 break;
1037 case COL_DETACH:
cdb4a946
KZ
1038 if (shmdsp->shm_dtim != 0)
1039 rc = scols_line_refer_data(ln, n,
1040 make_time(ctl->time_mode,
91c92cb5 1041 (time_t)shmdsp->shm_dtim));
91c92cb5
KZ
1042 break;
1043 case COL_CPID:
1044 xasprintf(&arg, "%u", shmdsp->shm_cprid);
cdb4a946 1045 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
1046 break;
1047 case COL_LPID:
1048 xasprintf(&arg, "%u", shmdsp->shm_lprid);
cdb4a946 1049 rc = scols_line_refer_data(ln, n, arg);
91c92cb5
KZ
1050 break;
1051 case COL_COMMAND:
1052 arg = proc_get_command(shmdsp->shm_cprid);
cdb4a946 1053 rc = scols_line_refer_data(ln, n, arg);
91c92cb5 1054 break;
9d20ffda
KZ
1055 }
1056 if (rc != 0)
1057 err(EXIT_FAILURE, _("failed to set data"));
9d20ffda
KZ
1058 arg = NULL;
1059 }
1060 if (id > -1)
1061 break;
1062 }
1063 ipc_shm_free_info(shmds);
1064}
1065
1066static void do_shm_global(struct libscols_table *tb)
1067{
1068 struct shm_data *shmds, *shmdsp;
32cfe498 1069 uint64_t nsegs = 0, sum_segsz = 0;
9d20ffda 1070 struct ipc_limits lim;
9d20ffda 1071
9d20ffda
KZ
1072 ipc_shm_get_limits(&lim);
1073
32cfe498
KZ
1074 if (ipc_shm_get_info(-1, &shmds) > 0) {
1075 for (shmdsp = shmds; shmdsp->next != NULL; shmdsp = shmdsp->next) {
1076 ++nsegs;
1077 sum_segsz += shmdsp->shm_segsz;
1078 }
90a9b991 1079 ipc_shm_free_info(shmds);
9d20ffda
KZ
1080 }
1081
a4839bc7
KZ
1082 global_set_data(tb, "SHMMNI", _("Shared memory segments"), nsegs, lim.shmmni, 1);
1083 global_set_data(tb, "SHMALL", _("Shared memory pages"), sum_segsz / getpagesize(), lim.shmall, 1);
1084 global_set_data(tb, "SHMMAX", _("Max size of shared memory segment (bytes)"), 0, lim.shmmax, 0);
1085 global_set_data(tb, "SHMMIN", _("Min size of shared memory segment (bytes)"), 0, lim.shmmin, 0);
9d20ffda
KZ
1086}
1087
1088int main(int argc, char *argv[])
1089{
e0154173 1090 int opt, msg = 0, sem = 0, shm = 0, id = -1;
9d20ffda
KZ
1091 int show_time = 0, show_creat = 0, global = 0;
1092 size_t i;
1093 struct lsipc_control *ctl = xcalloc(1, sizeof(struct lsipc_control));
1094 static struct libscols_table *tb;
e0154173 1095 char *outarg = NULL;
9d20ffda
KZ
1096
1097 /* long only options. */
1098 enum {
1099 OPT_NOTRUNC = CHAR_MAX + 1,
1100 OPT_NOHEAD,
2a7150ac 1101 OPT_TIME_FMT
9d20ffda
KZ
1102 };
1103
1104 static const struct option longopts[] = {
87918040
SK
1105 { "bytes", no_argument, NULL, 'b' },
1106 { "creator", no_argument, NULL, 'c' },
1107 { "export", no_argument, NULL, 'e' },
1108 { "global", no_argument, NULL, 'g' },
1109 { "help", no_argument, NULL, 'h' },
1110 { "id", required_argument, NULL, 'i' },
1111 { "json", no_argument, NULL, 'J' },
1112 { "list", no_argument, NULL, 'l' },
1113 { "newline", no_argument, NULL, 'n' },
1114 { "noheadings", no_argument, NULL, OPT_NOHEAD },
1115 { "notruncate", no_argument, NULL, OPT_NOTRUNC },
1116 { "numeric-perms", no_argument, NULL, 'P' },
1117 { "output", required_argument, NULL, 'o' },
87918040
SK
1118 { "queues", no_argument, NULL, 'q' },
1119 { "raw", no_argument, NULL, 'r' },
1120 { "semaphores", no_argument, NULL, 's' },
1121 { "shmems", no_argument, NULL, 'm' },
1122 { "time", no_argument, NULL, 't' },
1123 { "time-format", required_argument, NULL, OPT_TIME_FMT },
1124 { "version", no_argument, NULL, 'V' },
9d20ffda
KZ
1125 {NULL, 0, NULL, 0}
1126 };
1127
1128 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
2916afa3
KZ
1129 { 'J', 'e', 'l', 'n', 'r' },
1130 { 'g', 'i' },
1131 { 'c', 'o', 't' },
9d20ffda
KZ
1132 { 'm', 'q', 's' },
1133 { 0 }
1134 };
1135 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
1136
1137 setlocale(LC_ALL, "");
1138 bindtextdomain(PACKAGE, LOCALEDIR);
1139 textdomain(PACKAGE);
25b7045e 1140 close_stdout_atexit();
9d20ffda 1141
c8b47062 1142 ctl->time_mode = 0;
9d20ffda 1143
624de257
KZ
1144 scols_init_debug(0);
1145
1b71d08c 1146 while ((opt = getopt_long(argc, argv, "bceghi:Jlmno:PqrstV", longopts, NULL)) != -1) {
9d20ffda
KZ
1147
1148 err_exclusive_options(opt, longopts, excl, excl_st);
1149
1150 switch (opt) {
91c92cb5
KZ
1151 case 'b':
1152 ctl->bytes = 1;
1153 break;
1154 case 'i':
1155 id = strtos32_or_err(optarg, _("failed to parse IPC identifier"));
91c92cb5 1156 break;
91c92cb5 1157 case 'e':
d7500c6a 1158 ctl->outmode = OUT_EXPORT;
91c92cb5
KZ
1159 break;
1160 case 'r':
d7500c6a 1161 ctl->outmode = OUT_RAW;
91c92cb5
KZ
1162 break;
1163 case 'o':
1164 outarg = optarg;
1165 break;
1166 case 'g':
1167 global = 1;
2916afa3 1168 break;
91c92cb5
KZ
1169 case 'q':
1170 msg = 1;
1171 add_column(columns, ncolumns++, COL_KEY);
1172 add_column(columns, ncolumns++, COL_ID);
1173 add_column(columns, ncolumns++, COL_PERMS);
1174 add_column(columns, ncolumns++, COL_OWNER);
1175 add_column(columns, ncolumns++, COL_USEDBYTES);
1176 add_column(columns, ncolumns++, COL_MSGS);
1177 add_column(columns, ncolumns++, COL_LSPID);
1178 add_column(columns, ncolumns++, COL_LRPID);
1179 LOWER = COLDESC_IDX_MSG_FIRST;
1180 UPPER = COLDESC_IDX_MSG_LAST;
1181 break;
2916afa3
KZ
1182 case 'l':
1183 ctl->outmode = OUT_LIST;
1184 break;
91c92cb5
KZ
1185 case 'm':
1186 shm = 1;
1187 add_column(columns, ncolumns++, COL_KEY);
1188 add_column(columns, ncolumns++, COL_ID);
1189 add_column(columns, ncolumns++, COL_PERMS);
1190 add_column(columns, ncolumns++, COL_OWNER);
1191 add_column(columns, ncolumns++, COL_SIZE);
1192 add_column(columns, ncolumns++, COL_NATTCH);
1193 add_column(columns, ncolumns++, COL_STATUS);
1194 add_column(columns, ncolumns++, COL_CTIME);
1195 add_column(columns, ncolumns++, COL_CPID);
1196 add_column(columns, ncolumns++, COL_LPID);
1197 add_column(columns, ncolumns++, COL_COMMAND);
1198 LOWER = COLDESC_IDX_SHM_FIRST;
1199 UPPER = COLDESC_IDX_SHM_LAST;
1200 break;
1201 case 'n':
d7500c6a 1202 ctl->outmode = OUT_NEWLINE;
91c92cb5
KZ
1203 break;
1204 case 'P':
1205 ctl->numperms = 1;
1206 break;
1207 case 's':
1208 sem = 1;
1209 add_column(columns, ncolumns++, COL_KEY);
1210 add_column(columns, ncolumns++, COL_ID);
1211 add_column(columns, ncolumns++, COL_PERMS);
1212 add_column(columns, ncolumns++, COL_OWNER);
1213 add_column(columns, ncolumns++, COL_NSEMS);
1214 LOWER = COLDESC_IDX_SEM_FIRST;
1215 UPPER = COLDESC_IDX_SEM_LAST;
1216 break;
1217 case OPT_NOTRUNC:
1218 ctl->notrunc = 1;
1219 break;
1220 case OPT_NOHEAD:
1221 ctl->noheadings = 1;
1222 break;
1223 case OPT_TIME_FMT:
1224 ctl->time_mode = parse_time_mode(optarg);
1225 break;
1226 case 'J':
5de8fcfd 1227 ctl->outmode = OUT_JSON;
91c92cb5
KZ
1228 break;
1229 case 't':
1230 show_time = 1;
1231 break;
1232 case 'c':
1233 show_creat = 1;
1234 break;
2c308875 1235
91c92cb5 1236 case 'h':
9325dbfd 1237 usage();
91c92cb5 1238 case 'V':
2c308875 1239 print_version(EXIT_SUCCESS);
91c92cb5 1240 default:
9325dbfd 1241 errtryhelp(EXIT_FAILURE);
9d20ffda
KZ
1242 }
1243 }
1244
25456d5d 1245 /* default is global */
8f405a5b 1246 if (msg + shm + sem == 0) {
25456d5d 1247 msg = shm = sem = global = 1;
2916afa3 1248 if (show_time || show_creat || id != -1)
62eea9ce 1249 errx(EXIT_FAILURE, _("--global is mutually exclusive with --creator, --id and --time"));
8f405a5b 1250 }
25456d5d
KZ
1251 if (global) {
1252 add_column(columns, ncolumns++, COL_RESOURCE);
1253 add_column(columns, ncolumns++, COL_DESC);
1254 add_column(columns, ncolumns++, COL_LIMIT);
1255 add_column(columns, ncolumns++, COL_USED);
1256 add_column(columns, ncolumns++, COL_USEPERC);
1257 LOWER = COLDESC_IDX_SUM_FIRST;
1258 UPPER = COLDESC_IDX_SUM_LAST;
1259 }
9d20ffda 1260
2916afa3
KZ
1261 /* default to pretty-print if --id specified */
1262 if (id != -1 && !ctl->outmode)
1263 ctl->outmode = OUT_PRETTY;
1264
c8b47062 1265 if (!ctl->time_mode)
d7500c6a 1266 ctl->time_mode = ctl->outmode == OUT_PRETTY ? TIME_FULL : TIME_SHORT;
c8b47062 1267
2916afa3 1268 if (ctl->outmode == OUT_PRETTY && !(optarg || show_creat || show_time)) {
e0154173
KZ
1269 /* all columns for lsipc --<RESOURCE> --id <ID> */
1270 for (ncolumns = 0, i = 0; i < ARRAY_SIZE(coldescs); i++)
1271 columns[ncolumns++] = i;
9d20ffda 1272 } else {
e0154173
KZ
1273 if (show_creat) {
1274 add_column(columns, ncolumns++, COL_CUID);
1275 add_column(columns, ncolumns++, COL_CGID);
1276 add_column(columns, ncolumns++, COL_UID);
1277 add_column(columns, ncolumns++, COL_GID);
1278 }
1279 if (msg && show_time) {
1280 add_column(columns, ncolumns++, COL_SEND);
1281 add_column(columns, ncolumns++, COL_RECV);
1282 add_column(columns, ncolumns++, COL_CTIME);
1283 }
1284 if (shm && show_time) {
1285 /* keep "COMMAND" as last column */
1286 size_t cmd = columns[ncolumns - 1] == COL_COMMAND;
1287
1288 if (cmd)
1289 ncolumns--;
1290 add_column(columns, ncolumns++, COL_ATTACH);
1291 add_column(columns, ncolumns++, COL_DETACH);
1292 if (cmd)
be475287 1293 add_column(columns, ncolumns++, COL_COMMAND);
e0154173
KZ
1294 }
1295 if (sem && show_time) {
1296 add_column(columns, ncolumns++, COL_OTIME);
1297 add_column(columns, ncolumns++, COL_CTIME);
9d20ffda
KZ
1298 }
1299 }
1300
e0154173
KZ
1301 if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
1302 &ncolumns, column_name_to_id) < 0)
1303 return EXIT_FAILURE;
1304
9d20ffda
KZ
1305 tb = setup_table(ctl);
1306 if (!tb)
1307 return EXIT_FAILURE;
5de8fcfd
KZ
1308
1309 if (global)
1310 scols_table_set_name(tb, "ipclimits");
1311
9d20ffda
KZ
1312 if (msg) {
1313 if (global)
1314 do_msg_global(tb);
1315 else
1316 do_msg(id, ctl, tb);
32cfe498
KZ
1317 }
1318 if (shm) {
9d20ffda
KZ
1319 if (global)
1320 do_shm_global(tb);
1321 else
1322 do_shm(id, ctl, tb);
32cfe498
KZ
1323 }
1324 if (sem) {
9d20ffda
KZ
1325 if (global)
1326 do_sem_global(tb);
1327 else
32cfe498 1328 do_sem(id, ctl, tb);
9d20ffda
KZ
1329 }
1330
d7500c6a 1331 print_table(ctl, tb);
9d20ffda
KZ
1332
1333 scols_unref_table(tb);
1334 free(ctl);
1335
1336 return EXIT_SUCCESS;
1337}
1338