]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/tools/lxc_info.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
12 #include <sys/types.h>
17 #include "arguments.h"
22 lxc_log_define(lxc_info
, lxc
);
28 static bool humanize
= true;
29 static char **key
= NULL
;
30 static int nr_keys
= 0;
31 static int filter_count
= 0;
33 static int my_parser(struct lxc_arguments
*args
, int c
, char *arg
)
39 newk
= realloc(key
, (nr_keys
+ 1) * sizeof(key
[0]));
47 case 'i': ips
= true; filter_count
+= 1; break;
48 case 's': state
= true; filter_count
+= 1; break;
49 case 'p': pid
= true; filter_count
+= 1; break;
50 case 'S': stats
= true; filter_count
+= 5; break;
51 case 'H': humanize
= false; break;
56 static const struct option my_longopts
[] = {
57 {"config", required_argument
, 0, 'c'},
58 {"ips", no_argument
, 0, 'i'},
59 {"state", no_argument
, 0, 's'},
60 {"pid", no_argument
, 0, 'p'},
61 {"stats", no_argument
, 0, 'S'},
62 {"no-humanize", no_argument
, 0, 'H'},
66 static struct lxc_arguments my_args
= {
67 .progname
= "lxc-info",
71 lxc-info display some information about a container with the identifier NAME\n\
74 -n, --name=NAME NAME of the container\n\
75 -c, --config=KEY show configuration variable KEY from running container\n\
76 -i, --ips shows the IP addresses\n\
77 -p, --pid shows the process id of the init container\n\
78 -S, --stats shows usage stats\n\
79 -H, --no-humanize shows stats as raw numbers, not humanized\n\
80 -s, --state shows the state of the container\n\
81 --rcfile=FILE Load configuration file FILE\n",
83 .options
= my_longopts
,
88 static void str_chomp(char *buf
)
92 /* remove trailing whitespace from buf */
93 for(ch
= &buf
[strlen(buf
)-1];
94 ch
>= buf
&& (*ch
== '\t' || *ch
== '\n' || *ch
== ' ');
99 static void size_humanize(unsigned long long val
, char *buf
, size_t bufsz
)
102 (void)snprintf(buf
, bufsz
, "%u.%2.2u GiB",
103 (unsigned int)(val
>> 30),
104 (unsigned int)(val
& ((1 << 30) - 1)) / 10737419);
105 } else if (val
> 1 << 20) {
106 unsigned int x
= val
+ 5243; /* for rounding */
107 (void)snprintf(buf
, bufsz
, "%u.%2.2u MiB", x
>> 20,
108 ((x
& ((1 << 20) - 1)) * 100) >> 20);
109 } else if (val
> 1 << 10) {
110 unsigned int x
= val
+ 5; /* for rounding */
111 (void)snprintf(buf
, bufsz
, "%u.%2.2u KiB", x
>> 10,
112 ((x
& ((1 << 10) - 1)) * 100) >> 10);
114 (void)snprintf(buf
, bufsz
, "%u bytes", (unsigned int)val
);
118 static unsigned long long str_size_humanize(char *iobuf
, size_t iobufsz
)
120 unsigned long long val
;
123 val
= strtoull(iobuf
, &end
, 0);
125 if (*end
== '\0' || *end
== '\n')
126 size_humanize(val
, iobuf
, iobufsz
);
133 static void print_net_stats(struct lxc_container
*c
)
136 unsigned long long rx_bytes
= 0, tx_bytes
= 0;
141 for(netnr
= 0; ;netnr
++) {
142 sprintf(buf
, "lxc.net.%d.type", netnr
);
144 type
= c
->get_running_config_item(c
, buf
);
148 if (!strcmp(type
, "veth")) {
149 sprintf(buf
, "lxc.net.%d.veth.pair", netnr
);
151 sprintf(buf
, "lxc.net.%d.link", netnr
);
155 ifname
= c
->get_running_config_item(c
, buf
);
159 printf("%-15s %s\n", "Link:", ifname
);
162 /* XXX: tx and rx are reversed from the host vs container
163 * perspective, print them from the container perspective
165 rc
= snprintf(path
, sizeof(path
), "/sys/class/net/%s/statistics/rx_bytes", ifname
);
166 if (rc
< 0 || (size_t)rc
>= sizeof(path
))
169 rc
= lxc_read_from_file(path
, buf
, sizeof(buf
));
173 rx_bytes
= str_size_humanize(buf
, sizeof(buf
));
174 printf("%-15s %s\n", " TX bytes:", buf
);
178 rc
= snprintf(path
, sizeof(path
), "/sys/class/net/%s/statistics/tx_bytes", ifname
);
179 if (rc
< 0 || (size_t)rc
>= sizeof(path
))
182 rc
= lxc_read_from_file(path
, buf
, sizeof(buf
));
186 tx_bytes
= str_size_humanize(buf
, sizeof(buf
));
187 printf("%-15s %s\n", " RX bytes:", buf
);
191 sprintf(buf
, "%llu", rx_bytes
+ tx_bytes
);
192 str_size_humanize(buf
, sizeof(buf
));
193 printf("%-15s %s\n", " Total bytes:", buf
);
199 static void print_stats(struct lxc_container
*c
)
204 ret
= c
->get_cgroup_item(c
, "cpuacct.usage", buf
, sizeof(buf
));
205 if (ret
> 0 && (size_t)ret
< sizeof(buf
)) {
208 float seconds
= strtof(buf
, NULL
) / 1000000000.0;
209 printf("%-15s %.2f seconds\n", "CPU use:", seconds
);
211 printf("%-15s %s\n", "CPU use:", buf
);
216 ret
= c
->get_cgroup_item(c
, "blkio.throttle.io_service_bytes", buf
, sizeof(buf
));
217 if (ret
> 0 && (size_t)ret
< sizeof(buf
)) {
220 /* put ch on last "Total" line */
222 for(ch
= &buf
[strlen(buf
)-1]; ch
> buf
&& *ch
!= '\n'; ch
--)
227 if (strncmp(ch
, "Total", 5) == 0) {
229 memmove(buf
, ch
, strlen(ch
)+1);
230 str_size_humanize(buf
, sizeof(buf
));
231 printf("%-15s %s\n", "BlkIO use:", buf
);
236 static const struct {
240 { "Memory use:", "memory.usage_in_bytes" },
241 { "KMem use:", "memory.kmem.usage_in_bytes" },
245 for (i
= 0; lxstat
[i
].name
; i
++) {
246 ret
= c
->get_cgroup_item(c
, lxstat
[i
].file
, buf
, sizeof(buf
));
247 if (ret
> 0 && (size_t)ret
< sizeof(buf
)) {
249 str_size_humanize(buf
, sizeof(buf
));
250 printf("%-15s %s\n", lxstat
[i
].name
, buf
);
256 static void print_info_msg_int(const char *k
, int value
)
259 printf("%-15s %d\n", k
, value
);
261 if (filter_count
== 1)
262 printf("%d\n", value
);
264 printf("%-15s %d\n", k
, value
);
269 static void print_info_msg_str(const char *k
, const char *value
)
272 printf("%-15s %s\n", k
, value
);
274 if (filter_count
== 1)
275 printf("%s\n", value
);
277 printf("%-15s %s\n", k
, value
);
282 static int print_info(const char *name
, const char *lxcpath
)
285 struct lxc_container
*c
;
287 c
= lxc_container_new(name
, lxcpath
);
289 fprintf(stderr
, "Failure to retrieve information on %s:%s\n", lxcpath
? lxcpath
: "null",
290 name
? name
: "null");
294 if (my_args
.rcfile
) {
297 if (!c
->load_config(c
, my_args
.rcfile
)) {
298 fprintf(stderr
, "Failed to load rcfile\n");
299 lxc_container_put(c
);
303 c
->configfile
= strdup(my_args
.rcfile
);
304 if (!c
->configfile
) {
305 fprintf(stderr
, "Out of memory setting new config filename\n");
306 lxc_container_put(c
);
311 if (!c
->may_control(c
)) {
312 fprintf(stderr
, "Insufficent privileges to control %s\n", c
->name
);
313 lxc_container_put(c
);
317 if (!c
->is_running(c
) && !c
->is_defined(c
)) {
318 fprintf(stderr
, "%s doesn't exist\n", c
->name
);
319 lxc_container_put(c
);
323 if (!state
&& !pid
&& !ips
&& !stats
&& nr_keys
<= 0) {
324 state
= pid
= ips
= stats
= true;
325 print_info_msg_str("Name:", c
->name
);
329 print_info_msg_str("State:", c
->state(c
));
331 if (c
->is_running(c
)) {
335 initpid
= c
->init_pid(c
);
337 print_info_msg_int("PID:", initpid
);
343 char **addresses
= c
->get_ips(c
, NULL
, NULL
, 0);
348 while (addresses
[i
]) {
349 address
= addresses
[i
];
350 print_info_msg_str("IP:", address
);
362 for(i
= 0; i
< nr_keys
; i
++) {
363 int len
= c
->get_config_item(c
, key
[i
], NULL
, 0);
366 char *val
= (char*) malloc(sizeof(char)*len
+ 1);
368 if (c
->get_config_item(c
, key
[i
], val
, len
+ 1) != len
) {
369 fprintf(stderr
, "unable to read %s from configuration\n", key
[i
]);
371 if (!humanize
&& nr_keys
== 1)
374 printf("%s = %s\n", key
[i
], val
);
378 } else if (len
== 0) {
379 if (!humanize
&& nr_keys
== 1)
382 printf("%s =\n", key
[i
]);
384 fprintf(stderr
, "%s invalid\n", key
[i
]);
389 lxc_container_put(c
);
393 int main(int argc
, char *argv
[])
395 int ret
= EXIT_FAILURE
;
398 if (lxc_arguments_parse(&my_args
, argc
, argv
))
401 /* Only create log if explicitly instructed */
402 if (my_args
.log_file
|| my_args
.log_priority
) {
403 log
.name
= my_args
.name
;
404 log
.file
= my_args
.log_file
;
405 log
.level
= my_args
.log_priority
;
406 log
.prefix
= my_args
.progname
;
407 log
.quiet
= my_args
.quiet
;
408 log
.lxcpath
= my_args
.lxcpath
[0];
410 if (lxc_log_init(&log
))
414 if (print_info(my_args
.name
, my_args
.lxcpath
[0]) == 0)