Don't fail if HOSTNAME field is missing on Red Hat guests (RHBZ#726739).
[libguestfs.git] / fish / prep.c
1 /* guestfish - the filesystem interactive shell
2  * Copyright (C) 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 <unistd.h>
26
27 #include "fish.h"
28 #include "prepopts.h"
29
30 static prep_data *parse_type_string (const char *type_string);
31
32 void
33 list_prepared_drives (void)
34 {
35   size_t i, j;
36
37   printf (_("List of available prepared disk images:\n\n"));
38
39   for (i = 0; i < NR_PREPS; ++i) {
40     printf (_("\
41 guestfish -N %-8s - %s\n\
42 \n\
43 %s\n"),
44             preps[i].name, preps[i].shortdesc, preps[i].longdesc);
45
46     if (preps[i].nr_params > 0) {
47       printf ("\n");
48       printf (_("  Optional parameters:\n"));
49       printf ("    -N %s", preps[i].name);
50       for (j = 0; j < preps[i].nr_params; ++j)
51         printf (":<%s>", preps[i].params[j].pname);
52       printf ("\n");
53       for (j = 0; j < preps[i].nr_params; ++j) {
54         printf ("      ");
55         printf (_("<%s> %s (default: %s)\n"),
56                 preps[i].params[j].pname,
57                 preps[i].params[j].pdesc,
58                 preps[i].params[j].pdefault);
59       }
60     }
61
62     printf ("\n");
63   }
64
65   printf (_("\
66 Prepared disk images are written to file \"test1.img\" in the local\n\
67 directory.  (\"test2.img\" etc if -N option is given multiple times).\n\
68 For more information see the guestfish(1) manual.\n"));
69 }
70
71 /* Parse the type string (from the command line) and create the output
72  * file 'filename'.  This is called before launch.  Return the opaque
73  * prep_data which will be passed back to us in prepare_drive below.
74  */
75 prep_data *
76 create_prepared_file (const char *type_string, const char *filename)
77 {
78   prep_data *data = parse_type_string (type_string);
79   if (data->prep->prelaunch)
80     data->prep->prelaunch (filename, data);
81   return data;
82 }
83
84 static prep_data *
85 parse_type_string (const char *type_string)
86 {
87   size_t i;
88
89   /* Match on the type part (without parameters). */
90   size_t len = strcspn (type_string, ":");
91   for (i = 0; i < NR_PREPS; ++i)
92     if (STRCASEEQLEN (type_string, preps[i].name, len))
93       break;
94
95   if (i == NR_PREPS) {
96     fprintf (stderr, _("\
97 guestfish: -N parameter '%s': no such prepared disk image known.\n\
98 Use 'guestfish -N help' to list possible values for the -N parameter.\n"),
99              type_string);
100     exit (EXIT_FAILURE);
101   }
102
103   prep_data *data = malloc (sizeof *data);
104   if (data == NULL) {
105     perror ("malloc");
106     exit (EXIT_FAILURE);
107   }
108   data->prep = &preps[i];
109   data->orig_type_string = type_string;
110
111   /* Set up the optional parameters to all-defaults. */
112   data->params = malloc (data->prep->nr_params * sizeof (char *));
113   if (data->params == NULL) {
114     perror ("malloc");
115     exit (EXIT_FAILURE);
116   }
117
118   for (i = 0; i < data->prep->nr_params; ++i)
119     data->params[i] = bad_cast (data->prep->params[i].pdefault);
120
121   /* Parse the optional parameters. */
122   const char *p = type_string + len;
123   if (*p) p++; /* skip colon char */
124
125   i = 0;
126   while (*p) {
127     len = strcspn (p, ":");
128     data->params[i] = strndup (p, len);
129     if (data->params[i] == NULL) {
130       perror ("strndup");
131       exit (EXIT_FAILURE);
132     }
133
134     p += len;
135     if (*p) p++; /* skip colon char */
136     i++;
137   }
138
139   return data;
140 }
141
142 /* Prepare a drive.  The appliance has been launched, and 'device' is
143  * the libguestfs device.  'data' is the requested type.  'filename'
144  * is just used for error messages.
145  */
146 void
147 prepare_drive (const char *filename, prep_data *data,
148                const char *device)
149 {
150   if (data->prep->postlaunch)
151     data->prep->postlaunch (filename, data, device);
152 }
153
154 void
155 prep_error (prep_data *data, const char *filename, const char *fs, ...)
156 {
157   fprintf (stderr,
158            _("guestfish: error creating prepared disk image '%s' on '%s': "),
159            data->orig_type_string, filename);
160
161   va_list args;
162   va_start (args, fs);
163   vfprintf (stderr, fs, args);
164   va_end (args);
165
166   fprintf (stderr, "\n");
167
168   exit (EXIT_FAILURE);
169 }
170
171 void
172 free_prep_data (void *vp)
173 {
174   prep_data *data = vp;
175   size_t i;
176
177   for (i = 0; i < data->prep->nr_params; ++i)
178     if (data->params[i] != data->prep->params[i].pdefault)
179       free (data->params[i]);
180   free (data->params);
181   free (data);
182 }