lvm.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. /* lvm.c - module to read Logical Volumes. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2006,2007,2008,2009,2011 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 <grub/dl.h>
  20. #include <grub/disk.h>
  21. #include <grub/mm.h>
  22. #include <grub/err.h>
  23. #include <grub/misc.h>
  24. #include <grub/lvm.h>
  25. #include <grub/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. /* Go the string STR and return the number after STR. *P will point
  33. at the number. In case STR is not found, *P will be NULL and the
  34. return value will be 0. */
  35. static grub_uint64_t
  36. grub_lvm_getvalue (char **p, const char *str)
  37. {
  38. *p = grub_strstr (*p, str);
  39. if (! *p)
  40. return 0;
  41. *p += grub_strlen (str);
  42. return grub_strtoull (*p, p, 10);
  43. }
  44. #if 0
  45. static int
  46. grub_lvm_checkvalue (char **p, char *str, char *tmpl)
  47. {
  48. int tmpllen = grub_strlen (tmpl);
  49. *p = grub_strstr (*p, str);
  50. if (! *p)
  51. return 0;
  52. *p += grub_strlen (str);
  53. if (**p != '"')
  54. return 0;
  55. return (grub_memcmp (*p + 1, tmpl, tmpllen) == 0 && (*p)[tmpllen + 1] == '"');
  56. }
  57. #endif
  58. static int
  59. grub_lvm_check_flag (char *p, const char *str, const char *flag)
  60. {
  61. grub_size_t len_str = grub_strlen (str), len_flag = grub_strlen (flag);
  62. while (1)
  63. {
  64. char *q;
  65. p = grub_strstr (p, str);
  66. if (! p)
  67. return 0;
  68. p += len_str;
  69. if (grub_memcmp (p, " = [", sizeof (" = [") - 1) != 0)
  70. continue;
  71. q = p + sizeof (" = [") - 1;
  72. while (1)
  73. {
  74. while (grub_isspace (*q))
  75. q++;
  76. if (*q != '"')
  77. return 0;
  78. q++;
  79. if (grub_memcmp (q, flag, len_flag) == 0 && q[len_flag] == '"')
  80. return 1;
  81. while (*q != '"')
  82. q++;
  83. q++;
  84. if (*q == ']')
  85. return 0;
  86. q++;
  87. }
  88. }
  89. }
  90. static struct grub_diskfilter_vg *
  91. grub_lvm_detect (grub_disk_t disk,
  92. struct grub_diskfilter_pv_id *id,
  93. grub_disk_addr_t *start_sector)
  94. {
  95. grub_err_t err;
  96. grub_uint64_t mda_offset, mda_size;
  97. char buf[GRUB_LVM_LABEL_SIZE];
  98. char vg_id[GRUB_LVM_ID_STRLEN+1];
  99. char pv_id[GRUB_LVM_ID_STRLEN+1];
  100. char *metadatabuf, *p, *q, *vgname;
  101. struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
  102. struct grub_lvm_pv_header *pvh;
  103. struct grub_lvm_disk_locn *dlocn;
  104. struct grub_lvm_mda_header *mdah;
  105. struct grub_lvm_raw_locn *rlocn;
  106. unsigned int i, j;
  107. grub_size_t vgname_len;
  108. struct grub_diskfilter_vg *vg;
  109. struct grub_diskfilter_pv *pv;
  110. /* Search for label. */
  111. for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
  112. {
  113. err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
  114. if (err)
  115. goto fail;
  116. if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
  117. sizeof (lh->id)))
  118. && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
  119. sizeof (lh->type))))
  120. break;
  121. }
  122. /* Return if we didn't find a label. */
  123. if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
  124. {
  125. #ifdef GRUB_UTIL
  126. grub_util_info ("no LVM signature found");
  127. #endif
  128. goto fail;
  129. }
  130. pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
  131. for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++)
  132. {
  133. pv_id[j++] = pvh->pv_uuid[i];
  134. if ((i != 1) && (i != 29) && (i % 4 == 1))
  135. pv_id[j++] = '-';
  136. }
  137. pv_id[j] = '\0';
  138. dlocn = pvh->disk_areas_xl;
  139. dlocn++;
  140. /* Is it possible to have multiple data/metadata areas? I haven't
  141. seen devices that have it. */
  142. if (dlocn->offset)
  143. {
  144. grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
  145. "we don't support multiple LVM data areas");
  146. #ifdef GRUB_UTIL
  147. grub_util_info ("we don't support multiple LVM data areas");
  148. #endif
  149. goto fail;
  150. }
  151. dlocn++;
  152. mda_offset = grub_le_to_cpu64 (dlocn->offset);
  153. mda_size = grub_le_to_cpu64 (dlocn->size);
  154. /* It's possible to have multiple copies of metadata areas, we just use the
  155. first one. */
  156. /* Allocate buffer space for the circular worst-case scenario. */
  157. metadatabuf = grub_malloc (2 * mda_size);
  158. if (! metadatabuf)
  159. goto fail;
  160. err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf);
  161. if (err)
  162. goto fail2;
  163. mdah = (struct grub_lvm_mda_header *) metadatabuf;
  164. if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC,
  165. sizeof (mdah->magic)))
  166. || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION))
  167. {
  168. grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
  169. "unknown LVM metadata header");
  170. #ifdef GRUB_UTIL
  171. grub_util_info ("unknown LVM metadata header");
  172. #endif
  173. goto fail2;
  174. }
  175. rlocn = mdah->raw_locns;
  176. if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) >
  177. grub_le_to_cpu64 (mdah->size))
  178. {
  179. /* Metadata is circular. Copy the wrap in place. */
  180. grub_memcpy (metadatabuf + mda_size,
  181. metadatabuf + GRUB_LVM_MDA_HEADER_SIZE,
  182. grub_le_to_cpu64 (rlocn->offset) +
  183. grub_le_to_cpu64 (rlocn->size) -
  184. grub_le_to_cpu64 (mdah->size));
  185. }
  186. p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset);
  187. while (*q != ' ' && q < metadatabuf + mda_size)
  188. q++;
  189. if (q == metadatabuf + mda_size)
  190. {
  191. #ifdef GRUB_UTIL
  192. grub_util_info ("error parsing metadata");
  193. #endif
  194. goto fail2;
  195. }
  196. vgname_len = q - p;
  197. vgname = grub_malloc (vgname_len + 1);
  198. if (!vgname)
  199. goto fail2;
  200. grub_memcpy (vgname, p, vgname_len);
  201. vgname[vgname_len] = '\0';
  202. p = grub_strstr (q, "id = \"");
  203. if (p == NULL)
  204. {
  205. #ifdef GRUB_UTIL
  206. grub_util_info ("couldn't find ID");
  207. #endif
  208. goto fail3;
  209. }
  210. p += sizeof ("id = \"") - 1;
  211. grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
  212. vg_id[GRUB_LVM_ID_STRLEN] = '\0';
  213. vg = grub_diskfilter_get_vg_by_uuid (GRUB_LVM_ID_STRLEN, vg_id);
  214. if (! vg)
  215. {
  216. /* First time we see this volume group. We've to create the
  217. whole volume group structure. */
  218. vg = grub_malloc (sizeof (*vg));
  219. if (! vg)
  220. goto fail3;
  221. vg->name = vgname;
  222. vg->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
  223. if (! vg->uuid)
  224. goto fail3;
  225. grub_memcpy (vg->uuid, vg_id, GRUB_LVM_ID_STRLEN);
  226. vg->uuid_len = GRUB_LVM_ID_STRLEN;
  227. vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
  228. if (p == NULL)
  229. {
  230. #ifdef GRUB_UTIL
  231. grub_util_info ("unknown extent size");
  232. #endif
  233. goto fail4;
  234. }
  235. vg->lvs = NULL;
  236. vg->pvs = NULL;
  237. p = grub_strstr (p, "physical_volumes {");
  238. if (p)
  239. {
  240. p += sizeof ("physical_volumes {") - 1;
  241. /* Add all the pvs to the volume group. */
  242. while (1)
  243. {
  244. grub_ssize_t s;
  245. while (grub_isspace (*p))
  246. p++;
  247. if (*p == '}')
  248. break;
  249. pv = grub_zalloc (sizeof (*pv));
  250. q = p;
  251. while (*q != ' ')
  252. q++;
  253. s = q - p;
  254. pv->name = grub_malloc (s + 1);
  255. grub_memcpy (pv->name, p, s);
  256. pv->name[s] = '\0';
  257. p = grub_strstr (p, "id = \"");
  258. if (p == NULL)
  259. goto pvs_fail;
  260. p += sizeof("id = \"") - 1;
  261. pv->id.uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
  262. if (!pv->id.uuid)
  263. goto pvs_fail;
  264. grub_memcpy (pv->id.uuid, p, GRUB_LVM_ID_STRLEN);
  265. pv->id.uuidlen = GRUB_LVM_ID_STRLEN;
  266. pv->start_sector = grub_lvm_getvalue (&p, "pe_start = ");
  267. if (p == NULL)
  268. {
  269. #ifdef GRUB_UTIL
  270. grub_util_info ("unknown pe_start");
  271. #endif
  272. goto pvs_fail;
  273. }
  274. p = grub_strchr (p, '}');
  275. if (p == NULL)
  276. {
  277. #ifdef GRUB_UTIL
  278. grub_util_info ("error parsing pe_start");
  279. #endif
  280. goto pvs_fail;
  281. }
  282. p++;
  283. pv->disk = NULL;
  284. pv->next = vg->pvs;
  285. vg->pvs = pv;
  286. continue;
  287. pvs_fail:
  288. grub_free (pv->name);
  289. grub_free (pv);
  290. goto fail4;
  291. }
  292. }
  293. p = grub_strstr (p, "logical_volumes {");
  294. if (p)
  295. {
  296. p += sizeof ("logical_volumes {") - 1;
  297. /* And add all the lvs to the volume group. */
  298. while (1)
  299. {
  300. grub_ssize_t s;
  301. int skip_lv = 0;
  302. struct grub_diskfilter_lv *lv;
  303. struct grub_diskfilter_segment *seg;
  304. int is_pvmove;
  305. while (grub_isspace (*p))
  306. p++;
  307. if (*p == '}')
  308. break;
  309. lv = grub_zalloc (sizeof (*lv));
  310. q = p;
  311. while (*q != ' ')
  312. q++;
  313. s = q - p;
  314. lv->name = grub_strndup (p, s);
  315. if (!lv->name)
  316. goto lvs_fail;
  317. {
  318. const char *iptr;
  319. char *optr;
  320. lv->fullname = grub_malloc (sizeof ("lvm/") - 1 + 2 * vgname_len
  321. + 1 + 2 * s + 1);
  322. if (!lv->fullname)
  323. goto lvs_fail;
  324. grub_memcpy (lv->fullname, "lvm/", sizeof ("lvm/") - 1);
  325. optr = lv->fullname + sizeof ("lvm/") - 1;
  326. for (iptr = vgname; iptr < vgname + vgname_len; iptr++)
  327. {
  328. *optr++ = *iptr;
  329. if (*iptr == '-')
  330. *optr++ = '-';
  331. }
  332. *optr++ = '-';
  333. for (iptr = p; iptr < p + s; iptr++)
  334. {
  335. *optr++ = *iptr;
  336. if (*iptr == '-')
  337. *optr++ = '-';
  338. }
  339. *optr++ = 0;
  340. lv->idname = grub_malloc (sizeof ("lvmid/")
  341. + 2 * GRUB_LVM_ID_STRLEN + 1);
  342. if (!lv->idname)
  343. goto lvs_fail;
  344. grub_memcpy (lv->idname, "lvmid/",
  345. sizeof ("lvmid/") - 1);
  346. grub_memcpy (lv->idname + sizeof ("lvmid/") - 1,
  347. vg_id, GRUB_LVM_ID_STRLEN);
  348. lv->idname[sizeof ("lvmid/") - 1 + GRUB_LVM_ID_STRLEN] = '/';
  349. p = grub_strstr (q, "id = \"");
  350. if (p == NULL)
  351. {
  352. #ifdef GRUB_UTIL
  353. grub_util_info ("couldn't find ID");
  354. #endif
  355. goto lvs_fail;
  356. }
  357. p += sizeof ("id = \"") - 1;
  358. grub_memcpy (lv->idname + sizeof ("lvmid/") - 1
  359. + GRUB_LVM_ID_STRLEN + 1,
  360. p, GRUB_LVM_ID_STRLEN);
  361. lv->idname[sizeof ("lvmid/") - 1 + 2 * GRUB_LVM_ID_STRLEN + 1] = '\0';
  362. }
  363. lv->size = 0;
  364. lv->visible = grub_lvm_check_flag (p, "status", "VISIBLE");
  365. is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE");
  366. lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
  367. if (p == NULL)
  368. {
  369. #ifdef GRUB_UTIL
  370. grub_util_info ("unknown segment_count");
  371. #endif
  372. goto lvs_fail;
  373. }
  374. lv->segments = grub_zalloc (sizeof (*seg) * lv->segment_count);
  375. seg = lv->segments;
  376. for (i = 0; i < lv->segment_count; i++)
  377. {
  378. p = grub_strstr (p, "segment");
  379. if (p == NULL)
  380. {
  381. #ifdef GRUB_UTIL
  382. grub_util_info ("unknown segment");
  383. #endif
  384. goto lvs_segment_fail;
  385. }
  386. seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
  387. if (p == NULL)
  388. {
  389. #ifdef GRUB_UTIL
  390. grub_util_info ("unknown start_extent");
  391. #endif
  392. goto lvs_segment_fail;
  393. }
  394. seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
  395. if (p == NULL)
  396. {
  397. #ifdef GRUB_UTIL
  398. grub_util_info ("unknown extent_count");
  399. #endif
  400. goto lvs_segment_fail;
  401. }
  402. p = grub_strstr (p, "type = \"");
  403. if (p == NULL)
  404. goto lvs_segment_fail;
  405. p += sizeof("type = \"") - 1;
  406. lv->size += seg->extent_count * vg->extent_size;
  407. if (grub_memcmp (p, "striped\"",
  408. sizeof ("striped\"") - 1) == 0)
  409. {
  410. struct grub_diskfilter_node *stripe;
  411. seg->type = GRUB_DISKFILTER_STRIPED;
  412. seg->node_count = grub_lvm_getvalue (&p, "stripe_count = ");
  413. if (p == NULL)
  414. {
  415. #ifdef GRUB_UTIL
  416. grub_util_info ("unknown stripe_count");
  417. #endif
  418. goto lvs_segment_fail;
  419. }
  420. if (seg->node_count != 1)
  421. seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
  422. seg->nodes = grub_zalloc (sizeof (*stripe)
  423. * seg->node_count);
  424. stripe = seg->nodes;
  425. p = grub_strstr (p, "stripes = [");
  426. if (p == NULL)
  427. {
  428. #ifdef GRUB_UTIL
  429. grub_util_info ("unknown stripes");
  430. #endif
  431. goto lvs_segment_fail2;
  432. }
  433. p += sizeof("stripes = [") - 1;
  434. for (j = 0; j < seg->node_count; j++)
  435. {
  436. p = grub_strchr (p, '"');
  437. if (p == NULL)
  438. continue;
  439. q = ++p;
  440. while (*q != '"')
  441. q++;
  442. s = q - p;
  443. stripe->name = grub_malloc (s + 1);
  444. if (stripe->name == NULL)
  445. goto lvs_segment_fail2;
  446. grub_memcpy (stripe->name, p, s);
  447. stripe->name[s] = '\0';
  448. p = q + 1;
  449. stripe->start = grub_lvm_getvalue (&p, ",")
  450. * vg->extent_size;
  451. if (p == NULL)
  452. continue;
  453. stripe++;
  454. }
  455. }
  456. else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1)
  457. == 0)
  458. {
  459. seg->type = GRUB_DISKFILTER_MIRROR;
  460. seg->node_count = grub_lvm_getvalue (&p, "mirror_count = ");
  461. if (p == NULL)
  462. {
  463. #ifdef GRUB_UTIL
  464. grub_util_info ("unknown mirror_count");
  465. #endif
  466. goto lvs_segment_fail;
  467. }
  468. seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
  469. * seg->node_count);
  470. p = grub_strstr (p, "mirrors = [");
  471. if (p == NULL)
  472. {
  473. #ifdef GRUB_UTIL
  474. grub_util_info ("unknown mirrors");
  475. #endif
  476. goto lvs_segment_fail2;
  477. }
  478. p += sizeof("mirrors = [") - 1;
  479. for (j = 0; j < seg->node_count; j++)
  480. {
  481. char *lvname;
  482. p = grub_strchr (p, '"');
  483. if (p == NULL)
  484. continue;
  485. q = ++p;
  486. while (*q != '"')
  487. q++;
  488. s = q - p;
  489. lvname = grub_malloc (s + 1);
  490. if (lvname == NULL)
  491. goto lvs_segment_fail2;
  492. grub_memcpy (lvname, p, s);
  493. lvname[s] = '\0';
  494. seg->nodes[j].name = lvname;
  495. p = q + 1;
  496. }
  497. /* Only first (original) is ok with in progress pvmove. */
  498. if (is_pvmove)
  499. seg->node_count = 1;
  500. }
  501. else if (grub_memcmp (p, "raid", sizeof ("raid") - 1) == 0
  502. && ((p[sizeof ("raid") - 1] >= '4'
  503. && p[sizeof ("raid") - 1] <= '6')
  504. || p[sizeof ("raid") - 1] == '1')
  505. && p[sizeof ("raidX") - 1] == '"')
  506. {
  507. switch (p[sizeof ("raid") - 1])
  508. {
  509. case '1':
  510. seg->type = GRUB_DISKFILTER_MIRROR;
  511. break;
  512. case '4':
  513. seg->type = GRUB_DISKFILTER_RAID4;
  514. seg->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
  515. break;
  516. case '5':
  517. seg->type = GRUB_DISKFILTER_RAID5;
  518. seg->layout = GRUB_RAID_LAYOUT_LEFT_SYMMETRIC;
  519. break;
  520. case '6':
  521. seg->type = GRUB_DISKFILTER_RAID6;
  522. seg->layout = (GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC
  523. | GRUB_RAID_LAYOUT_MUL_FROM_POS);
  524. break;
  525. }
  526. seg->node_count = grub_lvm_getvalue (&p, "device_count = ");
  527. if (p == NULL)
  528. {
  529. #ifdef GRUB_UTIL
  530. grub_util_info ("unknown device_count");
  531. #endif
  532. goto lvs_segment_fail;
  533. }
  534. if (seg->type != GRUB_DISKFILTER_MIRROR)
  535. {
  536. seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
  537. if (p == NULL)
  538. {
  539. #ifdef GRUB_UTIL
  540. grub_util_info ("unknown stripe_size");
  541. #endif
  542. goto lvs_segment_fail;
  543. }
  544. }
  545. seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
  546. * seg->node_count);
  547. p = grub_strstr (p, "raids = [");
  548. if (p == NULL)
  549. {
  550. #ifdef GRUB_UTIL
  551. grub_util_info ("unknown raids");
  552. #endif
  553. goto lvs_segment_fail2;
  554. }
  555. p += sizeof("raids = [") - 1;
  556. for (j = 0; j < seg->node_count; j++)
  557. {
  558. char *lvname;
  559. p = grub_strchr (p, '"');
  560. p = p ? grub_strchr (p + 1, '"') : 0;
  561. p = p ? grub_strchr (p + 1, '"') : 0;
  562. if (p == NULL)
  563. continue;
  564. q = ++p;
  565. while (*q != '"')
  566. q++;
  567. s = q - p;
  568. lvname = grub_malloc (s + 1);
  569. if (lvname == NULL)
  570. goto lvs_segment_fail2;
  571. grub_memcpy (lvname, p, s);
  572. lvname[s] = '\0';
  573. seg->nodes[j].name = lvname;
  574. p = q + 1;
  575. }
  576. if (seg->type == GRUB_DISKFILTER_RAID4)
  577. {
  578. char *tmp;
  579. tmp = seg->nodes[0].name;
  580. grub_memmove (seg->nodes, seg->nodes + 1,
  581. sizeof (seg->nodes[0])
  582. * (seg->node_count - 1));
  583. seg->nodes[seg->node_count - 1].name = tmp;
  584. }
  585. }
  586. else
  587. {
  588. #ifdef GRUB_UTIL
  589. char *p2;
  590. p2 = grub_strchr (p, '"');
  591. if (p2)
  592. *p2 = 0;
  593. grub_util_info ("unknown LVM type %s", p);
  594. if (p2)
  595. *p2 ='"';
  596. #endif
  597. /* Found a non-supported type, give up and move on. */
  598. skip_lv = 1;
  599. break;
  600. }
  601. seg++;
  602. continue;
  603. lvs_segment_fail2:
  604. grub_free (seg->nodes);
  605. lvs_segment_fail:
  606. goto fail4;
  607. }
  608. if (p != NULL)
  609. p = grub_strchr (p, '}');
  610. if (p == NULL)
  611. goto lvs_fail;
  612. p += 3;
  613. if (skip_lv)
  614. {
  615. grub_free (lv->name);
  616. grub_free (lv);
  617. continue;
  618. }
  619. lv->vg = vg;
  620. lv->next = vg->lvs;
  621. vg->lvs = lv;
  622. continue;
  623. lvs_fail:
  624. grub_free (lv->name);
  625. grub_free (lv);
  626. goto fail4;
  627. }
  628. }
  629. /* Match lvs. */
  630. {
  631. struct grub_diskfilter_lv *lv1;
  632. struct grub_diskfilter_lv *lv2;
  633. for (lv1 = vg->lvs; lv1; lv1 = lv1->next)
  634. for (i = 0; i < lv1->segment_count; i++)
  635. for (j = 0; j < lv1->segments[i].node_count; j++)
  636. {
  637. if (vg->pvs)
  638. for (pv = vg->pvs; pv; pv = pv->next)
  639. {
  640. if (! grub_strcmp (pv->name,
  641. lv1->segments[i].nodes[j].name))
  642. {
  643. lv1->segments[i].nodes[j].pv = pv;
  644. break;
  645. }
  646. }
  647. if (lv1->segments[i].nodes[j].pv == NULL)
  648. for (lv2 = vg->lvs; lv2; lv2 = lv2->next)
  649. if (grub_strcmp (lv2->name,
  650. lv1->segments[i].nodes[j].name) == 0)
  651. lv1->segments[i].nodes[j].lv = lv2;
  652. }
  653. }
  654. if (grub_diskfilter_vg_register (vg))
  655. goto fail4;
  656. }
  657. else
  658. {
  659. grub_free (vgname);
  660. }
  661. id->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
  662. if (!id->uuid)
  663. goto fail4;
  664. grub_memcpy (id->uuid, pv_id, GRUB_LVM_ID_STRLEN);
  665. id->uuidlen = GRUB_LVM_ID_STRLEN;
  666. grub_free (metadatabuf);
  667. *start_sector = -1;
  668. return vg;
  669. /* Failure path. */
  670. fail4:
  671. grub_free (vg);
  672. fail3:
  673. grub_free (vgname);
  674. fail2:
  675. grub_free (metadatabuf);
  676. fail:
  677. return NULL;
  678. }
  679. static struct grub_diskfilter grub_lvm_dev = {
  680. .name = "lvm",
  681. .detect = grub_lvm_detect,
  682. .next = 0
  683. };
  684. GRUB_MOD_INIT (lvm)
  685. {
  686. grub_diskfilter_register_back (&grub_lvm_dev);
  687. }
  688. GRUB_MOD_FINI (lvm)
  689. {
  690. grub_diskfilter_unregister (&grub_lvm_dev);
  691. }