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