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