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