]>
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 | ||
71b63dc1 KZ |
236 | static char *get_username(struct passwd **pw, uid_t id) |
237 | { | |
238 | if (!*pw || (*pw)->pw_uid != id) | |
239 | *pw = getpwuid(id); | |
240 | ||
241 | return *pw ? xstrdup((*pw)->pw_name) : NULL; | |
242 | } | |
243 | ||
244 | static char *get_groupname(struct group **gr, gid_t id) | |
245 | { | |
246 | if (!*gr || (*gr)->gr_gid != id) | |
247 | *gr = getgrgid(id); | |
248 | ||
249 | return *gr ? xstrdup((*gr)->gr_name) : NULL; | |
250 | } | |
251 | ||
eb2306e6 | 252 | static int parse_time_mode(const char *s) |
9d20ffda KZ |
253 | { |
254 | struct lsipc_timefmt { | |
255 | const char *name; | |
256 | const int val; | |
257 | }; | |
258 | static const struct lsipc_timefmt timefmts[] = { | |
259 | {"iso", TIME_ISO}, | |
260 | {"full", TIME_FULL}, | |
261 | {"short", TIME_SHORT}, | |
262 | }; | |
263 | size_t i; | |
264 | ||
265 | for (i = 0; i < ARRAY_SIZE(timefmts); i++) { | |
eb2306e6 | 266 | if (strcmp(timefmts[i].name, s) == 0) |
9d20ffda KZ |
267 | return timefmts[i].val; |
268 | } | |
eb2306e6 | 269 | errx(EXIT_FAILURE, _("unknown time format: %s"), s); |
9d20ffda KZ |
270 | } |
271 | ||
9325dbfd | 272 | static void __attribute__((__noreturn__)) usage(void) |
9d20ffda | 273 | { |
9325dbfd | 274 | FILE *out = stdout; |
9d20ffda KZ |
275 | size_t i; |
276 | ||
277 | fputs(USAGE_HEADER, out); | |
9d20ffda KZ |
278 | fprintf(out, _(" %s [options]\n"), program_invocation_short_name); |
279 | ||
280 | fputs(USAGE_SEPARATOR, out); | |
281 | fputs(_("Show information on IPC facilities.\n"), out); | |
282 | ||
9d20ffda KZ |
283 | fputs(USAGE_SEPARATOR, out); |
284 | fputs(_("Resource options:\n"), out); | |
285 | fputs(_(" -m, --shmems shared memory segments\n"), out); | |
286 | fputs(_(" -q, --queues message queues\n"), out); | |
287 | fputs(_(" -s, --semaphores semaphores\n"), out); | |
32cfe498 | 288 | fputs(_(" -g, --global info about system-wide usage (may be used with -m, -q and -s)\n"), out); |
9d20ffda KZ |
289 | fputs(_(" -i, --id <id> print details on resource identified by <id>\n"), out); |
290 | ||
470a7332 | 291 | fputs(USAGE_OPTIONS, out); |
9d20ffda KZ |
292 | fputs(_(" --noheadings don't print headings\n"), out); |
293 | fputs(_(" --notruncate don't truncate output\n"), out); | |
294 | fputs(_(" --time-format=<type> display dates in short, full or iso format\n"), out); | |
295 | fputs(_(" -b, --bytes print SIZE in bytes rather than in human readable format\n"), out); | |
296 | fputs(_(" -c, --creator show creator and owner\n"), out); | |
297 | fputs(_(" -e, --export display in an export-able output format\n"), out); | |
9d20ffda KZ |
298 | fputs(_(" -J, --json use the JSON output format\n"), out); |
299 | fputs(_(" -n, --newline display each piece of information on a new line\n"), out); | |
2916afa3 | 300 | fputs(_(" -l, --list force list output format (for example with --id)\n"), out); |
9d20ffda KZ |
301 | fputs(_(" -o, --output[=<list>] define the columns to output\n"), out); |
302 | fputs(_(" -P, --numeric-perms print numeric permissions (PERMS column)\n"), out); | |
303 | fputs(_(" -r, --raw display in raw mode\n"), out); | |
304 | fputs(_(" -t, --time show attach, detach and change times\n"), out); | |
2a7150ac KZ |
305 | |
306 | fputs(USAGE_SEPARATOR, out); | |
f45f3ec3 | 307 | printf(USAGE_HELP_OPTIONS(26)); |
9d20ffda | 308 | |
470a7332 | 309 | fprintf(out, _("\nGeneric columns:\n")); |
32cfe498 | 310 | for (i = COLDESC_IDX_GEN_FIRST; i <= COLDESC_IDX_GEN_LAST; i++) |
470a7332 | 311 | fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); |
9d20ffda | 312 | |
62eea9ce | 313 | fprintf(out, _("\nShared-memory columns (--shmems):\n")); |
32cfe498 | 314 | for (i = COLDESC_IDX_SHM_FIRST; i <= COLDESC_IDX_SHM_LAST; i++) |
470a7332 | 315 | fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); |
9d20ffda | 316 | |
62eea9ce | 317 | fprintf(out, _("\nMessage-queue columns (--queues):\n")); |
32cfe498 | 318 | for (i = COLDESC_IDX_MSG_FIRST; i <= COLDESC_IDX_MSG_LAST; i++) |
470a7332 | 319 | fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); |
9d20ffda | 320 | |
62eea9ce | 321 | fprintf(out, _("\nSemaphore columns (--semaphores):\n")); |
32cfe498 | 322 | for (i = COLDESC_IDX_SEM_FIRST; i <= COLDESC_IDX_SEM_LAST; i++) |
470a7332 KZ |
323 | fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); |
324 | ||
325 | fprintf(out, _("\nSummary columns (--global):\n")); | |
32cfe498 | 326 | for (i = COLDESC_IDX_SUM_FIRST; i <= COLDESC_IDX_SUM_LAST; i++) |
470a7332 KZ |
327 | fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); |
328 | ||
f45f3ec3 | 329 | printf(USAGE_MAN_TAIL("lsipc(1)")); |
9325dbfd | 330 | exit(EXIT_SUCCESS); |
9d20ffda KZ |
331 | } |
332 | ||
624de257 | 333 | static struct libscols_table *new_table(struct lsipc_control *ctl) |
9d20ffda KZ |
334 | { |
335 | struct libscols_table *table = scols_new_table(); | |
9d20ffda KZ |
336 | |
337 | if (!table) | |
780ce22c KZ |
338 | err(EXIT_FAILURE, _("failed to allocate output table")); |
339 | ||
9d20ffda KZ |
340 | if (ctl->noheadings) |
341 | scols_table_enable_noheadings(table, 1); | |
9d20ffda | 342 | |
d7500c6a | 343 | switch(ctl->outmode) { |
9d20ffda KZ |
344 | case OUT_NEWLINE: |
345 | scols_table_set_column_separator(table, "\n"); | |
346 | /* fallthrough */ | |
347 | case OUT_EXPORT: | |
348 | scols_table_enable_export(table, 1); | |
349 | break; | |
9d20ffda KZ |
350 | case OUT_RAW: |
351 | scols_table_enable_raw(table, 1); | |
352 | break; | |
353 | case OUT_PRETTY: | |
354 | scols_table_enable_noheadings(table, 1); | |
5de8fcfd KZ |
355 | break; |
356 | case OUT_JSON: | |
357 | scols_table_enable_json(table, 1); | |
358 | break; | |
9d20ffda KZ |
359 | default: |
360 | break; | |
361 | } | |
624de257 KZ |
362 | return table; |
363 | } | |
364 | ||
365 | static struct libscols_table *setup_table(struct lsipc_control *ctl) | |
366 | { | |
367 | struct libscols_table *table = new_table(ctl); | |
368 | size_t n; | |
9d20ffda | 369 | |
e0154173 | 370 | for (n = 0; n < ncolumns; n++) { |
9d20ffda KZ |
371 | int flags = coldescs[columns[n]].flag; |
372 | ||
373 | if (ctl->notrunc) | |
374 | flags &= ~SCOLS_FL_TRUNC; | |
375 | ||
376 | if (!scols_table_new_column(table, | |
377 | coldescs[columns[n]].name, | |
378 | coldescs[columns[n]].whint, | |
379 | flags)) | |
380 | goto fail; | |
9d20ffda KZ |
381 | } |
382 | return table; | |
383 | fail: | |
384 | scols_unref_table(table); | |
385 | return NULL; | |
386 | } | |
387 | ||
388 | static int print_pretty(struct libscols_table *table) | |
389 | { | |
390 | struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD); | |
391 | struct libscols_column *col; | |
392 | struct libscols_cell *data; | |
393 | struct libscols_line *ln; | |
624de257 | 394 | const char *hstr, *dstr; |
9d20ffda KZ |
395 | int n = 0; |
396 | ||
397 | ln = scols_table_get_line(table, 0); | |
398 | while (!scols_table_next_column(table, itr, &col)) { | |
399 | ||
400 | data = scols_line_get_cell(ln, n); | |
401 | ||
402 | hstr = N_(coldescs[columns[n]].pretty_name); | |
403 | dstr = scols_cell_get_data(data); | |
404 | ||
405 | if (dstr) | |
406 | printf("%s:%*c%-36s\n", hstr, 35 - (int)strlen(hstr), ' ', dstr); | |
407 | ++n; | |
408 | } | |
409 | ||
410 | /* this is used to pretty-print detailed info about a semaphore array */ | |
411 | if (ln) { | |
624de257 KZ |
412 | struct libscols_table *subtab = scols_line_get_userdata(ln); |
413 | if (subtab) { | |
414 | printf(_("Elements:\n\n")); | |
415 | scols_print_table(subtab); | |
9d20ffda KZ |
416 | } |
417 | } | |
418 | ||
419 | scols_free_iter(itr); | |
420 | return 0; | |
421 | ||
422 | } | |
423 | ||
d7500c6a | 424 | static int print_table(struct lsipc_control *ctl, struct libscols_table *tb) |
9d20ffda | 425 | { |
d7500c6a | 426 | if (ctl->outmode == OUT_PRETTY) |
9d20ffda KZ |
427 | print_pretty(tb); |
428 | else | |
429 | scols_print_table(tb); | |
430 | return 0; | |
431 | } | |
432 | static struct timeval now; | |
433 | ||
9d20ffda KZ |
434 | static char *make_time(int mode, time_t time) |
435 | { | |
9d20ffda KZ |
436 | char buf[64] = {0}; |
437 | ||
9d20ffda KZ |
438 | switch(mode) { |
439 | case TIME_FULL: | |
bcf72069 KZ |
440 | { |
441 | struct tm tm; | |
442 | char *s; | |
443 | ||
444 | localtime_r(&time, &tm); | |
9d20ffda KZ |
445 | asctime_r(&tm, buf); |
446 | if (*(s = buf + strlen(buf) - 1) == '\n') | |
447 | *s = '\0'; | |
448 | break; | |
bcf72069 | 449 | } |
9d20ffda | 450 | case TIME_SHORT: |
bcf72069 | 451 | strtime_short(&time, &now, 0, buf, sizeof(buf)); |
9d20ffda KZ |
452 | break; |
453 | case TIME_ISO: | |
4111bb3a | 454 | strtime_iso(&time, ISO_TIMESTAMP_T, buf, sizeof(buf)); |
9d20ffda KZ |
455 | break; |
456 | default: | |
457 | errx(EXIT_FAILURE, _("unsupported time type")); | |
458 | } | |
459 | return xstrdup(buf); | |
460 | } | |
461 | ||
32cfe498 | 462 | static void global_set_data(struct libscols_table *tb, const char *resource, |
a4839bc7 | 463 | const char *desc, uintmax_t used, uintmax_t limit, int usage) |
32cfe498 KZ |
464 | { |
465 | struct libscols_line *ln; | |
e0154173 | 466 | size_t n; |
32cfe498 KZ |
467 | |
468 | ln = scols_table_new_line(tb, NULL); | |
469 | if (!ln) | |
780ce22c | 470 | err(EXIT_FAILURE, _("failed to allocate output line")); |
32cfe498 KZ |
471 | |
472 | for (n = 0; n < ncolumns; n++) { | |
473 | int rc = 0; | |
474 | char *arg = NULL; | |
475 | ||
476 | switch (columns[n]) { | |
477 | case COL_RESOURCE: | |
478 | rc = scols_line_set_data(ln, n, resource); | |
479 | break; | |
480 | case COL_DESC: | |
481 | rc = scols_line_set_data(ln, n, desc); | |
482 | break; | |
483 | case COL_USED: | |
a4839bc7 KZ |
484 | if (usage) { |
485 | xasprintf(&arg, "%ju", used); | |
486 | rc = scols_line_refer_data(ln, n, arg); | |
487 | } else | |
488 | rc = scols_line_set_data(ln, n, "-"); | |
32cfe498 | 489 | break; |
1a311071 | 490 | case COL_USEPERC: |
a4839bc7 KZ |
491 | if (usage) { |
492 | xasprintf(&arg, "%2.2f%%", (double) used / limit * 100); | |
493 | rc = scols_line_refer_data(ln, n, arg); | |
494 | } else | |
495 | rc = scols_line_set_data(ln, n, "-"); | |
1a311071 | 496 | break; |
32cfe498 KZ |
497 | case COL_LIMIT: |
498 | xasprintf(&arg, "%ju", limit); | |
cdb4a946 | 499 | rc = scols_line_refer_data(ln, n, arg); |
32cfe498 KZ |
500 | break; |
501 | } | |
502 | ||
503 | if (rc != 0) | |
780ce22c | 504 | err(EXIT_FAILURE, _("failed to add output data")); |
32cfe498 KZ |
505 | } |
506 | } | |
507 | ||
624de257 KZ |
508 | static void setup_sem_elements_columns(struct libscols_table *tb) |
509 | { | |
510 | scols_table_set_name(tb, "elements"); | |
511 | if (!scols_table_new_column(tb, "SEMNUM", 0, SCOLS_FL_RIGHT)) | |
512 | err_oom(); | |
513 | if (!scols_table_new_column(tb, "VALUE", 0, SCOLS_FL_RIGHT)) | |
514 | err_oom(); | |
515 | if (!scols_table_new_column(tb, "NCOUNT", 0, SCOLS_FL_RIGHT)) | |
516 | err_oom(); | |
517 | if (!scols_table_new_column(tb, "ZCOUNT", 0, SCOLS_FL_RIGHT)) | |
518 | err_oom(); | |
519 | if (!scols_table_new_column(tb, "PID", 0, SCOLS_FL_RIGHT)) | |
520 | err_oom(); | |
521 | if (!scols_table_new_column(tb, "COMMAND", 0, SCOLS_FL_RIGHT)) | |
522 | err_oom(); | |
523 | } | |
524 | ||
9d20ffda KZ |
525 | static void do_sem(int id, struct lsipc_control *ctl, struct libscols_table *tb) |
526 | { | |
9d20ffda KZ |
527 | struct libscols_line *ln; |
528 | struct passwd *pw = NULL, *cpw = NULL; | |
529 | struct group *gr = NULL, *cgr = NULL; | |
530 | struct sem_data *semds, *semdsp; | |
cdb4a946 | 531 | char *arg = NULL; |
9d20ffda | 532 | |
5de8fcfd KZ |
533 | scols_table_set_name(tb, "semaphores"); |
534 | ||
9d20ffda KZ |
535 | if (ipc_sem_get_info(id, &semds) < 1) { |
536 | if (id > -1) | |
537 | warnx(_("id %d not found"), id); | |
538 | return; | |
539 | } | |
540 | for (semdsp = semds; semdsp->next != NULL || id > -1; semdsp = semdsp->next) { | |
e0154173 | 541 | size_t n; |
780ce22c | 542 | |
9d20ffda | 543 | ln = scols_table_new_line(tb, NULL); |
780ce22c KZ |
544 | if (!ln) |
545 | err(EXIT_FAILURE, _("failed to allocate output line")); | |
9d20ffda | 546 | |
e0154173 KZ |
547 | for (n = 0; n < ncolumns; n++) { |
548 | int rc = 0; | |
9d20ffda | 549 | switch (columns[n]) { |
91c92cb5 KZ |
550 | case COL_KEY: |
551 | xasprintf(&arg, "0x%08x",semdsp->sem_perm.key); | |
cdb4a946 | 552 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
553 | break; |
554 | case COL_ID: | |
555 | xasprintf(&arg, "%d",semdsp->sem_perm.id); | |
cdb4a946 | 556 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
557 | break; |
558 | case COL_OWNER: | |
71b63dc1 KZ |
559 | arg = get_username(&pw, semdsp->sem_perm.uid); |
560 | if (!arg) | |
91c92cb5 | 561 | xasprintf(&arg, "%u", semdsp->sem_perm.uid); |
cdb4a946 | 562 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
563 | break; |
564 | case COL_PERMS: | |
565 | if (ctl->numperms) | |
566 | xasprintf(&arg, "%#o", semdsp->sem_perm.mode & 0777); | |
567 | else { | |
568 | arg = xmalloc(11); | |
b0b24b11 | 569 | xstrmode(semdsp->sem_perm.mode & 0777, arg); |
91c92cb5 | 570 | } |
cdb4a946 | 571 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
572 | break; |
573 | case COL_CUID: | |
574 | xasprintf(&arg, "%u", semdsp->sem_perm.cuid); | |
cdb4a946 | 575 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
576 | break; |
577 | case COL_CUSER: | |
71b63dc1 KZ |
578 | arg = get_username(&cpw, semdsp->sem_perm.cuid); |
579 | if (arg) | |
cdb4a946 | 580 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
581 | break; |
582 | case COL_CGID: | |
71b63dc1 | 583 | xasprintf(&arg, "%u", semdsp->sem_perm.cgid); |
cdb4a946 | 584 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
585 | break; |
586 | case COL_CGROUP: | |
71b63dc1 KZ |
587 | arg = get_groupname(&cgr, semdsp->sem_perm.cgid); |
588 | if (arg) | |
cdb4a946 | 589 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
590 | break; |
591 | case COL_UID: | |
592 | xasprintf(&arg, "%u", semdsp->sem_perm.uid); | |
cdb4a946 | 593 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
594 | break; |
595 | case COL_USER: | |
71b63dc1 KZ |
596 | arg = get_username(&pw, semdsp->sem_perm.uid); |
597 | if (arg) | |
cdb4a946 | 598 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
599 | break; |
600 | case COL_GID: | |
71b63dc1 | 601 | xasprintf(&arg, "%u", semdsp->sem_perm.gid); |
cdb4a946 | 602 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
603 | break; |
604 | case COL_GROUP: | |
71b63dc1 KZ |
605 | arg = get_groupname(&gr, semdsp->sem_perm.gid); |
606 | if (arg) | |
cdb4a946 | 607 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
608 | break; |
609 | case COL_CTIME: | |
610 | if (semdsp->sem_ctime != 0) { | |
cdb4a946 KZ |
611 | rc = scols_line_refer_data(ln, n, |
612 | make_time(ctl->time_mode, | |
91c92cb5 | 613 | (time_t)semdsp->sem_ctime)); |
91c92cb5 KZ |
614 | } |
615 | break; | |
616 | case COL_NSEMS: | |
617 | xasprintf(&arg, "%ju", semdsp->sem_nsems); | |
cdb4a946 | 618 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
619 | break; |
620 | case COL_OTIME: | |
621 | if (semdsp->sem_otime != 0) { | |
cdb4a946 KZ |
622 | rc = scols_line_refer_data(ln, n, |
623 | make_time(ctl->time_mode, | |
91c92cb5 | 624 | (time_t)semdsp->sem_otime)); |
91c92cb5 KZ |
625 | } |
626 | break; | |
9d20ffda KZ |
627 | } |
628 | if (rc != 0) | |
780ce22c | 629 | err(EXIT_FAILURE, _("failed to add output data")); |
9d20ffda KZ |
630 | arg = NULL; |
631 | } | |
9d20ffda | 632 | |
624de257 KZ |
633 | if (id > -1 && semds->sem_nsems) { |
634 | /* Create extra table with ID specific semaphore elements */ | |
635 | struct libscols_table *sub = new_table(ctl); | |
636 | size_t i; | |
fadf556a | 637 | int rc = 0; |
624de257 KZ |
638 | |
639 | scols_table_enable_noheadings(sub, 0); | |
640 | setup_sem_elements_columns(sub); | |
9d20ffda KZ |
641 | |
642 | for (i = 0; i < semds->sem_nsems; i++) { | |
643 | struct sem_elem *e = &semds->elements[i]; | |
624de257 KZ |
644 | struct libscols_line *sln = scols_table_new_line(sub, NULL); |
645 | ||
780ce22c KZ |
646 | if (!sln) |
647 | err(EXIT_FAILURE, _("failed to allocate output line")); | |
648 | ||
624de257 KZ |
649 | /* SEMNUM */ |
650 | xasprintf(&arg, "%zu", i); | |
fadf556a KZ |
651 | rc = scols_line_refer_data(sln, 0, arg); |
652 | if (rc) | |
653 | break; | |
624de257 KZ |
654 | |
655 | /* VALUE */ | |
656 | xasprintf(&arg, "%d", e->semval); | |
fadf556a KZ |
657 | rc = scols_line_refer_data(sln, 1, arg); |
658 | if (rc) | |
659 | break; | |
624de257 KZ |
660 | |
661 | /* NCOUNT */ | |
662 | xasprintf(&arg, "%d", e->ncount); | |
fadf556a KZ |
663 | rc = scols_line_refer_data(sln, 2, arg); |
664 | if (rc) | |
665 | break; | |
624de257 KZ |
666 | |
667 | /* ZCOUNT */ | |
668 | xasprintf(&arg, "%d", e->zcount); | |
fadf556a KZ |
669 | rc = scols_line_refer_data(sln, 3, arg); |
670 | if (rc) | |
671 | break; | |
624de257 KZ |
672 | |
673 | /* PID */ | |
674 | xasprintf(&arg, "%d", e->pid); | |
fadf556a KZ |
675 | rc = scols_line_refer_data(sln, 4, arg); |
676 | if (rc) | |
677 | break; | |
624de257 KZ |
678 | |
679 | /* COMMAND */ | |
680 | arg = proc_get_command(e->pid); | |
fadf556a KZ |
681 | rc = scols_line_refer_data(sln, 5, arg); |
682 | if (rc) | |
683 | break; | |
9d20ffda | 684 | } |
624de257 | 685 | |
fadf556a KZ |
686 | if (rc != 0) |
687 | err(EXIT_FAILURE, _("failed to set data")); | |
688 | ||
624de257 | 689 | scols_line_set_userdata(ln, (void *)sub); |
9d20ffda KZ |
690 | break; |
691 | } | |
692 | } | |
693 | ipc_sem_free_info(semds); | |
694 | } | |
695 | ||
696 | static void do_sem_global(struct libscols_table *tb) | |
697 | { | |
698 | struct sem_data *semds, *semdsp; | |
699 | struct ipc_limits lim; | |
32cfe498 | 700 | int nsems = 0, nsets = 0; |
9d20ffda | 701 | |
9d20ffda KZ |
702 | ipc_sem_get_limits(&lim); |
703 | ||
32cfe498 KZ |
704 | if (ipc_sem_get_info(-1, &semds) > 0) { |
705 | for (semdsp = semds; semdsp->next != NULL; semdsp = semdsp->next) { | |
706 | ++nsets; | |
707 | nsems += semds->sem_nsems; | |
708 | } | |
709 | ipc_sem_free_info(semds); | |
9d20ffda | 710 | } |
9d20ffda | 711 | |
a4839bc7 KZ |
712 | global_set_data(tb, "SEMMNI", _("Number of semaphore identifiers"), nsets, lim.semmni, 1); |
713 | global_set_data(tb, "SEMMNS", _("Total number of semaphores"), nsems, lim.semmns, 1); | |
714 | global_set_data(tb, "SEMMSL", _("Max semaphores per semaphore set."), 0, lim.semmsl, 0); | |
715 | global_set_data(tb, "SEMOPM", _("Max number of operations per semop(2)"), 0, lim.semopm, 0); | |
716 | global_set_data(tb, "SEMVMX", _("Semaphore max value"), 0, lim.semvmx, 0); | |
9d20ffda KZ |
717 | } |
718 | ||
719 | static void do_msg(int id, struct lsipc_control *ctl, struct libscols_table *tb) | |
720 | { | |
9d20ffda KZ |
721 | struct libscols_line *ln; |
722 | struct passwd *pw = NULL; | |
723 | struct group *gr = NULL; | |
724 | struct msg_data *msgds, *msgdsp; | |
cdb4a946 | 725 | char *arg = NULL; |
9d20ffda KZ |
726 | |
727 | if (ipc_msg_get_info(id, &msgds) < 1) { | |
728 | if (id > -1) | |
729 | warnx(_("id %d not found"), id); | |
730 | return; | |
731 | } | |
5de8fcfd | 732 | scols_table_set_name(tb, "messages"); |
9d20ffda KZ |
733 | |
734 | for (msgdsp = msgds; msgdsp->next != NULL || id > -1 ; msgdsp = msgdsp->next) { | |
e0154173 | 735 | size_t n; |
9d20ffda KZ |
736 | ln = scols_table_new_line(tb, NULL); |
737 | ||
780ce22c KZ |
738 | if (!ln) |
739 | err(EXIT_FAILURE, _("failed to allocate output line")); | |
740 | ||
9d20ffda KZ |
741 | /* no need to call getpwuid() for the same user */ |
742 | if (!(pw && pw->pw_uid == msgdsp->msg_perm.uid)) | |
743 | pw = getpwuid(msgdsp->msg_perm.uid); | |
744 | ||
745 | /* no need to call getgrgid() for the same user */ | |
746 | if (!(gr && gr->gr_gid == msgdsp->msg_perm.gid)) | |
747 | gr = getgrgid(msgdsp->msg_perm.gid); | |
748 | ||
e0154173 | 749 | for (n = 0; n < ncolumns; n++) { |
9d20ffda KZ |
750 | int rc = 0; |
751 | ||
752 | switch (columns[n]) { | |
91c92cb5 KZ |
753 | case COL_KEY: |
754 | xasprintf(&arg, "0x%08x",msgdsp->msg_perm.key); | |
cdb4a946 | 755 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
756 | break; |
757 | case COL_ID: | |
758 | xasprintf(&arg, "%d",msgdsp->msg_perm.id); | |
cdb4a946 | 759 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
760 | break; |
761 | case COL_OWNER: | |
71b63dc1 KZ |
762 | arg = get_username(&pw, msgdsp->msg_perm.uid); |
763 | if (!arg) | |
91c92cb5 | 764 | xasprintf(&arg, "%u", msgdsp->msg_perm.uid); |
cdb4a946 | 765 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
766 | break; |
767 | case COL_PERMS: | |
768 | if (ctl->numperms) | |
769 | xasprintf(&arg, "%#o", msgdsp->msg_perm.mode & 0777); | |
770 | else { | |
771 | arg = xmalloc(11); | |
b0b24b11 | 772 | xstrmode(msgdsp->msg_perm.mode & 0777, arg); |
cdb4a946 | 773 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
774 | } |
775 | break; | |
776 | case COL_CUID: | |
777 | xasprintf(&arg, "%u", msgdsp->msg_perm.cuid); | |
cdb4a946 | 778 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
779 | break; |
780 | case COL_CUSER: | |
71b63dc1 KZ |
781 | arg = get_username(&pw, msgdsp->msg_perm.cuid); |
782 | if (arg) | |
cdb4a946 | 783 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
784 | break; |
785 | case COL_CGID: | |
786 | xasprintf(&arg, "%u", msgdsp->msg_perm.cuid); | |
cdb4a946 | 787 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
788 | break; |
789 | case COL_CGROUP: | |
71b63dc1 KZ |
790 | arg = get_groupname(&gr, msgdsp->msg_perm.cgid); |
791 | if (arg) | |
cdb4a946 | 792 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
793 | break; |
794 | case COL_UID: | |
795 | xasprintf(&arg, "%u", msgdsp->msg_perm.uid); | |
cdb4a946 | 796 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
797 | break; |
798 | case COL_USER: | |
71b63dc1 KZ |
799 | arg = get_username(&pw, msgdsp->msg_perm.uid); |
800 | if (arg) | |
cdb4a946 | 801 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
802 | break; |
803 | case COL_GID: | |
804 | xasprintf(&arg, "%u", msgdsp->msg_perm.gid); | |
cdb4a946 | 805 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
806 | break; |
807 | case COL_GROUP: | |
71b63dc1 KZ |
808 | arg = get_groupname(&gr,msgdsp->msg_perm.gid); |
809 | if (arg) | |
cdb4a946 | 810 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
811 | break; |
812 | case COL_CTIME: | |
cdb4a946 KZ |
813 | if (msgdsp->q_ctime != 0) |
814 | rc = scols_line_refer_data(ln, n, | |
815 | make_time(ctl->time_mode, | |
91c92cb5 | 816 | (time_t)msgdsp->q_ctime)); |
91c92cb5 KZ |
817 | break; |
818 | case COL_USEDBYTES: | |
819 | xasprintf(&arg, "%ju", msgdsp->q_cbytes); | |
cdb4a946 | 820 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
821 | break; |
822 | case COL_MSGS: | |
823 | xasprintf(&arg, "%ju", msgdsp->q_qnum); | |
cdb4a946 | 824 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
825 | break; |
826 | case COL_SEND: | |
cdb4a946 KZ |
827 | if (msgdsp->q_stime != 0) |
828 | rc = scols_line_refer_data(ln, n, | |
829 | make_time(ctl->time_mode, | |
91c92cb5 | 830 | (time_t)msgdsp->q_stime)); |
91c92cb5 KZ |
831 | break; |
832 | case COL_RECV: | |
cdb4a946 KZ |
833 | if (msgdsp->q_rtime != 0) |
834 | rc = scols_line_refer_data(ln, n, | |
835 | make_time(ctl->time_mode, | |
91c92cb5 | 836 | (time_t)msgdsp->q_rtime)); |
91c92cb5 KZ |
837 | break; |
838 | case COL_LSPID: | |
839 | xasprintf(&arg, "%u", msgdsp->q_lspid); | |
cdb4a946 | 840 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
841 | break; |
842 | case COL_LRPID: | |
843 | xasprintf(&arg, "%u", msgdsp->q_lrpid); | |
cdb4a946 | 844 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 | 845 | break; |
9d20ffda KZ |
846 | } |
847 | if (rc != 0) | |
848 | err(EXIT_FAILURE, _("failed to set data")); | |
9d20ffda KZ |
849 | arg = NULL; |
850 | } | |
851 | if (id > -1) | |
852 | break; | |
853 | } | |
854 | ipc_msg_free_info(msgds); | |
855 | } | |
856 | ||
32cfe498 | 857 | |
9d20ffda KZ |
858 | static void do_msg_global(struct libscols_table *tb) |
859 | { | |
860 | struct msg_data *msgds, *msgdsp; | |
861 | struct ipc_limits lim; | |
32cfe498 | 862 | int msgqs = 0; |
9d20ffda | 863 | |
9d20ffda KZ |
864 | ipc_msg_get_limits(&lim); |
865 | ||
32cfe498 KZ |
866 | /* count number of used queues */ |
867 | if (ipc_msg_get_info(-1, &msgds) > 0) { | |
868 | for (msgdsp = msgds; msgdsp->next != NULL; msgdsp = msgdsp->next) | |
869 | ++msgqs; | |
870 | ipc_msg_free_info(msgds); | |
9d20ffda KZ |
871 | } |
872 | ||
a4839bc7 KZ |
873 | global_set_data(tb, "MSGMNI", _("Number of message queues"), msgqs, lim.msgmni, 1); |
874 | global_set_data(tb, "MSGMAX", _("Max size of message (bytes)"), 0, lim.msgmax, 0); | |
875 | global_set_data(tb, "MSGMNB", _("Default max size of queue (bytes)"), 0, lim.msgmnb, 0); | |
9d20ffda KZ |
876 | } |
877 | ||
d8461c4e | 878 | |
9d20ffda KZ |
879 | static void do_shm(int id, struct lsipc_control *ctl, struct libscols_table *tb) |
880 | { | |
9d20ffda KZ |
881 | struct libscols_line *ln; |
882 | struct passwd *pw = NULL; | |
883 | struct group *gr = NULL; | |
884 | struct shm_data *shmds, *shmdsp; | |
cdb4a946 | 885 | char *arg = NULL; |
9d20ffda KZ |
886 | |
887 | if (ipc_shm_get_info(id, &shmds) < 1) { | |
888 | if (id > -1) | |
889 | warnx(_("id %d not found"), id); | |
890 | return; | |
891 | } | |
892 | ||
5de8fcfd KZ |
893 | scols_table_set_name(tb, "sharedmemory"); |
894 | ||
9d20ffda | 895 | for (shmdsp = shmds; shmdsp->next != NULL || id > -1 ; shmdsp = shmdsp->next) { |
e0154173 | 896 | size_t n; |
9d20ffda | 897 | ln = scols_table_new_line(tb, NULL); |
780ce22c | 898 | |
32cfe498 | 899 | if (!ln) |
780ce22c | 900 | err(EXIT_FAILURE, _("failed to allocate output line")); |
9d20ffda | 901 | |
e0154173 | 902 | for (n = 0; n < ncolumns; n++) { |
9d20ffda KZ |
903 | int rc = 0; |
904 | ||
905 | switch (columns[n]) { | |
91c92cb5 KZ |
906 | case COL_KEY: |
907 | xasprintf(&arg, "0x%08x",shmdsp->shm_perm.key); | |
cdb4a946 | 908 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
909 | break; |
910 | case COL_ID: | |
911 | xasprintf(&arg, "%d",shmdsp->shm_perm.id); | |
cdb4a946 | 912 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
913 | break; |
914 | case COL_OWNER: | |
d8461c4e KZ |
915 | arg = get_username(&pw, shmdsp->shm_perm.uid); |
916 | if (!arg) | |
7458c061 | 917 | xasprintf(&arg, "%u", shmdsp->shm_perm.uid); |
cdb4a946 | 918 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
919 | break; |
920 | case COL_PERMS: | |
921 | if (ctl->numperms) | |
922 | xasprintf(&arg, "%#o", shmdsp->shm_perm.mode & 0777); | |
923 | else { | |
924 | arg = xmalloc(11); | |
b0b24b11 | 925 | xstrmode(shmdsp->shm_perm.mode & 0777, arg); |
91c92cb5 | 926 | } |
cdb4a946 | 927 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
928 | break; |
929 | case COL_CUID: | |
930 | xasprintf(&arg, "%u", shmdsp->shm_perm.cuid); | |
cdb4a946 | 931 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
932 | break; |
933 | case COL_CUSER: | |
d8461c4e KZ |
934 | arg = get_username(&pw, shmdsp->shm_perm.cuid); |
935 | if (arg) | |
cdb4a946 | 936 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
937 | break; |
938 | case COL_CGID: | |
939 | xasprintf(&arg, "%u", shmdsp->shm_perm.cuid); | |
cdb4a946 | 940 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
941 | break; |
942 | case COL_CGROUP: | |
d8461c4e KZ |
943 | arg = get_groupname(&gr, shmdsp->shm_perm.cgid); |
944 | if (arg) | |
cdb4a946 | 945 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
946 | break; |
947 | case COL_UID: | |
948 | xasprintf(&arg, "%u", shmdsp->shm_perm.uid); | |
cdb4a946 | 949 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
950 | break; |
951 | case COL_USER: | |
d8461c4e KZ |
952 | arg = get_username(&pw, shmdsp->shm_perm.uid); |
953 | if (arg) | |
cdb4a946 | 954 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
955 | break; |
956 | case COL_GID: | |
957 | xasprintf(&arg, "%u", shmdsp->shm_perm.gid); | |
cdb4a946 | 958 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
959 | break; |
960 | case COL_GROUP: | |
d8461c4e KZ |
961 | arg = get_groupname(&gr, shmdsp->shm_perm.gid); |
962 | if (arg) | |
cdb4a946 | 963 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
964 | break; |
965 | case COL_CTIME: | |
cdb4a946 KZ |
966 | if (shmdsp->shm_ctim != 0) |
967 | rc = scols_line_refer_data(ln, n, | |
968 | make_time(ctl->time_mode, | |
91c92cb5 | 969 | (time_t)shmdsp->shm_ctim)); |
91c92cb5 KZ |
970 | break; |
971 | case COL_SIZE: | |
972 | if (ctl->bytes) | |
973 | xasprintf(&arg, "%ju", shmdsp->shm_segsz); | |
974 | else | |
975 | arg = size_to_human_string(SIZE_SUFFIX_1LETTER, shmdsp->shm_segsz); | |
cdb4a946 | 976 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
977 | break; |
978 | case COL_NATTCH: | |
979 | xasprintf(&arg, "%ju", shmdsp->shm_nattch); | |
cdb4a946 | 980 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
981 | break; |
982 | case COL_STATUS: { | |
983 | int comma = 0; | |
984 | size_t offt = 0; | |
9380fbef KZ |
985 | |
986 | free(arg); | |
91c92cb5 KZ |
987 | arg = xcalloc(1, sizeof(char) * strlen(_("dest")) |
988 | + strlen(_("locked")) | |
989 | + strlen(_("hugetlb")) | |
990 | + strlen(_("noreserve")) + 4); | |
21ce5a5d | 991 | #ifdef SHM_DEST |
91c92cb5 KZ |
992 | if (shmdsp->shm_perm.mode & SHM_DEST) { |
993 | offt += sprintf(arg, "%s", _("dest")); | |
994 | comma++; | |
9d20ffda | 995 | } |
21ce5a5d KZ |
996 | #endif |
997 | #ifdef SHM_LOCKED | |
91c92cb5 KZ |
998 | if (shmdsp->shm_perm.mode & SHM_LOCKED) { |
999 | if (comma) | |
1000 | arg[offt++] = ','; | |
1001 | offt += sprintf(arg + offt, "%s", _("locked")); | |
9d20ffda | 1002 | } |
21ce5a5d KZ |
1003 | #endif |
1004 | #ifdef SHM_HUGETLB | |
91c92cb5 KZ |
1005 | if (shmdsp->shm_perm.mode & SHM_HUGETLB) { |
1006 | if (comma) | |
1007 | arg[offt++] = ','; | |
1008 | offt += sprintf(arg + offt, "%s", _("hugetlb")); | |
1009 | } | |
21ce5a5d KZ |
1010 | #endif |
1011 | #ifdef SHM_NORESERVE | |
91c92cb5 KZ |
1012 | if (shmdsp->shm_perm.mode & SHM_NORESERVE) { |
1013 | if (comma) | |
1014 | arg[offt++] = ','; | |
9380fbef | 1015 | sprintf(arg + offt, "%s", _("noreserve")); |
9d20ffda | 1016 | } |
21ce5a5d | 1017 | #endif |
cdb4a946 | 1018 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
1019 | } |
1020 | break; | |
1021 | case COL_ATTACH: | |
cdb4a946 KZ |
1022 | if (shmdsp->shm_atim != 0) |
1023 | rc = scols_line_refer_data(ln, n, | |
1024 | make_time(ctl->time_mode, | |
91c92cb5 | 1025 | (time_t)shmdsp->shm_atim)); |
91c92cb5 KZ |
1026 | break; |
1027 | case COL_DETACH: | |
cdb4a946 KZ |
1028 | if (shmdsp->shm_dtim != 0) |
1029 | rc = scols_line_refer_data(ln, n, | |
1030 | make_time(ctl->time_mode, | |
91c92cb5 | 1031 | (time_t)shmdsp->shm_dtim)); |
91c92cb5 KZ |
1032 | break; |
1033 | case COL_CPID: | |
1034 | xasprintf(&arg, "%u", shmdsp->shm_cprid); | |
cdb4a946 | 1035 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
1036 | break; |
1037 | case COL_LPID: | |
1038 | xasprintf(&arg, "%u", shmdsp->shm_lprid); | |
cdb4a946 | 1039 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 KZ |
1040 | break; |
1041 | case COL_COMMAND: | |
1042 | arg = proc_get_command(shmdsp->shm_cprid); | |
cdb4a946 | 1043 | rc = scols_line_refer_data(ln, n, arg); |
91c92cb5 | 1044 | break; |
9d20ffda KZ |
1045 | } |
1046 | if (rc != 0) | |
1047 | err(EXIT_FAILURE, _("failed to set data")); | |
9d20ffda KZ |
1048 | arg = NULL; |
1049 | } | |
1050 | if (id > -1) | |
1051 | break; | |
1052 | } | |
1053 | ipc_shm_free_info(shmds); | |
1054 | } | |
1055 | ||
1056 | static void do_shm_global(struct libscols_table *tb) | |
1057 | { | |
1058 | struct shm_data *shmds, *shmdsp; | |
32cfe498 | 1059 | uint64_t nsegs = 0, sum_segsz = 0; |
9d20ffda | 1060 | struct ipc_limits lim; |
9d20ffda | 1061 | |
9d20ffda KZ |
1062 | ipc_shm_get_limits(&lim); |
1063 | ||
32cfe498 KZ |
1064 | if (ipc_shm_get_info(-1, &shmds) > 0) { |
1065 | for (shmdsp = shmds; shmdsp->next != NULL; shmdsp = shmdsp->next) { | |
1066 | ++nsegs; | |
1067 | sum_segsz += shmdsp->shm_segsz; | |
1068 | } | |
90a9b991 | 1069 | ipc_shm_free_info(shmds); |
9d20ffda KZ |
1070 | } |
1071 | ||
a4839bc7 KZ |
1072 | global_set_data(tb, "SHMMNI", _("Shared memory segments"), nsegs, lim.shmmni, 1); |
1073 | global_set_data(tb, "SHMALL", _("Shared memory pages"), sum_segsz / getpagesize(), lim.shmall, 1); | |
1074 | global_set_data(tb, "SHMMAX", _("Max size of shared memory segment (bytes)"), 0, lim.shmmax, 0); | |
1075 | global_set_data(tb, "SHMMIN", _("Min size of shared memory segment (bytes)"), 0, lim.shmmin, 0); | |
9d20ffda KZ |
1076 | } |
1077 | ||
1078 | int main(int argc, char *argv[]) | |
1079 | { | |
e0154173 | 1080 | int opt, msg = 0, sem = 0, shm = 0, id = -1; |
9d20ffda KZ |
1081 | int show_time = 0, show_creat = 0, global = 0; |
1082 | size_t i; | |
1083 | struct lsipc_control *ctl = xcalloc(1, sizeof(struct lsipc_control)); | |
1084 | static struct libscols_table *tb; | |
e0154173 | 1085 | char *outarg = NULL; |
9d20ffda KZ |
1086 | |
1087 | /* long only options. */ | |
1088 | enum { | |
1089 | OPT_NOTRUNC = CHAR_MAX + 1, | |
1090 | OPT_NOHEAD, | |
2a7150ac | 1091 | OPT_TIME_FMT |
9d20ffda KZ |
1092 | }; |
1093 | ||
1094 | static const struct option longopts[] = { | |
87918040 SK |
1095 | { "bytes", no_argument, NULL, 'b' }, |
1096 | { "creator", no_argument, NULL, 'c' }, | |
1097 | { "export", no_argument, NULL, 'e' }, | |
1098 | { "global", no_argument, NULL, 'g' }, | |
1099 | { "help", no_argument, NULL, 'h' }, | |
1100 | { "id", required_argument, NULL, 'i' }, | |
1101 | { "json", no_argument, NULL, 'J' }, | |
1102 | { "list", no_argument, NULL, 'l' }, | |
1103 | { "newline", no_argument, NULL, 'n' }, | |
1104 | { "noheadings", no_argument, NULL, OPT_NOHEAD }, | |
1105 | { "notruncate", no_argument, NULL, OPT_NOTRUNC }, | |
1106 | { "numeric-perms", no_argument, NULL, 'P' }, | |
1107 | { "output", required_argument, NULL, 'o' }, | |
87918040 SK |
1108 | { "queues", no_argument, NULL, 'q' }, |
1109 | { "raw", no_argument, NULL, 'r' }, | |
1110 | { "semaphores", no_argument, NULL, 's' }, | |
1111 | { "shmems", no_argument, NULL, 'm' }, | |
1112 | { "time", no_argument, NULL, 't' }, | |
1113 | { "time-format", required_argument, NULL, OPT_TIME_FMT }, | |
1114 | { "version", no_argument, NULL, 'V' }, | |
9d20ffda KZ |
1115 | {NULL, 0, NULL, 0} |
1116 | }; | |
1117 | ||
1118 | static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ | |
2916afa3 KZ |
1119 | { 'J', 'e', 'l', 'n', 'r' }, |
1120 | { 'g', 'i' }, | |
1121 | { 'c', 'o', 't' }, | |
9d20ffda KZ |
1122 | { 'm', 'q', 's' }, |
1123 | { 0 } | |
1124 | }; | |
1125 | int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; | |
1126 | ||
1127 | setlocale(LC_ALL, ""); | |
1128 | bindtextdomain(PACKAGE, LOCALEDIR); | |
1129 | textdomain(PACKAGE); | |
1130 | atexit(close_stdout); | |
1131 | ||
c8b47062 | 1132 | ctl->time_mode = 0; |
9d20ffda | 1133 | |
624de257 KZ |
1134 | scols_init_debug(0); |
1135 | ||
1b71d08c | 1136 | while ((opt = getopt_long(argc, argv, "bceghi:Jlmno:PqrstV", longopts, NULL)) != -1) { |
9d20ffda KZ |
1137 | |
1138 | err_exclusive_options(opt, longopts, excl, excl_st); | |
1139 | ||
1140 | switch (opt) { | |
91c92cb5 KZ |
1141 | case 'b': |
1142 | ctl->bytes = 1; | |
1143 | break; | |
1144 | case 'i': | |
1145 | id = strtos32_or_err(optarg, _("failed to parse IPC identifier")); | |
91c92cb5 | 1146 | break; |
91c92cb5 | 1147 | case 'e': |
d7500c6a | 1148 | ctl->outmode = OUT_EXPORT; |
91c92cb5 KZ |
1149 | break; |
1150 | case 'r': | |
d7500c6a | 1151 | ctl->outmode = OUT_RAW; |
91c92cb5 KZ |
1152 | break; |
1153 | case 'o': | |
1154 | outarg = optarg; | |
1155 | break; | |
1156 | case 'g': | |
1157 | global = 1; | |
2916afa3 | 1158 | break; |
91c92cb5 KZ |
1159 | case 'q': |
1160 | msg = 1; | |
1161 | add_column(columns, ncolumns++, COL_KEY); | |
1162 | add_column(columns, ncolumns++, COL_ID); | |
1163 | add_column(columns, ncolumns++, COL_PERMS); | |
1164 | add_column(columns, ncolumns++, COL_OWNER); | |
1165 | add_column(columns, ncolumns++, COL_USEDBYTES); | |
1166 | add_column(columns, ncolumns++, COL_MSGS); | |
1167 | add_column(columns, ncolumns++, COL_LSPID); | |
1168 | add_column(columns, ncolumns++, COL_LRPID); | |
1169 | LOWER = COLDESC_IDX_MSG_FIRST; | |
1170 | UPPER = COLDESC_IDX_MSG_LAST; | |
1171 | break; | |
2916afa3 KZ |
1172 | case 'l': |
1173 | ctl->outmode = OUT_LIST; | |
1174 | break; | |
91c92cb5 KZ |
1175 | case 'm': |
1176 | shm = 1; | |
1177 | add_column(columns, ncolumns++, COL_KEY); | |
1178 | add_column(columns, ncolumns++, COL_ID); | |
1179 | add_column(columns, ncolumns++, COL_PERMS); | |
1180 | add_column(columns, ncolumns++, COL_OWNER); | |
1181 | add_column(columns, ncolumns++, COL_SIZE); | |
1182 | add_column(columns, ncolumns++, COL_NATTCH); | |
1183 | add_column(columns, ncolumns++, COL_STATUS); | |
1184 | add_column(columns, ncolumns++, COL_CTIME); | |
1185 | add_column(columns, ncolumns++, COL_CPID); | |
1186 | add_column(columns, ncolumns++, COL_LPID); | |
1187 | add_column(columns, ncolumns++, COL_COMMAND); | |
1188 | LOWER = COLDESC_IDX_SHM_FIRST; | |
1189 | UPPER = COLDESC_IDX_SHM_LAST; | |
1190 | break; | |
1191 | case 'n': | |
d7500c6a | 1192 | ctl->outmode = OUT_NEWLINE; |
91c92cb5 KZ |
1193 | break; |
1194 | case 'P': | |
1195 | ctl->numperms = 1; | |
1196 | break; | |
1197 | case 's': | |
1198 | sem = 1; | |
1199 | add_column(columns, ncolumns++, COL_KEY); | |
1200 | add_column(columns, ncolumns++, COL_ID); | |
1201 | add_column(columns, ncolumns++, COL_PERMS); | |
1202 | add_column(columns, ncolumns++, COL_OWNER); | |
1203 | add_column(columns, ncolumns++, COL_NSEMS); | |
1204 | LOWER = COLDESC_IDX_SEM_FIRST; | |
1205 | UPPER = COLDESC_IDX_SEM_LAST; | |
1206 | break; | |
1207 | case OPT_NOTRUNC: | |
1208 | ctl->notrunc = 1; | |
1209 | break; | |
1210 | case OPT_NOHEAD: | |
1211 | ctl->noheadings = 1; | |
1212 | break; | |
1213 | case OPT_TIME_FMT: | |
1214 | ctl->time_mode = parse_time_mode(optarg); | |
1215 | break; | |
1216 | case 'J': | |
5de8fcfd | 1217 | ctl->outmode = OUT_JSON; |
91c92cb5 KZ |
1218 | break; |
1219 | case 't': | |
1220 | show_time = 1; | |
1221 | break; | |
1222 | case 'c': | |
1223 | show_creat = 1; | |
1224 | break; | |
1225 | case 'h': | |
9325dbfd | 1226 | usage(); |
91c92cb5 KZ |
1227 | case 'V': |
1228 | printf(UTIL_LINUX_VERSION); | |
1229 | return EXIT_SUCCESS; | |
91c92cb5 | 1230 | default: |
9325dbfd | 1231 | errtryhelp(EXIT_FAILURE); |
9d20ffda KZ |
1232 | } |
1233 | } | |
1234 | ||
25456d5d | 1235 | /* default is global */ |
8f405a5b | 1236 | if (msg + shm + sem == 0) { |
25456d5d | 1237 | msg = shm = sem = global = 1; |
2916afa3 | 1238 | if (show_time || show_creat || id != -1) |
62eea9ce | 1239 | errx(EXIT_FAILURE, _("--global is mutually exclusive with --creator, --id and --time")); |
8f405a5b | 1240 | } |
25456d5d KZ |
1241 | if (global) { |
1242 | add_column(columns, ncolumns++, COL_RESOURCE); | |
1243 | add_column(columns, ncolumns++, COL_DESC); | |
1244 | add_column(columns, ncolumns++, COL_LIMIT); | |
1245 | add_column(columns, ncolumns++, COL_USED); | |
1246 | add_column(columns, ncolumns++, COL_USEPERC); | |
1247 | LOWER = COLDESC_IDX_SUM_FIRST; | |
1248 | UPPER = COLDESC_IDX_SUM_LAST; | |
1249 | } | |
9d20ffda | 1250 | |
2916afa3 KZ |
1251 | /* default to pretty-print if --id specified */ |
1252 | if (id != -1 && !ctl->outmode) | |
1253 | ctl->outmode = OUT_PRETTY; | |
1254 | ||
c8b47062 | 1255 | if (!ctl->time_mode) |
d7500c6a | 1256 | ctl->time_mode = ctl->outmode == OUT_PRETTY ? TIME_FULL : TIME_SHORT; |
c8b47062 | 1257 | |
2916afa3 | 1258 | if (ctl->outmode == OUT_PRETTY && !(optarg || show_creat || show_time)) { |
e0154173 KZ |
1259 | /* all columns for lsipc --<RESOURCE> --id <ID> */ |
1260 | for (ncolumns = 0, i = 0; i < ARRAY_SIZE(coldescs); i++) | |
1261 | columns[ncolumns++] = i; | |
9d20ffda | 1262 | } else { |
e0154173 KZ |
1263 | if (show_creat) { |
1264 | add_column(columns, ncolumns++, COL_CUID); | |
1265 | add_column(columns, ncolumns++, COL_CGID); | |
1266 | add_column(columns, ncolumns++, COL_UID); | |
1267 | add_column(columns, ncolumns++, COL_GID); | |
1268 | } | |
1269 | if (msg && show_time) { | |
1270 | add_column(columns, ncolumns++, COL_SEND); | |
1271 | add_column(columns, ncolumns++, COL_RECV); | |
1272 | add_column(columns, ncolumns++, COL_CTIME); | |
1273 | } | |
1274 | if (shm && show_time) { | |
1275 | /* keep "COMMAND" as last column */ | |
1276 | size_t cmd = columns[ncolumns - 1] == COL_COMMAND; | |
1277 | ||
1278 | if (cmd) | |
1279 | ncolumns--; | |
1280 | add_column(columns, ncolumns++, COL_ATTACH); | |
1281 | add_column(columns, ncolumns++, COL_DETACH); | |
1282 | if (cmd) | |
be475287 | 1283 | add_column(columns, ncolumns++, COL_COMMAND); |
e0154173 KZ |
1284 | } |
1285 | if (sem && show_time) { | |
1286 | add_column(columns, ncolumns++, COL_OTIME); | |
1287 | add_column(columns, ncolumns++, COL_CTIME); | |
9d20ffda KZ |
1288 | } |
1289 | } | |
1290 | ||
e0154173 KZ |
1291 | if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns), |
1292 | &ncolumns, column_name_to_id) < 0) | |
1293 | return EXIT_FAILURE; | |
1294 | ||
9d20ffda KZ |
1295 | tb = setup_table(ctl); |
1296 | if (!tb) | |
1297 | return EXIT_FAILURE; | |
5de8fcfd KZ |
1298 | |
1299 | if (global) | |
1300 | scols_table_set_name(tb, "ipclimits"); | |
1301 | ||
9d20ffda KZ |
1302 | if (msg) { |
1303 | if (global) | |
1304 | do_msg_global(tb); | |
1305 | else | |
1306 | do_msg(id, ctl, tb); | |
32cfe498 KZ |
1307 | } |
1308 | if (shm) { | |
9d20ffda KZ |
1309 | if (global) |
1310 | do_shm_global(tb); | |
1311 | else | |
1312 | do_shm(id, ctl, tb); | |
32cfe498 KZ |
1313 | } |
1314 | if (sem) { | |
9d20ffda KZ |
1315 | if (global) |
1316 | do_sem_global(tb); | |
1317 | else | |
32cfe498 | 1318 | do_sem(id, ctl, tb); |
9d20ffda KZ |
1319 | } |
1320 | ||
d7500c6a | 1321 | print_table(ctl, tb); |
9d20ffda KZ |
1322 | |
1323 | scols_unref_table(tb); | |
1324 | free(ctl); | |
1325 | ||
1326 | return EXIT_SUCCESS; | |
1327 | } | |
1328 |