[Settings] find_child_settings() accepts a NULL parent
[people/mcb30/gpxe.git] / src / core / settings.c
1 /*
2  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3  *
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.
8  *
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.
13  *
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.
17  */
18
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/vsprintf.h>
29 #include <gpxe/dhcp.h>
30 #include <gpxe/settings.h>
31
32 /** @file
33  *
34  * Configuration settings
35  *
36  */
37
38 /** Registered settings */
39 static struct setting settings[0]
40         __table_start ( struct setting, settings );
41 static struct setting settings_end[0]
42         __table_end ( struct setting, settings );
43
44 /** Registered setting types */
45 static struct setting_type setting_types[0]
46         __table_start ( struct setting_type, setting_types );
47 static struct setting_type setting_types_end[0]
48         __table_end ( struct setting_type, setting_types );
49
50 /** Registered settings applicators */
51 static struct settings_applicator settings_applicators[0]
52         __table_start ( struct settings_applicator, settings_applicators );
53 static struct settings_applicator settings_applicators_end[0]
54         __table_end ( struct settings_applicator, settings_applicators );
55
56 /******************************************************************************
57  *
58  * Registered settings blocks
59  *
60  ******************************************************************************
61  */
62
63 /**
64  * Store value of simple setting
65  *
66  * @v options           DHCP option block
67  * @v setting           Setting to store
68  * @v data              Setting data, or NULL to clear setting
69  * @v len               Length of setting data
70  * @ret rc              Return status code
71  */
72 int simple_settings_store ( struct settings *settings, struct setting *setting,
73                             const void *data, size_t len ) {
74         struct simple_settings *simple =
75                 container_of ( settings, struct simple_settings, settings );
76         return dhcpopt_extensible_store ( &simple->dhcpopts, setting->tag,
77                                           data, len );
78 }
79
80 /**
81  * Fetch value of simple setting
82  *
83  * @v options           DHCP option block
84  * @v setting           Setting to fetch
85  * @v data              Buffer to fill with setting data
86  * @v len               Length of buffer
87  * @ret len             Length of setting data, or negative error
88  */
89 int simple_settings_fetch ( struct settings *settings, struct setting *setting,
90                             void *data, size_t len ) {
91         struct simple_settings *simple =
92                 container_of ( settings, struct simple_settings, settings );
93         return dhcpopt_fetch ( &simple->dhcpopts, setting->tag, data, len );
94 }
95
96 /** Simple settings operations */
97 struct settings_operations simple_settings_operations = {
98         .store = simple_settings_store,
99         .fetch = simple_settings_fetch,
100 };
101
102 /** Root simple settings block */
103 struct simple_settings simple_settings_root = {
104         .settings = {
105                 .refcnt = NULL,
106                 .name = "",
107                 .siblings =
108                      LIST_HEAD_INIT ( simple_settings_root.settings.siblings ),
109                 .children =
110                      LIST_HEAD_INIT ( simple_settings_root.settings.children ),
111                 .op = &simple_settings_operations,
112         },
113 };
114
115 /** Root settings block */
116 #define settings_root simple_settings_root.settings
117
118 /**
119  * Apply all settings
120  *
121  * @ret rc              Return status code
122  */
123 static int apply_settings ( void ) {
124         struct settings_applicator *applicator;
125         int rc;
126
127         /* Call all settings applicators */
128         for ( applicator = settings_applicators ;
129               applicator < settings_applicators_end ; applicator++ ) {
130                 if ( ( rc = applicator->apply() ) != 0 ) {
131                         DBG ( "Could not apply settings using applicator "
132                               "%p: %s\n", applicator, strerror ( rc ) );
133                         return rc;
134                 }
135         }
136
137         return 0;
138 }
139
140 /**
141  * Reprioritise settings
142  *
143  * @v settings          Settings block
144  *
145  * Reorders the settings block amongst its siblings according to its
146  * priority.
147  */
148 static void reprioritise_settings ( struct settings *settings ) {
149         struct settings *parent = settings->parent;
150         long priority;
151         struct settings *tmp;
152         long tmp_priority;
153
154         /* Stop when we reach the top of the tree */
155         if ( ! parent )
156                 return;
157
158         /* Read priority, if present */
159         priority = fetch_intz_setting ( settings, &priority_setting );
160
161         /* Remove from siblings list */
162         list_del ( &settings->siblings );
163
164         /* Reinsert after any existing blocks which have a higher priority */
165         list_for_each_entry ( tmp, &parent->children, siblings ) {
166                 tmp_priority = fetch_intz_setting ( tmp, &priority_setting );
167                 if ( priority > tmp_priority )
168                         break;
169         }
170         list_add_tail ( &settings->siblings, &tmp->siblings );
171
172         /* Recurse up the tree */
173         reprioritise_settings ( parent );
174 }
175
176 /**
177  * Register settings block
178  *
179  * @v settings          Settings block
180  * @v parent            Parent settings block, or NULL
181  * @ret rc              Return status code
182  */
183 int register_settings ( struct settings *settings, struct settings *parent ) {
184
185         /* NULL parent => add to settings root */
186         assert ( settings != NULL );
187         if ( parent == NULL )
188                 parent = &settings_root;
189
190         /* Add to list of settings */
191         ref_get ( settings->refcnt );
192         ref_get ( parent->refcnt );
193         settings->parent = parent;
194         list_add_tail ( &settings->siblings, &parent->children );
195         DBGC ( settings, "Settings %p registered\n", settings );
196
197         /* Fix up settings priority */
198         reprioritise_settings ( settings );
199
200         /* Apply potentially-updated settings */
201         apply_settings();
202
203         return 0;
204 }
205
206 /**
207  * Unregister settings block
208  *
209  * @v settings          Settings block
210  */
211 void unregister_settings ( struct settings *settings ) {
212
213         /* Remove from list of settings */
214         ref_put ( settings->refcnt );
215         ref_put ( settings->parent->refcnt );
216         settings->parent = NULL;
217         list_del ( &settings->siblings );
218         DBGC ( settings, "Settings %p unregistered\n", settings );
219
220         /* Apply potentially-updated settings */
221         apply_settings();
222 }
223
224 /**
225  * Find child named settings block
226  *
227  * @v parent            Parent settings block
228  * @v name              Name within this parent
229  * @ret settings        Settings block, or NULL
230  */
231 struct settings * find_child_settings ( struct settings *parent,
232                                         const char *name ) {
233         struct settings *settings;
234         size_t len;
235
236         /* NULL parent => add to settings root */
237         if ( parent == NULL )
238                 parent = &settings_root;
239
240         /* Look for a child whose name matches the initial component */
241         list_for_each_entry ( settings, &parent->children, siblings ) {
242                 len = strlen ( settings->name );
243                 if ( strncmp ( name, settings->name, len ) != 0 )
244                         continue;
245                 if ( name[len] == 0 )
246                         return settings;
247                 if ( name[len] == '.' )
248                         return find_child_settings ( settings,
249                                                      ( name + len + 1 ) );
250         }
251
252         return NULL;
253 }
254
255 /**
256  * Find named settings block
257  *
258  * @v name              Name
259  * @ret settings        Settings block, or NULL
260  */
261 struct settings * find_settings ( const char *name ) {
262
263         /* If name is empty, use the root */
264         if ( ! *name )
265                 return &settings_root;
266
267         return find_child_settings ( &settings_root, name );
268 }
269
270 /******************************************************************************
271  *
272  * Core settings routines
273  *
274  ******************************************************************************
275  */
276
277 /**
278  * Store value of setting
279  *
280  * @v settings          Settings block
281  * @v setting           Setting to store
282  * @v data              Setting data, or NULL to clear setting
283  * @v len               Length of setting data
284  * @ret rc              Return status code
285  */
286 int store_setting ( struct settings *settings, struct setting *setting,
287                     const void *data, size_t len ) {
288         int rc;
289
290         /* Sanity check */
291         if ( ! settings )
292                 return -ENODEV;
293
294         /* Store setting */
295         if ( ( rc = settings->op->store ( settings, setting,
296                                           data, len ) ) != 0 )
297                 return rc;
298
299         /* Reprioritise settings if necessary */
300         if ( setting_cmp ( setting, &priority_setting ) == 0 )
301                 reprioritise_settings ( settings );
302
303         /* If these settings are registered, apply potentially-updated
304          * settings
305          */
306         for ( ; settings ; settings = settings->parent ) {
307                 if ( settings == &settings_root ) {
308                         if ( ( rc = apply_settings() ) != 0 )
309                                 return rc;
310                         break;
311                 }
312         }
313
314         return 0;
315 }
316
317 /**
318  * Fetch value of setting
319  *
320  * @v settings          Settings block, or NULL to search all blocks
321  * @v setting           Setting to fetch
322  * @v data              Buffer to fill with setting data
323  * @v len               Length of buffer
324  * @ret len             Length of setting data, or negative error
325  *
326  * The actual length of the setting will be returned even if
327  * the buffer was too small.
328  */
329 int fetch_setting ( struct settings *settings, struct setting *setting,
330                     void *data, size_t len ) {
331         struct settings *child;
332         int ret;
333
334         /* NULL settings implies starting at the global settings root */
335         if ( ! settings )
336                 settings = &settings_root;
337
338         /* Try this block first */
339         if ( ( ret = settings->op->fetch ( settings, setting,
340                                            data, len ) ) >= 0 )
341                 return ret;
342
343         /* Recurse into each child block in turn */
344         list_for_each_entry ( child, &settings->children, siblings ) {
345                 if ( ( ret = fetch_setting ( child, setting,
346                                              data, len ) ) >= 0 )
347                         return ret;
348         }
349
350         return -ENOENT;
351 }
352
353 /**
354  * Fetch length of setting
355  *
356  * @v settings          Settings block, or NULL to search all blocks
357  * @v setting           Setting to fetch
358  * @ret len             Length of setting data, or negative error
359  *
360  * This function can also be used as an existence check for the
361  * setting.
362  */
363 int fetch_setting_len ( struct settings *settings, struct setting *setting ) {
364         return fetch_setting ( settings, setting, NULL, 0 );
365 }
366
367 /**
368  * Fetch value of string setting
369  *
370  * @v settings          Settings block, or NULL to search all blocks
371  * @v setting           Setting to fetch
372  * @v data              Buffer to fill with setting string data
373  * @v len               Length of buffer
374  * @ret len             Length of string setting, or negative error
375  *
376  * The resulting string is guaranteed to be correctly NUL-terminated.
377  * The returned length will be the length of the underlying setting
378  * data.
379  */
380 int fetch_string_setting ( struct settings *settings, struct setting *setting,
381                            char *data, size_t len ) {
382         memset ( data, 0, len );
383         return fetch_setting ( settings, setting, data, ( len - 1 ) );
384 }
385
386 /**
387  * Fetch value of IPv4 address setting
388  *
389  * @v settings          Settings block, or NULL to search all blocks
390  * @v setting           Setting to fetch
391  * @v inp               IPv4 address to fill in
392  * @ret len             Length of setting, or negative error
393  */
394 int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
395                          struct in_addr *inp ) {
396         int len;
397
398         len = fetch_setting ( settings, setting, inp, sizeof ( *inp ) );
399         if ( len < 0 )
400                 return len;
401         if ( len < ( int ) sizeof ( *inp ) )
402                 return -ERANGE;
403         return len;
404 }
405
406 /**
407  * Fetch value of signed integer setting
408  *
409  * @v settings          Settings block, or NULL to search all blocks
410  * @v setting           Setting to fetch
411  * @v value             Integer value to fill in
412  * @ret len             Length of setting, or negative error
413  */
414 int fetch_int_setting ( struct settings *settings, struct setting *setting,
415                         long *value ) {
416         union {
417                 long value;
418                 uint8_t u8[ sizeof ( long ) ];
419                 int8_t s8[ sizeof ( long ) ];
420         } buf;
421         int len;
422         int i;
423
424         buf.value = 0;
425         len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
426         if ( len < 0 )
427                 return len;
428         if ( len > ( int ) sizeof ( buf ) )
429                 return -ERANGE;
430
431         *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
432         for ( i = 0 ; i < len ; i++ ) {
433                 *value = ( ( *value << 8 ) | buf.u8[i] );
434         }
435
436         return len;
437 }
438
439 /**
440  * Fetch value of unsigned integer setting
441  *
442  * @v settings          Settings block, or NULL to search all blocks
443  * @v setting           Setting to fetch
444  * @v value             Integer value to fill in
445  * @ret len             Length of setting, or negative error
446  */
447 int fetch_uint_setting ( struct settings *settings, struct setting *setting,
448                          unsigned long *value ) {
449         long svalue;
450         int len;
451
452         len = fetch_int_setting ( settings, setting, &svalue );
453         if ( len < 0 )
454                 return len;
455
456         *value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) );
457
458         return len;
459 }
460
461 /**
462  * Fetch value of signed integer setting, or zero
463  *
464  * @v settings          Settings block, or NULL to search all blocks
465  * @v setting           Setting to fetch
466  * @ret value           Setting value, or zero
467  */
468 long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
469         long value = 0;
470
471         fetch_int_setting ( settings, setting, &value );
472         return value;
473 }
474
475 /**
476  * Fetch value of unsigned integer setting, or zero
477  *
478  * @v settings          Settings block, or NULL to search all blocks
479  * @v setting           Setting to fetch
480  * @ret value           Setting value, or zero
481  */
482 unsigned long fetch_uintz_setting ( struct settings *settings,
483                                     struct setting *setting ) {
484         unsigned long value = 0;
485
486         fetch_uint_setting ( settings, setting, &value );
487         return value;
488 }
489
490 /**
491  * Compare two settings
492  *
493  * @v a                 Setting to compare
494  * @v b                 Setting to compare
495  * @ret 0               Settings are the same
496  * @ret non-zero        Settings are not the same
497  */
498 int setting_cmp ( struct setting *a, struct setting *b ) {
499
500         /* If the settings have tags, compare them */
501         if ( a->tag && ( a->tag == b->tag ) )
502                 return 0;
503
504         /* Otherwise, compare the names */
505         return strcmp ( a->name, b->name );
506 }
507
508 /******************************************************************************
509  *
510  * Formatted setting routines
511  *
512  ******************************************************************************
513  */
514
515 /**
516  * Store value of typed setting
517  *
518  * @v settings          Settings block
519  * @v setting           Setting to store
520  * @v type              Settings type
521  * @v value             Formatted setting data, or NULL
522  * @ret rc              Return status code
523  */
524 int storef_setting ( struct settings *settings, struct setting *setting,
525                      const char *value ) {
526
527         /* NULL value implies deletion.  Avoid imposing the burden of
528          * checking for NULL values on each typed setting's storef()
529          * method.
530          */
531         if ( ! value )
532                 return delete_setting ( settings, setting );
533                 
534         return setting->type->storef ( settings, setting, value );
535 }
536
537 /**
538  * Find named setting
539  *
540  * @v name              Name
541  * @ret setting         Named setting, or NULL
542  */
543 static struct setting * find_setting ( const char *name ) {
544         struct setting *setting;
545
546         for ( setting = settings ; setting < settings_end ; setting++ ) {
547                 if ( strcmp ( name, setting->name ) == 0 )
548                         return setting;
549         }
550         return NULL;
551 }
552
553 /**
554  * Find setting type
555  *
556  * @v name              Name
557  * @ret type            Setting type, or NULL
558  */
559 static struct setting_type * find_setting_type ( const char *name ) {
560         struct setting_type *type;
561
562         for ( type = setting_types ; type < setting_types_end ; type++ ) {
563                 if ( strcmp ( name, type->name ) == 0 )
564                         return type;
565         }
566         return NULL;
567 }
568
569 /**
570  * Parse setting name
571  *
572  * @v name              Name of setting
573  * @v settings          Settings block to fill in
574  * @v setting           Setting to fill in
575  * @ret rc              Return status code
576  *
577  * Interprets a name of the form
578  * "[settings_name/]tag_name[:type_name]" and fills in the appropriate
579  * fields.
580  */
581 static int parse_setting_name ( const char *name, struct settings **settings,
582                                 struct setting *setting ) {
583         char tmp_name[ strlen ( name ) + 1 ];
584         char *settings_name;
585         char *setting_name;
586         char *type_name;
587         struct setting *named_setting;
588         char *tmp;
589
590         /* Set defaults */
591         *settings = &settings_root;
592         memset ( setting, 0, sizeof ( *setting ) );
593         setting->type = &setting_type_hex;
594
595         /* Split name into "[settings_name/]setting_name[:type_name]" */
596         memcpy ( tmp_name, name, sizeof ( tmp_name ) );
597         if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) {
598                 *(setting_name++) = 0;
599                 settings_name = tmp_name;
600         } else {
601                 setting_name = tmp_name;
602                 settings_name = NULL;
603         }
604         if ( ( type_name = strchr ( setting_name, ':' ) ) != NULL )
605                 *(type_name++) = 0;
606
607         /* Identify settings block, if specified */
608         if ( settings_name ) {
609                 *settings = find_settings ( settings_name );
610                 if ( *settings == NULL ) {
611                         DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n",
612                               settings_name, name );
613                         return -ENODEV;
614                 }
615         }
616
617         /* Identify tag number */
618         if ( ( named_setting = find_setting ( setting_name ) ) != NULL ) {
619                 memcpy ( setting, named_setting, sizeof ( *setting ) );
620         } else {
621                 /* Unrecognised name: try to interpret as a tag number */
622                 tmp = setting_name;
623                 while ( 1 ) {
624                         setting->tag = ( ( setting->tag << 8 ) |
625                                          strtoul ( tmp, &tmp, 0 ) );
626                         if ( *tmp == 0 )
627                                 break;
628                         if ( *tmp != '.' ) {
629                                 DBG ( "Invalid setting \"%s\" in \"%s\"\n",
630                                       setting_name, name );
631                                 return -ENOENT;
632                         }
633                         tmp++;
634                 }
635         }
636
637         /* Identify setting type, if specified */
638         if ( type_name ) {
639                 setting->type = find_setting_type ( type_name );
640                 if ( setting->type == NULL ) {
641                         DBG ( "Invalid setting type \"%s\" in \"%s\"\n",
642                               type_name, name );
643                         return -ENOTSUP;
644                 }
645         }
646
647         return 0;
648 }
649
650 /**
651  * Parse and store value of named setting
652  *
653  * @v name              Name of setting
654  * @v value             Formatted setting data, or NULL
655  * @ret rc              Return status code
656  */
657 int storef_named_setting ( const char *name, const char *value ) {
658         struct settings *settings;
659         struct setting setting;
660         int rc;
661
662         if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
663                 return rc;
664         return storef_setting ( settings, &setting, value );
665 }
666
667 /**
668  * Fetch and format value of named setting
669  *
670  * @v name              Name of setting
671  * @v buf               Buffer to contain formatted value
672  * @v len               Length of buffer
673  * @ret len             Length of formatted value, or negative error
674  */
675 int fetchf_named_setting ( const char *name, char *buf, size_t len ) {
676         struct settings *settings;
677         struct setting setting;
678         int rc;
679
680         if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
681                 return rc;
682         return fetchf_setting ( settings, &setting, buf, len );
683 }
684
685 /******************************************************************************
686  *
687  * Setting types
688  *
689  ******************************************************************************
690  */
691
692 /**
693  * Parse and store value of string setting
694  *
695  * @v settings          Settings block
696  * @v setting           Setting to store
697  * @v value             Formatted setting data
698  * @ret rc              Return status code
699  */
700 static int storef_string ( struct settings *settings, struct setting *setting,
701                            const char *value ) {
702         return store_setting ( settings, setting, value, strlen ( value ) );
703 }
704
705 /**
706  * Fetch and format value of string setting
707  *
708  * @v settings          Settings block, or NULL to search all blocks
709  * @v setting           Setting to fetch
710  * @v buf               Buffer to contain formatted value
711  * @v len               Length of buffer
712  * @ret len             Length of formatted value, or negative error
713  */
714 static int fetchf_string ( struct settings *settings, struct setting *setting,
715                            char *buf, size_t len ) {
716         return fetch_string_setting ( settings, setting, buf, len );
717 }
718
719 /** A string setting type */
720 struct setting_type setting_type_string __setting_type = {
721         .name = "string",
722         .storef = storef_string,
723         .fetchf = fetchf_string,
724 };
725
726 /**
727  * Parse and store value of IPv4 address setting
728  *
729  * @v settings          Settings block
730  * @v setting           Setting to store
731  * @v value             Formatted setting data
732  * @ret rc              Return status code
733  */
734 static int storef_ipv4 ( struct settings *settings, struct setting *setting,
735                          const char *value ) {
736         struct in_addr ipv4;
737
738         if ( inet_aton ( value, &ipv4 ) == 0 )
739                 return -EINVAL;
740         return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) );
741 }
742
743 /**
744  * Fetch and format value of IPv4 address setting
745  *
746  * @v settings          Settings block, or NULL to search all blocks
747  * @v setting           Setting to fetch
748  * @v buf               Buffer to contain formatted value
749  * @v len               Length of buffer
750  * @ret len             Length of formatted value, or negative error
751  */
752 static int fetchf_ipv4 ( struct settings *settings, struct setting *setting,
753                          char *buf, size_t len ) {
754         struct in_addr ipv4;
755         int rc;
756
757         if ( ( rc = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0 )
758                 return rc;
759         return snprintf ( buf, len, inet_ntoa ( ipv4 ) );
760 }
761
762 /** An IPv4 address setting type */
763 struct setting_type setting_type_ipv4 __setting_type = {
764         .name = "ipv4",
765         .storef = storef_ipv4,
766         .fetchf = fetchf_ipv4,
767 };
768
769 /**
770  * Parse and store value of integer setting
771  *
772  * @v settings          Settings block
773  * @v setting           Setting to store
774  * @v value             Formatted setting data
775  * @v size              Integer size, in bytes
776  * @ret rc              Return status code
777  */
778 static int storef_int ( struct settings *settings, struct setting *setting,
779                         const char *value, unsigned int size ) {
780         union {
781                 uint32_t num;
782                 uint8_t bytes[4];
783         } u;
784         char *endp;
785
786         u.num = htonl ( strtoul ( value, &endp, 0 ) );
787         if ( *endp )
788                 return -EINVAL;
789         return store_setting ( settings, setting, 
790                                &u.bytes[ sizeof ( u ) - size ], size );
791 }
792
793 /**
794  * Parse and store value of 8-bit integer setting
795  *
796  * @v settings          Settings block
797  * @v setting           Setting to store
798  * @v value             Formatted setting data
799  * @v size              Integer size, in bytes
800  * @ret rc              Return status code
801  */
802 static int storef_int8 ( struct settings *settings, struct setting *setting,
803                          const char *value ) {
804         return storef_int ( settings, setting, value, 1 );
805 }
806
807 /**
808  * Parse and store value of 16-bit integer setting
809  *
810  * @v settings          Settings block
811  * @v setting           Setting to store
812  * @v value             Formatted setting data
813  * @v size              Integer size, in bytes
814  * @ret rc              Return status code
815  */
816 static int storef_int16 ( struct settings *settings, struct setting *setting,
817                           const char *value ) {
818         return storef_int ( settings, setting, value, 2 );
819 }
820
821 /**
822  * Parse and store value of 32-bit integer setting
823  *
824  * @v settings          Settings block
825  * @v setting           Setting to store
826  * @v value             Formatted setting data
827  * @v size              Integer size, in bytes
828  * @ret rc              Return status code
829  */
830 static int storef_int32 ( struct settings *settings, struct setting *setting,
831                           const char *value ) {
832         return storef_int ( settings, setting, value, 4 );
833 }
834
835 /**
836  * Fetch and format value of signed integer setting
837  *
838  * @v settings          Settings block, or NULL to search all blocks
839  * @v setting           Setting to fetch
840  * @v buf               Buffer to contain formatted value
841  * @v len               Length of buffer
842  * @ret len             Length of formatted value, or negative error
843  */
844 static int fetchf_int ( struct settings *settings, struct setting *setting,
845                         char *buf, size_t len ) {
846         long value;
847         int rc;
848
849         if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 )
850                 return rc;
851         return snprintf ( buf, len, "%ld", value );
852 }
853
854 /**
855  * Fetch and format value of unsigned integer setting
856  *
857  * @v settings          Settings block, or NULL to search all blocks
858  * @v setting           Setting to fetch
859  * @v buf               Buffer to contain formatted value
860  * @v len               Length of buffer
861  * @ret len             Length of formatted value, or negative error
862  */
863 static int fetchf_uint ( struct settings *settings, struct setting *setting,
864                          char *buf, size_t len ) {
865         unsigned long value;
866         int rc;
867
868         if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 )
869                 return rc;
870         return snprintf ( buf, len, "%#lx", value );
871 }
872
873 /** A signed 8-bit integer setting type */
874 struct setting_type setting_type_int8 __setting_type = {
875         .name = "int8",
876         .storef = storef_int8,
877         .fetchf = fetchf_int,
878 };
879
880 /** A signed 16-bit integer setting type */
881 struct setting_type setting_type_int16 __setting_type = {
882         .name = "int16",
883         .storef = storef_int16,
884         .fetchf = fetchf_int,
885 };
886
887 /** A signed 32-bit integer setting type */
888 struct setting_type setting_type_int32 __setting_type = {
889         .name = "int32",
890         .storef = storef_int32,
891         .fetchf = fetchf_int,
892 };
893
894 /** An unsigned 8-bit integer setting type */
895 struct setting_type setting_type_uint8 __setting_type = {
896         .name = "uint8",
897         .storef = storef_int8,
898         .fetchf = fetchf_uint,
899 };
900
901 /** An unsigned 16-bit integer setting type */
902 struct setting_type setting_type_uint16 __setting_type = {
903         .name = "uint16",
904         .storef = storef_int16,
905         .fetchf = fetchf_uint,
906 };
907
908 /** An unsigned 32-bit integer setting type */
909 struct setting_type setting_type_uint32 __setting_type = {
910         .name = "uint32",
911         .storef = storef_int32,
912         .fetchf = fetchf_uint,
913 };
914
915 /**
916  * Parse and store value of hex string setting
917  *
918  * @v settings          Settings block
919  * @v setting           Setting to store
920  * @v value             Formatted setting data
921  * @ret rc              Return status code
922  */
923 static int storef_hex ( struct settings *settings, struct setting *setting,
924                         const char *value ) {
925         char *ptr = ( char * ) value;
926         uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
927         unsigned int len = 0;
928
929         while ( 1 ) {
930                 bytes[len++] = strtoul ( ptr, &ptr, 16 );
931                 switch ( *ptr ) {
932                 case '\0' :
933                         return store_setting ( settings, setting, bytes, len );
934                 case ':' :
935                         ptr++;
936                         break;
937                 default :
938                         return -EINVAL;
939                 }
940         }
941 }
942
943 /**
944  * Fetch and format value of hex string setting
945  *
946  * @v settings          Settings block, or NULL to search all blocks
947  * @v setting           Setting to fetch
948  * @v buf               Buffer to contain formatted value
949  * @v len               Length of buffer
950  * @ret len             Length of formatted value, or negative error
951  */
952 static int fetchf_hex ( struct settings *settings, struct setting *setting,
953                         char *buf, size_t len ) {
954         int raw_len;
955         int check_len;
956         int used = 0;
957         int i;
958
959         raw_len = fetch_setting_len ( settings, setting );
960         if ( raw_len < 0 )
961                 return raw_len;
962
963         {
964                 uint8_t raw[raw_len];
965
966                 check_len = fetch_setting ( settings, setting, raw,
967                                             sizeof ( raw ) );
968                 assert ( check_len == raw_len );
969                 
970                 if ( len )
971                         buf[0] = 0; /* Ensure that a terminating NUL exists */
972                 for ( i = 0 ; i < raw_len ; i++ ) {
973                         used += ssnprintf ( ( buf + used ), ( len - used ),
974                                             "%s%02x", ( used ? ":" : "" ),
975                                             raw[i] );
976                 }
977                 return used;
978         }
979 }
980
981 /** A hex-string setting */
982 struct setting_type setting_type_hex __setting_type = {
983         .name = "hex",
984         .storef = storef_hex,
985         .fetchf = fetchf_hex,
986 };
987
988 /******************************************************************************
989  *
990  * Settings
991  *
992  ******************************************************************************
993  */
994
995 /** Hostname setting */
996 struct setting hostname_setting __setting = {
997         .name = "hostname",
998         .description = "Host name",
999         .tag = DHCP_HOST_NAME,
1000         .type = &setting_type_string,
1001 };
1002
1003 /** Filename setting */
1004 struct setting filename_setting __setting = {
1005         .name = "filename",
1006         .description = "Boot filename",
1007         .tag = DHCP_BOOTFILE_NAME,
1008         .type = &setting_type_string,
1009 };
1010
1011 /** Root path setting */
1012 struct setting root_path_setting __setting = {
1013         .name = "root-path",
1014         .description = "NFS/iSCSI root path",
1015         .tag = DHCP_ROOT_PATH,
1016         .type = &setting_type_string,
1017 };
1018
1019 /** Username setting */
1020 struct setting username_setting __setting = {
1021         .name = "username",
1022         .description = "User name",
1023         .tag = DHCP_EB_USERNAME,
1024         .type = &setting_type_string,
1025 };
1026
1027 /** Password setting */
1028 struct setting password_setting __setting = {
1029         .name = "password",
1030         .description = "Password",
1031         .tag = DHCP_EB_PASSWORD,
1032         .type = &setting_type_string,
1033 };
1034
1035 /** Priority setting */
1036 struct setting priority_setting __setting = {
1037         .name = "priority",
1038         .description = "Priority of these settings",
1039         .tag = DHCP_EB_PRIORITY,
1040         .type = &setting_type_int8,
1041 };