5de205a5522edc402fc4a1eded177f82eb2b842b
[virt-kernel-info.git] / src / main.c
1 /* Kernel info for virtual domains.
2  * (C) Copyright 2008-2010 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <getopt.h>
27
28 #include <libvirt/libvirt.h>
29 #include <libvirt/virterror.h>
30
31 #include "internal.h"
32
33 /* Global flags. */
34 int csv = 0;
35 int debug = 0;
36
37 /* Linked list of registered tools. */
38 static struct tool *tools = NULL;
39
40 /* Currently selected tool (may be NULL). */
41 struct tool *tool = NULL;
42
43 /* External DB location. */
44 static const char *externaldb = DATADIR "/" PACKAGE_NAME "/kerneldb";
45 static int fail_if_no_externaldb = 0;
46
47 /* URI and libvirt connection. */
48 static const char *uri = NULL;
49 static virConnectPtr conn = NULL;
50
51 /* If -t option was passed, this is the filename of the test image. */
52 static const char *test_image = NULL;
53
54 /* If --list-kernels was passed. */
55 static int list_kernels = 0;
56
57 /* Local functions. */
58 static void load_externaldb (const char *, int);
59 static void do_list_kernels (void) ATTRIBUTE_NORETURN;
60 static void usage (void) ATTRIBUTE_NORETURN;
61
62 static virDomainPtr *get_named_domains (char * const*, int);
63 static virDomainPtr *get_all_domains (void);
64
65 int
66 main (int argc, char *argv[])
67 {
68   int c;
69
70   /* argv[0] can be the name of the tool, or if not recognized then
71    * the name of the tool must be the first anonymous argument.
72    */
73   if (argv[0]) {
74     const char *prog = strrchr (argv[0], '/');
75
76     if (!prog)
77       prog = argv[0];
78
79     if (STRCASEEQLEN (prog+1, "virt-", 5)) {
80       struct tool *t;
81
82       prog += 6;
83
84       for (t = tools; t != NULL; t = t->next) {
85         if (STRCASEEQ (prog, t->name)) {
86           tool = t;
87           break;
88         }
89       }
90     }
91   }
92
93   /* Parse command line parameters. */
94   while (1) {
95     static const char *shortopts = "A:E:T:W:c:dt:x:?";
96     static struct option longopts[] = {
97       { "arch", required_argument, 0, 'A' },
98       { "endian", required_argument, 0, 'E' },
99       { "kernel-min", required_argument, 0, 0 },
100       { "kernel-max", required_argument, 0, 0 },
101       { "text", required_argument, 0, 'T' },
102       { "wordsize", required_argument, 0, 'W' },
103       { "connect", required_argument, 0, 'c' },
104       { "csv", no_argument, 0, 0 },
105       { "debug", no_argument, 0, 'd' },
106       { "help", no_argument, 0, '?' },
107       { "list-kernels", no_argument, 0, 0 },
108       { "image", required_argument, 0, 't' },
109       { "externaldb", required_argument, 0, 'x' },
110       { "version", no_argument, 0, 0 }
111     };
112     int option_index = 0;
113
114     c = getopt_long (argc, argv, shortopts, longopts, &option_index);
115     if (c == -1) break;
116
117     switch (c) {
118     case 0: {                   /* longopt without short equivalent */
119       const char *longopt_name = longopts[option_index].name;
120
121       if (STRCASEEQ (longopt_name, "csv")) /* csv output */
122         csv = 1;
123                                 /* list kernels and exit */
124       else if (STRCASEEQ (longopt_name, "list-kernels"))
125         list_kernels = 1;
126                                 /* set kernel-min */
127       else if (STRCASEEQ (longopt_name, "kernel-min"))
128         NOT_IMPL;
129                                 /* set kernel-max */
130       else if (STRCASEEQ (longopt_name, "kernel-max"))
131         NOT_IMPL;
132                                 /* display version and exit */
133       else if (STRCASEEQ (longopt_name, "version")) {
134         printf ("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
135         exit (0);
136       }
137       else
138         INTERNAL_ERROR;         /* this shouldn't happen */
139
140       break;
141     }
142
143     case 'A':                   /* set architecture */
144       NOT_IMPL;
145     case 'E':                   /* set endianness */
146       NOT_IMPL;
147     case 'T':                   /* set text address */
148       NOT_IMPL;
149     case 'W':                   /* set wordsize */
150       NOT_IMPL;
151
152     case 'c':                   /* connect to URI */
153       uri = optarg;
154       break;
155
156     case 'd':                   /* enable debugging */
157       debug = 1;
158       break;
159
160     case 't':                   /* load kernel image */
161       test_image = optarg;
162       break;
163
164     case 'x':                   /* location of external database */
165       externaldb = optarg;
166       fail_if_no_externaldb = 1;
167       break;
168
169     case '?':                   /* print help */
170       usage ();
171
172     default:
173       INTERNAL_ERROR;           /* this shouldn't happen */
174     }
175   } /* while */
176
177   /* Load the external database / kernel updates, if necessary. */
178   load_externaldb (externaldb, fail_if_no_externaldb);
179
180   /* If asked, list kernels and exit. */
181   if (list_kernels)
182     do_list_kernels ();
183
184   /* If we haven't got a tool name yet, then the first anon parameter
185    * must be a tool name.
186    */
187   if (!tool) {
188     if (optind < argc) {
189       const char *p;
190       struct tool *t;
191
192       p = argv[optind++];
193
194       for (t = tools; t != NULL; t = t->next) {
195         if (STRCASEEQ (p, t->name)) {
196           tool = t;
197           goto found_tool;
198         }
199       }
200
201       error (_("'%s' is not a recognized virt-kernel-info tool.\n\nMake sure you specify the virt-kernel-info tool as the first argument on the command line.  To get a list of recognized tools, use 'virt-kernel-info --help'."), p);
202     } else
203       error (_("Could not work out which virt-kernel-info tool you are trying to use.\n\nMake sure you specify the virt-kernel-info tool as the first argument on the command line.  To get a list of recognized tools, use 'virt-kernel-info --help'."));
204
205   found_tool: ;
206   }
207
208   /* We should have worked out which tool it is by now. */
209   assert (tool != NULL);
210
211   /* If -t was passed, then we load that forensic image, else we have
212    * to connect to libvirt.
213    */
214   if (test_image) {
215     if (optind < argc)
216       error (_("If '-t' is passed then there shouldn't be any additional command line arguments."));
217
218     NOT_IMPL;
219   }
220   else {
221     virDomainPtr *doms;
222
223     /* Connect to libvirt. */
224     conn = virConnectOpenReadOnly (uri);
225     if (!conn)
226       error (_("failed to connect to hypervisor '%s'.\nWhen connecting to some hypervisors you may need to be running as root.\nThere may be a more detailed error message above this, but if not then we didn't print one because libvirt's virterror mechanism is next to useless."),
227              uri != NULL ? uri : _("default"));
228
229     /* Extra parameters are a list of domain names, IDs or UUIDs. */
230     if (optind < argc)
231       doms = get_named_domains (&argv[optind], argc - optind);
232     else
233       doms = get_all_domains ();
234
235     /* Act on each domain. */
236     NOT_IMPL;
237   }
238
239   exit (0);
240 }
241
242 /* Usage. */
243 static void usage (void)
244 {
245   struct tool *t;
246
247   printf (_("\
248 virt-kernel-info: Tools for providing information about virtual machines\n\
249 \n\
250 General usage is:\n\
251   <tool> [-options]\n\
252   <tool> [-options] [domain-name|ID|UUID ...]\n\
253   <tool> [-options] -t <image>\n\
254 where <tool> is 'virt-ps', 'virt-dmesg' etc. (full list below) or a\n\
255 subtool such as 'virt-kernel-info ps', 'virt-kernel-info capture' etc.\n\
256 \n\
257 General options:\n\
258   --connect | -c <libvirt-uri>   Connect to URI (default: autodetect)\n\
259   --csv                          Output in CSV format for spreadsheets etc.\n\
260   --debug                        Print extra debugging information\n\
261   --list-kernels                 List known kernels, then exit\n\
262   --image | -t <image>           Examine saved image (see: virt-kernel-info capture)\n\
263   --externaldb | -x <externaldb> Load/override external kernels database\n\
264   --version                      Print program name and version, then exit\n\
265 \n\
266 These options may be used to override automatic detection of guest\n\
267 architecture, endianness, kernel location, etc.:\n\
268   -A | --arch      auto | <arch> | ...\n\
269   -E | --endian    auto | le | be\n\
270   --kernel-min     auto | <arch> | ... | 0x<addr>\n\
271   --kernel-max     auto | <arch> | ... | 0x<addr>\n\
272   -T | --text      auto | <arch> | ... | 0x<addr>\n\
273   -W | --wordsize  auto | 32 | 64\n\
274 where <arch> is the name of an architecture such as i386, x86-64, etc.\n\
275 \n\
276 List of tools:\n\
277 "));
278
279   for (t = tools; t != NULL; t = t->next) {
280     printf ("\n");
281
282     if (t->external_cmd)
283       printf ("  virt-%-12s - %s\n", t->name, t->summary);
284     else
285       printf ("  virt-kernel-info %8s - %s\n", t->name, t->summary);
286
287     printf ("%s", t->description);
288     if (t->next) printf ("\n");
289   }
290
291   exit (0);
292 }
293
294 static void
295 load_externaldb (const char *externaldb, int fail_if_no_externaldb)
296 {
297
298
299
300
301
302
303
304
305   NOT_IMPL;
306 }
307
308 static void
309 do_list_kernels (void)
310 {
311   NOT_IMPL;
312 }
313
314 static virDomainPtr *
315 get_named_domains (char * const *domains, int nr_domains)
316 {
317   NOT_IMPL;
318 }
319
320 static virDomainPtr *
321 get_all_domains (void)
322 {
323   NOT_IMPL;
324 }
325
326 /* Tools register themselves by calling this function.  Note that the
327  * function is called from constructors.  In particular it is called
328  * before main().  Also can be called in unspecified order.
329  */
330 void
331 register_tool (struct tool *tool)
332 {
333   struct tool *t, **p;
334
335   /* Insertion sort. */
336   p = &tools;
337   for (t = tools; t != NULL; t = t->next) {
338     if (strcmp (t->name, tool->name) < 0)
339       goto insert;
340     p = &t->next;
341   }
342  insert:
343   tool->next = *p;
344   *p = tool;
345 }
346
347 /* Warning, error message functions.  See internal.h for usage. */
348 static void
349 message (const char *pre, const char *fs, va_list args)
350 {
351   fprintf (stderr, "%s-%s: %s: ", PACKAGE_NAME, PACKAGE_VERSION, pre);
352   vfprintf (stderr, fs, args);
353   fprintf (stderr, "\n");
354 }
355
356 void
357 error (const char *fs, ...)
358 {
359   va_list args;
360   va_start (args, fs);
361   message (_("error"), fs, args);
362   va_end (args);
363   exit (1);
364 }
365
366 void
367 warning (const char *fs, ...)
368 {
369   va_list args;
370   va_start (args, fs);
371   message (_("warning"), fs, args);
372   va_end (args);
373 }
374
375 void
376 internal_error (const char *fs, ...)
377 {
378   va_list args;
379   va_start (args, fs);
380   message (_("internal error"), fs, args);
381   va_end (args);
382   abort ();
383 }