ldm.c 27 KB

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