Merge branch 'fixes-jgarzik' of git://git.kernel.org/pub/scm/linux/kernel/git/linvill...
[linux-2.6] / arch / x86 / boot / cmdline.c
1 /* -*- linux-c -*- ------------------------------------------------------- *
2  *
3  *   Copyright (C) 1991, 1992 Linus Torvalds
4  *   Copyright 2007 rPath, Inc. - All Rights Reserved
5  *
6  *   This file is part of the Linux kernel, and is made available under
7  *   the terms of the GNU General Public License version 2.
8  *
9  * ----------------------------------------------------------------------- */
10
11 /*
12  * arch/i386/boot/cmdline.c
13  *
14  * Simple command-line parser for early boot.
15  */
16
17 #include "boot.h"
18
19 static inline int myisspace(u8 c)
20 {
21         return c <= ' ';        /* Close enough approximation */
22 }
23
24 /*
25  * Find a non-boolean option, that is, "option=argument".  In accordance
26  * with standard Linux practice, if this option is repeated, this returns
27  * the last instance on the command line.
28  *
29  * Returns the length of the argument (regardless of if it was
30  * truncated to fit in the buffer), or -1 on not found.
31  */
32 int cmdline_find_option(const char *option, char *buffer, int bufsize)
33 {
34         u32 cmdline_ptr = boot_params.hdr.cmd_line_ptr;
35         addr_t cptr;
36         char c;
37         int len = -1;
38         const char *opptr = NULL;
39         char *bufptr = buffer;
40         enum {
41                 st_wordstart,   /* Start of word/after whitespace */
42                 st_wordcmp,     /* Comparing this word */
43                 st_wordskip,    /* Miscompare, skip */
44                 st_bufcpy       /* Copying this to buffer */
45         } state = st_wordstart;
46
47         if (!cmdline_ptr || cmdline_ptr >= 0x100000)
48                 return -1;      /* No command line, or inaccessible */
49
50         cptr = cmdline_ptr & 0xf;
51         set_fs(cmdline_ptr >> 4);
52
53         while (cptr < 0x10000 && (c = rdfs8(cptr++))) {
54                 switch (state) {
55                 case st_wordstart:
56                         if (myisspace(c))
57                                 break;
58
59                         /* else */
60                         state = st_wordcmp;
61                         opptr = option;
62                         /* fall through */
63
64                 case st_wordcmp:
65                         if (c == '=' && !*opptr) {
66                                 len = 0;
67                                 bufptr = buffer;
68                                 state = st_bufcpy;
69                         } else if (myisspace(c)) {
70                                 state = st_wordstart;
71                         } else if (c != *opptr++) {
72                                 state = st_wordskip;
73                         }
74                         break;
75
76                 case st_wordskip:
77                         if (myisspace(c))
78                                 state = st_wordstart;
79                         break;
80
81                 case st_bufcpy:
82                         if (myisspace(c)) {
83                                 state = st_wordstart;
84                         } else {
85                                 if (len < bufsize-1)
86                                         *bufptr++ = c;
87                                 len++;
88                         }
89                         break;
90                 }
91         }
92
93         if (bufsize)
94                 *bufptr = '\0';
95
96         return len;
97 }