1 /* febootstrap-supermin-helper reimplementation in C.
2 * Copyright (C) 2009-2011 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[] = {
56 "ext4.ko*", /* CONFIG_EXT4_USE_FOR_EXT23=y option might be set */
61 "scsi_transport_spi.ko*",
73 /* Module dependencies. */
80 struct module *modules = NULL;
88 ext2_make_initrd (const char *modpath, const char *initrd)
90 char dir[] = "/tmp/ext2initrdXXXXXX";
91 if (mkdtemp (dir) == NULL)
92 error (EXIT_FAILURE, errno, "mkdtemp");
94 read_module_deps (modpath);
96 for (int i = 0; kmods[i] != NULL; ++i) {
97 for (struct module *m = modules; m; m = m->next) {
98 char *n = strrchr (m->name, '/');
103 if (fnmatch (kmods[i], n, FNM_PATHNAME) == 0) {
105 fprintf (stderr, "Adding top-level dependency %s (%s)\n", m->name, kmods[i]);
106 add_module_dep ("", m->name);
111 char *cmd = xasprintf ("cd %s; xargs cp -t %s", modpath, dir);
112 char *outfile = xasprintf ("%s/modules", dir);
113 if (verbose >= 2) fprintf (stderr, "writing to %s\n", cmd);
115 FILE *f = fopen (outfile, "w");
117 error (EXIT_FAILURE, errno, "failed to create modules list (%s)", outfile);
118 FILE *pp = popen (cmd, "w");
120 error (EXIT_FAILURE, errno, "failed to create pipe (%s)", cmd);
122 /* The "pseudo" module depends on all modules matched by the contents of kmods */
123 struct module *pseudo = find_module ("");
124 print_module_load_order (pp, f, pseudo);
131 /* Copy in the init program, linked into this program as a data blob. */
132 char *init = xasprintf ("%s/init", dir);
133 int fd = open (init, O_WRONLY|O_TRUNC|O_CREAT|O_NOCTTY, 0755);
135 error (EXIT_FAILURE, errno, "open: %s", init);
137 size_t n = (size_t) &_binary_init_size;
138 if (full_write (fd, &_binary_init_start, n) != n)
139 error (EXIT_FAILURE, errno, "write: %s", init);
141 if (close (fd) == -1)
142 error (EXIT_FAILURE, errno, "close: %s", init);
146 /* Build the cpio file. */
147 cmd = xasprintf ("(cd %s && (echo . ; ls -1)"
148 " | cpio --quiet -o -H newc) > '%s'",
150 if (verbose >= 2) fprintf (stderr, "%s\n", cmd);
151 int r = system (cmd);
152 if (r == -1 || WEXITSTATUS (r) != 0)
153 error (EXIT_FAILURE, 0, "ext2_make_initrd: cpio failed");
156 /* Construction of 'dir' above ensures this is safe. */
157 cmd = xasprintf ("rm -rf %s", dir);
158 if (verbose >= 2) fprintf (stderr, "%s\n", cmd);
164 free_module_deps (void)
166 /* Short-lived program, don't bother to free it. */
170 /* Read modules.dep into internal structure. */
172 read_module_deps (const char *modpath)
176 char *filename = xasprintf ("%s/modules.dep", modpath);
177 FILE *fp = fopen (filename, "r");
179 error (EXIT_FAILURE, errno, "open: %s/modules.dep", modpath);
184 while ((len = getline (&line, &llen, fp)) != -1) {
185 if (len > 0 && line[len-1] == '\n')
188 char *name = strtok (line, ": ");
193 while ((dep = strtok (NULL, " ")) != NULL) {
194 add_module_dep (name, dep);
202 static struct module *
203 add_module (const char *name)
205 struct module *m = find_module (name);
208 m = xmalloc (sizeof *m);
209 m->name = xstrdup (name);
217 static struct module *
218 find_module (const char *name)
221 for (m = modules; m; m = m->next) {
222 if (strcmp (name, m->name) == 0)
228 /* Module 'name' requires 'dep' to be loaded first. */
230 add_module_dep (const char *name, const char *dep)
232 if (verbose >= 2) fprintf (stderr, "add_module_dep %s: %s\n", name, dep);
233 struct module *m1 = add_module (name);
234 struct module *m2 = add_module (dep);
236 for (d = m1->deps; d; d = d->next) {
240 d = xmalloc (sizeof *d);
247 /* DFS on the dependency graph */
249 print_module_load_order (FILE *pipe, FILE *list, struct module *m)
254 for (struct moddep *d = m->deps; d; d = d->next)
255 print_module_load_order (pipe, list, d->dep);
260 char *basename = strrchr (m->name, '/');
266 fputs (m->name, pipe);
268 fputs (basename, list);