linux.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. #include <grub/types.h>
  2. #include <grub/err.h>
  3. #include <grub/linux.h>
  4. #include <grub/misc.h>
  5. #include <grub/file.h>
  6. #include <grub/mm.h>
  7. #include <grub/safemath.h>
  8. struct newc_head
  9. {
  10. char magic[6];
  11. char ino[8];
  12. char mode[8];
  13. char uid[8];
  14. char gid[8];
  15. char nlink[8];
  16. char mtime[8];
  17. char filesize[8];
  18. char devmajor[8];
  19. char devminor[8];
  20. char rdevmajor[8];
  21. char rdevminor[8];
  22. char namesize[8];
  23. char check[8];
  24. } GRUB_PACKED;
  25. struct grub_linux_initrd_component
  26. {
  27. grub_file_t file;
  28. char *newc_name;
  29. grub_off_t size;
  30. };
  31. struct dir
  32. {
  33. char *name;
  34. struct dir *next;
  35. struct dir *child;
  36. };
  37. static char
  38. hex (grub_uint8_t val)
  39. {
  40. if (val < 10)
  41. return '0' + val;
  42. return 'a' + val - 10;
  43. }
  44. static void
  45. set_field (char *var, grub_uint32_t val)
  46. {
  47. int i;
  48. char *ptr = var;
  49. for (i = 28; i >= 0; i -= 4)
  50. *ptr++ = hex((val >> i) & 0xf);
  51. }
  52. static grub_uint8_t *
  53. make_header (grub_uint8_t *ptr,
  54. const char *name, grub_size_t len,
  55. grub_uint32_t mode,
  56. grub_off_t fsize)
  57. {
  58. struct newc_head *head = (struct newc_head *) ptr;
  59. grub_uint8_t *optr;
  60. grub_size_t oh = 0;
  61. grub_memcpy (head->magic, "070701", 6);
  62. set_field (head->ino, 0);
  63. set_field (head->mode, mode);
  64. set_field (head->uid, 0);
  65. set_field (head->gid, 0);
  66. set_field (head->nlink, 1);
  67. set_field (head->mtime, 0);
  68. set_field (head->filesize, fsize);
  69. set_field (head->devmajor, 0);
  70. set_field (head->devminor, 0);
  71. set_field (head->rdevmajor, 0);
  72. set_field (head->rdevminor, 0);
  73. set_field (head->namesize, len);
  74. set_field (head->check, 0);
  75. optr = ptr;
  76. ptr += sizeof (struct newc_head);
  77. grub_memcpy (ptr, name, len);
  78. ptr += len;
  79. oh = ALIGN_UP_OVERHEAD (ptr - optr, 4);
  80. grub_memset (ptr, 0, oh);
  81. ptr += oh;
  82. return ptr;
  83. }
  84. static void
  85. free_dir (struct dir *root)
  86. {
  87. if (!root)
  88. return;
  89. free_dir (root->next);
  90. free_dir (root->child);
  91. grub_free (root->name);
  92. grub_free (root);
  93. }
  94. static grub_err_t
  95. insert_dir (const char *name, struct dir **root,
  96. grub_uint8_t *ptr, grub_size_t *size)
  97. {
  98. struct dir *cur, **head = root;
  99. const char *cb, *ce = name;
  100. *size = 0;
  101. while (1)
  102. {
  103. for (cb = ce; *cb == '/'; cb++);
  104. for (ce = cb; *ce && *ce != '/'; ce++);
  105. if (!*ce)
  106. break;
  107. for (cur = *root; cur; cur = cur->next)
  108. if (grub_memcmp (cur->name, cb, ce - cb)
  109. && cur->name[ce - cb] == 0)
  110. break;
  111. if (!cur)
  112. {
  113. struct dir *n;
  114. n = grub_zalloc (sizeof (*n));
  115. if (!n)
  116. return 0;
  117. n->next = *head;
  118. n->name = grub_strndup (cb, ce - cb);
  119. if (ptr)
  120. {
  121. grub_dprintf ("linux", "Creating directory %s, %s\n", name, ce);
  122. ptr = make_header (ptr, name, ce - name,
  123. 040777, 0);
  124. }
  125. if (grub_add (*size,
  126. ALIGN_UP ((ce - (char *) name)
  127. + sizeof (struct newc_head), 4),
  128. size))
  129. {
  130. grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
  131. grub_free (n->name);
  132. grub_free (n);
  133. return grub_errno;
  134. }
  135. *head = n;
  136. cur = n;
  137. }
  138. root = &cur->next;
  139. }
  140. return GRUB_ERR_NONE;
  141. }
  142. grub_err_t
  143. grub_initrd_init (int argc, char *argv[],
  144. struct grub_linux_initrd_context *initrd_ctx)
  145. {
  146. int i;
  147. int newc = 0;
  148. struct dir *root = 0;
  149. initrd_ctx->nfiles = 0;
  150. initrd_ctx->components = 0;
  151. initrd_ctx->components = grub_calloc (argc, sizeof (initrd_ctx->components[0]));
  152. if (!initrd_ctx->components)
  153. return grub_errno;
  154. initrd_ctx->size = 0;
  155. for (i = 0; i < argc; i++)
  156. {
  157. const char *fname = argv[i];
  158. initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
  159. if (grub_memcmp (argv[i], "newc:", 5) == 0)
  160. {
  161. const char *ptr, *eptr;
  162. ptr = argv[i] + 5;
  163. while (*ptr == '/')
  164. ptr++;
  165. eptr = grub_strchr (ptr, ':');
  166. if (eptr)
  167. {
  168. grub_size_t dir_size, name_len;
  169. initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr);
  170. if (!initrd_ctx->components[i].newc_name ||
  171. insert_dir (initrd_ctx->components[i].newc_name, &root, 0,
  172. &dir_size))
  173. {
  174. grub_initrd_close (initrd_ctx);
  175. return grub_errno;
  176. }
  177. name_len = grub_strlen (initrd_ctx->components[i].newc_name);
  178. if (grub_add (initrd_ctx->size,
  179. ALIGN_UP (sizeof (struct newc_head) + name_len, 4),
  180. &initrd_ctx->size) ||
  181. grub_add (initrd_ctx->size, dir_size, &initrd_ctx->size))
  182. goto overflow;
  183. newc = 1;
  184. fname = eptr + 1;
  185. }
  186. }
  187. else if (newc)
  188. {
  189. if (grub_add (initrd_ctx->size,
  190. ALIGN_UP (sizeof (struct newc_head)
  191. + sizeof ("TRAILER!!!") - 1, 4),
  192. &initrd_ctx->size))
  193. goto overflow;
  194. free_dir (root);
  195. root = 0;
  196. newc = 0;
  197. }
  198. initrd_ctx->components[i].file = grub_file_open (fname,
  199. GRUB_FILE_TYPE_LINUX_INITRD
  200. | GRUB_FILE_TYPE_NO_DECOMPRESS);
  201. if (!initrd_ctx->components[i].file)
  202. {
  203. grub_initrd_close (initrd_ctx);
  204. return grub_errno;
  205. }
  206. initrd_ctx->nfiles++;
  207. initrd_ctx->components[i].size
  208. = grub_file_size (initrd_ctx->components[i].file);
  209. if (grub_add (initrd_ctx->size, initrd_ctx->components[i].size,
  210. &initrd_ctx->size))
  211. goto overflow;
  212. }
  213. if (newc)
  214. {
  215. initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
  216. if (grub_add (initrd_ctx->size,
  217. ALIGN_UP (sizeof (struct newc_head)
  218. + sizeof ("TRAILER!!!") - 1, 4),
  219. &initrd_ctx->size))
  220. goto overflow;
  221. free_dir (root);
  222. root = 0;
  223. }
  224. return GRUB_ERR_NONE;
  225. overflow:
  226. free_dir (root);
  227. grub_initrd_close (initrd_ctx);
  228. return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
  229. }
  230. grub_size_t
  231. grub_get_initrd_size (struct grub_linux_initrd_context *initrd_ctx)
  232. {
  233. return initrd_ctx->size;
  234. }
  235. void
  236. grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx)
  237. {
  238. int i;
  239. if (!initrd_ctx->components)
  240. return;
  241. for (i = 0; i < initrd_ctx->nfiles; i++)
  242. {
  243. grub_free (initrd_ctx->components[i].newc_name);
  244. grub_file_close (initrd_ctx->components[i].file);
  245. }
  246. grub_free (initrd_ctx->components);
  247. initrd_ctx->components = 0;
  248. }
  249. grub_err_t
  250. grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
  251. char *argv[], void *target)
  252. {
  253. grub_uint8_t *ptr = target;
  254. int i;
  255. int newc = 0;
  256. struct dir *root = 0;
  257. grub_ssize_t cursize = 0;
  258. for (i = 0; i < initrd_ctx->nfiles; i++)
  259. {
  260. grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
  261. ptr += ALIGN_UP_OVERHEAD (cursize, 4);
  262. if (initrd_ctx->components[i].newc_name)
  263. {
  264. grub_size_t dir_size;
  265. if (insert_dir (initrd_ctx->components[i].newc_name, &root, ptr,
  266. &dir_size))
  267. {
  268. free_dir (root);
  269. grub_initrd_close (initrd_ctx);
  270. return grub_errno;
  271. }
  272. ptr += dir_size;
  273. ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
  274. grub_strlen (initrd_ctx->components[i].newc_name),
  275. 0100777,
  276. initrd_ctx->components[i].size);
  277. newc = 1;
  278. }
  279. else if (newc)
  280. {
  281. ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1,
  282. 0, 0);
  283. free_dir (root);
  284. root = 0;
  285. newc = 0;
  286. }
  287. cursize = initrd_ctx->components[i].size;
  288. if (grub_file_read (initrd_ctx->components[i].file, ptr, cursize)
  289. != cursize)
  290. {
  291. if (!grub_errno)
  292. grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
  293. argv[i]);
  294. grub_initrd_close (initrd_ctx);
  295. return grub_errno;
  296. }
  297. ptr += cursize;
  298. }
  299. if (newc)
  300. {
  301. grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
  302. ptr += ALIGN_UP_OVERHEAD (cursize, 4);
  303. ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1, 0, 0);
  304. }
  305. free_dir (root);
  306. root = 0;
  307. return GRUB_ERR_NONE;
  308. }