linux.c 6.7 KB

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