You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

settings.c 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  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. #include <stdint.h>
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <strings.h>
  23. #include <byteswap.h>
  24. #include <errno.h>
  25. #include <assert.h>
  26. #include <gpxe/in.h>
  27. #include <gpxe/settings.h>
  28. /** @file
  29. *
  30. * Configuration settings
  31. *
  32. */
  33. /** Registered configuration setting types */
  34. static struct config_setting_type config_setting_types[0]
  35. __table_start ( struct config_setting_type, config_setting_types );
  36. static struct config_setting_type config_setting_types_end[0]
  37. __table_end ( struct config_setting_type, config_setting_types );
  38. /** Registered configuration settings */
  39. static struct config_setting config_settings[0]
  40. __table_start ( struct config_setting, config_settings );
  41. static struct config_setting config_settings_end[0]
  42. __table_end ( struct config_setting, config_settings );
  43. /**
  44. * Find configuration setting type
  45. *
  46. * @v name Name
  47. * @ret type Configuration setting type, or NULL
  48. */
  49. static struct config_setting_type *
  50. find_config_setting_type ( const char *name ) {
  51. struct config_setting_type *type;
  52. for ( type = config_setting_types ; type < config_setting_types_end ;
  53. type++ ) {
  54. if ( strcasecmp ( name, type->name ) == 0 )
  55. return type;
  56. }
  57. return NULL;
  58. }
  59. /**
  60. * Find configuration setting
  61. *
  62. * @v name Name
  63. * @ret setting Configuration setting, or NULL
  64. */
  65. static struct config_setting * find_config_setting ( const char *name ) {
  66. struct config_setting *setting;
  67. for ( setting = config_settings ; setting < config_settings_end ;
  68. setting++ ) {
  69. if ( strcasecmp ( name, setting->name ) == 0 )
  70. return setting;
  71. }
  72. return NULL;
  73. }
  74. /**
  75. * Find or build configuration setting
  76. *
  77. * @v name Name
  78. * @v tmp_setting Temporary buffer for constructing a setting
  79. * @ret setting Configuration setting, or NULL
  80. *
  81. * Find setting if it exists. If it doesn't exist, but the name is of
  82. * the form "<num>.<type>" (e.g. "12.string"), then construct a
  83. * setting for that tag and data type, and return it. The constructed
  84. * setting will be placed in the temporary buffer.
  85. */
  86. static struct config_setting *
  87. find_or_build_config_setting ( const char *name,
  88. struct config_setting *tmp_setting ) {
  89. struct config_setting *setting;
  90. char *separator;
  91. /* Look in the list of registered settings first */
  92. setting = find_config_setting ( name );
  93. if ( setting )
  94. return setting;
  95. /* If name is of the form "<num>.<type>", try to construct a setting */
  96. setting = tmp_setting;
  97. memset ( setting, 0, sizeof ( *setting ) );
  98. setting->name = name;
  99. setting->tag = strtoul ( name, &separator, 10 );
  100. if ( *separator != '.' )
  101. return NULL;
  102. setting->type = find_config_setting_type ( separator + 1 );
  103. if ( ! setting->type )
  104. return NULL;
  105. return setting;
  106. }
  107. /**
  108. * Show value of named setting
  109. *
  110. * @v context Configuration context
  111. * @v name Configuration setting name
  112. * @v buf Buffer to contain value
  113. * @v len Length of buffer
  114. * @ret rc Return status code
  115. */
  116. int show_named_setting ( struct config_context *context, const char *name,
  117. char *buf, size_t len ) {
  118. struct config_setting *setting;
  119. struct config_setting tmp_setting;
  120. setting = find_or_build_config_setting ( name, &tmp_setting );
  121. if ( ! setting )
  122. return -ENOENT;
  123. return show_setting ( context, setting, buf, len );
  124. }
  125. /**
  126. * Set value of named setting
  127. *
  128. * @v context Configuration context
  129. * @v name Configuration setting name
  130. * @v value Setting value (as a string)
  131. * @ret rc Return status code
  132. */
  133. int set_named_setting ( struct config_context *context, const char *name,
  134. const char *value ) {
  135. struct config_setting *setting;
  136. struct config_setting tmp_setting;
  137. setting = find_or_build_config_setting ( name, &tmp_setting );
  138. if ( ! setting )
  139. return -ENOENT;
  140. return setting->type->set ( context, setting, value );
  141. }
  142. /**
  143. * Set value of setting
  144. *
  145. * @v context Configuration context
  146. * @v setting Configuration setting
  147. * @v value Setting value (as a string), or NULL
  148. * @ret rc Return status code
  149. */
  150. int set_setting ( struct config_context *context,
  151. struct config_setting *setting,
  152. const char *value ) {
  153. if ( ( ! value ) || ( ! *value ) ) {
  154. /* Save putting deletion logic in each individual handler */
  155. return clear_setting ( context, setting );
  156. }
  157. return setting->type->set ( context, setting, value );
  158. }
  159. /**
  160. * Show value of string setting
  161. *
  162. * @v context Configuration context
  163. * @v setting Configuration setting
  164. * @v buf Buffer to contain value
  165. * @v len Length of buffer
  166. * @ret rc Return status code
  167. */
  168. static int show_string ( struct config_context *context,
  169. struct config_setting *setting,
  170. char *buf, size_t len ) {
  171. struct dhcp_option *option;
  172. option = find_dhcp_option ( context->options, setting->tag );
  173. if ( ! option )
  174. return -ENODATA;
  175. dhcp_snprintf ( buf, len, option );
  176. return 0;
  177. }
  178. /**
  179. * Set value of string setting
  180. *
  181. * @v context Configuration context
  182. * @v setting Configuration setting
  183. * @v value Setting value (as a string)
  184. * @ret rc Return status code
  185. */
  186. static int set_string ( struct config_context *context,
  187. struct config_setting *setting,
  188. const char *value ) {
  189. struct dhcp_option *option;
  190. option = set_dhcp_option ( context->options, setting->tag,
  191. value, strlen ( value ) );
  192. if ( ! option )
  193. return -ENOSPC;
  194. return 0;
  195. }
  196. /** A string configuration setting */
  197. struct config_setting_type config_setting_type_string __config_setting_type = {
  198. .name = "string",
  199. .description = "Text string",
  200. .show = show_string,
  201. .set = set_string,
  202. };
  203. /**
  204. * Show value of IPv4 setting
  205. *
  206. * @v context Configuration context
  207. * @v setting Configuration setting
  208. * @v buf Buffer to contain value
  209. * @v len Length of buffer
  210. * @ret rc Return status code
  211. */
  212. static int show_ipv4 ( struct config_context *context,
  213. struct config_setting *setting,
  214. char *buf, size_t len ) {
  215. struct dhcp_option *option;
  216. struct in_addr ipv4;
  217. option = find_dhcp_option ( context->options, setting->tag );
  218. if ( ! option )
  219. return -ENODATA;
  220. dhcp_ipv4_option ( option, &ipv4 );
  221. snprintf ( buf, len, inet_ntoa ( ipv4 ) );
  222. return 0;
  223. }
  224. /**
  225. * Set value of IPV4 setting
  226. *
  227. * @v context Configuration context
  228. * @v setting Configuration setting
  229. * @v value Setting value (as a string)
  230. * @ret rc Return status code
  231. */
  232. static int set_ipv4 ( struct config_context *context,
  233. struct config_setting *setting,
  234. const char *value ) {
  235. struct dhcp_option *option;
  236. struct in_addr ipv4;
  237. if ( inet_aton ( value, &ipv4 ) == 0 )
  238. return -EINVAL;
  239. option = set_dhcp_option ( context->options, setting->tag,
  240. &ipv4, sizeof ( ipv4 ) );
  241. if ( ! option )
  242. return -ENOSPC;
  243. return 0;
  244. }
  245. /** An IPv4 configuration setting */
  246. struct config_setting_type config_setting_type_ipv4 __config_setting_type = {
  247. .name = "ipv4",
  248. .description = "IPv4 address",
  249. .show = show_ipv4,
  250. .set = set_ipv4,
  251. };
  252. /**
  253. * Show value of integer setting
  254. *
  255. * @v context Configuration context
  256. * @v setting Configuration setting
  257. * @v buf Buffer to contain value
  258. * @v len Length of buffer
  259. * @ret rc Return status code
  260. */
  261. static int show_int ( struct config_context *context,
  262. struct config_setting *setting,
  263. char *buf, size_t len ) {
  264. struct dhcp_option *option;
  265. long num;
  266. option = find_dhcp_option ( context->options, setting->tag );
  267. if ( ! option )
  268. return -ENODATA;
  269. num = dhcp_num_option ( option );
  270. snprintf ( buf, len, "%ld", num );
  271. return 0;
  272. }
  273. /**
  274. * Set value of integer setting
  275. *
  276. * @v context Configuration context
  277. * @v setting Configuration setting
  278. * @v value Setting value (as a string)
  279. * @v size Size of integer (in bytes)
  280. * @ret rc Return status code
  281. */
  282. static int set_int ( struct config_context *context,
  283. struct config_setting *setting,
  284. const char *value, unsigned int size ) {
  285. struct dhcp_option *option;
  286. union {
  287. uint32_t num;
  288. uint8_t bytes[4];
  289. } u;
  290. char *endp;
  291. /* Parse number */
  292. if ( ! *value )
  293. return -EINVAL;
  294. u.num = htonl ( strtoul ( value, &endp, 0 ) );
  295. if ( *endp )
  296. return -EINVAL;
  297. /* Set option */
  298. option = set_dhcp_option ( context->options, setting->tag,
  299. &u.bytes[ sizeof ( u ) - size ], size );
  300. if ( ! option )
  301. return -ENOSPC;
  302. return 0;
  303. }
  304. /**
  305. * Set value of 8-bit integer setting
  306. *
  307. * @v context Configuration context
  308. * @v setting Configuration setting
  309. * @v value Setting value (as a string)
  310. * @v size Size of integer (in bytes)
  311. * @ret rc Return status code
  312. */
  313. static int set_int8 ( struct config_context *context,
  314. struct config_setting *setting,
  315. const char *value ) {
  316. return set_int ( context, setting, value, 1 );
  317. }
  318. /** An 8-bit integer configuration setting */
  319. struct config_setting_type config_setting_type_int8 __config_setting_type = {
  320. .name = "int8",
  321. .description = "8-bit integer",
  322. .show = show_int,
  323. .set = set_int8,
  324. };
  325. /** Some basic setting definitions */
  326. struct config_setting basic_config_settings[] __config_setting = {
  327. {
  328. .name = "ip",
  329. .description = "IP address of this machine (e.g. 192.168.0.1)",
  330. .tag = DHCP_EB_YIADDR,
  331. .type = &config_setting_type_ipv4,
  332. },
  333. {
  334. .name = "hostname",
  335. .description = "Host name of this machine",
  336. .tag = DHCP_HOST_NAME,
  337. .type = &config_setting_type_string,
  338. },
  339. {
  340. .name = "username",
  341. .description = "User name for authentication to servers",
  342. .tag = DHCP_EB_USERNAME,
  343. .type = &config_setting_type_string,
  344. },
  345. {
  346. .name = "password",
  347. .description = "Password for authentication to servers",
  348. .tag = DHCP_EB_PASSWORD,
  349. .type = &config_setting_type_string,
  350. },
  351. {
  352. .name = "root-path",
  353. .description = "NFS/iSCSI root path",
  354. .tag = DHCP_ROOT_PATH,
  355. .type = &config_setting_type_string,
  356. },
  357. {
  358. .name = "priority",
  359. .description = "Priority of these options",
  360. .tag = DHCP_EB_PRIORITY,
  361. .type = &config_setting_type_int8,
  362. },
  363. {
  364. .name = "initiator-iqn",
  365. .description = "iSCSI qualified name of this machine",
  366. .tag = DHCP_ISCSI_INITIATOR_IQN,
  367. .type = &config_setting_type_string,
  368. }
  369. };