1 /* $NetBSD: bootcfg.c,v 1.2 2014/08/10 07:40:49 isaki Exp $ */
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/types.h>
30 #include <sys/reboot.h>
32 #include <lib/libsa/stand.h>
33 #include <lib/libsa/bootcfg.h>
34 #include <lib/libkern/libkern.h>
36 #define MENUFORMAT_AUTO 0
37 #define MENUFORMAT_NUMBER 1
38 #define MENUFORMAT_LETTER 2
40 #define DEFAULT_FORMAT MENUFORMAT_AUTO
41 #define DEFAULT_TIMEOUT 10
43 struct bootcfg_def bootcfg_info
;
46 bootcfg_do_noop(const char *cmd
, char *arg
)
48 /* noop, do nothing */
52 * This function parses a boot.cfg file in the root of the filesystem
53 * (if present) and populates the global boot configuration.
55 * The file consists of a number of lines each terminated by \n
56 * The lines are in the format keyword=value. There should not be spaces
59 * perform_bootcfg(conf, command, maxsz)
61 * conf Path to boot.cfg to be passed verbatim to open()
63 * command Pointer to a function that will be called when
64 * perform_bootcfg() encounters a key (command) it does not
66 * The command function is provided both the keyword and
67 * value parsed as arguments to the function.
69 * maxsz Limit the size of the boot.cfg perform_bootcfg() will parse.
70 * - If maxsz is < 0 boot.cfg will not be processed.
71 * - If maxsz is = 0 no limit will be imposed but parsing may
72 * fail due to platform or other constraints e.g. maximum
74 * - If 0 < maxsz and boot.cfg exceeds maxsz it will not be
75 * parsed, otherwise it will be parsed.
77 * The recognised keywords are:
78 * banner: text displayed instead of the normal welcome text
79 * menu: Descriptive text:command to use
80 * timeout: Timeout in seconds (overrides that set by installboot)
81 * default: the default menu option to use if Return is pressed
82 * consdev: the console device to use
83 * format: how menu choices are displayed: (a)utomatic, (n)umbers or (l)etters
84 * clear: whether to clear the screen or not
86 * Example boot.cfg file:
87 * banner=Welcome to NetBSD
88 * banner=Please choose the boot type from the following menu
89 * menu=Boot NetBSD:boot netbsd
90 * menu=Boot into single user mode:boot netbsd -s
91 * menu=:boot hd1a:netbsd -cs
92 * menu=Goto boot comand line:prompt
98 perform_bootcfg(const char *conf
, bootcfg_command command
, const off_t maxsz
)
101 int cmenu
, cbanner
, len
;
104 char *next
, *key
, *value
, *v2
;
106 /* clear bootcfg structure */
107 memset(&bootcfg_info
, 0, sizeof(bootcfg_info
));
109 /* set default timeout */
110 bootcfg_info
.timeout
= DEFAULT_TIMEOUT
;
112 /* automatically switch between letter and numbers on menu */
113 bootcfg_info
.menuformat
= DEFAULT_FORMAT
;
119 err
= fstat(fd
, &st
);
125 /* if a maximum size is being requested for the boot.cfg enforce it. */
126 if (0 < maxsz
&& st
.st_size
> maxsz
) {
131 bc
= alloc(st
.st_size
+ 1);
133 printf("Could not allocate memory for boot configuration\n");
139 * XXX original code, assumes error or eof return from read()
140 * results in the entire boot.cfg being buffered.
141 * - should bail out on read() failing.
142 * - assumption is made that the file size doesn't change between
143 * fstat() and read()ing. probably safe in this context
144 * arguably should check that reading the file won't overflow
145 * the storage anyway.
149 len
= read(fd
, bc
+ off
, 1024);
158 /* bc is now assumed to contain the whole boot.cfg file (see above) */
162 for (c
= bc
; *c
; c
= next
) {
164 /* find end of line */
165 for (; *c
&& *c
!= '\n'; c
++)
166 /* zero terminate line on start of comment */
169 /* zero terminate line */
172 /* Look for = separator between key and value */
173 for (c
= key
; *c
&& *c
!= '='; c
++)
175 /* Ignore lines with no key=value pair */
179 /* zero terminate key which points to keyword */
182 /* Look for end of line (or file) and zero terminate value */
183 for (; *c
&& *c
!= '\n'; c
++)
187 if (!strncmp(key
, "menu", 4)) {
189 * Parse "menu=<description>:<command>". If the
190 * description is empty ("menu=:<command>)",
191 * then re-use the command as the description.
192 * Note that the command may contain embedded
195 if (cmenu
>= BOOTCFG_MAXMENU
)
197 bootcfg_info
.desc
[cmenu
] = value
;
198 for (v2
= value
; *v2
&& *v2
!= ':'; v2
++)
202 bootcfg_info
.command
[cmenu
] = v2
;
204 bootcfg_info
.desc
[cmenu
] = v2
;
207 /* No delimiter means invalid line */
208 bootcfg_info
.desc
[cmenu
] = NULL
;
210 } else if (!strncmp(key
, "banner", 6)) {
211 if (cbanner
< BOOTCFG_MAXBANNER
)
212 bootcfg_info
.banner
[cbanner
++] = value
;
213 } else if (!strncmp(key
, "timeout", 7)) {
214 if (!isdigit(*value
))
215 bootcfg_info
.timeout
= -1;
217 bootcfg_info
.timeout
= atoi(value
);
218 } else if (!strncmp(key
, "default", 7)) {
219 bootcfg_info
.def
= atoi(value
) - 1;
220 } else if (!strncmp(key
, "consdev", 7)) {
221 bootcfg_info
.consdev
= value
;
222 } else if (!strncmp(key
, BOOTCFG_CMD_LOAD
, 4)) {
223 command(BOOTCFG_CMD_LOAD
, value
);
224 } else if (!strncmp(key
, "format", 6)) {
225 printf("value:%c\n", *value
);
229 bootcfg_info
.menuformat
= MENUFORMAT_AUTO
;
236 bootcfg_info
.menuformat
= MENUFORMAT_NUMBER
;
241 bootcfg_info
.menuformat
= MENUFORMAT_LETTER
;
244 } else if (!strncmp(key
, "clear", 5)) {
245 bootcfg_info
.clear
= !!atoi(value
);
246 } else if (!strncmp(key
, BOOTCFG_CMD_USERCONF
, 8)) {
247 command(BOOTCFG_CMD_USERCONF
, value
);
253 switch (bootcfg_info
.menuformat
) {
254 case MENUFORMAT_AUTO
:
255 if (cmenu
> 9 && bootcfg_info
.timeout
> 0)
256 bootcfg_info
.menuformat
= MENUFORMAT_LETTER
;
258 bootcfg_info
.menuformat
= MENUFORMAT_NUMBER
;
261 case MENUFORMAT_NUMBER
:
262 if (cmenu
> 9 && bootcfg_info
.timeout
> 0)
267 bootcfg_info
.nummenu
= cmenu
;
268 if (bootcfg_info
.def
< 0)
269 bootcfg_info
.def
= 0;
270 if (bootcfg_info
.def
>= cmenu
)
271 bootcfg_info
.def
= cmenu
- 1;