]>
Commit | Line | Data |
---|---|---|
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 | * */ | |
47 | enum { | |
48 | TIME_INVALID = 0, | |
49 | TIME_SHORT, | |
50 | TIME_FULL, | |
c8b47062 | 51 | TIME_ISO |
9d20ffda KZ |
52 | }; |
53 | ||
54 | /* | |
55 | * IDs | |
56 | */ | |
57 | enum { | |
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 */ |
114 | static size_t LOWER, UPPER; | |
115 | ||
116 | /* | |
117 | * output modes | |
118 | */ | |
119 | enum { | |
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 | ||
128 | struct 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 | ||
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}, | |
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 */ | |
198 | static int columns[ARRAY_SIZE(coldescs) * 2]; | |
e0154173 | 199 | static size_t ncolumns; |
9d20ffda KZ |
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 | ||
8941e5cb KZ |
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 | ||
71b63dc1 KZ |
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 | ||
eb2306e6 | 265 | static 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 | 285 | static 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 | 346 | static 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 | ||
378 | static 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; | |
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; | |
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 | 434 | static 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 | } | |
442 | static struct timeval now; | |
443 | ||
9d20ffda KZ |
444 | static 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 | 472 | static 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 |
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 | ||
9d20ffda KZ |
535 | static 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 | ||
706 | static 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 | ||
729 | static 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 |
868 | static 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 |
889 | static 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 | ||
1066 | static 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 | ||
1088 | int 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 |