]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxc_info.c
Fix grammar in some of the executables
[mirror_lxc.git] / src / lxc / lxc_info.c
CommitLineData
0ad19a3f 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
0ad19a3f 8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0ad19a3f 22 */
211e51e8 23
0ad19a3f 24#include <stdio.h>
5d42011a 25#include <stdbool.h>
ef6e34ee 26#include <stdlib.h>
0ad19a3f 27#include <unistd.h>
b9d957c3 28#include <limits.h>
0ad19a3f 29#include <libgen.h>
30#include <sys/types.h>
31
a9ac16e2 32#include <lxc/lxccontainer.h>
f549edcc 33
f2363e38
ÇO
34#include "lxc.h"
35#include "log.h"
36#include "utils.h"
f549edcc 37#include "commands.h"
4237c6ca 38#include "arguments.h"
0ad19a3f 39
6ea518f6
SG
40lxc_log_define(lxc_info_ui, lxc);
41
211e51e8 42static bool ips;
5d42011a
DL
43static bool state;
44static bool pid;
b9d957c3
DE
45static bool stats;
46static bool humanize = true;
9c631ea7
DE
47static char **key = NULL;
48static int keys = 0;
5444216b 49static int filter_count = 0;
5d42011a
DL
50
51static int my_parser(struct lxc_arguments* args, int c, char* arg)
52{
5135b555 53 char **newk;
5d42011a 54 switch (c) {
9c631ea7 55 case 'c':
5135b555
SH
56 newk = realloc(key, keys+1 * sizeof(key[0]));
57 if (!newk)
58 return -1;
59 key = newk;
9c631ea7
DE
60 key[keys] = arg;
61 keys++;
62 break;
5444216b
SG
63 case 'i': ips = true; filter_count += 1; break;
64 case 's': state = true; filter_count += 1; break;
65 case 'p': pid = true; filter_count += 1; break;
66 case 'S': stats = true; filter_count += 5; break;
b9d957c3 67 case 'H': humanize = false; break;
5d42011a
DL
68 }
69 return 0;
70}
71
4237c6ca 72static const struct option my_longopts[] = {
9c631ea7 73 {"config", required_argument, 0, 'c'},
211e51e8 74 {"ips", no_argument, 0, 'i'},
5d42011a
DL
75 {"state", no_argument, 0, 's'},
76 {"pid", no_argument, 0, 'p'},
b9d957c3
DE
77 {"stats", no_argument, 0, 'S'},
78 {"no-humanize", no_argument, 0, 'H'},
5d42011a 79 LXC_COMMON_OPTIONS,
4237c6ca
MN
80};
81
82static struct lxc_arguments my_args = {
83 .progname = "lxc-info",
84 .help = "\
85--name=NAME\n\
86\n\
5d42011a 87lxc-info display some information about a container with the identifier NAME\n\
4237c6ca
MN
88\n\
89Options :\n\
5e8757ed 90 -n, --name=NAME NAME of the container\n\
9c631ea7 91 -c, --config=KEY show configuration variable KEY from running container\n\
211e51e8 92 -i, --ips shows the IP addresses\n\
b917ef75 93 -p, --pid shows the process id of the init container\n\
b9d957c3
DE
94 -S, --stats shows usage stats\n\
95 -H, --no-humanize shows stats as raw numbers, not humanized\n\
5444216b
SG
96 -s, --state shows the state of the container\n",
97 .name = NULL,
4237c6ca 98 .options = my_longopts,
5d42011a 99 .parser = my_parser,
4237c6ca
MN
100 .checker = NULL,
101};
0ad19a3f 102
b9d957c3 103static void str_chomp(char *buf)
0ad19a3f 104{
b9d957c3 105 char *ch;
0ad19a3f 106
b9d957c3
DE
107 /* remove trailing whitespace from buf */
108 for(ch = &buf[strlen(buf)-1];
109 ch >= buf && (*ch == '\t' || *ch == '\n' || *ch == ' ');
110 ch--)
111 *ch = '\0';
112}
a9ac16e2 113
b9d957c3
DE
114static void size_humanize(unsigned long long val, char *buf, size_t bufsz)
115{
116 if (val > 1 << 30) {
117 snprintf(buf, bufsz, "%u.%2.2u GiB",
118 (int)(val >> 30),
119 (int)(val & ((1 << 30) - 1)) / 10737419);
120 } else if (val > 1 << 20) {
121 int x = val + 5243; /* for rounding */
122 snprintf(buf, bufsz, "%u.%2.2u MiB",
123 x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
124 } else if (val > 1 << 10) {
125 int x = val + 5; /* for rounding */
126 snprintf(buf, bufsz, "%u.%2.2u KiB",
127 x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
128 } else {
129 snprintf(buf, bufsz, "%u bytes", (int)val);
130 }
131}
0ad19a3f 132
b9d957c3
DE
133static unsigned long long str_size_humanize(char *iobuf, size_t iobufsz)
134{
135 unsigned long long val;
136 char *end = NULL;
f5abd74d 137
b9d957c3
DE
138 val = strtoull(iobuf, &end, 0);
139 if (humanize) {
140 if (*end == '\0' || *end == '\n')
141 size_humanize(val, iobuf, iobufsz);
142 else
143 *iobuf = '\0';
144 }
145 return val;
146}
147
8ac18377 148static void print_net_stats(struct lxc_container *c)
b9d957c3
DE
149{
150 int rc,netnr;
151 unsigned long long rx_bytes = 0, tx_bytes = 0;
152 char *ifname, *type;
153 char path[PATH_MAX];
154 char buf[256];
155
156 for(netnr = 0; ;netnr++) {
157 sprintf(buf, "lxc.network.%d.type", netnr);
8ac18377 158 type = c->get_running_config_item(c, buf);
b9d957c3
DE
159 if (!type)
160 break;
a9ac16e2 161
b9d957c3
DE
162 if (!strcmp(type, "veth")) {
163 sprintf(buf, "lxc.network.%d.veth.pair", netnr);
164 } else {
165 sprintf(buf, "lxc.network.%d.link", netnr);
166 }
167 free(type);
8ac18377 168 ifname = c->get_running_config_item(c, buf);
b9d957c3
DE
169 if (!ifname)
170 return;
171 printf("%-15s %s\n", "Link:", ifname);
d52f2fd3 172 fflush(stdout);
b9d957c3
DE
173
174 /* XXX: tx and rx are reversed from the host vs container
175 * perspective, print them from the container perspective
176 */
177 snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/rx_bytes", ifname);
178 rc = lxc_read_from_file(path, buf, sizeof(buf));
179 if (rc > 0) {
180 str_chomp(buf);
181 rx_bytes = str_size_humanize(buf, sizeof(buf));
182 printf("%-15s %s\n", " TX bytes:", buf);
d52f2fd3 183 fflush(stdout);
b9d957c3
DE
184 }
185
186 snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/tx_bytes", ifname);
187 rc = lxc_read_from_file(path, buf, sizeof(buf));
188 if (rc > 0) {
189 str_chomp(buf);
190 tx_bytes = str_size_humanize(buf, sizeof(buf));
191 printf("%-15s %s\n", " RX bytes:", buf);
d52f2fd3 192 fflush(stdout);
b9d957c3
DE
193 }
194
195 sprintf(buf, "%llu", rx_bytes + tx_bytes);
196 str_size_humanize(buf, sizeof(buf));
197 printf("%-15s %s\n", " Total bytes:", buf);
d52f2fd3 198 fflush(stdout);
b9d957c3
DE
199 free(ifname);
200 }
201}
202
203static void print_stats(struct lxc_container *c)
204{
205 int i, ret;
206 char buf[256];
207
208 ret = c->get_cgroup_item(c, "cpuacct.usage", buf, sizeof(buf));
209 if (ret > 0 && ret < sizeof(buf)) {
210 str_chomp(buf);
211 if (humanize) {
212 float seconds = strtof(buf, NULL) / 1000000000.0;
213 printf("%-15s %.2f seconds\n", "CPU use:", seconds);
214 } else {
215 printf("%-15s %s\n", "CPU use:", buf);
216 }
d52f2fd3 217 fflush(stdout);
b9d957c3
DE
218 }
219
220 ret = c->get_cgroup_item(c, "blkio.throttle.io_service_bytes", buf, sizeof(buf));
221 if (ret > 0 && ret < sizeof(buf)) {
222 char *ch;
223
224 /* put ch on last "Total" line */
225 str_chomp(buf);
226 for(ch = &buf[strlen(buf)-1]; ch > buf && *ch != '\n'; ch--)
227 ;
228 if (*ch == '\n')
229 ch++;
230
231 if (strncmp(ch, "Total", 5) == 0) {
232 ch += 6;
233 memmove(buf, ch, strlen(ch)+1);
234 str_size_humanize(buf, sizeof(buf));
235 printf("%-15s %s\n", "BlkIO use:", buf);
236 }
d52f2fd3 237 fflush(stdout);
b9d957c3
DE
238 }
239
240 static const struct {
241 const char *name;
242 const char *file;
243 } lxstat[] = {
244 { "Memory use:", "memory.usage_in_bytes" },
245 { "KMem use:", "memory.kmem.usage_in_bytes" },
246 { NULL, NULL },
247 };
248
249 for (i = 0; lxstat[i].name; i++) {
250 ret = c->get_cgroup_item(c, lxstat[i].file, buf, sizeof(buf));
251 if (ret > 0 && ret < sizeof(buf)) {
252 str_chomp(buf);
253 str_size_humanize(buf, sizeof(buf));
254 printf("%-15s %s\n", lxstat[i].name, buf);
d52f2fd3 255 fflush(stdout);
b9d957c3
DE
256 }
257 }
258}
259
74a3920a 260static void print_info_msg_int(const char *key, int value)
5444216b
SG
261{
262 if (humanize)
263 printf("%-15s %d\n", key, value);
264 else {
265 if (filter_count == 1)
266 printf("%d\n", value);
267 else
268 printf("%-15s %d\n", key, value);
269 }
d52f2fd3 270 fflush(stdout);
5444216b
SG
271}
272
74a3920a 273static void print_info_msg_str(const char *key, const char *value)
5444216b
SG
274{
275 if (humanize)
276 printf("%-15s %s\n", key, value);
277 else {
278 if (filter_count == 1)
279 printf("%s\n", value);
280 else
281 printf("%-15s %s\n", key, value);
282 }
d52f2fd3 283 fflush(stdout);
5444216b
SG
284}
285
b9d957c3
DE
286static int print_info(const char *name, const char *lxcpath)
287{
288 int i;
289 struct lxc_container *c;
290
291 c = lxc_container_new(name, lxcpath);
5444216b 292 if (!c) {
915614c7
SH
293 fprintf(stderr, "Failure to retrieve information on %s:%s\n", lxcpath ? lxcpath : "null",
294 name ? name : "null");
a9ac16e2 295 return -1;
5444216b 296 }
51cab631 297
f5abd74d
SG
298 if (!c->may_control(c)) {
299 fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
f3e52710 300 lxc_container_put(c);
f5abd74d
SG
301 return -1;
302 }
303
5444216b
SG
304 if (!c->is_running(c) && !c->is_defined(c)) {
305 fprintf(stderr, "%s doesn't exist\n", c->name);
306 lxc_container_put(c);
307 return -1;
308 }
5d42011a 309
5444216b
SG
310 if (!state && !pid && !ips && !stats && keys <= 0) {
311 state = pid = ips = stats = true;
312 print_info_msg_str("Name:", c->name);
313 }
5d42011a 314
5444216b
SG
315 if (state) {
316 print_info_msg_str("State:", c->state(c));
5d42011a 317 }
0ad19a3f 318
2177dbc7
SG
319 if (c->is_running(c)) {
320 if (pid) {
321 pid_t initpid;
ef6e34ee 322
2177dbc7
SG
323 initpid = c->init_pid(c);
324 if (initpid >= 0)
325 print_info_msg_int("PID:", initpid);
326 }
211e51e8 327
2177dbc7 328 if (ips) {
e2426f0b 329 fflush(stdout);
2177dbc7
SG
330 char **addresses = c->get_ips(c, NULL, NULL, 0);
331 if (addresses) {
332 char *address;
333 i = 0;
334 while (addresses[i]) {
335 address = addresses[i];
336 print_info_msg_str("IP:", address);
337 i++;
338 }
bd79cb22 339 }
211e51e8 340 }
ef6e34ee 341 }
0ad19a3f 342
b9d957c3
DE
343 if (stats) {
344 print_stats(c);
8ac18377 345 print_net_stats(c);
b9d957c3
DE
346 }
347
9c631ea7 348 for(i = 0; i < keys; i++) {
a9ac16e2
SG
349 int len = c->get_config_item(c, key[i], NULL, 0);
350
2eee1b96 351 if (len > 0) {
a9ac16e2 352 char *val = (char*) malloc(sizeof(char)*len + 1);
9c631ea7 353
a9ac16e2
SG
354 if (c->get_config_item(c, key[i], val, len + 1) != len) {
355 fprintf(stderr, "unable to read %s from configuration\n", key[i]);
356 } else {
44fa8e7e
SG
357 if (!humanize && keys == 1)
358 printf("%s\n", val);
359 else
360 printf("%s = %s\n", key[i], val);
a9ac16e2 361 }
9c631ea7 362 free(val);
2eee1b96 363 } else if (len == 0) {
44fa8e7e
SG
364 if (!humanize && keys == 1)
365 printf("\n");
366 else
367 printf("%s =\n", key[i]);
9c631ea7 368 } else {
2eee1b96 369 fprintf(stderr, "%s invalid\n", key[i]);
9c631ea7 370 }
d52f2fd3 371 fflush(stdout);
9c631ea7
DE
372 }
373
f3e52710 374 lxc_container_put(c);
0ad19a3f 375 return 0;
376}
b9d957c3
DE
377
378int main(int argc, char *argv[])
379{
5444216b 380 int ret = EXIT_FAILURE;
b9d957c3
DE
381
382 if (lxc_arguments_parse(&my_args, argc, argv))
5444216b 383 return ret;
b9d957c3
DE
384
385 if (!my_args.log_file)
386 my_args.log_file = "none";
387
388 if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
389 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
5444216b 390 return ret;
6edbfc86 391 lxc_log_options_no_override();
b9d957c3 392
5444216b
SG
393 if (print_info(my_args.name, my_args.lxcpath[0]) == 0)
394 ret = EXIT_SUCCESS;
b9d957c3 395
b9d957c3
DE
396 return ret;
397}