envblk.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /* envblk.c - Common functions for environment block. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2008,2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <config.h>
  20. #include <grub/types.h>
  21. #include <grub/misc.h>
  22. #include <grub/mm.h>
  23. #include <grub/lib/envblk.h>
  24. grub_envblk_t
  25. grub_envblk_open (char *buf, grub_size_t size)
  26. {
  27. grub_envblk_t envblk;
  28. if (size < sizeof (GRUB_ENVBLK_SIGNATURE)
  29. || grub_memcmp (buf, GRUB_ENVBLK_SIGNATURE,
  30. sizeof (GRUB_ENVBLK_SIGNATURE) - 1))
  31. {
  32. grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
  33. return 0;
  34. }
  35. envblk = grub_malloc (sizeof (*envblk));
  36. if (envblk)
  37. {
  38. envblk->buf = buf;
  39. envblk->size = size;
  40. }
  41. return envblk;
  42. }
  43. void
  44. grub_envblk_close (grub_envblk_t envblk)
  45. {
  46. grub_free (envblk->buf);
  47. grub_free (envblk);
  48. }
  49. static int
  50. escaped_value_len (const char *value)
  51. {
  52. int n = 0;
  53. char *p;
  54. for (p = (char *) value; *p; p++)
  55. {
  56. if (*p == '\\' || *p == '\n')
  57. n += 2;
  58. else
  59. n++;
  60. }
  61. return n;
  62. }
  63. static char *
  64. find_next_line (char *p, const char *pend)
  65. {
  66. while (p < pend)
  67. {
  68. if (*p == '\\')
  69. p += 2;
  70. else if (*p == '\n')
  71. break;
  72. else
  73. p++;
  74. }
  75. return p + 1;
  76. }
  77. int
  78. grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value)
  79. {
  80. char *p, *pend;
  81. char *space;
  82. int found = 0;
  83. int nl;
  84. int vl;
  85. int i;
  86. nl = grub_strlen (name);
  87. vl = escaped_value_len (value);
  88. p = envblk->buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1;
  89. pend = envblk->buf + envblk->size;
  90. /* First, look at free space. */
  91. for (space = pend - 1; *space == '#'; space--)
  92. ;
  93. if (*space != '\n')
  94. /* Broken. */
  95. return 0;
  96. space++;
  97. while (p + nl + 1 < space)
  98. {
  99. if (grub_memcmp (p, name, nl) == 0 && p[nl] == '=')
  100. {
  101. int len;
  102. /* Found the same name. */
  103. p += nl + 1;
  104. /* Check the length of the current value. */
  105. len = 0;
  106. while (p + len < pend && p[len] != '\n')
  107. {
  108. if (p[len] == '\\')
  109. len += 2;
  110. else
  111. len++;
  112. }
  113. if (p + len >= pend)
  114. /* Broken. */
  115. return 0;
  116. if (pend - space < vl - len)
  117. /* No space. */
  118. return 0;
  119. if (vl < len)
  120. {
  121. /* Move the following characters backward, and fill the new
  122. space with harmless characters. */
  123. grub_memmove (p + vl, p + len, pend - (p + len));
  124. grub_memset (space - (len - vl), '#', len - vl);
  125. }
  126. else
  127. /* Move the following characters forward. */
  128. grub_memmove (p + vl, p + len, pend - (p + vl));
  129. found = 1;
  130. break;
  131. }
  132. p = find_next_line (p, pend);
  133. }
  134. if (! found)
  135. {
  136. /* Append a new variable. */
  137. if (pend - space < nl + 1 + vl + 1)
  138. /* No space. */
  139. return 0;
  140. grub_memcpy (space, name, nl);
  141. p = space + nl;
  142. *p++ = '=';
  143. }
  144. /* Write the value. */
  145. for (i = 0; value[i]; i++)
  146. {
  147. if (value[i] == '\\' || value[i] == '\n')
  148. *p++ = '\\';
  149. *p++ = value[i];
  150. }
  151. *p = '\n';
  152. return 1;
  153. }
  154. void
  155. grub_envblk_delete (grub_envblk_t envblk, const char *name)
  156. {
  157. char *p, *pend;
  158. int nl;
  159. nl = grub_strlen (name);
  160. p = envblk->buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1;
  161. pend = envblk->buf + envblk->size;
  162. while (p + nl + 1 < pend)
  163. {
  164. if (grub_memcmp (p, name, nl) == 0 && p[nl] == '=')
  165. {
  166. /* Found. */
  167. int len = nl + 1;
  168. while (p + len < pend)
  169. {
  170. if (p[len] == '\n')
  171. break;
  172. else if (p[len] == '\\')
  173. len += 2;
  174. else
  175. len++;
  176. }
  177. if (p + len >= pend)
  178. /* Broken. */
  179. return;
  180. len++;
  181. grub_memmove (p, p + len, pend - (p + len));
  182. grub_memset (pend - len, '#', len);
  183. break;
  184. }
  185. p = find_next_line (p, pend);
  186. }
  187. }
  188. void
  189. grub_envblk_iterate (grub_envblk_t envblk,
  190. void *hook_data,
  191. int hook (const char *name, const char *value, void *hook_data))
  192. {
  193. char *p, *pend;
  194. p = envblk->buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1;
  195. pend = envblk->buf + envblk->size;
  196. while (p < pend)
  197. {
  198. if (*p != '#')
  199. {
  200. char *name;
  201. char *value;
  202. char *name_start, *name_end, *value_start;
  203. char *q;
  204. int ret;
  205. name_start = p;
  206. while (p < pend && *p != '=')
  207. p++;
  208. if (p == pend)
  209. /* Broken. */
  210. return;
  211. name_end = p;
  212. p++;
  213. value_start = p;
  214. while (p < pend)
  215. {
  216. if (*p == '\n')
  217. break;
  218. else if (*p == '\\')
  219. p += 2;
  220. else
  221. p++;
  222. }
  223. if (p >= pend)
  224. /* Broken. */
  225. return;
  226. name = grub_malloc (p - name_start + 1);
  227. if (! name)
  228. /* out of memory. */
  229. return;
  230. value = name + (value_start - name_start);
  231. grub_memcpy (name, name_start, name_end - name_start);
  232. name[name_end - name_start] = '\0';
  233. for (p = value_start, q = value; *p != '\n'; ++p)
  234. {
  235. if (*p == '\\')
  236. *q++ = *++p;
  237. else
  238. *q++ = *p;
  239. }
  240. *q = '\0';
  241. ret = hook (name, value, hook_data);
  242. grub_free (name);
  243. if (ret)
  244. return;
  245. }
  246. p = find_next_line (p, pend);
  247. }
  248. }