f194008f324ed582e5d97682d6d777f6c66cfd7a
[febootstrap.git] / helper / main.c
1 /* febootstrap-supermin-helper reimplementation in C.
2  * Copyright (C) 2009-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 <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <getopt.h>
27 #include <limits.h>
28 #include <sys/types.h>
29 #include <sys/time.h>
30 #include <assert.h>
31
32 #include "error.h"
33
34 #include "helper.h"
35
36 struct timeval start_t;
37 int verbose = 0;
38
39 static const char *format = "cpio";
40
41 enum { HELP_OPTION = CHAR_MAX + 1 };
42
43 static const char *options = "f:k:vV";
44 static const struct option long_options[] = {
45   { "help", 0, 0, HELP_OPTION },
46   { "format", required_argument, 0, 'f' },
47   { "kmods", required_argument, 0, 'k' },
48   { "verbose", 0, 0, 'v' },
49   { "version", 0, 0, 'V' },
50   { 0, 0, 0, 0 }
51 };
52
53 static void
54 usage (FILE *f, const char *progname)
55 {
56   fprintf (f,
57           "%s: build the supermin appliance on the fly\n"
58           "\n"
59           "Usage:\n"
60           "  %s [-options] inputs [...] host_cpu kernel initrd\n"
61           "  %s -f ext2 inputs [...] host_cpu kernel initrd appliance\n"
62           "  %s -f checksum inputs [...] host_cpu\n"
63           "  %s --help\n"
64           "  %s --version\n"
65           "\n"
66           "This script is used by febootstrap to build the supermin appliance\n"
67           "(kernel and initrd output files).  You should NOT need to run this\n"
68           "program directly except if you are debugging tricky supermin\n"
69           "appliance problems.\n"
70           "\n"
71           "NB: The kernel and initrd parameters are OUTPUT parameters.  If\n"
72           "those files exist, they are overwritten by the output.\n"
73           "\n"
74           "Options:\n"
75           "  --help\n"
76           "       Display this help text and exit.\n"
77           "  -f cpio|ext2|checksum | --format cpio|ext2|checksum\n"
78           "       Specify output format (default: cpio).\n"
79           "  -k file | --kmods file\n"
80           "       Specify kernel module whitelist.\n"
81           "  --verbose | -v\n"
82           "       Enable verbose messages (give multiple times for more verbosity).\n"
83           "  --version | -V\n"
84           "       Display version number and exit.\n",
85           progname, progname, progname, progname, progname, progname);
86 }
87
88 int
89 main (int argc, char *argv[])
90 {
91   /* First thing: start the clock. */
92   gettimeofday (&start_t, NULL);
93
94   const char *whitelist = NULL;
95
96   /* Command line arguments. */
97   for (;;) {
98     int c = getopt_long (argc, argv, options, long_options, NULL);
99     if (c == -1) break;
100
101     switch (c) {
102     case HELP_OPTION:
103       usage (stdout, argv[0]);
104       exit (EXIT_SUCCESS);
105
106     case 'f':
107       format = optarg;
108       break;
109
110     case 'k':
111       whitelist = optarg;
112       break;
113
114     case 'v':
115       verbose++;
116       break;
117
118     case 'V':
119       printf (PACKAGE_NAME " " PACKAGE_VERSION "\n");
120       exit (EXIT_SUCCESS);
121
122     default:
123       usage (stderr, argv[0]);
124       exit (EXIT_FAILURE);
125     }
126   }
127
128   /* Select the correct writer module. */
129   struct writer *writer;
130   int nr_outputs;
131
132   if (strcmp (format, "cpio") == 0) {
133     writer = &cpio_writer;
134     nr_outputs = 2;             /* kernel and appliance (== initrd) */
135   }
136   else if (strcmp (format, "ext2") == 0) {
137     writer = &ext2_writer;
138     nr_outputs = 3;             /* kernel, initrd, appliance */
139   }
140   else if (strcmp (format, "checksum") == 0) {
141     writer = &checksum_writer;
142     nr_outputs = 0;             /* (none) */
143   }
144   else {
145     fprintf (stderr,
146              "%s: incorrect output format (-f): must be cpio|ext2|checksum\n",
147              argv[0]);
148     exit (EXIT_FAILURE);
149   }
150
151   /* [optind .. optind+nr_inputs-1] hostcpu [argc-nr_outputs-1 .. argc-1]
152    * <----     nr_inputs      ---->    1    <----    nr_outputs     ---->
153    */
154   char **inputs = &argv[optind];
155   int nr_inputs = argc - nr_outputs - 1 - optind;
156   char **outputs = &argv[optind+nr_inputs+1];
157   /*assert (outputs [nr_outputs] == NULL);
158     assert (inputs [nr_inputs + 1 + nr_outputs] == NULL);*/
159
160   if (nr_inputs < 1) {
161     fprintf (stderr, "%s: not enough files specified on the command line\n",
162              argv[0]);
163     exit (EXIT_FAILURE);
164   }
165
166   /* See: https://bugzilla.redhat.com/show_bug.cgi?id=558593 */
167   const char *hostcpu = outputs[-1];
168
169   /* Output files. */
170   const char *kernel = NULL, *initrd = NULL, *appliance = NULL;
171   if (nr_outputs > 0)
172     kernel = outputs[0];
173   if (nr_outputs > 1)
174     initrd = appliance = outputs[1];
175   if (nr_outputs > 2)
176     appliance = outputs[2];
177
178   if (verbose) {
179     print_timestamped_message ("whitelist = %s, "
180                                "host_cpu = %s, "
181                                "kernel = %s, "
182                                "initrd = %s, "
183                                "appliance = %s",
184                                whitelist ? : "(not specified)",
185                                hostcpu, kernel, initrd, appliance);
186     int i;
187     for (i = 0; i < nr_inputs; ++i)
188       print_timestamped_message ("inputs[%d] = %s", i, inputs[i]);
189   }
190
191   /* Remove the output files if they exist. */
192   if (kernel)
193     unlink (kernel);
194   if (initrd)
195     unlink (initrd);
196   if (appliance && initrd != appliance)
197     unlink (appliance);
198
199   /* Create kernel output file. */
200   const char *modpath = create_kernel (hostcpu, kernel);
201
202   if (verbose)
203     print_timestamped_message ("finished creating kernel");
204
205   /* Create the appliance. */
206   create_appliance (hostcpu, inputs, nr_inputs, whitelist, modpath,
207                     initrd, appliance, writer);
208
209   if (verbose)
210     print_timestamped_message ("finished creating appliance");
211
212   exit (EXIT_SUCCESS);
213 }