6 #include <asm/setup.h> /* for COMMAND_LINE_SIZE */
9 #include <sys/utsname.h>
14 #include "fstype/fstype.h"
16 #ifndef COMMAND_LINE_SIZE
17 # define COMMAND_LINE_SIZE 256
20 /* filesystems built into the kernel */
21 static Eina_List
*fs_core
;
22 /* filesystems supported by kernel modules */
23 static Eina_List
*fs_mods
;
24 /* partitions read from /proc/partitions */
25 static Eina_List
*partitions
;
26 /* systems which were found to boot */
27 static Eina_List
*systems
;
29 static Eina_List
* get_partitions() {
30 FILE *f
= fopen("/proc/partitions", "r");
35 Eina_List
*partitions
= NULL
;
40 fgets(line
, sizeof(line
), f
);
41 fgets(line
, sizeof(line
), f
);
43 while (fgets(line
, sizeof(line
), f
)) {
44 char *dev
, *q
, *p
= line
;
47 /* skip first two columns */
52 /* read number of blocks */
53 blocks
= strtol(p
, &q
, 10);
54 if (!blocks
|| p
== q
)
56 /* ignore small partitions < 10MB */
57 if (blocks
< 10 * 1024)
59 /* read partition name and remove trailing \n */
66 dev
= malloc(sstrlen("/dev/") + len
+ 1);
69 partitions
= eina_list_append(partitions
, dev
);
76 static Eina_List
* get_kernel_filesystems_builtin() {
77 FILE *f
= fopen("/proc/filesystems", "r");
86 while (fgets(line
, sizeof(line
), f
)) {
87 /* ignore lines starting with nodev */
88 if (!strncmp(line
, "nodev", sstrlen("nodev")))
90 line
[strlen(line
) - 1] = '\0';
91 /* skip tab with line + 1*/
92 fs
= eina_list_append(fs
, strdup(line
+ 1));
99 static Eina_List
* get_kernel_filesystems_modules() {
101 #ifdef CONFIG_SUPPORT_KERNEL_FS_MODULES
103 Eina_List
*fs
= NULL
;
106 char buf
[1024], *p
, *q
;
112 len
= snprintf(buf
, sizeof(buf
), "/lib/modules/%s/modules.dep", uts
.release
);
121 /* calculate the length of the prefix for the modules, this assumes that the
122 * modules are installed under the directroy where we found the modules.dep file.
125 len
-= sstrlen("modules.dep");
127 /* Maybe we should readdir("/lib/modules/`uname -r`/kernel/fs") instead? */
129 while (fgets(buf
, sizeof(buf
), f
)) {
130 /* skip lines which don't contain a colon */
131 if (!(p
= strchr(buf
, ':')))
133 /* we are only interested in the part before '.ko:' */
134 *(p
- sstrlen(".ko")) = '\0';
137 /* skip the prefix '/lib/modules/`uname -r`/' */
140 if (strncmp(p
, "kernel/fs/", sstrlen("kernel/fs/")))
143 q
= p
+= sstrlen("kernel/fs/");
148 /* XXX: check for duplicates? */
149 fs
= eina_list_append(fs
, strdup(p
));
156 #endif /* CONFIG_SUPPORT_KERNEL_FS_MODULES */
159 static bool is_supported_filesystem(const char *fs
) {
161 if (eina_list_search_unsorted(fs_core
, EINA_COMPARE_CB(strcmp
), fs
))
164 #ifdef CONFIG_SUPPORT_KERNEL_FS_MODULES
165 const char *modprobe
[] = { MODPROBE
, fs
};
166 if (eina_list_search_unsorted(fs_mods
, EINA_COMPARE_CB(strcmp
), fs
) &&
167 fexecw(modprobe
[0], (char *const *)modprobe
, NULL
) == 0) {
168 debug("Successfully loaded kernel filesystem module: '%s'\n", fs
);
169 fs_mods
= eina_list_remove(fs_mods
, fs
);
170 fs_core
= eina_list_append(fs_core
, fs
);
178 Eina_List
* scan_system() {
181 const char *dev
, *mnt
, *fs
;
182 char buf
[COMMAND_LINE_SIZE
];
188 /* check if we need to read data from /proc first */
190 partitions
= get_partitions();
192 fs_core
= get_kernel_filesystems_builtin();
194 fs_mods
= get_kernel_filesystems_modules();
196 /* XXX: doesn't handle sub directories assumes /mnt */
197 mkdir(MOUNTPOINT
, 0755);
198 /* chdir so we can use relative paths for mount(2) */
199 if (chdir(MOUNTPOINT
)) {
204 EINA_LIST_FOREACH(partitions
, l
, dev
) {
206 int fd
= open(dev
, O_RDONLY
);
212 if (identify_fs(fd
, &fs
, NULL
, 0)) {
213 eprint("Couldn't identify filesystem on '%s'\n", dev
);
217 if (!is_supported_filesystem(fs
)) {
218 eprint("Unsupported filesystem '%s' on '%s'\n", fs
, dev
);
222 /* we chdir()-ed and now use relative paths */
223 mnt
= dev
+ sstrlen("/dev/");
224 if (mkdir(mnt
, 0755) && errno
!= EEXIST
) {
229 if (mount(dev
, mnt
, fs
, MS_RDONLY
, NULL
) && errno
!= EBUSY
) {
234 /* XXX: replace fixed GTA02 with machine type */
235 snprintf(buf
, sizeof buf
, "%s/%s/boot/uImage-GTA02.bin", MOUNTPOINT
, mnt
);
236 if (stat(buf
, &st
)) {
237 /* no uImage present now check for zImage */
238 buf
[sstrlen(MOUNTPOINT
) + sstrlen("/") + strlen(mnt
) + sstrlen("/boot/")] = 'z';
239 if (stat(buf
, &st
)) {
240 eprint("No kernel found at '%s'\n", buf
);
246 BootItem
*sys
= calloc(sizeof(BootItem
), 1);
249 sys
->kernel
= strdup(buf
);
251 /* XXX: replace fixed GTA02 with machine type */
252 snprintf(buf
, sizeof buf
, "%s/%s/boot/append-GTA02", MOUNTPOINT
, mnt
);
253 FILE *f
= fopen(buf
, "r");
255 fgets(buf
, sizeof buf
, f
);
256 sys
->cmdline
= strdup(buf
);
260 snprintf(buf
, sizeof buf
, "%s/%s/boot/bootlogo.png", MOUNTPOINT
, mnt
);
262 sys
->logo
= strdup(buf
);
264 sys
->logo
= DEFAULT_LOGO
;
266 systems
= eina_list_append(systems
, sys
);
275 /* Genereate kernel command line for use with kexec. It consist of the following:
277 * - /proc/cmdline of the running system
278 * - root=$PARTITON rootfstype=$FS
279 * - append-$MACHINE in the same directory as the kernel
282 char* get_kernel_cmdline(BootItem
*i
) {
283 static char cmdline
[2 * COMMAND_LINE_SIZE
] = KEXEC_CMDLINE
, *s
= cmdline
+ sstrlen(KEXEC_CMDLINE
);
285 /* read the cmdline of the currently running system only once */
286 if (!cmdline
[sstrlen(KEXEC_CMDLINE
) + 1]) {
287 FILE *f
= fopen("/proc/cmdline","r");
288 if (f
&& fgets(s
, sizeof(cmdline
) - sstrlen(KEXEC_CMDLINE
), f
)) {
289 /* /proc/cmdline ends with a new line which we want to overwrite thus -1 */
295 /* append root partition, filesystem and the image specific command line */
296 int len
= snprintf(s
, sizeof(cmdline
) - (s
- cmdline
), "root=%s rootfstype=%s %s",
297 i
->dev
, i
->fs
, i
->cmdline
|| "");
298 if (len
> 0 && s
[len
- 1] == '\n')
304 bool boot_kernel(BootItem
*i
) {
308 /* umount all filesystem we probed except the one where the kernel is located */
309 EINA_LIST_FOREACH(systems
, l
, s
) {
311 /* XXX: assumes we are still chdir()-ed */
312 umount(s
->dev
+ sstrlen("/dev/"));
316 const char *kexec_load
[] = { KEXEC
, get_kernel_cmdline(i
), "-l", i
->kernel
, NULL
};
317 if (fexecw(kexec_load
[0], (char *const *)kexec_load
, NULL
)) {
318 eprint("Couldn't load kernel from '%s'\n", i
->kernel
);
322 const char *kexec_exec
[] = { KEXEC
, "-e", NULL
};
324 /* XXX: assumes we are still chdir()-ed */
325 umount(i
->dev
+ sstrlen("/dev/"));
327 if (execve(kexec_exec
[0], (char *const *)kexec_exec
, NULL
)) {
328 eprint("Couldn't exec kernel '%s'\n", i
->kernel
);
332 /* can't be reached just here to silence compiler warning */
341 if (!eina_mempool_init() || !eina_list_init())
345 partitions
= get_partitions();
347 EINA_LIST_FOREACH(partitions
, l
, p
) {
351 puts("Built in filesystems:");
352 fs_core
= get_kernel_filesystems_builtin();
354 EINA_LIST_FOREACH(fs_core
, l
, p
) {
358 #ifdef CONFIG_SUPPORT_KERNEL_FS_MODULES
359 puts("Filesystem modules:");
360 fs_mods
= get_kernel_filesystems_modules();
362 EINA_LIST_FOREACH(fs_mods
, l
, p
) {
367 puts("Bootable images:");
368 systems
= scan_system();
370 EINA_LIST_FOREACH(systems
, l
, s
) {
371 printf("kexec %s'%s' -l %s\n", KEXEC_CMDLINE
,
372 get_kernel_cmdline(s
) + sstrlen(KEXEC_CMDLINE
), s
->kernel
);
373 printf("umount '%s'\n", s
->dev
);
374 printf("kexec -e\n\n");