ofpath.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. /* ofpath.c - calculate OpenFirmware path names given an OS device */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2009, 2011,2012, 2013 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. #undef OFPATH_STANDALONE
  20. #ifndef OFPATH_STANDALONE
  21. #include <grub/types.h>
  22. #include <grub/util/misc.h>
  23. #include <grub/util/ofpath.h>
  24. #include <grub/i18n.h>
  25. #endif
  26. #include <limits.h>
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <stdarg.h>
  30. #include <unistd.h>
  31. #include <string.h>
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <fcntl.h>
  35. #include <errno.h>
  36. #include <ctype.h>
  37. #ifdef __sparc__
  38. typedef enum
  39. {
  40. GRUB_OFPATH_SPARC_WWN_ADDR = 1,
  41. GRUB_OFPATH_SPARC_TGT_LUN,
  42. } ofpath_sparc_addressing;
  43. struct ofpath_sparc_hba
  44. {
  45. grub_uint32_t device_id;
  46. ofpath_sparc_addressing addressing;
  47. };
  48. static struct ofpath_sparc_hba sparc_lsi_hba[] = {
  49. /* Rhea, Jasper 320, LSI53C1020/1030. */
  50. {0x30, GRUB_OFPATH_SPARC_TGT_LUN},
  51. /* SAS-1068E. */
  52. {0x50, GRUB_OFPATH_SPARC_TGT_LUN},
  53. /* SAS-1064E. */
  54. {0x56, GRUB_OFPATH_SPARC_TGT_LUN},
  55. /* Pandora SAS-1068E. */
  56. {0x58, GRUB_OFPATH_SPARC_TGT_LUN},
  57. /* Aspen, Invader, LSI SAS-3108. */
  58. {0x5d, GRUB_OFPATH_SPARC_TGT_LUN},
  59. /* Niwot, SAS 2108. */
  60. {0x79, GRUB_OFPATH_SPARC_TGT_LUN},
  61. /* Erie, Falcon, LSI SAS 2008. */
  62. {0x72, GRUB_OFPATH_SPARC_WWN_ADDR},
  63. /* LSI WarpDrive 6203. */
  64. {0x7e, GRUB_OFPATH_SPARC_WWN_ADDR},
  65. /* LSI SAS 2308. */
  66. {0x87, GRUB_OFPATH_SPARC_WWN_ADDR},
  67. /* LSI SAS 3008. */
  68. {0x97, GRUB_OFPATH_SPARC_WWN_ADDR},
  69. {0, 0}
  70. };
  71. static const int LSI_VENDOR_ID = 0x1000;
  72. #endif
  73. #ifdef OFPATH_STANDALONE
  74. #define xmalloc malloc
  75. void
  76. grub_util_error (const char *fmt, ...)
  77. {
  78. va_list ap;
  79. fprintf (stderr, "ofpath: error: ");
  80. va_start (ap, fmt);
  81. vfprintf (stderr, fmt, ap);
  82. va_end (ap);
  83. fputc ('\n', stderr);
  84. exit (1);
  85. }
  86. void
  87. grub_util_info (const char *fmt, ...)
  88. {
  89. va_list ap;
  90. fprintf (stderr, "ofpath: info: ");
  91. va_start (ap, fmt);
  92. vfprintf (stderr, fmt, ap);
  93. va_end (ap);
  94. fputc ('\n', stderr);
  95. }
  96. #define grub_util_warn grub_util_info
  97. #define _(x) x
  98. #define xstrdup strdup
  99. #endif
  100. static void
  101. kill_trailing_dir(char *path)
  102. {
  103. char *end = path + strlen(path) - 1;
  104. while (end >= path)
  105. {
  106. if (*end != '/')
  107. {
  108. end--;
  109. continue;
  110. }
  111. *end = '\0';
  112. break;
  113. }
  114. }
  115. static void
  116. trim_newline (char *path)
  117. {
  118. char *end = path + strlen(path) - 1;
  119. while (*end == '\n')
  120. *end-- = '\0';
  121. }
  122. #define MAX_DISK_CAT 64
  123. static char *
  124. find_obppath (const char *sysfs_path_orig)
  125. {
  126. char *sysfs_path, *path;
  127. size_t path_size = strlen (sysfs_path_orig) + sizeof ("/obppath");
  128. sysfs_path = xstrdup (sysfs_path_orig);
  129. path = xmalloc (path_size);
  130. while (1)
  131. {
  132. int fd;
  133. char *of_path;
  134. struct stat st;
  135. size_t size;
  136. snprintf(path, path_size, "%s/obppath", sysfs_path);
  137. #if 0
  138. printf("Trying %s\n", path);
  139. #endif
  140. fd = open(path, O_RDONLY);
  141. #ifndef __sparc__
  142. if (fd < 0 || fstat (fd, &st) < 0)
  143. {
  144. if (fd >= 0)
  145. close (fd);
  146. snprintf(path, path_size, "%s/devspec", sysfs_path);
  147. fd = open(path, O_RDONLY);
  148. }
  149. #endif
  150. if (fd < 0 || fstat (fd, &st) < 0)
  151. {
  152. if (fd >= 0)
  153. close (fd);
  154. kill_trailing_dir(sysfs_path);
  155. if (!strcmp(sysfs_path, "/sys"))
  156. {
  157. grub_util_info (_("`obppath' not found in parent dirs of `%s',"
  158. " no IEEE1275 name discovery"),
  159. sysfs_path_orig);
  160. free (path);
  161. free (sysfs_path);
  162. return NULL;
  163. }
  164. continue;
  165. }
  166. size = st.st_size;
  167. of_path = xmalloc (size + MAX_DISK_CAT + 1);
  168. memset(of_path, 0, size + MAX_DISK_CAT + 1);
  169. if (read(fd, of_path, size) < 0)
  170. {
  171. grub_util_info (_("cannot read `%s': %s"), path, strerror (errno));
  172. close(fd);
  173. free (path);
  174. free (of_path);
  175. free (sysfs_path);
  176. return NULL;
  177. }
  178. close(fd);
  179. trim_newline(of_path);
  180. free (path);
  181. free (sysfs_path);
  182. return of_path;
  183. }
  184. }
  185. static char *
  186. xrealpath (const char *in)
  187. {
  188. char *out;
  189. #ifdef PATH_MAX
  190. out = xmalloc (PATH_MAX);
  191. out = realpath (in, out);
  192. #else
  193. out = realpath (in, NULL);
  194. #endif
  195. if (!out)
  196. grub_util_error (_("failed to get canonical path of `%s'"), in);
  197. return out;
  198. }
  199. static char *
  200. block_device_get_sysfs_path_and_link(const char *devicenode)
  201. {
  202. char *rpath;
  203. char *rpath2;
  204. char *ret;
  205. size_t tmp_size = strlen (devicenode) + sizeof ("/sys/block/");
  206. char *tmp = xmalloc (tmp_size);
  207. memcpy (tmp, "/sys/block/", sizeof ("/sys/block/"));
  208. strcat (tmp, devicenode);
  209. rpath = xrealpath (tmp);
  210. rpath2 = xmalloc (strlen (rpath) + sizeof ("/device"));
  211. strcpy (rpath2, rpath);
  212. strcat (rpath2, "/device");
  213. ret = xrealpath (rpath2);
  214. free (tmp);
  215. free (rpath);
  216. free (rpath2);
  217. return ret;
  218. }
  219. static inline int
  220. my_isdigit (int c)
  221. {
  222. return (c >= '0' && c <= '9');
  223. }
  224. static const char *
  225. trailing_digits (const char *p)
  226. {
  227. const char *end;
  228. end = p + strlen(p) - 1;
  229. while (end >= p)
  230. {
  231. if (! my_isdigit(*end))
  232. break;
  233. end--;
  234. }
  235. return end + 1;
  236. }
  237. static char *
  238. __of_path_common(char *sysfs_path,
  239. const char *device, int devno)
  240. {
  241. const char *digit_string;
  242. char disk[MAX_DISK_CAT];
  243. char *of_path = find_obppath(sysfs_path);
  244. if (!of_path)
  245. return NULL;
  246. digit_string = trailing_digits (device);
  247. if (*digit_string == '\0')
  248. {
  249. snprintf(disk, sizeof (disk), "/disk@%d", devno);
  250. }
  251. else
  252. {
  253. int part;
  254. sscanf(digit_string, "%d", &part);
  255. snprintf(disk, sizeof (disk), "/disk@%d:%c", devno, 'a' + (part - 1));
  256. }
  257. strcat(of_path, disk);
  258. return of_path;
  259. }
  260. static char *
  261. get_basename(char *p)
  262. {
  263. char *ret = p;
  264. while (*p)
  265. {
  266. if (*p == '/')
  267. ret = p + 1;
  268. p++;
  269. }
  270. return ret;
  271. }
  272. static char *
  273. of_path_of_vdisk(const char *sys_devname __attribute__((unused)),
  274. const char *device,
  275. const char *devnode __attribute__((unused)),
  276. const char *devicenode)
  277. {
  278. char *sysfs_path, *p;
  279. int devno, junk;
  280. char *ret;
  281. sysfs_path = block_device_get_sysfs_path_and_link(devicenode);
  282. p = get_basename (sysfs_path);
  283. sscanf(p, "vdc-port-%d-%d", &devno, &junk);
  284. ret = __of_path_common (sysfs_path, device, devno);
  285. free (sysfs_path);
  286. return ret;
  287. }
  288. static char *
  289. of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *device,
  290. const char *devnode __attribute__((unused)),
  291. const char *devicenode)
  292. {
  293. char *sysfs_path, *p;
  294. int chan, devno;
  295. char *ret;
  296. sysfs_path = block_device_get_sysfs_path_and_link(devicenode);
  297. p = get_basename (sysfs_path);
  298. sscanf(p, "%d.%d", &chan, &devno);
  299. ret = __of_path_common(sysfs_path, device, 2 * chan + devno);
  300. free (sysfs_path);
  301. return ret;
  302. }
  303. #ifdef __sparc__
  304. static char *
  305. of_path_of_nvme(const char *sys_devname __attribute__((unused)),
  306. const char *device,
  307. const char *devnode __attribute__((unused)),
  308. const char *devicenode)
  309. {
  310. char *sysfs_path, *of_path, disk[MAX_DISK_CAT];
  311. const char *digit_string, *part_end;
  312. digit_string = trailing_digits (device);
  313. part_end = devicenode + strlen (devicenode) - 1;
  314. if ((*digit_string != '\0') && (*part_end == 'p'))
  315. {
  316. /* We have a partition number, strip it off. */
  317. int part;
  318. char *nvmedev, *end;
  319. nvmedev = strdup (devicenode);
  320. if (!nvmedev)
  321. return NULL;
  322. end = nvmedev + strlen (nvmedev) - 1;
  323. /* Remove the p. */
  324. *end = '\0';
  325. sscanf (digit_string, "%d", &part);
  326. snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1));
  327. sysfs_path = block_device_get_sysfs_path_and_link (nvmedev);
  328. free (nvmedev);
  329. }
  330. else
  331. {
  332. /* We do not have the parition. */
  333. snprintf (disk, sizeof (disk), "/disk@1");
  334. sysfs_path = block_device_get_sysfs_path_and_link (device);
  335. }
  336. of_path = find_obppath (sysfs_path);
  337. if (of_path)
  338. strcat (of_path, disk);
  339. free (sysfs_path);
  340. return of_path;
  341. }
  342. #endif
  343. static int
  344. vendor_is_ATA(const char *path)
  345. {
  346. int fd, err;
  347. char *bufname;
  348. char bufcont[3];
  349. size_t path_size;
  350. path_size = strlen (path) + sizeof ("/vendor");
  351. bufname = xmalloc (path_size);
  352. snprintf (bufname, path_size, "%s/vendor", path);
  353. fd = open (bufname, O_RDONLY);
  354. if (fd < 0)
  355. grub_util_error (_("cannot open `%s': %s"), bufname, strerror (errno));
  356. memset(bufcont, 0, sizeof (bufcont));
  357. err = read(fd, bufcont, sizeof (bufcont));
  358. if (err < 0)
  359. grub_util_error (_("cannot open `%s': %s"), bufname, strerror (errno));
  360. close(fd);
  361. free (bufname);
  362. return (memcmp(bufcont, "ATA", 3) == 0);
  363. }
  364. #ifdef __sparc__
  365. static void
  366. check_hba_identifiers (const char *sysfs_path, int *vendor, int *device_id)
  367. {
  368. char *ed = strstr (sysfs_path, "host");
  369. size_t path_size;
  370. char *p, *path;
  371. char buf[8];
  372. int fd;
  373. if (!ed)
  374. return;
  375. p = xstrdup (sysfs_path);
  376. ed = strstr (p, "host");
  377. *ed = '\0';
  378. path_size = (strlen (p) + sizeof ("vendor"));
  379. path = xmalloc (path_size);
  380. if (!path)
  381. goto out;
  382. snprintf (path, path_size, "%svendor", p);
  383. fd = open (path, O_RDONLY);
  384. if (fd < 0)
  385. goto out;
  386. memset (buf, 0, sizeof (buf));
  387. if (read (fd, buf, sizeof (buf) - 1) < 0)
  388. goto out;
  389. close (fd);
  390. sscanf (buf, "%x", vendor);
  391. snprintf (path, path_size, "%sdevice", p);
  392. fd = open (path, O_RDONLY);
  393. if (fd < 0)
  394. goto out;
  395. memset (buf, 0, sizeof (buf));
  396. if (read (fd, buf, sizeof (buf) - 1) < 0)
  397. goto out;
  398. close (fd);
  399. sscanf (buf, "%x", device_id);
  400. out:
  401. free (path);
  402. free (p);
  403. }
  404. #endif
  405. static void
  406. check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address)
  407. {
  408. char *ed = strstr (sysfs_path, "end_device");
  409. char *p, *q, *path;
  410. char phy[21];
  411. int fd;
  412. size_t path_size;
  413. if (!ed)
  414. return;
  415. /* SAS devices are identified using disk@$PHY_ID */
  416. p = xstrdup (sysfs_path);
  417. ed = strstr(p, "end_device");
  418. if (!ed)
  419. return;
  420. q = ed;
  421. while (*q && *q != '/')
  422. q++;
  423. *q = '\0';
  424. path_size = (strlen (p) + strlen (ed)
  425. + sizeof ("%s/sas_device/%s/phy_identifier"));
  426. path = xmalloc (path_size);
  427. snprintf (path, path_size, "%s/sas_device/%s/phy_identifier", p, ed);
  428. fd = open (path, O_RDONLY);
  429. if (fd < 0)
  430. grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
  431. memset (phy, 0, sizeof (phy));
  432. if (read (fd, phy, sizeof (phy) - 1) < 0)
  433. grub_util_error (_("cannot read `%s': %s"), path, strerror (errno));
  434. close (fd);
  435. sscanf (phy, "%d", tgt);
  436. snprintf (path, path_size, "%s/sas_device/%s/sas_address", p, ed);
  437. fd = open (path, O_RDONLY);
  438. if (fd < 0)
  439. grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
  440. memset (phy, 0, sizeof (phy));
  441. if (read (fd, phy, sizeof (phy) - 1) < 0)
  442. grub_util_error (_("cannot read `%s': %s"), path, strerror (errno));
  443. sscanf (phy, "%lx", sas_address);
  444. free (path);
  445. free (p);
  446. close (fd);
  447. }
  448. static char *
  449. of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *device,
  450. const char *devnode __attribute__((unused)),
  451. const char *devicenode)
  452. {
  453. const char *p, *digit_string, *disk_name;
  454. int host, bus, tgt, lun;
  455. unsigned long int sas_address = 0;
  456. char *sysfs_path, disk[MAX_DISK_CAT - sizeof ("/fp@0,0")];
  457. char *of_path;
  458. sysfs_path = block_device_get_sysfs_path_and_link(devicenode);
  459. p = get_basename (sysfs_path);
  460. sscanf(p, "%d:%d:%d:%d", &host, &bus, &tgt, &lun);
  461. check_sas (sysfs_path, &tgt, &sas_address);
  462. if (vendor_is_ATA(sysfs_path))
  463. {
  464. of_path = __of_path_common(sysfs_path, device, tgt);
  465. free (sysfs_path);
  466. return of_path;
  467. }
  468. of_path = find_obppath(sysfs_path);
  469. if (!of_path)
  470. goto out;
  471. if (strstr (of_path, "qlc"))
  472. strcat (of_path, "/fp@0,0");
  473. if (strstr (of_path, "sbus"))
  474. disk_name = "sd";
  475. else
  476. disk_name = "disk";
  477. digit_string = trailing_digits (device);
  478. if (strncmp (of_path, "/vdevice/", sizeof ("/vdevice/") - 1) == 0)
  479. {
  480. unsigned long id = 0x8000 | (tgt << 8) | (bus << 5) | lun;
  481. if (*digit_string == '\0')
  482. {
  483. snprintf(disk, sizeof (disk), "/%s@%04lx000000000000", disk_name, id);
  484. }
  485. else
  486. {
  487. int part;
  488. sscanf(digit_string, "%d", &part);
  489. snprintf(disk, sizeof (disk),
  490. "/%s@%04lx000000000000:%c", disk_name, id, 'a' + (part - 1));
  491. }
  492. }
  493. else
  494. {
  495. #ifdef __sparc__
  496. ofpath_sparc_addressing addressing = GRUB_OFPATH_SPARC_TGT_LUN;
  497. int vendor = 0, device_id = 0;
  498. char *optr = disk;
  499. check_hba_identifiers (sysfs_path, &vendor, &device_id);
  500. if (vendor == LSI_VENDOR_ID)
  501. {
  502. struct ofpath_sparc_hba *lsi_hba;
  503. /*
  504. * Over time different OF addressing schemes have been supported.
  505. * There is no generic addressing scheme that works across
  506. * every HBA.
  507. */
  508. for (lsi_hba = sparc_lsi_hba; lsi_hba->device_id; lsi_hba++)
  509. if (lsi_hba->device_id == device_id)
  510. {
  511. addressing = lsi_hba->addressing;
  512. break;
  513. }
  514. }
  515. if (addressing == GRUB_OFPATH_SPARC_WWN_ADDR)
  516. optr += snprintf (disk, sizeof (disk), "/%s@w%lx,%x", disk_name,
  517. sas_address, lun);
  518. else
  519. optr += snprintf (disk, sizeof (disk), "/%s@%x,%x", disk_name, tgt,
  520. lun);
  521. if (*digit_string != '\0')
  522. {
  523. int part;
  524. sscanf (digit_string, "%d", &part);
  525. snprintf (optr, sizeof (disk) - (optr - disk - 1), ":%c", 'a'
  526. + (part - 1));
  527. }
  528. #else
  529. if (lun == 0)
  530. {
  531. int sas_id = 0;
  532. sas_id = bus << 16 | tgt << 8 | lun;
  533. if (*digit_string == '\0')
  534. {
  535. snprintf(disk, sizeof (disk), "/sas/%s@%x", disk_name, sas_id);
  536. }
  537. else
  538. {
  539. int part;
  540. sscanf(digit_string, "%d", &part);
  541. snprintf(disk, sizeof (disk),
  542. "/sas/%s@%x:%c", disk_name, sas_id, 'a' + (part - 1));
  543. }
  544. }
  545. else
  546. {
  547. char *lunstr;
  548. int lunpart[4];
  549. lunstr = xmalloc (20);
  550. lunpart[0] = (lun >> 8) & 0xff;
  551. lunpart[1] = lun & 0xff;
  552. lunpart[2] = (lun >> 24) & 0xff;
  553. lunpart[3] = (lun >> 16) & 0xff;
  554. sprintf(lunstr, "%02x%02x%02x%02x00000000", lunpart[0], lunpart[1], lunpart[2], lunpart[3]);
  555. long int longlun = atol(lunstr);
  556. if (*digit_string == '\0')
  557. {
  558. snprintf(disk, sizeof (disk), "/sas/%s@%lx,%lu", disk_name, sas_address, longlun);
  559. }
  560. else
  561. {
  562. int part;
  563. sscanf(digit_string, "%d", &part);
  564. snprintf(disk, sizeof (disk),
  565. "/sas/%s@%lx,%lu:%c", disk_name, sas_address, longlun, 'a' + (part - 1));
  566. }
  567. free (lunstr);
  568. }
  569. #endif
  570. }
  571. strcat(of_path, disk);
  572. out:
  573. free (sysfs_path);
  574. return of_path;
  575. }
  576. static char *
  577. strip_trailing_digits (const char *p)
  578. {
  579. char *new, *end;
  580. new = strdup (p);
  581. end = new + strlen(new) - 1;
  582. while (end >= new)
  583. {
  584. if (! my_isdigit(*end))
  585. break;
  586. *end-- = '\0';
  587. }
  588. return new;
  589. }
  590. char *
  591. grub_util_devname_to_ofpath (const char *sys_devname)
  592. {
  593. char *name_buf, *device, *devnode, *devicenode, *ofpath;
  594. name_buf = xrealpath (sys_devname);
  595. device = get_basename (name_buf);
  596. devnode = strip_trailing_digits (name_buf);
  597. devicenode = strip_trailing_digits (device);
  598. if (device[0] == 'h' && device[1] == 'd')
  599. ofpath = of_path_of_ide(name_buf, device, devnode, devicenode);
  600. else if (device[0] == 's'
  601. && (device[1] == 'd' || device[1] == 'r'))
  602. ofpath = of_path_of_scsi(name_buf, device, devnode, devicenode);
  603. else if (device[0] == 'v' && device[1] == 'd' && device[2] == 'i'
  604. && device[3] == 's' && device[4] == 'k')
  605. ofpath = of_path_of_vdisk(name_buf, device, devnode, devicenode);
  606. else if (device[0] == 'f' && device[1] == 'd'
  607. && device[2] == '0' && device[3] == '\0')
  608. /* All the models I've seen have a devalias "floppy".
  609. New models have no floppy at all. */
  610. ofpath = xstrdup ("floppy");
  611. #ifdef __sparc__
  612. else if (device[0] == 'n' && device[1] == 'v' && device[2] == 'm'
  613. && device[3] == 'e')
  614. ofpath = of_path_of_nvme (name_buf, device, devnode, devicenode);
  615. #endif
  616. else
  617. {
  618. grub_util_warn (_("unknown device type %s"), device);
  619. ofpath = NULL;
  620. }
  621. free (devnode);
  622. free (devicenode);
  623. free (name_buf);
  624. return ofpath;
  625. }
  626. #ifdef OFPATH_STANDALONE
  627. int main(int argc, char **argv)
  628. {
  629. char *of_path;
  630. if (argc != 2)
  631. {
  632. printf(_("Usage: %s DEVICE\n"), argv[0]);
  633. return 1;
  634. }
  635. of_path = grub_util_devname_to_ofpath (argv[1]);
  636. if (of_path)
  637. printf("%s\n", of_path);
  638. free (of_path);
  639. return 0;
  640. }
  641. #endif