ldm.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2006,2007,2008,2009,2011 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/dl.h>
  19. #include <grub/disk.h>
  20. #include <grub/mm.h>
  21. #include <grub/err.h>
  22. #include <grub/misc.h>
  23. #include <grub/diskfilter.h>
  24. #include <grub/msdos_partition.h>
  25. #include <grub/gpt_partition.h>
  26. #include <grub/i18n.h>
  27. #ifdef GRUB_UTIL
  28. #include <grub/emu/misc.h>
  29. #include <grub/emu/hostdisk.h>
  30. #endif
  31. GRUB_MOD_LICENSE ("GPLv3+");
  32. #define LDM_GUID_STRLEN 64
  33. #define LDM_NAME_STRLEN 32
  34. typedef grub_uint8_t *grub_ldm_id_t;
  35. enum { STRIPE = 1, SPANNED = 2, RAID5 = 3 };
  36. #define LDM_LABEL_SECTOR 6
  37. struct grub_ldm_vblk {
  38. char magic[4];
  39. grub_uint8_t unused1[12];
  40. grub_uint16_t update_status;
  41. grub_uint8_t flags;
  42. grub_uint8_t type;
  43. grub_uint32_t unused2;
  44. grub_uint8_t dynamic[104];
  45. } GRUB_PACKED;
  46. #define LDM_VBLK_MAGIC "VBLK"
  47. enum
  48. {
  49. STATUS_CONSISTENT = 0,
  50. STATUS_STILL_ACTIVE = 1,
  51. STATUS_NOT_ACTIVE_YET = 2
  52. };
  53. enum
  54. {
  55. ENTRY_COMPONENT = 0x32,
  56. ENTRY_PARTITION = 0x33,
  57. ENTRY_DISK = 0x34,
  58. ENTRY_VOLUME = 0x51,
  59. };
  60. struct grub_ldm_label
  61. {
  62. char magic[8];
  63. grub_uint32_t unused1;
  64. grub_uint16_t ver_major;
  65. grub_uint16_t ver_minor;
  66. grub_uint8_t unused2[32];
  67. char disk_guid[LDM_GUID_STRLEN];
  68. char host_guid[LDM_GUID_STRLEN];
  69. char group_guid[LDM_GUID_STRLEN];
  70. char group_name[LDM_NAME_STRLEN];
  71. grub_uint8_t unused3[11];
  72. grub_uint64_t pv_start;
  73. grub_uint64_t pv_size;
  74. grub_uint64_t config_start;
  75. grub_uint64_t config_size;
  76. } GRUB_PACKED;
  77. #define LDM_MAGIC "PRIVHEAD"
  78. static inline grub_uint64_t
  79. read_int (grub_uint8_t *in, grub_size_t s)
  80. {
  81. grub_uint8_t *ptr2;
  82. grub_uint64_t ret;
  83. ret = 0;
  84. for (ptr2 = in; ptr2 < in + s; ptr2++)
  85. {
  86. ret <<= 8;
  87. ret |= *ptr2;
  88. }
  89. return ret;
  90. }
  91. static int
  92. check_ldm_partition (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t p, void *data)
  93. {
  94. int *has_ldm = data;
  95. if (p->number >= 4)
  96. return 1;
  97. if (p->msdostype == GRUB_PC_PARTITION_TYPE_LDM)
  98. {
  99. *has_ldm = 1;
  100. return 1;
  101. }
  102. return 0;
  103. }
  104. static int
  105. msdos_has_ldm_partition (grub_disk_t dsk)
  106. {
  107. grub_err_t err;
  108. int has_ldm = 0;
  109. err = grub_partition_msdos_iterate (dsk, check_ldm_partition, &has_ldm);
  110. if (err)
  111. {
  112. grub_errno = GRUB_ERR_NONE;
  113. return 0;
  114. }
  115. return has_ldm;
  116. }
  117. static const grub_gpt_part_type_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM;
  118. /* Helper for gpt_ldm_sector. */
  119. static int
  120. gpt_ldm_sector_iter (grub_disk_t disk, const grub_partition_t p, void *data)
  121. {
  122. grub_disk_addr_t *sector = data;
  123. struct grub_gpt_partentry gptdata;
  124. grub_partition_t p2;
  125. p2 = disk->partition;
  126. disk->partition = p->parent;
  127. if (grub_disk_read (disk, p->offset, p->index,
  128. sizeof (gptdata), &gptdata))
  129. {
  130. disk->partition = p2;
  131. return 0;
  132. }
  133. disk->partition = p2;
  134. if (! grub_memcmp (&gptdata.type, &ldm_type, 16))
  135. {
  136. *sector = p->start + p->len - 1;
  137. return 1;
  138. }
  139. return 0;
  140. }
  141. static grub_disk_addr_t
  142. gpt_ldm_sector (grub_disk_t dsk)
  143. {
  144. grub_disk_addr_t sector = 0;
  145. grub_err_t err;
  146. err = grub_gpt_partition_map_iterate (dsk, gpt_ldm_sector_iter, &sector);
  147. if (err)
  148. {
  149. grub_errno = GRUB_ERR_NONE;
  150. return 0;
  151. }
  152. return sector;
  153. }
  154. static struct grub_diskfilter_vg *
  155. make_vg (grub_disk_t disk,
  156. const struct grub_ldm_label *label)
  157. {
  158. grub_disk_addr_t startsec, endsec, cursec;
  159. struct grub_diskfilter_vg *vg;
  160. grub_err_t err;
  161. /* First time we see this volume group. We've to create the
  162. whole volume group structure. */
  163. vg = grub_malloc (sizeof (*vg));
  164. if (! vg)
  165. return NULL;
  166. vg->extent_size = 1;
  167. vg->name = grub_malloc (LDM_NAME_STRLEN + 1);
  168. vg->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
  169. if (! vg->uuid || !vg->name)
  170. {
  171. grub_free (vg->uuid);
  172. grub_free (vg->name);
  173. return NULL;
  174. }
  175. grub_memcpy (vg->uuid, label->group_guid, LDM_GUID_STRLEN);
  176. grub_memcpy (vg->name, label->group_name, LDM_NAME_STRLEN);
  177. vg->name[LDM_NAME_STRLEN] = 0;
  178. vg->uuid[LDM_GUID_STRLEN] = 0;
  179. vg->uuid_len = grub_strlen (vg->uuid);
  180. vg->lvs = NULL;
  181. vg->pvs = NULL;
  182. startsec = grub_be_to_cpu64 (label->config_start);
  183. endsec = startsec + grub_be_to_cpu64 (label->config_size);
  184. /* First find disks. */
  185. for (cursec = startsec + 0x12; cursec < endsec; cursec++)
  186. {
  187. struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
  188. / sizeof (struct grub_ldm_vblk)];
  189. unsigned i;
  190. err = grub_disk_read (disk, cursec, 0,
  191. sizeof(vblk), &vblk);
  192. if (err)
  193. goto fail2;
  194. for (i = 0; i < ARRAY_SIZE (vblk); i++)
  195. {
  196. struct grub_diskfilter_pv *pv;
  197. grub_uint8_t *ptr;
  198. if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
  199. sizeof (vblk[i].magic)) != 0)
  200. continue;
  201. if (grub_be_to_cpu16 (vblk[i].update_status)
  202. != STATUS_CONSISTENT
  203. && grub_be_to_cpu16 (vblk[i].update_status)
  204. != STATUS_STILL_ACTIVE)
  205. continue;
  206. if (vblk[i].type != ENTRY_DISK)
  207. continue;
  208. pv = grub_zalloc (sizeof (*pv));
  209. if (!pv)
  210. goto fail2;
  211. pv->disk = 0;
  212. ptr = vblk[i].dynamic;
  213. if (ptr + *ptr + 1 >= vblk[i].dynamic
  214. + sizeof (vblk[i].dynamic))
  215. {
  216. grub_free (pv);
  217. goto fail2;
  218. }
  219. pv->internal_id = grub_malloc (ptr[0] + 2);
  220. if (!pv->internal_id)
  221. {
  222. grub_free (pv);
  223. goto fail2;
  224. }
  225. grub_memcpy (pv->internal_id, ptr, (grub_size_t) ptr[0] + 1);
  226. pv->internal_id[(grub_size_t) ptr[0] + 1] = 0;
  227. ptr += *ptr + 1;
  228. if (ptr + *ptr + 1 >= vblk[i].dynamic
  229. + sizeof (vblk[i].dynamic))
  230. {
  231. grub_free (pv);
  232. goto fail2;
  233. }
  234. /* ptr = name. */
  235. ptr += *ptr + 1;
  236. if (ptr + *ptr + 1
  237. >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  238. {
  239. grub_free (pv);
  240. goto fail2;
  241. }
  242. pv->id.uuidlen = *ptr;
  243. pv->id.uuid = grub_malloc (pv->id.uuidlen + 1);
  244. grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
  245. pv->id.uuid[pv->id.uuidlen] = 0;
  246. pv->next = vg->pvs;
  247. vg->pvs = pv;
  248. }
  249. }
  250. /* Then find LVs. */
  251. for (cursec = startsec + 0x12; cursec < endsec; cursec++)
  252. {
  253. struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
  254. / sizeof (struct grub_ldm_vblk)];
  255. unsigned i;
  256. err = grub_disk_read (disk, cursec, 0,
  257. sizeof(vblk), &vblk);
  258. if (err)
  259. goto fail2;
  260. for (i = 0; i < ARRAY_SIZE (vblk); i++)
  261. {
  262. struct grub_diskfilter_lv *lv;
  263. grub_uint8_t *ptr;
  264. if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
  265. sizeof (vblk[i].magic)) != 0)
  266. continue;
  267. if (grub_be_to_cpu16 (vblk[i].update_status)
  268. != STATUS_CONSISTENT
  269. && grub_be_to_cpu16 (vblk[i].update_status)
  270. != STATUS_STILL_ACTIVE)
  271. continue;
  272. if (vblk[i].type != ENTRY_VOLUME)
  273. continue;
  274. lv = grub_zalloc (sizeof (*lv));
  275. if (!lv)
  276. goto fail2;
  277. lv->vg = vg;
  278. lv->segment_count = 1;
  279. lv->segment_alloc = 1;
  280. lv->visible = 1;
  281. lv->segments = grub_zalloc (sizeof (*lv->segments));
  282. if (!lv->segments)
  283. goto fail2;
  284. lv->segments->start_extent = 0;
  285. lv->segments->type = GRUB_DISKFILTER_MIRROR;
  286. lv->segments->node_count = 0;
  287. lv->segments->node_alloc = 8;
  288. lv->segments->nodes = grub_zalloc (sizeof (*lv->segments->nodes)
  289. * lv->segments->node_alloc);
  290. if (!lv->segments->nodes)
  291. goto fail2;
  292. ptr = vblk[i].dynamic;
  293. if (ptr + *ptr + 1 >= vblk[i].dynamic
  294. + sizeof (vblk[i].dynamic))
  295. {
  296. grub_free (lv);
  297. goto fail2;
  298. }
  299. lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
  300. if (!lv->internal_id)
  301. {
  302. grub_free (lv);
  303. goto fail2;
  304. }
  305. grub_memcpy (lv->internal_id, ptr, ptr[0] + 1);
  306. lv->internal_id[ptr[0] + 1] = 0;
  307. ptr += *ptr + 1;
  308. if (ptr + *ptr + 1 >= vblk[i].dynamic
  309. + sizeof (vblk[i].dynamic))
  310. {
  311. grub_free (lv);
  312. goto fail2;
  313. }
  314. lv->name = grub_malloc (*ptr + 1);
  315. if (!lv->name)
  316. {
  317. grub_free (lv->internal_id);
  318. grub_free (lv);
  319. goto fail2;
  320. }
  321. grub_memcpy (lv->name, ptr + 1, *ptr);
  322. lv->name[*ptr] = 0;
  323. lv->fullname = grub_xasprintf ("ldm/%s/%s",
  324. vg->uuid, lv->name);
  325. if (!lv->fullname)
  326. {
  327. grub_free (lv->internal_id);
  328. grub_free (lv->name);
  329. grub_free (lv);
  330. goto fail2;
  331. }
  332. ptr += *ptr + 1;
  333. if (ptr + *ptr + 1
  334. >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  335. {
  336. grub_free (lv->internal_id);
  337. grub_free (lv->name);
  338. grub_free (lv);
  339. goto fail2;
  340. }
  341. /* ptr = volume type. */
  342. ptr += *ptr + 1;
  343. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  344. {
  345. grub_free (lv->internal_id);
  346. grub_free (lv->name);
  347. grub_free (lv);
  348. goto fail2;
  349. }
  350. /* ptr = flags. */
  351. ptr += *ptr + 1;
  352. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  353. {
  354. grub_free (lv->internal_id);
  355. grub_free (lv->name);
  356. grub_free (lv);
  357. goto fail2;
  358. }
  359. /* Skip state, type, unknown, volume number, zeros, flags. */
  360. ptr += 14 + 1 + 1 + 1 + 3 + 1;
  361. /* ptr = number of children. */
  362. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  363. {
  364. grub_free (lv->internal_id);
  365. grub_free (lv->name);
  366. grub_free (lv);
  367. goto fail2;
  368. }
  369. ptr += *ptr + 1;
  370. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  371. {
  372. grub_free (lv->internal_id);
  373. grub_free (lv->name);
  374. grub_free (lv);
  375. goto fail2;
  376. }
  377. /* Skip 2 more fields. */
  378. ptr += 8 + 8;
  379. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
  380. || ptr + *ptr + 1>= vblk[i].dynamic
  381. + sizeof (vblk[i].dynamic))
  382. {
  383. grub_free (lv->internal_id);
  384. grub_free (lv->name);
  385. grub_free (lv);
  386. goto fail2;
  387. }
  388. lv->size = read_int (ptr + 1, *ptr);
  389. lv->segments->extent_count = lv->size;
  390. lv->next = vg->lvs;
  391. vg->lvs = lv;
  392. }
  393. }
  394. /* Now the components. */
  395. for (cursec = startsec + 0x12; cursec < endsec; cursec++)
  396. {
  397. struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
  398. / sizeof (struct grub_ldm_vblk)];
  399. unsigned i;
  400. err = grub_disk_read (disk, cursec, 0,
  401. sizeof(vblk), &vblk);
  402. if (err)
  403. goto fail2;
  404. for (i = 0; i < ARRAY_SIZE (vblk); i++)
  405. {
  406. struct grub_diskfilter_lv *comp;
  407. struct grub_diskfilter_lv *lv;
  408. grub_uint8_t type;
  409. grub_uint8_t *ptr;
  410. if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
  411. sizeof (vblk[i].magic)) != 0)
  412. continue;
  413. if (grub_be_to_cpu16 (vblk[i].update_status)
  414. != STATUS_CONSISTENT
  415. && grub_be_to_cpu16 (vblk[i].update_status)
  416. != STATUS_STILL_ACTIVE)
  417. continue;
  418. if (vblk[i].type != ENTRY_COMPONENT)
  419. continue;
  420. comp = grub_zalloc (sizeof (*comp));
  421. if (!comp)
  422. goto fail2;
  423. comp->visible = 0;
  424. comp->name = 0;
  425. comp->fullname = 0;
  426. ptr = vblk[i].dynamic;
  427. if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  428. {
  429. goto fail2;
  430. }
  431. comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
  432. if (!comp->internal_id)
  433. {
  434. grub_free (comp);
  435. goto fail2;
  436. }
  437. grub_memcpy (comp->internal_id, ptr, ptr[0] + 1);
  438. comp->internal_id[ptr[0] + 1] = 0;
  439. ptr += *ptr + 1;
  440. if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  441. {
  442. grub_free (comp->internal_id);
  443. grub_free (comp);
  444. goto fail2;
  445. }
  446. /* ptr = name. */
  447. ptr += *ptr + 1;
  448. if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  449. {
  450. grub_free (comp->internal_id);
  451. grub_free (comp);
  452. goto fail2;
  453. }
  454. /* ptr = state. */
  455. ptr += *ptr + 1;
  456. type = *ptr++;
  457. /* skip zeros. */
  458. ptr += 4;
  459. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  460. {
  461. grub_free (comp->internal_id);
  462. grub_free (comp);
  463. goto fail2;
  464. }
  465. /* ptr = number of children. */
  466. ptr += *ptr + 1;
  467. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  468. {
  469. grub_free (comp->internal_id);
  470. grub_free (comp);
  471. goto fail2;
  472. }
  473. ptr += 8 + 8;
  474. if (ptr + *ptr + 1 >= vblk[i].dynamic
  475. + sizeof (vblk[i].dynamic))
  476. {
  477. grub_free (comp->internal_id);
  478. grub_free (comp);
  479. goto fail2;
  480. }
  481. for (lv = vg->lvs; lv; lv = lv->next)
  482. {
  483. if (lv->internal_id[0] == ptr[0]
  484. && grub_memcmp (lv->internal_id + 1, ptr + 1, ptr[0]) == 0)
  485. break;
  486. }
  487. if (!lv)
  488. {
  489. grub_free (comp->internal_id);
  490. grub_free (comp);
  491. continue;
  492. }
  493. comp->size = lv->size;
  494. if (type == SPANNED)
  495. {
  496. comp->segment_alloc = 8;
  497. comp->segment_count = 0;
  498. comp->segments = grub_malloc (sizeof (*comp->segments)
  499. * comp->segment_alloc);
  500. if (!comp->segments)
  501. goto fail2;
  502. }
  503. else
  504. {
  505. comp->segment_alloc = 1;
  506. comp->segment_count = 1;
  507. comp->segments = grub_malloc (sizeof (*comp->segments));
  508. if (!comp->segments)
  509. goto fail2;
  510. comp->segments->start_extent = 0;
  511. comp->segments->extent_count = lv->size;
  512. comp->segments->layout = 0;
  513. if (type == STRIPE)
  514. comp->segments->type = GRUB_DISKFILTER_STRIPED;
  515. else if (type == RAID5)
  516. {
  517. comp->segments->type = GRUB_DISKFILTER_RAID5;
  518. comp->segments->layout = GRUB_RAID_LAYOUT_SYMMETRIC_MASK;
  519. }
  520. else
  521. goto fail2;
  522. ptr += *ptr + 1;
  523. ptr++;
  524. if (!(vblk[i].flags & 0x10))
  525. goto fail2;
  526. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
  527. || ptr + *ptr + 1 >= vblk[i].dynamic
  528. + sizeof (vblk[i].dynamic))
  529. {
  530. grub_free (comp->internal_id);
  531. grub_free (comp);
  532. goto fail2;
  533. }
  534. comp->segments->stripe_size = read_int (ptr + 1, *ptr);
  535. ptr += *ptr + 1;
  536. if (ptr + *ptr + 1 >= vblk[i].dynamic
  537. + sizeof (vblk[i].dynamic))
  538. {
  539. grub_free (comp->internal_id);
  540. grub_free (comp);
  541. goto fail2;
  542. }
  543. comp->segments->node_count = read_int (ptr + 1, *ptr);
  544. comp->segments->node_alloc = comp->segments->node_count;
  545. comp->segments->nodes = grub_zalloc (sizeof (*comp->segments->nodes)
  546. * comp->segments->node_alloc);
  547. if (!lv->segments->nodes)
  548. goto fail2;
  549. }
  550. if (lv->segments->node_alloc == lv->segments->node_count)
  551. {
  552. void *t;
  553. lv->segments->node_alloc *= 2;
  554. t = grub_realloc (lv->segments->nodes,
  555. sizeof (*lv->segments->nodes)
  556. * lv->segments->node_alloc);
  557. if (!t)
  558. goto fail2;
  559. lv->segments->nodes = t;
  560. }
  561. lv->segments->nodes[lv->segments->node_count].pv = 0;
  562. lv->segments->nodes[lv->segments->node_count].start = 0;
  563. lv->segments->nodes[lv->segments->node_count++].lv = comp;
  564. comp->next = vg->lvs;
  565. vg->lvs = comp;
  566. }
  567. }
  568. /* Partitions. */
  569. for (cursec = startsec + 0x12; cursec < endsec; cursec++)
  570. {
  571. struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
  572. / sizeof (struct grub_ldm_vblk)];
  573. unsigned i;
  574. err = grub_disk_read (disk, cursec, 0,
  575. sizeof(vblk), &vblk);
  576. if (err)
  577. goto fail2;
  578. for (i = 0; i < ARRAY_SIZE (vblk); i++)
  579. {
  580. struct grub_diskfilter_lv *comp;
  581. struct grub_diskfilter_node part;
  582. grub_disk_addr_t start, size;
  583. grub_uint8_t *ptr;
  584. part.name = 0;
  585. if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
  586. sizeof (vblk[i].magic)) != 0)
  587. continue;
  588. if (grub_be_to_cpu16 (vblk[i].update_status)
  589. != STATUS_CONSISTENT
  590. && grub_be_to_cpu16 (vblk[i].update_status)
  591. != STATUS_STILL_ACTIVE)
  592. continue;
  593. if (vblk[i].type != ENTRY_PARTITION)
  594. continue;
  595. part.lv = 0;
  596. part.pv = 0;
  597. ptr = vblk[i].dynamic;
  598. if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  599. {
  600. goto fail2;
  601. }
  602. /* ID */
  603. ptr += *ptr + 1;
  604. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  605. {
  606. goto fail2;
  607. }
  608. /* ptr = name. */
  609. ptr += *ptr + 1;
  610. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  611. {
  612. goto fail2;
  613. }
  614. /* skip zeros and logcommit id. */
  615. ptr += 4 + 8;
  616. if (ptr + 16 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  617. {
  618. goto fail2;
  619. }
  620. part.start = read_int (ptr, 8);
  621. start = read_int (ptr + 8, 8);
  622. ptr += 16;
  623. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
  624. || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  625. {
  626. goto fail2;
  627. }
  628. size = read_int (ptr + 1, *ptr);
  629. ptr += *ptr + 1;
  630. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
  631. || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  632. {
  633. goto fail2;
  634. }
  635. for (comp = vg->lvs; comp; comp = comp->next)
  636. if (comp->internal_id[0] == ptr[0]
  637. && grub_memcmp (ptr + 1, comp->internal_id + 1,
  638. comp->internal_id[0]) == 0)
  639. goto out;
  640. continue;
  641. out:
  642. if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
  643. || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
  644. {
  645. goto fail2;
  646. }
  647. ptr += *ptr + 1;
  648. struct grub_diskfilter_pv *pv;
  649. for (pv = vg->pvs; pv; pv = pv->next)
  650. if (pv->internal_id[0] == ptr[0]
  651. && grub_memcmp (pv->internal_id + 1, ptr + 1, ptr[0]) == 0)
  652. part.pv = pv;
  653. if (comp->segment_alloc == 1)
  654. {
  655. unsigned node_index;
  656. ptr += *ptr + 1;
  657. if (ptr + *ptr + 1 >= vblk[i].dynamic
  658. + sizeof (vblk[i].dynamic))
  659. {
  660. goto fail2;
  661. }
  662. node_index = read_int (ptr + 1, *ptr);
  663. if (node_index < comp->segments->node_count)
  664. comp->segments->nodes[node_index] = part;
  665. }
  666. else
  667. {
  668. if (comp->segment_alloc == comp->segment_count)
  669. {
  670. void *t;
  671. comp->segment_alloc *= 2;
  672. t = grub_realloc (comp->segments,
  673. comp->segment_alloc
  674. * sizeof (*comp->segments));
  675. if (!t)
  676. goto fail2;
  677. comp->segments = t;
  678. }
  679. comp->segments[comp->segment_count].start_extent = start;
  680. comp->segments[comp->segment_count].extent_count = size;
  681. comp->segments[comp->segment_count].type = GRUB_DISKFILTER_STRIPED;
  682. comp->segments[comp->segment_count].node_count = 1;
  683. comp->segments[comp->segment_count].node_alloc = 1;
  684. comp->segments[comp->segment_count].nodes
  685. = grub_malloc (sizeof (*comp->segments[comp->segment_count].nodes));
  686. if (!comp->segments[comp->segment_count].nodes)
  687. goto fail2;
  688. comp->segments[comp->segment_count].nodes[0] = part;
  689. comp->segment_count++;
  690. }
  691. }
  692. }
  693. if (grub_diskfilter_vg_register (vg))
  694. goto fail2;
  695. return vg;
  696. fail2:
  697. {
  698. struct grub_diskfilter_lv *lv, *next_lv;
  699. struct grub_diskfilter_pv *pv, *next_pv;
  700. for (lv = vg->lvs; lv; lv = next_lv)
  701. {
  702. unsigned i;
  703. for (i = 0; i < lv->segment_count; i++)
  704. grub_free (lv->segments[i].nodes);
  705. next_lv = lv->next;
  706. grub_free (lv->segments);
  707. grub_free (lv->internal_id);
  708. grub_free (lv->name);
  709. grub_free (lv->fullname);
  710. grub_free (lv);
  711. }
  712. for (pv = vg->pvs; pv; pv = next_pv)
  713. {
  714. next_pv = pv->next;
  715. grub_free (pv->id.uuid);
  716. grub_free (pv);
  717. }
  718. }
  719. grub_free (vg->uuid);
  720. grub_free (vg);
  721. return NULL;
  722. }
  723. static struct grub_diskfilter_vg *
  724. grub_ldm_detect (grub_disk_t disk,
  725. struct grub_diskfilter_pv_id *id,
  726. grub_disk_addr_t *start_sector)
  727. {
  728. grub_err_t err;
  729. struct grub_ldm_label label;
  730. struct grub_diskfilter_vg *vg;
  731. #ifdef GRUB_UTIL
  732. grub_util_info ("scanning %s for LDM", disk->name);
  733. #endif
  734. {
  735. int i;
  736. int has_ldm = msdos_has_ldm_partition (disk);
  737. for (i = 0; i < 3; i++)
  738. {
  739. grub_disk_addr_t sector = LDM_LABEL_SECTOR;
  740. switch (i)
  741. {
  742. case 0:
  743. if (!has_ldm)
  744. continue;
  745. sector = LDM_LABEL_SECTOR;
  746. break;
  747. case 1:
  748. /* LDM is never inside a partition. */
  749. if (!has_ldm || disk->partition)
  750. continue;
  751. sector = grub_disk_get_size (disk);
  752. if (sector == GRUB_DISK_SIZE_UNKNOWN)
  753. continue;
  754. sector--;
  755. break;
  756. /* FIXME: try the third copy. */
  757. case 2:
  758. sector = gpt_ldm_sector (disk);
  759. if (!sector)
  760. continue;
  761. break;
  762. }
  763. err = grub_disk_read (disk, sector, 0,
  764. sizeof(label), &label);
  765. if (err)
  766. return NULL;
  767. if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0
  768. && grub_be_to_cpu16 (label.ver_major) == 0x02
  769. && grub_be_to_cpu16 (label.ver_minor) >= 0x0b
  770. && grub_be_to_cpu16 (label.ver_minor) <= 0x0c)
  771. break;
  772. }
  773. /* Return if we didn't find a label. */
  774. if (i == 3)
  775. {
  776. #ifdef GRUB_UTIL
  777. grub_util_info ("no LDM signature found");
  778. #endif
  779. return NULL;
  780. }
  781. }
  782. id->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
  783. if (!id->uuid)
  784. return NULL;
  785. grub_memcpy (id->uuid, label.disk_guid, LDM_GUID_STRLEN);
  786. id->uuid[LDM_GUID_STRLEN] = 0;
  787. id->uuidlen = grub_strlen ((char *) id->uuid);
  788. *start_sector = grub_be_to_cpu64 (label.pv_start);
  789. {
  790. grub_size_t s;
  791. for (s = 0; s < LDM_GUID_STRLEN && label.group_guid[s]; s++);
  792. vg = grub_diskfilter_get_vg_by_uuid (s, label.group_guid);
  793. if (! vg)
  794. vg = make_vg (disk, &label);
  795. }
  796. if (!vg)
  797. {
  798. grub_free (id->uuid);
  799. return NULL;
  800. }
  801. return vg;
  802. }
  803. #ifdef GRUB_UTIL
  804. char *
  805. grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start)
  806. {
  807. struct grub_diskfilter_pv *pv = NULL;
  808. struct grub_diskfilter_vg *vg = NULL;
  809. struct grub_diskfilter_lv *res = 0, *lv, *res_lv = 0;
  810. pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
  811. if (!pv)
  812. return NULL;
  813. for (lv = vg->lvs; lv; lv = lv->next)
  814. if (lv->segment_count == 1 && lv->segments->node_count == 1
  815. && lv->segments->type == GRUB_DISKFILTER_STRIPED
  816. && lv->segments->nodes->pv == pv
  817. && lv->segments->nodes->start + pv->start_sector == start)
  818. {
  819. res_lv = lv;
  820. break;
  821. }
  822. if (!res_lv)
  823. return NULL;
  824. for (lv = vg->lvs; lv; lv = lv->next)
  825. if (lv->segment_count == 1 && lv->segments->node_count == 1
  826. && lv->segments->type == GRUB_DISKFILTER_MIRROR
  827. && lv->segments->nodes->lv == res_lv)
  828. {
  829. res = lv;
  830. break;
  831. }
  832. if (res && res->fullname)
  833. return grub_strdup (res->fullname);
  834. return NULL;
  835. }
  836. int
  837. grub_util_is_ldm (grub_disk_t disk)
  838. {
  839. int i;
  840. int has_ldm = msdos_has_ldm_partition (disk);
  841. for (i = 0; i < 3; i++)
  842. {
  843. grub_disk_addr_t sector = LDM_LABEL_SECTOR;
  844. grub_err_t err;
  845. struct grub_ldm_label label;
  846. switch (i)
  847. {
  848. case 0:
  849. if (!has_ldm)
  850. continue;
  851. sector = LDM_LABEL_SECTOR;
  852. break;
  853. case 1:
  854. /* LDM is never inside a partition. */
  855. if (!has_ldm || disk->partition)
  856. continue;
  857. sector = grub_disk_get_size (disk);
  858. if (sector == GRUB_DISK_SIZE_UNKNOWN)
  859. continue;
  860. sector--;
  861. break;
  862. /* FIXME: try the third copy. */
  863. case 2:
  864. sector = gpt_ldm_sector (disk);
  865. if (!sector)
  866. continue;
  867. break;
  868. }
  869. err = grub_disk_read (disk, sector, 0, sizeof(label), &label);
  870. if (err)
  871. {
  872. grub_errno = GRUB_ERR_NONE;
  873. return 0;
  874. }
  875. /* This check is more relaxed on purpose. */
  876. if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0)
  877. return 1;
  878. }
  879. return 0;
  880. }
  881. grub_err_t
  882. grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
  883. unsigned int max_nsectors,
  884. grub_embed_type_t embed_type,
  885. grub_disk_addr_t **sectors)
  886. {
  887. struct grub_diskfilter_pv *pv = NULL;
  888. struct grub_diskfilter_vg *vg;
  889. struct grub_diskfilter_lv *lv;
  890. unsigned i;
  891. if (embed_type != GRUB_EMBED_PCBIOS)
  892. return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
  893. "LDM currently supports only PC-BIOS embedding");
  894. if (disk->partition)
  895. return grub_error (GRUB_ERR_BUG, "disk isn't LDM");
  896. pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
  897. if (!pv)
  898. return grub_error (GRUB_ERR_BUG, "disk isn't LDM");
  899. for (lv = vg->lvs; lv; lv = lv->next)
  900. {
  901. struct grub_diskfilter_lv *comp;
  902. if (!lv->visible || !lv->fullname)
  903. continue;
  904. if (lv->segment_count != 1)
  905. continue;
  906. if (lv->segments->type != GRUB_DISKFILTER_MIRROR
  907. || lv->segments->node_count != 1
  908. || lv->segments->start_extent != 0
  909. || lv->segments->extent_count != lv->size)
  910. continue;
  911. comp = lv->segments->nodes->lv;
  912. if (!comp)
  913. continue;
  914. if (comp->segment_count != 1 || comp->size != lv->size)
  915. continue;
  916. if (comp->segments->type != GRUB_DISKFILTER_STRIPED
  917. || comp->segments->node_count != 1
  918. || comp->segments->start_extent != 0
  919. || comp->segments->extent_count != lv->size)
  920. continue;
  921. /* How to implement proper check is to be discussed. */
  922. #if 1
  923. if (1)
  924. continue;
  925. #else
  926. if (grub_strcmp (lv->name, "Volume5") != 0)
  927. continue;
  928. #endif
  929. if (lv->size < *nsectors)
  930. return grub_error (GRUB_ERR_OUT_OF_RANGE,
  931. /* TRANSLATORS: it's a partition for embedding,
  932. not a partition embed into something. GRUB
  933. install tools put core.img into a place
  934. usable for bootloaders (called generically
  935. "embedding zone") and this operation is
  936. called "embedding". */
  937. N_("your LDM Embedding Partition is too small;"
  938. " embedding won't be possible"));
  939. *nsectors = lv->size;
  940. if (*nsectors > max_nsectors)
  941. *nsectors = max_nsectors;
  942. *sectors = grub_malloc (*nsectors * sizeof (**sectors));
  943. if (!*sectors)
  944. return grub_errno;
  945. for (i = 0; i < *nsectors; i++)
  946. (*sectors)[i] = (lv->segments->nodes->start
  947. + comp->segments->nodes->start
  948. + comp->segments->nodes->pv->start_sector + i);
  949. return GRUB_ERR_NONE;
  950. }
  951. return grub_error (GRUB_ERR_FILE_NOT_FOUND,
  952. /* TRANSLATORS: it's a partition for embedding,
  953. not a partition embed into something. */
  954. N_("this LDM has no Embedding Partition;"
  955. " embedding won't be possible"));
  956. }
  957. #endif
  958. static struct grub_diskfilter grub_ldm_dev = {
  959. .name = "ldm",
  960. .detect = grub_ldm_detect,
  961. .next = 0
  962. };
  963. GRUB_MOD_INIT (ldm)
  964. {
  965. grub_diskfilter_register_back (&grub_ldm_dev);
  966. }
  967. GRUB_MOD_FINI (ldm)
  968. {
  969. grub_diskfilter_unregister (&grub_ldm_dev);
  970. }