source: bootcd/isolinux/syslinux-6.03/com32/modules/linux.c @ dd1be7c

Last change on this file since dd1be7c was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 9.7 KB
RevLine 
[e16e8f2]1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
4 *   Copyright 2009-2012 Intel Corporation; author: H. Peter Anvin
5 *
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:
14 *
15 *   The above copyright notice and this permission notice shall
16 *   be included in all copies or substantial portions of the Software.
17 *
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.
26 *
27 * ----------------------------------------------------------------------- */
28
29/*
30 * linux.c
31 *
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.
34 *
35 * If -dhcpinfo is specified, the DHCP info is written into the file
36 * /dhcpinfo.dat in the initramfs.
37 *
38 * Usage: linux.c32 [-dhcpinfo] kernel arguments...
39 */
40
41#include <errno.h>
42#include <stdbool.h>
43#include <stdlib.h>
44#include <stdio.h>
45#include <string.h>
46#include <console.h>
47#include <syslinux/loadfile.h>
48#include <syslinux/linux.h>
49#include <syslinux/pxe.h>
50
51enum ldmode {
52    ldmode_raw,
53    ldmode_cpio,
54    ldmodes
55};
56
57typedef int f_ldinitramfs(struct initramfs *, char *);
58
59const char *progname = "linux.c32";
60
61/* Find the last instance of a particular command line argument
62   (which should include the final =; do not use for boolean arguments) */
63static char *find_argument(char **argv, const char *argument)
64{
65    int la = strlen(argument);
66    char **arg;
67    char *ptr = NULL;
68
69    for (arg = argv; *arg; arg++) {
70        if (!strncmp(*arg, argument, la))
71            ptr = *arg + la;
72    }
73
74    return ptr;
75}
76
77/* Find the next instance of a particular command line argument */
78static char **find_arguments(char **argv, char **ptr,
79                             const char *argument)
80{
81    int la = strlen(argument);
82    char **arg;
83
84    for (arg = argv; *arg; arg++) {
85        if (!strncmp(*arg, argument, la)) {
86            *ptr = *arg + la;
87            break;
88        }
89    }
90
91    /* Exhausted all arguments */
92    if (!*arg)
93        return NULL;
94
95    return arg;
96}
97
98/* Search for a boolean argument; return its position, or 0 if not present */
99static int find_boolean(char **argv, const char *argument)
100{
101    char **arg;
102
103    for (arg = argv; *arg; arg++) {
104        if (!strcmp(*arg, argument))
105            return (arg - argv) + 1;
106    }
107
108    return 0;
109}
110
111/* Stitch together the command line from a set of argv's */
112static char *make_cmdline(char **argv)
113{
114    char **arg;
115    size_t bytes;
116    char *cmdline, *p;
117
118    bytes = 1;                  /* Just in case we have a zero-entry cmdline */
119    for (arg = argv; *arg; arg++) {
120        bytes += strlen(*arg) + 1;
121    }
122
123    p = cmdline = malloc(bytes);
124    if (!cmdline)
125        return NULL;
126
127    for (arg = argv; *arg; arg++) {
128        int len = strlen(*arg);
129        memcpy(p, *arg, len);
130        p[len] = ' ';
131        p += len + 1;
132    }
133
134    if (p > cmdline)
135        p--;                    /* Remove the last space */
136    *p = '\0';
137
138    return cmdline;
139}
140
141static f_ldinitramfs ldinitramfs_raw;
142static int ldinitramfs_raw(struct initramfs *initramfs, char *fname)
143{
144    return initramfs_load_archive(initramfs, fname);
145}
146
147static f_ldinitramfs ldinitramfs_cpio;
148static int ldinitramfs_cpio(struct initramfs *initramfs, char *fname)
149{
150    char *target_fname, *p;
151    int do_mkdir, unmangle, rc;
152
153    /* Choose target_fname based on presence of "@" syntax */
154    target_fname = strchr(fname, '@');
155    if (target_fname) {
156        /* Temporarily mangle */
157        unmangle = 1;
158        *target_fname++ = '\0';
159
160        /* Make parent directories? */
161        do_mkdir = !!strchr(target_fname, '/');
162    } else {
163        unmangle = 0;
164
165        /* Forget the source path */
166        target_fname = fname;
167        while ((p = strchr(target_fname, '/')))
168            target_fname = p + 1;
169
170        /* The user didn't specify a desired path */
171        do_mkdir = 0;
172    }
173
174    /*
175     * Load the file, encapsulate it with the desired path, make the
176     * parent directories if the desired path contains them, add to initramfs
177     */
178    rc = initramfs_load_file(initramfs, fname, target_fname, do_mkdir, 0755);
179
180    /* Unmangle, if needed*/
181    if (unmangle)
182        *--target_fname = '@';
183
184    return rc;
185}
186
187/* It only makes sense to call this function from main */
188static int process_initramfs_args(char *arg, struct initramfs *initramfs,
189                                  const char *kernel_name, enum ldmode mode,
190                                  bool opt_quiet)
191{
192    const char *mode_msg;
193    f_ldinitramfs *ldinitramfs;
194    char *p;
195
196    switch (mode) {
197    case ldmode_raw:
198        mode_msg = "Loading";
199        ldinitramfs = ldinitramfs_raw;
200        break;
201    case ldmode_cpio:
202        mode_msg = "Encapsulating";
203        ldinitramfs = ldinitramfs_cpio;
204        break;
205    case ldmodes:
206    default:
207        return 1;
208    }
209
210    do {
211        p = strchr(arg, ',');
212        if (p)
213            *p = '\0';
214
215        if (!opt_quiet)
216            printf("%s %s... ", mode_msg, arg);
217        errno = 0;
218        if (ldinitramfs(initramfs, arg)) {
219            if (opt_quiet)
220                printf("Loading %s ", kernel_name);
221            printf("failed: ");
222            return 1;
223        }
224        if (!opt_quiet)
225            printf("ok\n");
226
227        if (p)
228            *p++ = ',';
229    } while ((arg = p));
230
231    return 0;
232}
233
234static int setup_data_file(struct setup_data *setup_data,
235                           uint32_t type, const char *filename,
236                           bool opt_quiet)
237{
238    if (!opt_quiet)
239        printf("Loading %s... ", filename);
240
241    if (setup_data_load(setup_data, type, filename)) {
242        if (opt_quiet)
243            printf("Loading %s ", filename);
244        printf("failed\n");
245        return -1;
246    }
247           
248    if (!opt_quiet)
249        printf("ok\n");
250   
251    return 0;
252}
253
254int main(int argc, char *argv[])
255{
256    const char *kernel_name;
257    struct initramfs *initramfs;
258    struct setup_data *setup_data;
259    char *cmdline;
260    char *boot_image;
261    void *kernel_data;
262    size_t kernel_len;
263    bool opt_dhcpinfo = false;
264    bool opt_quiet = false;
265    void *dhcpdata;
266    size_t dhcplen;
267    char **argp, **argl, *arg;
268
269    (void)argc;
270    argp = argv + 1;
271
272    while ((arg = *argp) && arg[0] == '-') {
273        if (!strcmp("-dhcpinfo", arg)) {
274            opt_dhcpinfo = true;
275        } else {
276            fprintf(stderr, "%s: unknown option: %s\n", progname, arg);
277            return 1;
278        }
279        argp++;
280    }
281
282    if (!arg) {
283        fprintf(stderr, "%s: missing kernel name\n", progname);
284        return 1;
285    }
286
287    kernel_name = arg;
288
289    errno = 0;
290    boot_image = malloc(strlen(kernel_name) + 12);
291    if (!boot_image) {
292        fprintf(stderr, "Error allocating BOOT_IMAGE string: ");
293        goto bail;
294    }
295    strcpy(boot_image, "BOOT_IMAGE=");
296    strcpy(boot_image + 11, kernel_name);
297    /* argp now points to the kernel name, and the command line follows.
298       Overwrite the kernel name with the BOOT_IMAGE= argument, and thus
299       we have the final argument. */
300    *argp = boot_image;
301
302    if (find_boolean(argp, "quiet"))
303        opt_quiet = true;
304
305    if (!opt_quiet)
306        printf("Loading %s... ", kernel_name);
307    errno = 0;
308    if (loadfile(kernel_name, &kernel_data, &kernel_len)) {
309        if (opt_quiet)
310            printf("Loading %s ", kernel_name);
311        printf("failed: ");
312        goto bail;
313    }
314    if (!opt_quiet)
315        printf("ok\n");
316
317    errno = 0;
318    cmdline = make_cmdline(argp);
319    if (!cmdline) {
320        fprintf(stderr, "make_cmdline() failed: ");
321        goto bail;
322    }
323
324    /* Initialize the initramfs chain */
325    errno = 0;
326    initramfs = initramfs_init();
327    if (!initramfs) {
328        fprintf(stderr, "initramfs_init() failed: ");
329        goto bail;
330    }
331
332    /* Process initramfs arguments */
333    if ((arg = find_argument(argp, "initrd="))) {
334        if (process_initramfs_args(arg, initramfs, kernel_name, ldmode_raw,
335                                   opt_quiet))
336            goto bail;
337    }
338
339    argl = argv;
340    while ((argl = find_arguments(argl, &arg, "initrd+="))) {
341        argl++;
342        if (process_initramfs_args(arg, initramfs, kernel_name, ldmode_raw,
343                                   opt_quiet))
344            goto bail;
345    }
346
347    argl = argv;
348    while ((argl = find_arguments(argl, &arg, "initrdfile="))) {
349        argl++;
350        if (process_initramfs_args(arg, initramfs, kernel_name, ldmode_cpio,
351                                   opt_quiet))
352            goto bail;
353    }
354
355    /* Append the DHCP info */
356    if (opt_dhcpinfo &&
357        !pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) {
358        errno = 0;
359        if (initramfs_add_file(initramfs, dhcpdata, dhcplen, dhcplen,
360                               "/dhcpinfo.dat", 0, 0755)) {
361            fprintf(stderr, "Unable to add DHCP info: ");
362            goto bail;
363        }
364    }
365
366    /* Handle dtb and eventually other setup data */
367    setup_data = setup_data_init();
368    if (!setup_data)
369        goto bail;
370
371    argl = argv;
372    while ((argl = find_arguments(argl, &arg, "dtb="))) {
373        argl++;
374        if (setup_data_file(setup_data, SETUP_DTB, arg, opt_quiet))
375            goto bail;
376    }
377
378    argl = argv;
379    while ((argl = find_arguments(argl, &arg, "blob."))) {
380        uint32_t type;
381        char *ep;
382
383        argl++;
384        type = strtoul(arg, &ep, 10);
385        if (ep[0] != '=' || !ep[1])
386            continue;
387
388        if (!type)
389            continue;
390
391        if (setup_data_file(setup_data, type, ep+1, opt_quiet))
392            goto bail;
393    }
394
395    /* This should not return... */
396    errno = 0;
397    syslinux_boot_linux(kernel_data, kernel_len, initramfs,
398                        setup_data, cmdline);
399    fprintf(stderr, "syslinux_boot_linux() failed: ");
400
401bail:
402    switch(errno) {
403    case ENOENT:
404        fprintf(stderr, "File not found\n");
405        break;
406    case ENOMEM:
407        fprintf(stderr, "Out of memory\n");
408        break;
409    default:
410        fprintf(stderr, "Error %d\n", errno);
411        break;
412    }
413    fprintf(stderr, "%s: Boot aborted!\n", progname);
414    return 1;
415}
Note: See TracBrowser for help on using the repository browser.