[Settings] Remove assumption that all settings have DHCP tag values
[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         /* Look for a child whose name matches the initial component */
237         list_for_each_entry ( settings, &parent->children, siblings ) {
238                 len = strlen ( settings->name );
239                 if ( strncmp ( name, settings->name, len ) != 0 )
240                         continue;
241                 if ( name[len] == 0 )
242                         return settings;
243                 if ( name[len] == '.' )
244                         return find_child_settings ( settings,
245                                                      ( name + len + 1 ) );
246         }
247
248         return NULL;
249 }
250
251 /**
252  * Find named settings block
253  *
254  * @v name              Name
255  * @ret settings        Settings block, or NULL
256  */
257 struct settings * find_settings ( const char *name ) {
258
259         /* If name is empty, use the root */
260         if ( ! *name )
261                 return &settings_root;
262
263         return find_child_settings ( &settings_root, name );
264 }
265
266 /******************************************************************************
267  *
268  * Core settings routines
269  *
270  ******************************************************************************
271  */
272
273 /**
274  * Store value of setting
275  *
276  * @v settings          Settings block
277  * @v setting           Setting to store
278  * @v data              Setting data, or NULL to clear setting
279  * @v len               Length of setting data
280  * @ret rc              Return status code
281  */
282 int store_setting ( struct settings *settings, struct setting *setting,
283                     const void *data, size_t len ) {
284         int rc;
285
286         /* Sanity check */
287         if ( ! settings )
288                 return -ENODEV;
289
290         /* Store setting */
291         if ( ( rc = settings->op->store ( settings, setting,
292                                           data, len ) ) != 0 )
293                 return rc;
294
295         /* Reprioritise settings if necessary */
296         if ( setting_cmp ( setting, &priority_setting ) == 0 )
297                 reprioritise_settings ( settings );
298
299         /* If these settings are registered, apply potentially-updated
300          * settings
301          */
302         for ( ; settings ; settings = settings->parent ) {
303                 if ( settings == &settings_root ) {
304                         if ( ( rc = apply_settings() ) != 0 )
305                                 return rc;
306                         break;
307                 }
308         }
309
310         return 0;
311 }
312
313 /**
314  * Fetch value of setting
315  *
316  * @v settings          Settings block, or NULL to search all blocks
317  * @v setting           Setting to fetch
318  * @v data              Buffer to fill with setting data
319  * @v len               Length of buffer
320  * @ret len             Length of setting data, or negative error
321  *
322  * The actual length of the setting will be returned even if
323  * the buffer was too small.
324  */
325 int fetch_setting ( struct settings *settings, struct setting *setting,
326                     void *data, size_t len ) {
327         struct settings *child;
328         int ret;
329
330         /* NULL settings implies starting at the global settings root */
331         if ( ! settings )
332                 settings = &settings_root;
333
334         /* Try this block first */
335         if ( ( ret = settings->op->fetch ( settings, setting,
336                                            data, len ) ) >= 0 )
337                 return ret;
338
339         /* Recurse into each child block in turn */
340         list_for_each_entry ( child, &settings->children, siblings ) {
341                 if ( ( ret = fetch_setting ( child, setting,
342                                              data, len ) ) >= 0 )
343                         return ret;
344         }
345
346         return -ENOENT;
347 }
348
349 /**
350  * Fetch length of setting
351  *
352  * @v settings          Settings block, or NULL to search all blocks
353  * @v setting           Setting to fetch
354  * @ret len             Length of setting data, or negative error
355  *
356  * This function can also be used as an existence check for the
357  * setting.
358  */
359 int fetch_setting_len ( struct settings *settings, struct setting *setting ) {
360         return fetch_setting ( settings, setting, NULL, 0 );
361 }
362
363 /**
364  * Fetch value of string setting
365  *
366  * @v settings          Settings block, or NULL to search all blocks
367  * @v setting           Setting to fetch
368  * @v data              Buffer to fill with setting string data
369  * @v len               Length of buffer
370  * @ret len             Length of string setting, or negative error
371  *
372  * The resulting string is guaranteed to be correctly NUL-terminated.
373  * The returned length will be the length of the underlying setting
374  * data.
375  */
376 int fetch_string_setting ( struct settings *settings, struct setting *setting,
377                            char *data, size_t len ) {
378         memset ( data, 0, len );
379         return fetch_setting ( settings, setting, data, ( len - 1 ) );
380 }
381
382 /**
383  * Fetch value of IPv4 address setting
384  *
385  * @v settings          Settings block, or NULL to search all blocks
386  * @v setting           Setting to fetch
387  * @v inp               IPv4 address to fill in
388  * @ret len             Length of setting, or negative error
389  */
390 int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
391                          struct in_addr *inp ) {
392         int len;
393
394         len = fetch_setting ( settings, setting, inp, sizeof ( *inp ) );
395         if ( len < 0 )
396                 return len;
397         if ( len < ( int ) sizeof ( *inp ) )
398                 return -ERANGE;
399         return len;
400 }
401
402 /**
403  * Fetch value of signed integer setting
404  *
405  * @v settings          Settings block, or NULL to search all blocks
406  * @v setting           Setting to fetch
407  * @v value             Integer value to fill in
408  * @ret len             Length of setting, or negative error
409  */
410 int fetch_int_setting ( struct settings *settings, struct setting *setting,
411                         long *value ) {
412         union {
413                 long value;
414                 uint8_t u8[ sizeof ( long ) ];
415                 int8_t s8[ sizeof ( long ) ];
416         } buf;
417         int len;
418         int i;
419
420         buf.value = 0;
421         len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
422         if ( len < 0 )
423                 return len;
424         if ( len > ( int ) sizeof ( buf ) )
425                 return -ERANGE;
426
427         *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
428         for ( i = 0 ; i < len ; i++ ) {
429                 *value = ( ( *value << 8 ) | buf.u8[i] );
430         }
431
432         return len;
433 }
434
435 /**
436  * Fetch value of unsigned integer setting
437  *
438  * @v settings          Settings block, or NULL to search all blocks
439  * @v setting           Setting to fetch
440  * @v value             Integer value to fill in
441  * @ret len             Length of setting, or negative error
442  */
443 int fetch_uint_setting ( struct settings *settings, struct setting *setting,
444                          unsigned long *value ) {
445         long svalue;
446         int len;
447
448         len = fetch_int_setting ( settings, setting, &svalue );
449         if ( len < 0 )
450                 return len;
451
452         *value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) );
453
454         return len;
455 }
456
457 /**
458  * Fetch value of signed integer setting, or zero
459  *
460  * @v settings          Settings block, or NULL to search all blocks
461  * @v setting           Setting to fetch
462  * @ret value           Setting value, or zero
463  */
464 long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
465         long value = 0;
466
467         fetch_int_setting ( settings, setting, &value );
468         return value;
469 }
470
471 /**
472  * Fetch value of unsigned integer setting, or zero
473  *
474  * @v settings          Settings block, or NULL to search all blocks
475  * @v setting           Setting to fetch
476  * @ret value           Setting value, or zero
477  */
478 unsigned long fetch_uintz_setting ( struct settings *settings,
479                                     struct setting *setting ) {
480         unsigned long value = 0;
481
482         fetch_uint_setting ( settings, setting, &value );
483         return value;
484 }
485
486 /**
487  * Compare two settings
488  *
489  * @v a                 Setting to compare
490  * @v b                 Setting to compare
491  * @ret 0               Settings are the same
492  * @ret non-zero        Settings are not the same
493  */
494 int setting_cmp ( struct setting *a, struct setting *b ) {
495
496         /* If the settings have tags, compare them */
497         if ( a->tag && ( a->tag == b->tag ) )
498                 return 0;
499
500         /* Otherwise, compare the names */
501         return strcmp ( a->name, b->name );
502 }
503
504 /******************************************************************************
505  *
506  * Formatted setting routines
507  *
508  ******************************************************************************
509  */
510
511 /**
512  * Store value of typed setting
513  *
514  * @v settings          Settings block
515  * @v setting           Setting to store
516  * @v type              Settings type
517  * @v value             Formatted setting data, or NULL
518  * @ret rc              Return status code
519  */
520 int storef_setting ( struct settings *settings, struct setting *setting,
521                      const char *value ) {
522
523         /* NULL value implies deletion.  Avoid imposing the burden of
524          * checking for NULL values on each typed setting's storef()
525          * method.
526          */
527         if ( ! value )
528                 return delete_setting ( settings, setting );
529                 
530         return setting->type->storef ( settings, setting, value );
531 }
532
533 /**
534  * Find named setting
535  *
536  * @v name              Name
537  * @ret setting         Named setting, or NULL
538  */
539 static struct setting * find_setting ( const char *name ) {
540         struct setting *setting;
541
542         for ( setting = settings ; setting < settings_end ; setting++ ) {
543                 if ( strcmp ( name, setting->name ) == 0 )
544                         return setting;
545         }
546         return NULL;
547 }
548
549 /**
550  * Find setting type
551  *
552  * @v name              Name
553  * @ret type            Setting type, or NULL
554  */
555 static struct setting_type * find_setting_type ( const char *name ) {
556         struct setting_type *type;
557
558         for ( type = setting_types ; type < setting_types_end ; type++ ) {
559                 if ( strcmp ( name, type->name ) == 0 )
560                         return type;
561         }
562         return NULL;
563 }
564
565 /**
566  * Parse setting name
567  *
568  * @v name              Name of setting
569  * @v settings          Settings block to fill in
570  * @v setting           Setting to fill in
571  * @ret rc              Return status code
572  *
573  * Interprets a name of the form
574  * "[settings_name/]tag_name[:type_name]" and fills in the appropriate
575  * fields.
576  */
577 static int parse_setting_name ( const char *name, struct settings **settings,
578                                 struct setting *setting ) {
579         char tmp_name[ strlen ( name ) + 1 ];
580         char *settings_name;
581         char *setting_name;
582         char *type_name;
583         struct setting *named_setting;
584         char *tmp;
585
586         /* Set defaults */
587         *settings = &settings_root;
588         memset ( setting, 0, sizeof ( *setting ) );
589         setting->type = &setting_type_hex;
590
591         /* Split name into "[settings_name/]setting_name[:type_name]" */
592         memcpy ( tmp_name, name, sizeof ( tmp_name ) );
593         if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) {
594                 *(setting_name++) = 0;
595                 settings_name = tmp_name;
596         } else {
597                 setting_name = tmp_name;
598                 settings_name = NULL;
599         }
600         if ( ( type_name = strchr ( setting_name, ':' ) ) != NULL )
601                 *(type_name++) = 0;
602
603         /* Identify settings block, if specified */
604         if ( settings_name ) {
605                 *settings = find_settings ( settings_name );
606                 if ( *settings == NULL ) {
607                         DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n",
608                               settings_name, name );
609                         return -ENODEV;
610                 }
611         }
612
613         /* Identify tag number */
614         if ( ( named_setting = find_setting ( setting_name ) ) != NULL ) {
615                 memcpy ( setting, named_setting, sizeof ( *setting ) );
616         } else {
617                 /* Unrecognised name: try to interpret as a tag number */
618                 tmp = setting_name;
619                 while ( 1 ) {
620                         setting->tag = ( ( setting->tag << 8 ) |
621                                          strtoul ( tmp, &tmp, 0 ) );
622                         if ( *tmp == 0 )
623                                 break;
624                         if ( *tmp != '.' ) {
625                                 DBG ( "Invalid setting \"%s\" in \"%s\"\n",
626                                       setting_name, name );
627                                 return -ENOENT;
628                         }
629                         tmp++;
630                 }
631         }
632
633         /* Identify setting type, if specified */
634         if ( type_name ) {
635                 setting->type = find_setting_type ( type_name );
636                 if ( setting->type == NULL ) {
637                         DBG ( "Invalid setting type \"%s\" in \"%s\"\n",
638                               type_name, name );
639                         return -ENOTSUP;
640                 }
641         }
642
643         return 0;
644 }
645
646 /**
647  * Parse and store value of named setting
648  *
649  * @v name              Name of setting
650  * @v value             Formatted setting data, or NULL
651  * @ret rc              Return status code
652  */
653 int storef_named_setting ( const char *name, const char *value ) {
654         struct settings *settings;
655         struct setting setting;
656         int rc;
657
658         if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
659                 return rc;
660         return storef_setting ( settings, &setting, value );
661 }
662
663 /**
664  * Fetch and format value of named setting
665  *
666  * @v name              Name of setting
667  * @v buf               Buffer to contain formatted value
668  * @v len               Length of buffer
669  * @ret len             Length of formatted value, or negative error
670  */
671 int fetchf_named_setting ( const char *name, char *buf, size_t len ) {
672         struct settings *settings;
673         struct setting setting;
674         int rc;
675
676         if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
677                 return rc;
678         return fetchf_setting ( settings, &setting, buf, len );
679 }
680
681 /******************************************************************************
682  *
683  * Setting types
684  *
685  ******************************************************************************
686  */
687
688 /**
689  * Parse and store value of string setting
690  *
691  * @v settings          Settings block
692  * @v setting           Setting to store
693  * @v value             Formatted setting data
694  * @ret rc              Return status code
695  */
696 static int storef_string ( struct settings *settings, struct setting *setting,
697                            const char *value ) {
698         return store_setting ( settings, setting, value, strlen ( value ) );
699 }
700
701 /**
702  * Fetch and format value of string setting
703  *
704  * @v settings          Settings block, or NULL to search all blocks
705  * @v setting           Setting to fetch
706  * @v buf               Buffer to contain formatted value
707  * @v len               Length of buffer
708  * @ret len             Length of formatted value, or negative error
709  */
710 static int fetchf_string ( struct settings *settings, struct setting *setting,
711                            char *buf, size_t len ) {
712         return fetch_string_setting ( settings, setting, buf, len );
713 }
714
715 /** A string setting type */
716 struct setting_type setting_type_string __setting_type = {
717         .name = "string",
718         .storef = storef_string,
719         .fetchf = fetchf_string,
720 };
721
722 /**
723  * Parse and store value of IPv4 address setting
724  *
725  * @v settings          Settings block
726  * @v setting           Setting to store
727  * @v value             Formatted setting data
728  * @ret rc              Return status code
729  */
730 static int storef_ipv4 ( struct settings *settings, struct setting *setting,
731                          const char *value ) {
732         struct in_addr ipv4;
733
734         if ( inet_aton ( value, &ipv4 ) == 0 )
735                 return -EINVAL;
736         return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) );
737 }
738
739 /**
740  * Fetch and format value of IPv4 address setting
741  *
742  * @v settings          Settings block, or NULL to search all blocks
743  * @v setting           Setting to fetch
744  * @v buf               Buffer to contain formatted value
745  * @v len               Length of buffer
746  * @ret len             Length of formatted value, or negative error
747  */
748 static int fetchf_ipv4 ( struct settings *settings, struct setting *setting,
749                          char *buf, size_t len ) {
750         struct in_addr ipv4;
751         int rc;
752
753         if ( ( rc = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0 )
754                 return rc;
755         return snprintf ( buf, len, inet_ntoa ( ipv4 ) );
756 }
757
758 /** An IPv4 address setting type */
759 struct setting_type setting_type_ipv4 __setting_type = {
760         .name = "ipv4",
761         .storef = storef_ipv4,
762         .fetchf = fetchf_ipv4,
763 };
764
765 /**
766  * Parse and store value of integer setting
767  *
768  * @v settings          Settings block
769  * @v setting           Setting to store
770  * @v value             Formatted setting data
771  * @v size              Integer size, in bytes
772  * @ret rc              Return status code
773  */
774 static int storef_int ( struct settings *settings, struct setting *setting,
775                         const char *value, unsigned int size ) {
776         union {
777                 uint32_t num;
778                 uint8_t bytes[4];
779         } u;
780         char *endp;
781
782         u.num = htonl ( strtoul ( value, &endp, 0 ) );
783         if ( *endp )
784                 return -EINVAL;
785         return store_setting ( settings, setting, 
786                                &u.bytes[ sizeof ( u ) - size ], size );
787 }
788
789 /**
790  * Parse and store value of 8-bit integer setting
791  *
792  * @v settings          Settings block
793  * @v setting           Setting to store
794  * @v value             Formatted setting data
795  * @v size              Integer size, in bytes
796  * @ret rc              Return status code
797  */
798 static int storef_int8 ( struct settings *settings, struct setting *setting,
799                          const char *value ) {
800         return storef_int ( settings, setting, value, 1 );
801 }
802
803 /**
804  * Parse and store value of 16-bit integer setting
805  *
806  * @v settings          Settings block
807  * @v setting           Setting to store
808  * @v value             Formatted setting data
809  * @v size              Integer size, in bytes
810  * @ret rc              Return status code
811  */
812 static int storef_int16 ( struct settings *settings, struct setting *setting,
813                           const char *value ) {
814         return storef_int ( settings, setting, value, 2 );
815 }
816
817 /**
818  * Parse and store value of 32-bit integer setting
819  *
820  * @v settings          Settings block
821  * @v setting           Setting to store
822  * @v value             Formatted setting data
823  * @v size              Integer size, in bytes
824  * @ret rc              Return status code
825  */
826 static int storef_int32 ( struct settings *settings, struct setting *setting,
827                           const char *value ) {
828         return storef_int ( settings, setting, value, 4 );
829 }
830
831 /**
832  * Fetch and format value of signed integer setting
833  *
834  * @v settings          Settings block, or NULL to search all blocks
835  * @v setting           Setting to fetch
836  * @v buf               Buffer to contain formatted value
837  * @v len               Length of buffer
838  * @ret len             Length of formatted value, or negative error
839  */
840 static int fetchf_int ( struct settings *settings, struct setting *setting,
841                         char *buf, size_t len ) {
842         long value;
843         int rc;
844
845         if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 )
846                 return rc;
847         return snprintf ( buf, len, "%ld", value );
848 }
849
850 /**
851  * Fetch and format value of unsigned integer setting
852  *
853  * @v settings          Settings block, or NULL to search all blocks
854  * @v setting           Setting to fetch
855  * @v buf               Buffer to contain formatted value
856  * @v len               Length of buffer
857  * @ret len             Length of formatted value, or negative error
858  */
859 static int fetchf_uint ( struct settings *settings, struct setting *setting,
860                          char *buf, size_t len ) {
861         unsigned long value;
862         int rc;
863
864         if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 )
865                 return rc;
866         return snprintf ( buf, len, "%#lx", value );
867 }
868
869 /** A signed 8-bit integer setting type */
870 struct setting_type setting_type_int8 __setting_type = {
871         .name = "int8",
872         .storef = storef_int8,
873         .fetchf = fetchf_int,
874 };
875
876 /** A signed 16-bit integer setting type */
877 struct setting_type setting_type_int16 __setting_type = {
878         .name = "int16",
879         .storef = storef_int16,
880         .fetchf = fetchf_int,
881 };
882
883 /** A signed 32-bit integer setting type */
884 struct setting_type setting_type_int32 __setting_type = {
885         .name = "int32",
886         .storef = storef_int32,
887         .fetchf = fetchf_int,
888 };
889
890 /** An unsigned 8-bit integer setting type */
891 struct setting_type setting_type_uint8 __setting_type = {
892         .name = "uint8",
893         .storef = storef_int8,
894         .fetchf = fetchf_uint,
895 };
896
897 /** An unsigned 16-bit integer setting type */
898 struct setting_type setting_type_uint16 __setting_type = {
899         .name = "uint16",
900         .storef = storef_int16,
901         .fetchf = fetchf_uint,
902 };
903
904 /** An unsigned 32-bit integer setting type */
905 struct setting_type setting_type_uint32 __setting_type = {
906         .name = "uint32",
907         .storef = storef_int32,
908         .fetchf = fetchf_uint,
909 };
910
911 /**
912  * Parse and store value of hex string setting
913  *
914  * @v settings          Settings block
915  * @v setting           Setting to store
916  * @v value             Formatted setting data
917  * @ret rc              Return status code
918  */
919 static int storef_hex ( struct settings *settings, struct setting *setting,
920                         const char *value ) {
921         char *ptr = ( char * ) value;
922         uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
923         unsigned int len = 0;
924
925         while ( 1 ) {
926                 bytes[len++] = strtoul ( ptr, &ptr, 16 );
927                 switch ( *ptr ) {
928                 case '\0' :
929                         return store_setting ( settings, setting, bytes, len );
930                 case ':' :
931                         ptr++;
932                         break;
933                 default :
934                         return -EINVAL;
935                 }
936         }
937 }
938
939 /**
940  * Fetch and format value of hex string setting
941  *
942  * @v settings          Settings block, or NULL to search all blocks
943  * @v setting           Setting to fetch
944  * @v buf               Buffer to contain formatted value
945  * @v len               Length of buffer
946  * @ret len             Length of formatted value, or negative error
947  */
948 static int fetchf_hex ( struct settings *settings, struct setting *setting,
949                         char *buf, size_t len ) {
950         int raw_len;
951         int check_len;
952         int used = 0;
953         int i;
954
955         raw_len = fetch_setting_len ( settings, setting );
956         if ( raw_len < 0 )
957                 return raw_len;
958
959         {
960                 uint8_t raw[raw_len];
961
962                 check_len = fetch_setting ( settings, setting, raw,
963                                             sizeof ( raw ) );
964                 assert ( check_len == raw_len );
965                 
966                 if ( len )
967                         buf[0] = 0; /* Ensure that a terminating NUL exists */
968                 for ( i = 0 ; i < raw_len ; i++ ) {
969                         used += ssnprintf ( ( buf + used ), ( len - used ),
970                                             "%s%02x", ( used ? ":" : "" ),
971                                             raw[i] );
972                 }
973                 return used;
974         }
975 }
976
977 /** A hex-string setting */
978 struct setting_type setting_type_hex __setting_type = {
979         .name = "hex",
980         .storef = storef_hex,
981         .fetchf = fetchf_hex,
982 };
983
984 /******************************************************************************
985  *
986  * Settings
987  *
988  ******************************************************************************
989  */
990
991 /** Hostname setting */
992 struct setting hostname_setting __setting = {
993         .name = "hostname",
994         .description = "Host name",
995         .tag = DHCP_HOST_NAME,
996         .type = &setting_type_string,
997 };
998
999 /** Filename setting */
1000 struct setting filename_setting __setting = {
1001         .name = "filename",
1002         .description = "Boot filename",
1003         .tag = DHCP_BOOTFILE_NAME,
1004         .type = &setting_type_string,
1005 };
1006
1007 /** Root path setting */
1008 struct setting root_path_setting __setting = {
1009         .name = "root-path",
1010         .description = "NFS/iSCSI root path",
1011         .tag = DHCP_ROOT_PATH,
1012         .type = &setting_type_string,
1013 };
1014
1015 /** Username setting */
1016 struct setting username_setting __setting = {
1017         .name = "username",
1018         .description = "User name",
1019         .tag = DHCP_EB_USERNAME,
1020         .type = &setting_type_string,
1021 };
1022
1023 /** Password setting */
1024 struct setting password_setting __setting = {
1025         .name = "password",
1026         .description = "Password",
1027         .tag = DHCP_EB_PASSWORD,
1028         .type = &setting_type_string,
1029 };
1030
1031 /** Priority setting */
1032 struct setting priority_setting __setting = {
1033         .name = "priority",
1034         .description = "Priority of these settings",
1035         .tag = DHCP_EB_PRIORITY,
1036         .type = &setting_type_int8,
1037 };