Tied NVO commands into the human-interactable settings code that I
[people/mcb30/gpxe.git] / src / core / settings.c
1 /*
2  * Copyright (C) 2006 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 <string.h>
22 #include <errno.h>
23 #include <assert.h>
24 #include <vsprintf.h>
25 #include <gpxe/in.h>
26 #include <gpxe/settings.h>
27
28 /** @file
29  *
30  * Configuration settings
31  *
32  */
33
34 /** Registered configuration setting types */
35 static struct config_setting_type
36 config_setting_types[0] __table_start ( config_setting_types );
37 static struct config_setting_type
38 config_setting_types_end[0] __table_end ( config_setting_types );
39
40 /** Registered configuration settings */
41 static struct config_setting
42 config_settings[0] __table_start ( config_settings );
43 static struct config_setting
44 config_settings_end[0] __table_end ( config_settings );
45
46 /**
47  * Find configuration setting type
48  *
49  * @v name              Name
50  * @ret type            Configuration setting type, or NULL
51  */
52 static struct config_setting_type *
53 find_config_setting_type ( const char *name ) {
54         struct config_setting_type *type;
55
56         for ( type = config_setting_types ; type < config_setting_types_end ;
57               type++ ) {
58                 if ( strcmp ( name, type->name ) == 0 )
59                         return type;
60         }
61         return NULL;
62 }
63
64 /**
65  * Find configuration setting
66  *
67  * @v name              Name
68  * @ret setting         Configuration setting, or NULL
69  */
70 static struct config_setting * find_config_setting ( const char *name ) {
71         struct config_setting *setting;
72
73         for ( setting = config_settings ; setting < config_settings_end ;
74               setting++ ) {
75                 if ( strcmp ( name, setting->name ) == 0 )
76                         return setting;
77         }
78         return NULL;
79 }
80
81 /**
82  * Find or build configuration setting
83  *
84  * @v name              Name
85  * @v tmp_setting       Temporary buffer for constructing a setting
86  * @ret setting         Configuration setting, or NULL
87  *
88  * Find setting if it exists.  If it doesn't exist, but the name is of
89  * the form "<num>.<type>" (e.g. "12.string"), then construct a
90  * setting for that tag and data type, and return it.  The constructed
91  * setting will be placed in the temporary buffer.
92  */
93 static struct config_setting *
94 find_or_build_config_setting ( const char *name,
95                                struct config_setting *tmp_setting ) {
96         struct config_setting *setting;
97         char *separator;
98
99         /* Look in the list of registered settings first */
100         setting = find_config_setting ( name );
101         if ( setting )
102                 return setting;
103
104         /* If name is of the form "<num>.<type>", try to construct a setting */
105         setting = tmp_setting;
106         memset ( setting, 0, sizeof ( *setting ) );
107         setting->name = name;
108         setting->tag = strtoul ( name, &separator, 10 );
109         if ( *separator != '.' )
110                 return NULL;
111         setting->type = find_config_setting_type ( separator + 1 );
112         if ( ! setting->type )
113                 return NULL;
114         return setting;
115 }
116
117 /** Show value of setting
118  *
119  * @v context           Configuration context
120  * @v name              Configuration setting name
121  * @v buf               Buffer to contain value
122  * @v len               Length of buffer
123  * @ret rc              Return status code
124  */
125 int show_setting ( struct config_context *context, const char *name,
126                    char *buf, size_t len ) {
127         struct config_setting *setting;
128         struct config_setting tmp_setting;
129
130         setting = find_or_build_config_setting ( name, &tmp_setting );
131         if ( ! setting )
132                 return -ENOENT;
133         return setting->type->show ( context, setting, buf, len );
134 }
135
136 /** Set value of setting
137  *
138  * @v context           Configuration context
139  * @v name              Configuration setting name
140  * @v value             Setting value (as a string)
141  * @ret rc              Return status code
142  */
143 int set_setting ( struct config_context *context, const char *name,
144                   const char *value ) {
145         struct config_setting *setting;
146         struct config_setting tmp_setting;
147
148         setting = find_or_build_config_setting ( name, &tmp_setting );
149         if ( ! setting )
150                 return -ENOENT;
151         return setting->type->set ( context, setting, value );
152 }
153
154 /**
155  * Show value of string setting
156  *
157  * @v context           Configuration context
158  * @v setting           Configuration setting
159  * @v buf               Buffer to contain value
160  * @v len               Length of buffer
161  * @ret rc              Return status code
162  */
163 static int show_string ( struct config_context *context,
164                          struct config_setting *setting,
165                          char *buf, size_t len ) {
166         struct dhcp_option *option;
167
168         option = find_dhcp_option ( context->options, setting->tag );
169         if ( ! option )
170                 return -ENODATA;
171         dhcp_snprintf ( buf, len, option );
172         return 0;
173 }
174
175 /** Set value of string setting
176  *
177  * @v context           Configuration context
178  * @v setting           Configuration setting
179  * @v value             Setting value (as a string)
180  * @ret rc              Return status code
181  */ 
182 static int set_string ( struct config_context *context,
183                         struct config_setting *setting,
184                         const char *value ) {
185         struct dhcp_option *option;
186
187         option = set_dhcp_option ( context->options, setting->tag,
188                                    value, strlen ( value ) );
189         if ( ! option )
190                 return -ENOMEM;
191         return 0;
192 }
193
194 /** A string configuration setting */
195 struct config_setting_type config_setting_type_string __config_setting_type = {
196         .name = "string",
197         .show = show_string,
198         .set = set_string,
199 };
200
201 /**
202  * Show value of IPv4 setting
203  *
204  * @v context           Configuration context
205  * @v setting           Configuration setting
206  * @v buf               Buffer to contain value
207  * @v len               Length of buffer
208  * @ret rc              Return status code
209  */
210 static int show_ipv4 ( struct config_context *context,
211                        struct config_setting *setting,
212                        char *buf, size_t len ) {
213         struct dhcp_option *option;
214         struct in_addr ipv4;
215
216         option = find_dhcp_option ( context->options, setting->tag );
217         if ( ! option )
218                 return -ENODATA;
219         dhcp_ipv4_option ( option, &ipv4 );
220         snprintf ( buf, len, inet_ntoa ( ipv4 ) );
221         return 0;
222 }
223
224 /** Set value of IPV4 setting
225  *
226  * @v context           Configuration context
227  * @v setting           Configuration setting
228  * @v value             Setting value (as a string)
229  * @ret rc              Return status code
230  */ 
231 static int set_ipv4 ( struct config_context *context,
232                       struct config_setting *setting,
233                       const char *value ) {
234         struct dhcp_option *option;
235         struct in_addr ipv4;
236         int rc;
237         
238         if ( ( rc = inet_aton ( value, &ipv4 ) ) != 0 )
239                 return rc;
240         option = set_dhcp_option ( context->options, setting->tag,
241                                    &ipv4, sizeof ( ipv4 ) );
242         if ( ! option )
243                 return -ENOMEM;
244         return 0;
245 }
246
247 /** An IPv4 configuration setting */
248 struct config_setting_type config_setting_type_ipv4 __config_setting_type = {
249         .name = "ipv4",
250         .show = show_ipv4,
251         .set = set_ipv4,
252 };
253
254 /** Some basic setting definitions */
255 struct config_setting ip_config_setting __config_setting = {
256         .name = "ip",
257         .tag = DHCP_EB_YIADDR,
258         .type = &config_setting_type_ipv4,
259 };
260 struct config_setting hostname_config_setting __config_setting = {
261         .name = "hostname",
262         .tag = DHCP_HOST_NAME,
263         .type = &config_setting_type_string,
264 };
265 struct config_setting username_config_setting __config_setting = {
266         .name = "username",
267         .tag = DHCP_EB_USERNAME,
268         .type = &config_setting_type_string,
269 };
270 struct config_setting password_config_setting __config_setting = {
271         .name = "password",
272         .tag = DHCP_EB_PASSWORD,
273         .type = &config_setting_type_string,
274 };