1 /* febootstrap-supermin-helper reimplementation in C.
2 * Copyright (C) 2009-2010 Red Hat Inc.
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.
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.
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.
19 /* ext2 requires a small initrd in order to boot. This builds it. */
33 #include "full-write.h"
35 #include "xvasprintf.h"
38 #include "ext2internal.h"
40 static void read_module_deps (const char *modpath);
41 static void free_module_deps (void);
42 static void add_module_dep (const char *name, const char *dep);
43 static struct module * add_module (const char *name);
44 static struct module * find_module (const char *name);
45 static void print_module_load_order (FILE *f, FILE *pp, struct module *m);
47 /* The init binary. */
48 extern char _binary_init_start, _binary_init_end, _binary_init_size;
50 /* The list of modules (wildcards) we consider for inclusion in the
51 * mini initrd. Only what is needed in order to find a device with an
52 * ext2 filesystem on it.
54 static const char *kmods[] = {
60 "scsi_transport_spi.ko",
72 /* Module dependencies. */
79 struct module *modules = NULL;
87 ext2_make_initrd (const char *modpath, const char *initrd)
89 char dir[] = "/tmp/ext2initrdXXXXXX";
90 if (mkdtemp (dir) == NULL)
91 error (EXIT_FAILURE, errno, "mkdtemp");
93 read_module_deps (modpath);
95 for (int i = 0; kmods[i] != NULL; ++i) {
96 for (struct module *m = modules; m; m = m->next) {
97 char *n = strrchr (m->name, '/');
102 if (fnmatch (kmods[i], n, FNM_PATHNAME) == 0) {
104 fprintf (stderr, "Adding top-level dependency %s (%s)\n", m->name, kmods[i]);
105 add_module_dep ("", m->name);
110 char *cmd = xasprintf ("cd %s; xargs cp -t %s", modpath, dir);
111 char *outfile = xasprintf ("%s/modules", dir);
112 if (verbose >= 2) fprintf (stderr, "writing to %s\n", cmd);
114 FILE *f = fopen (outfile, "w");
116 error (EXIT_FAILURE, errno, "failed to create modules list (%s)", outfile);
117 FILE *pp = popen (cmd, "w");
119 error (EXIT_FAILURE, errno, "failed to create pipe (%s)", cmd);
121 /* The "pseudo" module depends on all modules matched by the contents of kmods */
122 struct module *pseudo = find_module ("");
123 print_module_load_order (pp, f, pseudo);
130 /* Copy in the init program, linked into this program as a data blob. */
131 char *init = xasprintf ("%s/init", dir);
132 int fd = open (init, O_WRONLY|O_TRUNC|O_CREAT|O_NOCTTY, 0755);
134 error (EXIT_FAILURE, errno, "open: %s", init);
136 size_t n = (size_t) &_binary_init_size;
137 if (full_write (fd, &_binary_init_start, n) != n)
138 error (EXIT_FAILURE, errno, "write: %s", init);
140 if (close (fd) == -1)
141 error (EXIT_FAILURE, errno, "close: %s", init);
145 /* Build the cpio file. */
146 cmd = xasprintf ("(cd %s && (echo . ; ls -1)"
147 " | cpio --quiet -o -H newc) > '%s'",
149 if (verbose >= 2) fprintf (stderr, "%s\n", cmd);
150 int r = system (cmd);
151 if (r == -1 || WEXITSTATUS (r) != 0)
152 error (EXIT_FAILURE, 0, "ext2_make_initrd: cpio failed");
155 /* Construction of 'dir' above ensures this is safe. */
156 cmd = xasprintf ("rm -rf %s", dir);
157 if (verbose >= 2) fprintf (stderr, "%s\n", cmd);
163 free_module_deps (void)
165 /* Short-lived program, don't bother to free it. */
169 /* Read modules.dep into internal structure. */
171 read_module_deps (const char *modpath)
175 char *filename = xasprintf ("%s/modules.dep", modpath);
176 FILE *fp = fopen (filename, "r");
178 error (EXIT_FAILURE, errno, "open: %s/modules.dep", modpath);
183 while ((len = getline (&line, &llen, fp)) != -1) {
184 if (len > 0 && line[len-1] == '\n')
187 char *name = strtok (line, ": ");
192 while ((dep = strtok (NULL, " ")) != NULL) {
193 add_module_dep (name, dep);
201 static struct module *
202 add_module (const char *name)
204 struct module *m = find_module (name);
207 m = xmalloc (sizeof *m);
208 m->name = xstrdup (name);
216 static struct module *
217 find_module (const char *name)
220 for (m = modules; m; m = m->next) {
221 if (strcmp (name, m->name) == 0)
227 /* Module 'name' requires 'dep' to be loaded first. */
229 add_module_dep (const char *name, const char *dep)
231 if (verbose >= 2) fprintf (stderr, "add_module_dep %s: %s\n", name, dep);
232 struct module *m1 = add_module (name);
233 struct module *m2 = add_module (dep);
235 for (d = m1->deps; d; d = d->next) {
239 d = xmalloc (sizeof *d);
246 /* DFS on the dependency graph */
248 print_module_load_order (FILE *pipe, FILE *list, struct module *m)
253 for (struct moddep *d = m->deps; d; d = d->next)
254 print_module_load_order (pipe, list, d->dep);
259 char *basename = strrchr (m->name, '/');
265 fputs (m->name, pipe);
267 fputs (basename, list);