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.
28 #include <gpxe/vsprintf.h>
29 #include <gpxe/settings.h>
33 * Configuration settings
37 /** Registered configuration setting types */
38 static struct config_setting_type config_setting_types[0]
39 __table_start ( struct config_setting_type, config_setting_types );
40 static struct config_setting_type config_setting_types_end[0]
41 __table_end ( struct config_setting_type, config_setting_types );
43 /** Registered configuration settings */
44 static struct config_setting config_settings[0]
45 __table_start ( struct config_setting, config_settings );
46 static struct config_setting config_settings_end[0]
47 __table_end ( struct config_setting, config_settings );
49 struct config_setting_type config_setting_type_hex __config_setting_type;
52 * Find configuration setting type
55 * @ret type Configuration setting type, or NULL
57 static struct config_setting_type *
58 find_config_setting_type ( const char *name ) {
59 struct config_setting_type *type;
61 for ( type = config_setting_types ; type < config_setting_types_end ;
63 if ( strcasecmp ( name, type->name ) == 0 )
70 * Find configuration setting
73 * @ret setting Configuration setting, or NULL
75 static struct config_setting * find_config_setting ( const char *name ) {
76 struct config_setting *setting;
78 for ( setting = config_settings ; setting < config_settings_end ;
80 if ( strcasecmp ( name, setting->name ) == 0 )
87 * Find or build configuration setting
90 * @v setting Buffer to fill in with setting
91 * @ret rc Return status code
93 * Find setting if it exists. If it doesn't exist, but the name is of
94 * the form "<num>:<type>" (e.g. "12:string"), then construct a
95 * setting for that tag and data type, and return it. The constructed
96 * setting will be placed in the buffer.
98 static int find_or_build_config_setting ( const char *name,
99 struct config_setting *setting ) {
100 struct config_setting *known_setting;
101 char tmp_name[ strlen ( name ) + 1 ];
106 memset ( setting, 0, sizeof ( *setting ) );
107 setting->name = name;
108 setting->type = &config_setting_type_hex;
110 /* Strip qualifier, if present */
111 memcpy ( tmp_name, name, sizeof ( tmp_name ) );
112 if ( ( qualifier = strchr ( tmp_name, ':' ) ) != NULL )
115 /* If we recognise the name of the setting, use it */
116 if ( ( known_setting = find_config_setting ( tmp_name ) ) != NULL ) {
117 memcpy ( setting, known_setting, sizeof ( *setting ) );
119 /* Otherwise, try to interpret as a numerical setting */
120 for ( tmp = tmp_name ; 1 ; tmp++ ) {
121 setting->tag = ( ( setting->tag << 8 ) |
122 strtoul ( tmp, &tmp, 0 ) );
130 /* Apply qualifier, if present */
132 setting->type = find_config_setting_type ( qualifier );
133 if ( ! setting->type )
141 * Show value of named setting
143 * @v context Configuration context
144 * @v name Configuration setting name
145 * @v buf Buffer to contain value
146 * @v len Length of buffer
147 * @ret len Length of formatted value, or negative error
149 int show_named_setting ( struct config_context *context, const char *name,
150 char *buf, size_t len ) {
151 struct config_setting setting;
154 if ( ( rc = find_or_build_config_setting ( name, &setting ) ) != 0 )
156 return show_setting ( context, &setting, buf, len );
160 * Set value of named setting
162 * @v context Configuration context
163 * @v name Configuration setting name
164 * @v value Setting value (as a string)
165 * @ret rc Return status code
167 int set_named_setting ( struct config_context *context, const char *name,
168 const char *value ) {
169 struct config_setting setting;
172 if ( ( rc = find_or_build_config_setting ( name, &setting ) ) != 0 )
174 return set_setting ( context, &setting, value );
178 * Set value of setting
180 * @v context Configuration context
181 * @v setting Configuration setting
182 * @v value Setting value (as a string), or NULL
183 * @ret rc Return status code
185 int set_setting ( struct config_context *context,
186 struct config_setting *setting,
187 const char *value ) {
188 if ( ( ! value ) || ( ! *value ) ) {
189 /* Save putting deletion logic in each individual handler */
190 return clear_setting ( context, setting );
192 return setting->type->set ( context, setting, value );
196 * Show value of string setting
198 * @v context Configuration context
199 * @v setting Configuration setting
200 * @v buf Buffer to contain value
201 * @v len Length of buffer
202 * @ret len Length of formatted value, or negative error
204 static int show_string ( struct config_context *context,
205 struct config_setting *setting,
206 char *buf, size_t len ) {
207 struct dhcp_option *option;
209 option = find_dhcp_option ( context->options, setting->tag );
212 return dhcp_snprintf ( buf, len, option );
216 * Set value of string setting
218 * @v context Configuration context
219 * @v setting Configuration setting
220 * @v value Setting value (as a string)
221 * @ret rc Return status code
223 static int set_string ( struct config_context *context,
224 struct config_setting *setting,
225 const char *value ) {
226 struct dhcp_option *option;
228 option = set_dhcp_option ( context->options, setting->tag,
229 value, strlen ( value ) );
235 /** A string configuration setting */
236 struct config_setting_type config_setting_type_string __config_setting_type = {
238 .description = "Text string",
244 * Show value of IPv4 setting
246 * @v context Configuration context
247 * @v setting Configuration setting
248 * @v buf Buffer to contain value
249 * @v len Length of buffer
250 * @ret len Length of formatted value, or negative error
252 static int show_ipv4 ( struct config_context *context,
253 struct config_setting *setting,
254 char *buf, size_t len ) {
255 struct dhcp_option *option;
258 option = find_dhcp_option ( context->options, setting->tag );
261 dhcp_ipv4_option ( option, &ipv4 );
262 return snprintf ( buf, len, inet_ntoa ( ipv4 ) );
266 * Set value of IPV4 setting
268 * @v context Configuration context
269 * @v setting Configuration setting
270 * @v value Setting value (as a string)
271 * @ret rc Return status code
273 static int set_ipv4 ( struct config_context *context,
274 struct config_setting *setting,
275 const char *value ) {
276 struct dhcp_option *option;
279 if ( inet_aton ( value, &ipv4 ) == 0 )
281 option = set_dhcp_option ( context->options, setting->tag,
282 &ipv4, sizeof ( ipv4 ) );
288 /** An IPv4 configuration setting */
289 struct config_setting_type config_setting_type_ipv4 __config_setting_type = {
291 .description = "IPv4 address",
297 * Show value of integer setting
299 * @v context Configuration context
300 * @v setting Configuration setting
301 * @v buf Buffer to contain value
302 * @v len Length of buffer
303 * @ret len Length of formatted value, or negative error
305 static int show_int ( struct config_context *context,
306 struct config_setting *setting,
307 char *buf, size_t len ) {
308 struct dhcp_option *option;
311 option = find_dhcp_option ( context->options, setting->tag );
314 num = dhcp_num_option ( option );
315 return snprintf ( buf, len, "%ld", num );
319 * Set value of integer setting
321 * @v context Configuration context
322 * @v setting Configuration setting
323 * @v value Setting value (as a string)
324 * @v size Size of integer (in bytes)
325 * @ret rc Return status code
327 static int set_int ( struct config_context *context,
328 struct config_setting *setting,
329 const char *value, unsigned int size ) {
330 struct dhcp_option *option;
340 u.num = htonl ( strtoul ( value, &endp, 0 ) );
345 option = set_dhcp_option ( context->options, setting->tag,
346 &u.bytes[ sizeof ( u ) - size ], size );
353 * Set value of 8-bit integer setting
355 * @v context Configuration context
356 * @v setting Configuration setting
357 * @v value Setting value (as a string)
358 * @v size Size of integer (in bytes)
359 * @ret rc Return status code
361 static int set_int8 ( struct config_context *context,
362 struct config_setting *setting,
363 const char *value ) {
364 return set_int ( context, setting, value, 1 );
368 * Set value of 16-bit integer setting
370 * @v context Configuration context
371 * @v setting Configuration setting
372 * @v value Setting value (as a string)
373 * @v size Size of integer (in bytes)
374 * @ret rc Return status code
376 static int set_int16 ( struct config_context *context,
377 struct config_setting *setting,
378 const char *value ) {
379 return set_int ( context, setting, value, 2 );
383 * Set value of 32-bit integer setting
385 * @v context Configuration context
386 * @v setting Configuration setting
387 * @v value Setting value (as a string)
388 * @v size Size of integer (in bytes)
389 * @ret rc Return status code
391 static int set_int32 ( struct config_context *context,
392 struct config_setting *setting,
393 const char *value ) {
394 return set_int ( context, setting, value, 4 );
397 /** An 8-bit integer configuration setting */
398 struct config_setting_type config_setting_type_int8 __config_setting_type = {
400 .description = "8-bit integer",
405 /** A 16-bit integer configuration setting */
406 struct config_setting_type config_setting_type_int16 __config_setting_type = {
408 .description = "16-bit integer",
413 /** A 32-bit integer configuration setting */
414 struct config_setting_type config_setting_type_int32 __config_setting_type = {
416 .description = "32-bit integer",
422 * Set value of hex-string setting
424 * @v context Configuration context
425 * @v setting Configuration setting
426 * @v value Setting value (as a string)
427 * @ret rc Return status code
429 static int set_hex ( struct config_context *context,
430 struct config_setting *setting,
431 const char *value ) {
432 struct dhcp_option *option;
433 char *ptr = ( char * ) value;
434 uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
435 unsigned int len = 0;
438 bytes[len++] = strtoul ( ptr, &ptr, 16 );
441 option = set_dhcp_option ( context->options,
442 setting->tag, bytes, len );
456 * Show value of hex-string setting
458 * @v context Configuration context
459 * @v setting Configuration setting
460 * @v buf Buffer to contain value
461 * @v len Length of buffer
462 * @ret len Length of formatted value, or negative error
464 static int show_hex ( struct config_context *context,
465 struct config_setting *setting,
466 char *buf, size_t len ) {
467 struct dhcp_option *option;
471 option = find_dhcp_option ( context->options, setting->tag );
475 for ( i = 0 ; i < option->len ; i++ ) {
476 used += ssnprintf ( ( buf + used ), ( len - used ),
477 "%s%02x", ( used ? ":" : "" ),
478 option->data.bytes[i] );
483 /** A hex-string configuration setting */
484 struct config_setting_type config_setting_type_hex __config_setting_type = {
486 .description = "Hex string",
491 /** Some basic setting definitions */
492 struct config_setting basic_config_settings[] __config_setting = {
495 .description = "IP address of this machine (e.g. 192.168.0.1)",
496 .tag = DHCP_EB_YIADDR,
497 .type = &config_setting_type_ipv4,
501 .description = "Host name of this machine",
502 .tag = DHCP_HOST_NAME,
503 .type = &config_setting_type_string,
507 .description = "User name for authentication to servers",
508 .tag = DHCP_EB_USERNAME,
509 .type = &config_setting_type_string,
513 .description = "Password for authentication to servers",
514 .tag = DHCP_EB_PASSWORD,
515 .type = &config_setting_type_string,
519 .description = "NFS/iSCSI root path",
520 .tag = DHCP_ROOT_PATH,
521 .type = &config_setting_type_string,
525 .description = "Priority of these options",
526 .tag = DHCP_EB_PRIORITY,
527 .type = &config_setting_type_int8,
530 .name = "initiator-iqn",
531 .description = "iSCSI qualified name of this machine",
532 .tag = DHCP_ISCSI_INITIATOR_IQN,
533 .type = &config_setting_type_string,