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