Merge remote-tracking branch 'hpa/master'
[syslinux.git] / com32 / modules / linux.c
blobb902ebc5e4e42c1a2e666587ef07ae120f1d8a12
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009 Intel Corporation; author: H. Peter Anvin
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following
13 * conditions:
15 * The above copyright notice and this permission notice shall
16 * be included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
27 * ----------------------------------------------------------------------- */
30 * linux.c
32 * Sample module to load Linux kernels. This module can also create
33 * a file out of the DHCP return data if running under PXELINUX.
35 * If -dhcpinfo is specified, the DHCP info is written into the file
36 * /dhcpinfo.dat in the initramfs.
38 * Usage: linux.c32 [-dhcpinfo] kernel arguments...
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <console.h>
46 #include <syslinux/loadfile.h>
47 #include <syslinux/linux.h>
48 #include <syslinux/pxe.h>
50 const char *progname = "linux.c32";
52 /* Find the last instance of a particular command line argument
53 (which should include the final =; do not use for boolean arguments) */
54 static char *find_argument(char **argv, const char *argument)
56 int la = strlen(argument);
57 char **arg;
58 char *ptr = NULL;
60 for (arg = argv; *arg; arg++) {
61 if (!memcmp(*arg, argument, la))
62 ptr = *arg + la;
65 return ptr;
68 /* Search for a boolean argument; return its position, or 0 if not present */
69 static int find_boolean(char **argv, const char *argument)
71 char **arg;
73 for (arg = argv; *arg; arg++) {
74 if (!strcmp(*arg, argument))
75 return (arg - argv) + 1;
78 return 0;
81 /* Stitch together the command line from a set of argv's */
82 static char *make_cmdline(char **argv)
84 char **arg;
85 size_t bytes;
86 char *cmdline, *p;
88 bytes = 1; /* Just in case we have a zero-entry cmdline */
89 for (arg = argv; *arg; arg++) {
90 bytes += strlen(*arg) + 1;
93 p = cmdline = malloc(bytes);
94 if (!cmdline)
95 return NULL;
97 for (arg = argv; *arg; arg++) {
98 int len = strlen(*arg);
99 memcpy(p, *arg, len);
100 p[len] = ' ';
101 p += len + 1;
104 if (p > cmdline)
105 p--; /* Remove the last space */
106 *p = '\0';
108 return cmdline;
111 int main(int argc, char *argv[])
113 const char *kernel_name;
114 struct initramfs *initramfs;
115 char *cmdline;
116 char *boot_image;
117 void *kernel_data;
118 size_t kernel_len;
119 bool opt_dhcpinfo = false;
120 bool opt_quiet = false;
121 void *dhcpdata;
122 size_t dhcplen;
123 char **argp, *arg, *p;
125 openconsole(&dev_null_r, &dev_stdcon_w);
127 (void)argc;
128 argp = argv + 1;
130 while ((arg = *argp) && arg[0] == '-') {
131 if (!strcmp("-dhcpinfo", arg)) {
132 opt_dhcpinfo = true;
133 } else {
134 fprintf(stderr, "%s: unknown option: %s\n", progname, arg);
135 return 1;
137 argp++;
140 if (!arg) {
141 fprintf(stderr, "%s: missing kernel name\n", progname);
142 return 1;
145 kernel_name = arg;
147 boot_image = malloc(strlen(kernel_name) + 12);
148 if (!boot_image)
149 goto bail;
150 strcpy(boot_image, "BOOT_IMAGE=");
151 strcpy(boot_image + 11, kernel_name);
152 /* argp now points to the kernel name, and the command line follows.
153 Overwrite the kernel name with the BOOT_IMAGE= argument, and thus
154 we have the final argument. */
155 *argp = boot_image;
157 if (find_boolean(argp, "quiet"))
158 opt_quiet = true;
160 if (!opt_quiet)
161 printf("Loading %s... ", kernel_name);
162 if (loadfile(kernel_name, &kernel_data, &kernel_len)) {
163 if (opt_quiet)
164 printf("Loading %s ", kernel_name);
165 printf("failed!\n");
166 goto bail;
168 if (!opt_quiet)
169 printf("ok\n");
171 cmdline = make_cmdline(argp);
172 if (!cmdline)
173 goto bail;
175 /* Initialize the initramfs chain */
176 initramfs = initramfs_init();
177 if (!initramfs)
178 goto bail;
180 if ((arg = find_argument(argp, "initrd="))) {
181 do {
182 p = strchr(arg, ',');
183 if (p)
184 *p = '\0';
186 if (!opt_quiet)
187 printf("Loading %s... ", arg);
188 if (initramfs_load_archive(initramfs, arg)) {
189 if (opt_quiet)
190 printf("Loading %s ", kernel_name);
191 printf("failed!\n");
192 goto bail;
194 if (!opt_quiet)
195 printf("ok\n");
197 if (p)
198 *p++ = ',';
199 } while ((arg = p));
202 /* Append the DHCP info */
203 if (opt_dhcpinfo &&
204 !pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) {
205 if (initramfs_add_file(initramfs, dhcpdata, dhcplen, dhcplen,
206 "/dhcpinfo.dat", 0, 0755))
207 goto bail;
210 /* This should not return... */
211 syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline);
213 bail:
214 fprintf(stderr, "Kernel load failure (insufficient memory?)\n");
215 return 1;