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.

guestinfo.c 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. /** @file
  21. *
  22. * VMware GuestInfo settings
  23. *
  24. */
  25. #include <stdint.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <errno.h>
  30. #include <ipxe/init.h>
  31. #include <ipxe/settings.h>
  32. #include <ipxe/netdevice.h>
  33. #include <ipxe/guestrpc.h>
  34. /** GuestInfo GuestRPC channel */
  35. static int guestinfo_channel;
  36. /**
  37. * Fetch value of typed GuestInfo setting
  38. *
  39. * @v settings Settings block
  40. * @v setting Setting to fetch
  41. * @v type Setting type to attempt (or NULL for default)
  42. * @v data Buffer to fill with setting data
  43. * @v len Length of buffer
  44. * @ret found Setting found in GuestInfo
  45. * @ret len Length of setting data, or negative error
  46. */
  47. static int guestinfo_fetch_type ( struct settings *settings,
  48. struct setting *setting,
  49. const struct setting_type *type,
  50. void *data, size_t len, int *found ) {
  51. const char *parent_name = settings->parent->name;
  52. char command[ 24 /* "info-get guestinfo.ipxe." */ +
  53. strlen ( parent_name ) + 1 /* "." */ +
  54. strlen ( setting->name ) + 1 /* "." */ +
  55. ( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ];
  56. struct setting *predefined;
  57. char *info;
  58. int info_len;
  59. int check_len;
  60. int ret;
  61. /* Construct info-get command */
  62. snprintf ( command, sizeof ( command ),
  63. "info-get guestinfo.ipxe.%s%s%s%s%s",
  64. parent_name, ( parent_name[0] ? "." : "" ), setting->name,
  65. ( type ? "." : "" ), ( type ? type->name : "" ) );
  66. /* Check for existence and obtain length of GuestInfo value */
  67. info_len = guestrpc_command ( guestinfo_channel, command, NULL, 0 );
  68. if ( info_len < 0 ) {
  69. ret = info_len;
  70. goto err_get_info_len;
  71. }
  72. /* Mark as found */
  73. *found = 1;
  74. /* Determine default type if necessary */
  75. if ( ! type ) {
  76. predefined = find_setting ( setting->name );
  77. type = ( predefined ? predefined->type : &setting_type_string );
  78. }
  79. assert ( type != NULL );
  80. /* Allocate temporary block to hold GuestInfo value */
  81. info = zalloc ( info_len + 1 /* NUL */ );
  82. if ( ! info ) {
  83. DBGC ( settings, "GuestInfo %p could not allocate %d bytes\n",
  84. settings, info_len );
  85. ret = -ENOMEM;
  86. goto err_alloc;
  87. }
  88. info[info_len] = '\0';
  89. /* Fetch GuestInfo value */
  90. check_len = guestrpc_command ( guestinfo_channel, command,
  91. info, info_len );
  92. if ( check_len < 0 ) {
  93. ret = check_len;
  94. goto err_get_info;
  95. }
  96. if ( check_len != info_len ) {
  97. DBGC ( settings, "GuestInfo %p length mismatch (expected %d, "
  98. "got %d)\n", settings, info_len, check_len );
  99. ret = -EIO;
  100. goto err_get_info;
  101. }
  102. DBGC2 ( settings, "GuestInfo %p found %s = \"%s\"\n",
  103. settings, &command[9] /* Skip "info-get " */, info );
  104. /* Parse GuestInfo value according to type */
  105. ret = setting_parse ( type, info, data, len );
  106. if ( ret < 0 ) {
  107. DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: "
  108. "%s\n", settings, info, type->name, strerror ( ret ) );
  109. goto err_parse;
  110. }
  111. err_parse:
  112. err_get_info:
  113. free ( info );
  114. err_alloc:
  115. err_get_info_len:
  116. return ret;
  117. }
  118. /**
  119. * Fetch value of GuestInfo setting
  120. *
  121. * @v settings Settings block
  122. * @v setting Setting to fetch
  123. * @v data Buffer to fill with setting data
  124. * @v len Length of buffer
  125. * @ret len Length of setting data, or negative error
  126. */
  127. static int guestinfo_fetch ( struct settings *settings,
  128. struct setting *setting,
  129. void *data, size_t len ) {
  130. struct setting_type *type;
  131. int found = 0;
  132. int ret;
  133. /* Try default type first */
  134. ret = guestinfo_fetch_type ( settings, setting, NULL,
  135. data, len, &found );
  136. if ( found )
  137. return ret;
  138. /* Otherwise, try all possible types */
  139. for_each_table_entry ( type, SETTING_TYPES ) {
  140. ret = guestinfo_fetch_type ( settings, setting, type,
  141. data, len, &found );
  142. if ( found )
  143. return ret;
  144. }
  145. /* Not found */
  146. return -ENOENT;
  147. }
  148. /** GuestInfo settings operations */
  149. static struct settings_operations guestinfo_settings_operations = {
  150. .fetch = guestinfo_fetch,
  151. };
  152. /** GuestInfo settings */
  153. static struct settings guestinfo_settings = {
  154. .refcnt = NULL,
  155. .siblings = LIST_HEAD_INIT ( guestinfo_settings.siblings ),
  156. .children = LIST_HEAD_INIT ( guestinfo_settings.children ),
  157. .op = &guestinfo_settings_operations,
  158. };
  159. /** Initialise GuestInfo settings */
  160. static void guestinfo_init ( void ) {
  161. int rc;
  162. /* Open GuestRPC channel */
  163. guestinfo_channel = guestrpc_open();
  164. if ( guestinfo_channel < 0 ) {
  165. rc = guestinfo_channel;
  166. DBG ( "GuestInfo could not open channel: %s\n",
  167. strerror ( rc ) );
  168. return;
  169. }
  170. /* Register root GuestInfo settings */
  171. if ( ( rc = register_settings ( &guestinfo_settings, NULL,
  172. "vmware" ) ) != 0 ) {
  173. DBG ( "GuestInfo could not register settings: %s\n",
  174. strerror ( rc ) );
  175. return;
  176. }
  177. }
  178. /** GuestInfo settings initialiser */
  179. struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = {
  180. .initialise = guestinfo_init,
  181. };
  182. /**
  183. * Create per-netdevice GuestInfo settings
  184. *
  185. * @v netdev Network device
  186. * @ret rc Return status code
  187. */
  188. static int guestinfo_net_probe ( struct net_device *netdev ) {
  189. struct settings *settings;
  190. int rc;
  191. /* Do nothing unless we have a GuestInfo channel available */
  192. if ( guestinfo_channel < 0 )
  193. return 0;
  194. /* Allocate and initialise settings block */
  195. settings = zalloc ( sizeof ( *settings ) );
  196. if ( ! settings ) {
  197. rc = -ENOMEM;
  198. goto err_alloc;
  199. }
  200. settings_init ( settings, &guestinfo_settings_operations, NULL, NULL );
  201. /* Register settings */
  202. if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
  203. "vmware" ) ) != 0 ) {
  204. DBGC ( settings, "GuestInfo %p could not register for %s: %s\n",
  205. settings, netdev->name, strerror ( rc ) );
  206. goto err_register;
  207. }
  208. DBGC ( settings, "GuestInfo %p registered for %s\n",
  209. settings, netdev->name );
  210. return 0;
  211. err_register:
  212. free ( settings );
  213. err_alloc:
  214. return rc;
  215. }
  216. /**
  217. * Remove per-netdevice GuestInfo settings
  218. *
  219. * @v netdev Network device
  220. */
  221. static void guestinfo_net_remove ( struct net_device *netdev ) {
  222. struct settings *parent = netdev_settings ( netdev );
  223. struct settings *settings;
  224. list_for_each_entry ( settings, &parent->children, siblings ) {
  225. if ( settings->op == &guestinfo_settings_operations ) {
  226. DBGC ( settings, "GuestInfo %p unregistered for %s\n",
  227. settings, netdev->name );
  228. unregister_settings ( settings );
  229. free ( settings );
  230. return;
  231. }
  232. }
  233. }
  234. /** GuestInfo per-netdevice driver */
  235. struct net_driver guestinfo_net_driver __net_driver = {
  236. .name = "GuestInfo",
  237. .probe = guestinfo_net_probe,
  238. .remove = guestinfo_net_remove,
  239. };