]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/lsipc.c
5ba9cd7bfe0a9717638a7dd3cdc8381a5f2c3175
[thirdparty/util-linux.git] / sys-utils / lsipc.c
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>
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"
40 #include "procutils.h"
41 #include "ipcutils.h"
42 #include "timeutils.h"
43
44 /*
45 * time modes
46 * */
47 enum {
48 TIME_INVALID = 0,
49 TIME_SHORT,
50 TIME_FULL,
51 TIME_ISO
52 };
53
54 /*
55 * IDs
56 */
57 enum {
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,
65 COL_CUSER,
66 COL_CGID,
67 COL_CGROUP,
68 COL_UID,
69 COL_USER,
70 COL_GID,
71 COL_GROUP,
72 COL_CTIME,
73 COLDESC_IDX_GEN_LAST = COL_CTIME,
74
75 /* msgq-specific */
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
85 /* shm-specific */
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
97 /* sem-specific */
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,
105 COL_RESOURCE = COLDESC_IDX_SUM_FIRST,
106 COL_DESC,
107 COL_LIMIT,
108 COL_USED,
109 COL_USEPERC,
110 COLDESC_IDX_SUM_LAST = COL_USEPERC
111 };
112
113 /* not all columns apply to all options, so we specify a legal range for each */
114 static size_t LOWER, UPPER;
115
116 /*
117 * output modes
118 */
119 enum {
120 OUT_EXPORT = 1,
121 OUT_NEWLINE,
122 OUT_RAW,
123 OUT_JSON,
124 OUT_PRETTY,
125 OUT_LIST
126 };
127
128 struct lsipc_control {
129 int outmode;
130 unsigned int noheadings : 1, /* don't print header line */
131 notrunc : 1, /* don't truncate columns */
132 bytes : 1, /* SIZE in bytes */
133 numperms : 1, /* numeric permissions */
134 time_mode : 2;
135 };
136
137 struct 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
146 static 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},
151 [COL_OWNER] = { "OWNER", N_("Owner's username or UID"), N_("Owner"), 1, SCOLS_FL_RIGHT},
152 [COL_PERMS] = { "PERMS", N_("Permissions"), N_("Permissions"), 1, SCOLS_FL_RIGHT},
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 },
157 [COL_UID] = { "UID", N_("User ID"), N_("UID"), 1, SCOLS_FL_RIGHT},
158 [COL_USER] = { "USER", N_("User name"), N_("User name"), 1},
159 [COL_GID] = { "GID", N_("Group ID"), N_("GID"), 1, SCOLS_FL_RIGHT},
160 [COL_GROUP] = { "GROUP", N_("Group name"), N_("Group name"), 1},
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},
177 [COL_COMMAND] = { "COMMAND", N_("Creator command line"), N_("Creator command"), 0, SCOLS_FL_TRUNC},
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 },
188 [COL_USED] = { "USED", N_("Currently used"), N_("Used"), 1, SCOLS_FL_RIGHT },
189 [COL_USEPERC] = { "USE%", N_("Currently use percentage"), N_("Use"), 1, SCOLS_FL_RIGHT },
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 */
198 static int columns[ARRAY_SIZE(coldescs) * 2];
199 static size_t ncolumns;
200
201 static 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
213 static 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;
224 else {
225 warnx(_("column %s does not apply to the specified IPC"), name);
226 return -1;
227 }
228 } else
229 return i;
230 }
231 }
232 warnx(_("unknown column: %s"), name);
233 return -1;
234 }
235
236 static 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
244 static const struct lsipc_coldesc *get_column_desc(int num)
245 {
246 return &coldescs[ get_column_id(num) ];
247 }
248
249 static 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
257 static 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
265 static int parse_time_mode(const char *s)
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++) {
279 if (strcmp(timefmts[i].name, s) == 0)
280 return timefmts[i].val;
281 }
282 errx(EXIT_FAILURE, _("unknown time format: %s"), s);
283 }
284
285 static void __attribute__((__noreturn__)) usage(void)
286 {
287 FILE *out = stdout;
288 size_t i;
289
290 fputs(USAGE_HEADER, out);
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
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);
301 fputs(_(" -g, --global info about system-wide usage (may be used with -m, -q and -s)\n"), out);
302 fputs(_(" -i, --id <id> print details on resource identified by <id>\n"), out);
303
304 fputs(USAGE_OPTIONS, out);
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);
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);
313 fputs(_(" -l, --list force list output format (for example with --id)\n"), out);
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);
318
319 fputs(USAGE_SEPARATOR, out);
320 printf(USAGE_HELP_OPTIONS(26));
321
322 fprintf(out, _("\nGeneric columns:\n"));
323 for (i = COLDESC_IDX_GEN_FIRST; i <= COLDESC_IDX_GEN_LAST; i++)
324 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
325
326 fprintf(out, _("\nShared-memory columns (--shmems):\n"));
327 for (i = COLDESC_IDX_SHM_FIRST; i <= COLDESC_IDX_SHM_LAST; i++)
328 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
329
330 fprintf(out, _("\nMessage-queue columns (--queues):\n"));
331 for (i = COLDESC_IDX_MSG_FIRST; i <= COLDESC_IDX_MSG_LAST; i++)
332 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
333
334 fprintf(out, _("\nSemaphore columns (--semaphores):\n"));
335 for (i = COLDESC_IDX_SEM_FIRST; i <= COLDESC_IDX_SEM_LAST; i++)
336 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
337
338 fprintf(out, _("\nSummary columns (--global):\n"));
339 for (i = COLDESC_IDX_SUM_FIRST; i <= COLDESC_IDX_SUM_LAST; i++)
340 fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
341
342 printf(USAGE_MAN_TAIL("lsipc(1)"));
343 exit(EXIT_SUCCESS);
344 }
345
346 static struct libscols_table *new_table(struct lsipc_control *ctl)
347 {
348 struct libscols_table *table = scols_new_table();
349
350 if (!table)
351 err(EXIT_FAILURE, _("failed to allocate output table"));
352
353 if (ctl->noheadings)
354 scols_table_enable_noheadings(table, 1);
355
356 switch(ctl->outmode) {
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;
363 case OUT_RAW:
364 scols_table_enable_raw(table, 1);
365 break;
366 case OUT_PRETTY:
367 scols_table_enable_noheadings(table, 1);
368 break;
369 case OUT_JSON:
370 scols_table_enable_json(table, 1);
371 break;
372 default:
373 break;
374 }
375 return table;
376 }
377
378 static struct libscols_table *setup_table(struct lsipc_control *ctl)
379 {
380 struct libscols_table *table = new_table(ctl);
381 size_t n;
382
383 for (n = 0; n < ncolumns; n++) {
384 const struct lsipc_coldesc *desc = get_column_desc(n);
385 int flags = desc->flag;
386
387 if (ctl->notrunc)
388 flags &= ~SCOLS_FL_TRUNC;
389 if (!scols_table_new_column(table, desc->name, desc->whint, flags))
390 goto fail;
391 }
392 return table;
393 fail:
394 scols_unref_table(table);
395 return NULL;
396 }
397
398 static 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;
404 const char *hstr, *dstr;
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
412 hstr = N_(get_column_desc(n)->pretty_name);
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) {
422 struct libscols_table *subtab = scols_line_get_userdata(ln);
423 if (subtab) {
424 printf(_("Elements:\n\n"));
425 scols_print_table(subtab);
426 }
427 }
428
429 scols_free_iter(itr);
430 return 0;
431
432 }
433
434 static int print_table(struct lsipc_control *ctl, struct libscols_table *tb)
435 {
436 if (ctl->outmode == OUT_PRETTY)
437 print_pretty(tb);
438 else
439 scols_print_table(tb);
440 return 0;
441 }
442 static struct timeval now;
443
444 static char *make_time(int mode, time_t time)
445 {
446 char buf[64] = {0};
447
448 switch(mode) {
449 case TIME_FULL:
450 {
451 struct tm tm;
452 char *s;
453
454 localtime_r(&time, &tm);
455 asctime_r(&tm, buf);
456 if (*(s = buf + strlen(buf) - 1) == '\n')
457 *s = '\0';
458 break;
459 }
460 case TIME_SHORT:
461 strtime_short(&time, &now, 0, buf, sizeof(buf));
462 break;
463 case TIME_ISO:
464 strtime_iso(&time, ISO_TIMESTAMP_T, buf, sizeof(buf));
465 break;
466 default:
467 errx(EXIT_FAILURE, _("unsupported time type"));
468 }
469 return xstrdup(buf);
470 }
471
472 static void global_set_data(struct libscols_table *tb, const char *resource,
473 const char *desc, uintmax_t used, uintmax_t limit, int usage)
474 {
475 struct libscols_line *ln;
476 size_t n;
477
478 ln = scols_table_new_line(tb, NULL);
479 if (!ln)
480 err(EXIT_FAILURE, _("failed to allocate output line"));
481
482 for (n = 0; n < ncolumns; n++) {
483 int rc = 0;
484 char *arg = NULL;
485
486 switch (get_column_id(n)) {
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:
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, "-");
499 break;
500 case COL_USEPERC:
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, "-");
506 break;
507 case COL_LIMIT:
508 xasprintf(&arg, "%ju", limit);
509 rc = scols_line_refer_data(ln, n, arg);
510 break;
511 }
512
513 if (rc != 0)
514 err(EXIT_FAILURE, _("failed to add output data"));
515 }
516 }
517
518 static 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
535 static void do_sem(int id, struct lsipc_control *ctl, struct libscols_table *tb)
536 {
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;
541 char *arg = NULL;
542
543 scols_table_set_name(tb, "semaphores");
544
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) {
551 size_t n;
552
553 ln = scols_table_new_line(tb, NULL);
554 if (!ln)
555 err(EXIT_FAILURE, _("failed to allocate output line"));
556
557 for (n = 0; n < ncolumns; n++) {
558 int rc = 0;
559 switch (get_column_id(n)) {
560 case COL_KEY:
561 xasprintf(&arg, "0x%08x",semdsp->sem_perm.key);
562 rc = scols_line_refer_data(ln, n, arg);
563 break;
564 case COL_ID:
565 xasprintf(&arg, "%d",semdsp->sem_perm.id);
566 rc = scols_line_refer_data(ln, n, arg);
567 break;
568 case COL_OWNER:
569 arg = get_username(&pw, semdsp->sem_perm.uid);
570 if (!arg)
571 xasprintf(&arg, "%u", semdsp->sem_perm.uid);
572 rc = scols_line_refer_data(ln, n, arg);
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);
579 xstrmode(semdsp->sem_perm.mode & 0777, arg);
580 }
581 rc = scols_line_refer_data(ln, n, arg);
582 break;
583 case COL_CUID:
584 xasprintf(&arg, "%u", semdsp->sem_perm.cuid);
585 rc = scols_line_refer_data(ln, n, arg);
586 break;
587 case COL_CUSER:
588 arg = get_username(&cpw, semdsp->sem_perm.cuid);
589 if (arg)
590 rc = scols_line_refer_data(ln, n, arg);
591 break;
592 case COL_CGID:
593 xasprintf(&arg, "%u", semdsp->sem_perm.cgid);
594 rc = scols_line_refer_data(ln, n, arg);
595 break;
596 case COL_CGROUP:
597 arg = get_groupname(&cgr, semdsp->sem_perm.cgid);
598 if (arg)
599 rc = scols_line_refer_data(ln, n, arg);
600 break;
601 case COL_UID:
602 xasprintf(&arg, "%u", semdsp->sem_perm.uid);
603 rc = scols_line_refer_data(ln, n, arg);
604 break;
605 case COL_USER:
606 arg = get_username(&pw, semdsp->sem_perm.uid);
607 if (arg)
608 rc = scols_line_refer_data(ln, n, arg);
609 break;
610 case COL_GID:
611 xasprintf(&arg, "%u", semdsp->sem_perm.gid);
612 rc = scols_line_refer_data(ln, n, arg);
613 break;
614 case COL_GROUP:
615 arg = get_groupname(&gr, semdsp->sem_perm.gid);
616 if (arg)
617 rc = scols_line_refer_data(ln, n, arg);
618 break;
619 case COL_CTIME:
620 if (semdsp->sem_ctime != 0) {
621 rc = scols_line_refer_data(ln, n,
622 make_time(ctl->time_mode,
623 (time_t)semdsp->sem_ctime));
624 }
625 break;
626 case COL_NSEMS:
627 xasprintf(&arg, "%ju", semdsp->sem_nsems);
628 rc = scols_line_refer_data(ln, n, arg);
629 break;
630 case COL_OTIME:
631 if (semdsp->sem_otime != 0) {
632 rc = scols_line_refer_data(ln, n,
633 make_time(ctl->time_mode,
634 (time_t)semdsp->sem_otime));
635 }
636 break;
637 }
638 if (rc != 0)
639 err(EXIT_FAILURE, _("failed to add output data"));
640 arg = NULL;
641 }
642
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;
647 int rc = 0;
648
649 scols_table_enable_noheadings(sub, 0);
650 setup_sem_elements_columns(sub);
651
652 for (i = 0; i < semds->sem_nsems; i++) {
653 struct sem_elem *e = &semds->elements[i];
654 struct libscols_line *sln = scols_table_new_line(sub, NULL);
655
656 if (!sln)
657 err(EXIT_FAILURE, _("failed to allocate output line"));
658
659 /* SEMNUM */
660 xasprintf(&arg, "%zu", i);
661 rc = scols_line_refer_data(sln, 0, arg);
662 if (rc)
663 break;
664
665 /* VALUE */
666 xasprintf(&arg, "%d", e->semval);
667 rc = scols_line_refer_data(sln, 1, arg);
668 if (rc)
669 break;
670
671 /* NCOUNT */
672 xasprintf(&arg, "%d", e->ncount);
673 rc = scols_line_refer_data(sln, 2, arg);
674 if (rc)
675 break;
676
677 /* ZCOUNT */
678 xasprintf(&arg, "%d", e->zcount);
679 rc = scols_line_refer_data(sln, 3, arg);
680 if (rc)
681 break;
682
683 /* PID */
684 xasprintf(&arg, "%d", e->pid);
685 rc = scols_line_refer_data(sln, 4, arg);
686 if (rc)
687 break;
688
689 /* COMMAND */
690 arg = proc_get_command(e->pid);
691 rc = scols_line_refer_data(sln, 5, arg);
692 if (rc)
693 break;
694 }
695
696 if (rc != 0)
697 err(EXIT_FAILURE, _("failed to set data"));
698
699 scols_line_set_userdata(ln, (void *)sub);
700 break;
701 }
702 }
703 ipc_sem_free_info(semds);
704 }
705
706 static void do_sem_global(struct libscols_table *tb)
707 {
708 struct sem_data *semds, *semdsp;
709 struct ipc_limits lim;
710 int nsems = 0, nsets = 0;
711
712 ipc_sem_get_limits(&lim);
713
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);
720 }
721
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);
727 }
728
729 static void do_msg(int id, struct lsipc_control *ctl, struct libscols_table *tb)
730 {
731 struct libscols_line *ln;
732 struct passwd *pw = NULL;
733 struct group *gr = NULL;
734 struct msg_data *msgds, *msgdsp;
735 char *arg = NULL;
736
737 if (ipc_msg_get_info(id, &msgds) < 1) {
738 if (id > -1)
739 warnx(_("id %d not found"), id);
740 return;
741 }
742 scols_table_set_name(tb, "messages");
743
744 for (msgdsp = msgds; msgdsp->next != NULL || id > -1 ; msgdsp = msgdsp->next) {
745 size_t n;
746 ln = scols_table_new_line(tb, NULL);
747
748 if (!ln)
749 err(EXIT_FAILURE, _("failed to allocate output line"));
750
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
759 for (n = 0; n < ncolumns; n++) {
760 int rc = 0;
761
762 switch (get_column_id(n)) {
763 case COL_KEY:
764 xasprintf(&arg, "0x%08x",msgdsp->msg_perm.key);
765 rc = scols_line_refer_data(ln, n, arg);
766 break;
767 case COL_ID:
768 xasprintf(&arg, "%d",msgdsp->msg_perm.id);
769 rc = scols_line_refer_data(ln, n, arg);
770 break;
771 case COL_OWNER:
772 arg = get_username(&pw, msgdsp->msg_perm.uid);
773 if (!arg)
774 xasprintf(&arg, "%u", msgdsp->msg_perm.uid);
775 rc = scols_line_refer_data(ln, n, arg);
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);
782 xstrmode(msgdsp->msg_perm.mode & 0777, arg);
783 rc = scols_line_refer_data(ln, n, arg);
784 }
785 break;
786 case COL_CUID:
787 xasprintf(&arg, "%u", msgdsp->msg_perm.cuid);
788 rc = scols_line_refer_data(ln, n, arg);
789 break;
790 case COL_CUSER:
791 arg = get_username(&pw, msgdsp->msg_perm.cuid);
792 if (arg)
793 rc = scols_line_refer_data(ln, n, arg);
794 break;
795 case COL_CGID:
796 xasprintf(&arg, "%u", msgdsp->msg_perm.cuid);
797 rc = scols_line_refer_data(ln, n, arg);
798 break;
799 case COL_CGROUP:
800 arg = get_groupname(&gr, msgdsp->msg_perm.cgid);
801 if (arg)
802 rc = scols_line_refer_data(ln, n, arg);
803 break;
804 case COL_UID:
805 xasprintf(&arg, "%u", msgdsp->msg_perm.uid);
806 rc = scols_line_refer_data(ln, n, arg);
807 break;
808 case COL_USER:
809 arg = get_username(&pw, msgdsp->msg_perm.uid);
810 if (arg)
811 rc = scols_line_refer_data(ln, n, arg);
812 break;
813 case COL_GID:
814 xasprintf(&arg, "%u", msgdsp->msg_perm.gid);
815 rc = scols_line_refer_data(ln, n, arg);
816 break;
817 case COL_GROUP:
818 arg = get_groupname(&gr,msgdsp->msg_perm.gid);
819 if (arg)
820 rc = scols_line_refer_data(ln, n, arg);
821 break;
822 case COL_CTIME:
823 if (msgdsp->q_ctime != 0)
824 rc = scols_line_refer_data(ln, n,
825 make_time(ctl->time_mode,
826 (time_t)msgdsp->q_ctime));
827 break;
828 case COL_USEDBYTES:
829 xasprintf(&arg, "%ju", msgdsp->q_cbytes);
830 rc = scols_line_refer_data(ln, n, arg);
831 break;
832 case COL_MSGS:
833 xasprintf(&arg, "%ju", msgdsp->q_qnum);
834 rc = scols_line_refer_data(ln, n, arg);
835 break;
836 case COL_SEND:
837 if (msgdsp->q_stime != 0)
838 rc = scols_line_refer_data(ln, n,
839 make_time(ctl->time_mode,
840 (time_t)msgdsp->q_stime));
841 break;
842 case COL_RECV:
843 if (msgdsp->q_rtime != 0)
844 rc = scols_line_refer_data(ln, n,
845 make_time(ctl->time_mode,
846 (time_t)msgdsp->q_rtime));
847 break;
848 case COL_LSPID:
849 xasprintf(&arg, "%u", msgdsp->q_lspid);
850 rc = scols_line_refer_data(ln, n, arg);
851 break;
852 case COL_LRPID:
853 xasprintf(&arg, "%u", msgdsp->q_lrpid);
854 rc = scols_line_refer_data(ln, n, arg);
855 break;
856 }
857 if (rc != 0)
858 err(EXIT_FAILURE, _("failed to set data"));
859 arg = NULL;
860 }
861 if (id > -1)
862 break;
863 }
864 ipc_msg_free_info(msgds);
865 }
866
867
868 static void do_msg_global(struct libscols_table *tb)
869 {
870 struct msg_data *msgds, *msgdsp;
871 struct ipc_limits lim;
872 int msgqs = 0;
873
874 ipc_msg_get_limits(&lim);
875
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);
881 }
882
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);
886 }
887
888
889 static void do_shm(int id, struct lsipc_control *ctl, struct libscols_table *tb)
890 {
891 struct libscols_line *ln;
892 struct passwd *pw = NULL;
893 struct group *gr = NULL;
894 struct shm_data *shmds, *shmdsp;
895 char *arg = NULL;
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
903 scols_table_set_name(tb, "sharedmemory");
904
905 for (shmdsp = shmds; shmdsp->next != NULL || id > -1 ; shmdsp = shmdsp->next) {
906 size_t n;
907 ln = scols_table_new_line(tb, NULL);
908
909 if (!ln)
910 err(EXIT_FAILURE, _("failed to allocate output line"));
911
912 for (n = 0; n < ncolumns; n++) {
913 int rc = 0;
914
915 switch (get_column_id(n)) {
916 case COL_KEY:
917 xasprintf(&arg, "0x%08x",shmdsp->shm_perm.key);
918 rc = scols_line_refer_data(ln, n, arg);
919 break;
920 case COL_ID:
921 xasprintf(&arg, "%d",shmdsp->shm_perm.id);
922 rc = scols_line_refer_data(ln, n, arg);
923 break;
924 case COL_OWNER:
925 arg = get_username(&pw, shmdsp->shm_perm.uid);
926 if (!arg)
927 xasprintf(&arg, "%u", shmdsp->shm_perm.uid);
928 rc = scols_line_refer_data(ln, n, arg);
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);
935 xstrmode(shmdsp->shm_perm.mode & 0777, arg);
936 }
937 rc = scols_line_refer_data(ln, n, arg);
938 break;
939 case COL_CUID:
940 xasprintf(&arg, "%u", shmdsp->shm_perm.cuid);
941 rc = scols_line_refer_data(ln, n, arg);
942 break;
943 case COL_CUSER:
944 arg = get_username(&pw, shmdsp->shm_perm.cuid);
945 if (arg)
946 rc = scols_line_refer_data(ln, n, arg);
947 break;
948 case COL_CGID:
949 xasprintf(&arg, "%u", shmdsp->shm_perm.cuid);
950 rc = scols_line_refer_data(ln, n, arg);
951 break;
952 case COL_CGROUP:
953 arg = get_groupname(&gr, shmdsp->shm_perm.cgid);
954 if (arg)
955 rc = scols_line_refer_data(ln, n, arg);
956 break;
957 case COL_UID:
958 xasprintf(&arg, "%u", shmdsp->shm_perm.uid);
959 rc = scols_line_refer_data(ln, n, arg);
960 break;
961 case COL_USER:
962 arg = get_username(&pw, shmdsp->shm_perm.uid);
963 if (arg)
964 rc = scols_line_refer_data(ln, n, arg);
965 break;
966 case COL_GID:
967 xasprintf(&arg, "%u", shmdsp->shm_perm.gid);
968 rc = scols_line_refer_data(ln, n, arg);
969 break;
970 case COL_GROUP:
971 arg = get_groupname(&gr, shmdsp->shm_perm.gid);
972 if (arg)
973 rc = scols_line_refer_data(ln, n, arg);
974 break;
975 case COL_CTIME:
976 if (shmdsp->shm_ctim != 0)
977 rc = scols_line_refer_data(ln, n,
978 make_time(ctl->time_mode,
979 (time_t)shmdsp->shm_ctim));
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);
986 rc = scols_line_refer_data(ln, n, arg);
987 break;
988 case COL_NATTCH:
989 xasprintf(&arg, "%ju", shmdsp->shm_nattch);
990 rc = scols_line_refer_data(ln, n, arg);
991 break;
992 case COL_STATUS: {
993 int comma = 0;
994 size_t offt = 0;
995
996 free(arg);
997 arg = xcalloc(1, sizeof(char) * strlen(_("dest"))
998 + strlen(_("locked"))
999 + strlen(_("hugetlb"))
1000 + strlen(_("noreserve")) + 4);
1001 #ifdef SHM_DEST
1002 if (shmdsp->shm_perm.mode & SHM_DEST) {
1003 offt += sprintf(arg, "%s", _("dest"));
1004 comma++;
1005 }
1006 #endif
1007 #ifdef SHM_LOCKED
1008 if (shmdsp->shm_perm.mode & SHM_LOCKED) {
1009 if (comma)
1010 arg[offt++] = ',';
1011 offt += sprintf(arg + offt, "%s", _("locked"));
1012 }
1013 #endif
1014 #ifdef SHM_HUGETLB
1015 if (shmdsp->shm_perm.mode & SHM_HUGETLB) {
1016 if (comma)
1017 arg[offt++] = ',';
1018 offt += sprintf(arg + offt, "%s", _("hugetlb"));
1019 }
1020 #endif
1021 #ifdef SHM_NORESERVE
1022 if (shmdsp->shm_perm.mode & SHM_NORESERVE) {
1023 if (comma)
1024 arg[offt++] = ',';
1025 sprintf(arg + offt, "%s", _("noreserve"));
1026 }
1027 #endif
1028 rc = scols_line_refer_data(ln, n, arg);
1029 }
1030 break;
1031 case COL_ATTACH:
1032 if (shmdsp->shm_atim != 0)
1033 rc = scols_line_refer_data(ln, n,
1034 make_time(ctl->time_mode,
1035 (time_t)shmdsp->shm_atim));
1036 break;
1037 case COL_DETACH:
1038 if (shmdsp->shm_dtim != 0)
1039 rc = scols_line_refer_data(ln, n,
1040 make_time(ctl->time_mode,
1041 (time_t)shmdsp->shm_dtim));
1042 break;
1043 case COL_CPID:
1044 xasprintf(&arg, "%u", shmdsp->shm_cprid);
1045 rc = scols_line_refer_data(ln, n, arg);
1046 break;
1047 case COL_LPID:
1048 xasprintf(&arg, "%u", shmdsp->shm_lprid);
1049 rc = scols_line_refer_data(ln, n, arg);
1050 break;
1051 case COL_COMMAND:
1052 arg = proc_get_command(shmdsp->shm_cprid);
1053 rc = scols_line_refer_data(ln, n, arg);
1054 break;
1055 }
1056 if (rc != 0)
1057 err(EXIT_FAILURE, _("failed to set data"));
1058 arg = NULL;
1059 }
1060 if (id > -1)
1061 break;
1062 }
1063 ipc_shm_free_info(shmds);
1064 }
1065
1066 static void do_shm_global(struct libscols_table *tb)
1067 {
1068 struct shm_data *shmds, *shmdsp;
1069 uint64_t nsegs = 0, sum_segsz = 0;
1070 struct ipc_limits lim;
1071
1072 ipc_shm_get_limits(&lim);
1073
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 }
1079 ipc_shm_free_info(shmds);
1080 }
1081
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);
1086 }
1087
1088 int main(int argc, char *argv[])
1089 {
1090 int opt, msg = 0, sem = 0, shm = 0, id = -1;
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;
1095 char *outarg = NULL;
1096
1097 /* long only options. */
1098 enum {
1099 OPT_NOTRUNC = CHAR_MAX + 1,
1100 OPT_NOHEAD,
1101 OPT_TIME_FMT
1102 };
1103
1104 static const struct option longopts[] = {
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' },
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' },
1125 {NULL, 0, NULL, 0}
1126 };
1127
1128 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
1129 { 'J', 'e', 'l', 'n', 'r' },
1130 { 'g', 'i' },
1131 { 'c', 'o', 't' },
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);
1140 atexit(close_stdout);
1141
1142 ctl->time_mode = 0;
1143
1144 scols_init_debug(0);
1145
1146 while ((opt = getopt_long(argc, argv, "bceghi:Jlmno:PqrstV", longopts, NULL)) != -1) {
1147
1148 err_exclusive_options(opt, longopts, excl, excl_st);
1149
1150 switch (opt) {
1151 case 'b':
1152 ctl->bytes = 1;
1153 break;
1154 case 'i':
1155 id = strtos32_or_err(optarg, _("failed to parse IPC identifier"));
1156 break;
1157 case 'e':
1158 ctl->outmode = OUT_EXPORT;
1159 break;
1160 case 'r':
1161 ctl->outmode = OUT_RAW;
1162 break;
1163 case 'o':
1164 outarg = optarg;
1165 break;
1166 case 'g':
1167 global = 1;
1168 break;
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;
1182 case 'l':
1183 ctl->outmode = OUT_LIST;
1184 break;
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':
1202 ctl->outmode = OUT_NEWLINE;
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':
1227 ctl->outmode = OUT_JSON;
1228 break;
1229 case 't':
1230 show_time = 1;
1231 break;
1232 case 'c':
1233 show_creat = 1;
1234 break;
1235
1236 case 'h':
1237 usage();
1238 case 'V':
1239 print_version(EXIT_SUCCESS);
1240 default:
1241 errtryhelp(EXIT_FAILURE);
1242 }
1243 }
1244
1245 /* default is global */
1246 if (msg + shm + sem == 0) {
1247 msg = shm = sem = global = 1;
1248 if (show_time || show_creat || id != -1)
1249 errx(EXIT_FAILURE, _("--global is mutually exclusive with --creator, --id and --time"));
1250 }
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 }
1260
1261 /* default to pretty-print if --id specified */
1262 if (id != -1 && !ctl->outmode)
1263 ctl->outmode = OUT_PRETTY;
1264
1265 if (!ctl->time_mode)
1266 ctl->time_mode = ctl->outmode == OUT_PRETTY ? TIME_FULL : TIME_SHORT;
1267
1268 if (ctl->outmode == OUT_PRETTY && !(optarg || show_creat || show_time)) {
1269 /* all columns for lsipc --<RESOURCE> --id <ID> */
1270 for (ncolumns = 0, i = 0; i < ARRAY_SIZE(coldescs); i++)
1271 columns[ncolumns++] = i;
1272 } else {
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)
1293 add_column(columns, ncolumns++, COL_COMMAND);
1294 }
1295 if (sem && show_time) {
1296 add_column(columns, ncolumns++, COL_OTIME);
1297 add_column(columns, ncolumns++, COL_CTIME);
1298 }
1299 }
1300
1301 if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
1302 &ncolumns, column_name_to_id) < 0)
1303 return EXIT_FAILURE;
1304
1305 tb = setup_table(ctl);
1306 if (!tb)
1307 return EXIT_FAILURE;
1308
1309 if (global)
1310 scols_table_set_name(tb, "ipclimits");
1311
1312 if (msg) {
1313 if (global)
1314 do_msg_global(tb);
1315 else
1316 do_msg(id, ctl, tb);
1317 }
1318 if (shm) {
1319 if (global)
1320 do_shm_global(tb);
1321 else
1322 do_shm(id, ctl, tb);
1323 }
1324 if (sem) {
1325 if (global)
1326 do_sem_global(tb);
1327 else
1328 do_sem(id, ctl, tb);
1329 }
1330
1331 print_table(ctl, tb);
1332
1333 scols_unref_table(tb);
1334 free(ctl);
1335
1336 return EXIT_SUCCESS;
1337 }
1338