Added netdev_nullify to natsemi_remove()
[gpxe.git] / src / core / settings.c
blob42029fdcde6dfd4cec8381bfb0a4b10c365c8f71
1 /*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <strings.h>
24 #include <byteswap.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <gpxe/in.h>
28 #include <gpxe/settings.h>
30 /** @file
32 * Configuration settings
36 /** Registered configuration setting types */
37 static struct config_setting_type config_setting_types[0]
38 __table_start ( struct config_setting_type, config_setting_types );
39 static struct config_setting_type config_setting_types_end[0]
40 __table_end ( struct config_setting_type, config_setting_types );
42 /** Registered configuration settings */
43 static struct config_setting config_settings[0]
44 __table_start ( struct config_setting, config_settings );
45 static struct config_setting config_settings_end[0]
46 __table_end ( struct config_setting, config_settings );
48 /**
49 * Find configuration setting type
51 * @v name Name
52 * @ret type Configuration setting type, or NULL
54 static struct config_setting_type *
55 find_config_setting_type ( const char *name ) {
56 struct config_setting_type *type;
58 for ( type = config_setting_types ; type < config_setting_types_end ;
59 type++ ) {
60 if ( strcasecmp ( name, type->name ) == 0 )
61 return type;
63 return NULL;
66 /**
67 * Find configuration setting
69 * @v name Name
70 * @ret setting Configuration setting, or NULL
72 static struct config_setting * find_config_setting ( const char *name ) {
73 struct config_setting *setting;
75 for ( setting = config_settings ; setting < config_settings_end ;
76 setting++ ) {
77 if ( strcasecmp ( name, setting->name ) == 0 )
78 return setting;
80 return NULL;
83 /**
84 * Find or build configuration setting
86 * @v name Name
87 * @v tmp_setting Temporary buffer for constructing a setting
88 * @ret setting Configuration setting, or NULL
90 * Find setting if it exists. If it doesn't exist, but the name is of
91 * the form "<num>.<type>" (e.g. "12.string"), then construct a
92 * setting for that tag and data type, and return it. The constructed
93 * setting will be placed in the temporary buffer.
95 static struct config_setting *
96 find_or_build_config_setting ( const char *name,
97 struct config_setting *tmp_setting ) {
98 struct config_setting *setting;
99 char *separator;
101 /* Look in the list of registered settings first */
102 setting = find_config_setting ( name );
103 if ( setting )
104 return setting;
106 /* If name is of the form "<num>.<type>", try to construct a setting */
107 setting = tmp_setting;
108 memset ( setting, 0, sizeof ( *setting ) );
109 setting->name = name;
110 setting->tag = strtoul ( name, &separator, 10 );
111 if ( *separator != '.' )
112 return NULL;
113 setting->type = find_config_setting_type ( separator + 1 );
114 if ( ! setting->type )
115 return NULL;
116 return setting;
120 * Show value of named setting
122 * @v context Configuration context
123 * @v name Configuration setting name
124 * @v buf Buffer to contain value
125 * @v len Length of buffer
126 * @ret rc Return status code
128 int show_named_setting ( struct config_context *context, const char *name,
129 char *buf, size_t len ) {
130 struct config_setting *setting;
131 struct config_setting tmp_setting;
133 setting = find_or_build_config_setting ( name, &tmp_setting );
134 if ( ! setting )
135 return -ENOENT;
136 return show_setting ( context, setting, buf, len );
140 * Set value of named setting
142 * @v context Configuration context
143 * @v name Configuration setting name
144 * @v value Setting value (as a string)
145 * @ret rc Return status code
147 int set_named_setting ( struct config_context *context, const char *name,
148 const char *value ) {
149 struct config_setting *setting;
150 struct config_setting tmp_setting;
152 setting = find_or_build_config_setting ( name, &tmp_setting );
153 if ( ! setting )
154 return -ENOENT;
155 return setting->type->set ( context, setting, value );
159 * Set value of setting
161 * @v context Configuration context
162 * @v setting Configuration setting
163 * @v value Setting value (as a string), or NULL
164 * @ret rc Return status code
166 int set_setting ( struct config_context *context,
167 struct config_setting *setting,
168 const char *value ) {
169 if ( ( ! value ) || ( ! *value ) ) {
170 /* Save putting deletion logic in each individual handler */
171 return clear_setting ( context, setting );
173 return setting->type->set ( context, setting, value );
177 * Show value of string setting
179 * @v context Configuration context
180 * @v setting Configuration setting
181 * @v buf Buffer to contain value
182 * @v len Length of buffer
183 * @ret rc Return status code
185 static int show_string ( struct config_context *context,
186 struct config_setting *setting,
187 char *buf, size_t len ) {
188 struct dhcp_option *option;
190 option = find_dhcp_option ( context->options, setting->tag );
191 if ( ! option )
192 return -ENODATA;
193 dhcp_snprintf ( buf, len, option );
194 return 0;
198 * Set value of string setting
200 * @v context Configuration context
201 * @v setting Configuration setting
202 * @v value Setting value (as a string)
203 * @ret rc Return status code
205 static int set_string ( struct config_context *context,
206 struct config_setting *setting,
207 const char *value ) {
208 struct dhcp_option *option;
210 option = set_dhcp_option ( context->options, setting->tag,
211 value, strlen ( value ) );
212 if ( ! option )
213 return -ENOSPC;
214 return 0;
217 /** A string configuration setting */
218 struct config_setting_type config_setting_type_string __config_setting_type = {
219 .name = "string",
220 .description = "Text string",
221 .show = show_string,
222 .set = set_string,
226 * Show value of IPv4 setting
228 * @v context Configuration context
229 * @v setting Configuration setting
230 * @v buf Buffer to contain value
231 * @v len Length of buffer
232 * @ret rc Return status code
234 static int show_ipv4 ( struct config_context *context,
235 struct config_setting *setting,
236 char *buf, size_t len ) {
237 struct dhcp_option *option;
238 struct in_addr ipv4;
240 option = find_dhcp_option ( context->options, setting->tag );
241 if ( ! option )
242 return -ENODATA;
243 dhcp_ipv4_option ( option, &ipv4 );
244 snprintf ( buf, len, inet_ntoa ( ipv4 ) );
245 return 0;
249 * Set value of IPV4 setting
251 * @v context Configuration context
252 * @v setting Configuration setting
253 * @v value Setting value (as a string)
254 * @ret rc Return status code
256 static int set_ipv4 ( struct config_context *context,
257 struct config_setting *setting,
258 const char *value ) {
259 struct dhcp_option *option;
260 struct in_addr ipv4;
262 if ( inet_aton ( value, &ipv4 ) == 0 )
263 return -EINVAL;
264 option = set_dhcp_option ( context->options, setting->tag,
265 &ipv4, sizeof ( ipv4 ) );
266 if ( ! option )
267 return -ENOSPC;
268 return 0;
271 /** An IPv4 configuration setting */
272 struct config_setting_type config_setting_type_ipv4 __config_setting_type = {
273 .name = "ipv4",
274 .description = "IPv4 address",
275 .show = show_ipv4,
276 .set = set_ipv4,
280 * Show value of integer setting
282 * @v context Configuration context
283 * @v setting Configuration setting
284 * @v buf Buffer to contain value
285 * @v len Length of buffer
286 * @ret rc Return status code
288 static int show_int ( struct config_context *context,
289 struct config_setting *setting,
290 char *buf, size_t len ) {
291 struct dhcp_option *option;
292 long num;
294 option = find_dhcp_option ( context->options, setting->tag );
295 if ( ! option )
296 return -ENODATA;
297 num = dhcp_num_option ( option );
298 snprintf ( buf, len, "%ld", num );
299 return 0;
303 * Set value of integer setting
305 * @v context Configuration context
306 * @v setting Configuration setting
307 * @v value Setting value (as a string)
308 * @v size Size of integer (in bytes)
309 * @ret rc Return status code
311 static int set_int ( struct config_context *context,
312 struct config_setting *setting,
313 const char *value, unsigned int size ) {
314 struct dhcp_option *option;
315 union {
316 uint32_t num;
317 uint8_t bytes[4];
318 } u;
319 char *endp;
321 /* Parse number */
322 if ( ! *value )
323 return -EINVAL;
324 u.num = htonl ( strtoul ( value, &endp, 0 ) );
325 if ( *endp )
326 return -EINVAL;
328 /* Set option */
329 option = set_dhcp_option ( context->options, setting->tag,
330 &u.bytes[ sizeof ( u ) - size ], size );
331 if ( ! option )
332 return -ENOSPC;
333 return 0;
337 * Set value of 8-bit integer setting
339 * @v context Configuration context
340 * @v setting Configuration setting
341 * @v value Setting value (as a string)
342 * @v size Size of integer (in bytes)
343 * @ret rc Return status code
345 static int set_int8 ( struct config_context *context,
346 struct config_setting *setting,
347 const char *value ) {
348 return set_int ( context, setting, value, 1 );
351 /** An 8-bit integer configuration setting */
352 struct config_setting_type config_setting_type_int8 __config_setting_type = {
353 .name = "int8",
354 .description = "8-bit integer",
355 .show = show_int,
356 .set = set_int8,
359 /** Some basic setting definitions */
360 struct config_setting basic_config_settings[] __config_setting = {
362 .name = "ip",
363 .description = "IP address of this machine (e.g. 192.168.0.1)",
364 .tag = DHCP_EB_YIADDR,
365 .type = &config_setting_type_ipv4,
368 .name = "hostname",
369 .description = "Host name of this machine",
370 .tag = DHCP_HOST_NAME,
371 .type = &config_setting_type_string,
374 .name = "username",
375 .description = "User name for authentication to servers",
376 .tag = DHCP_EB_USERNAME,
377 .type = &config_setting_type_string,
380 .name = "password",
381 .description = "Password for authentication to servers",
382 .tag = DHCP_EB_PASSWORD,
383 .type = &config_setting_type_string,
386 .name = "root-path",
387 .description = "NFS/iSCSI root path",
388 .tag = DHCP_ROOT_PATH,
389 .type = &config_setting_type_string,
392 .name = "priority",
393 .description = "Priority of these options",
394 .tag = DHCP_EB_PRIORITY,
395 .type = &config_setting_type_int8,
398 .name = "initiator-iqn",
399 .description = "iSCSI qualified name of this machine",
400 .tag = DHCP_ISCSI_INITIATOR_IQN,
401 .type = &config_setting_type_string,