1 /* ofpath.c - calculate OpenFirmware path names given an OS device */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2009 Free Software Foundation, Inc.
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.
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.
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/>.
20 #undef OFPATH_STANDALONE
22 #ifndef OFPATH_STANDALONE
23 #include <grub/types.h>
24 #include <grub/util/misc.h>
25 #include <grub/util/ofpath.h>
34 #include <sys/types.h>
41 #ifdef OFPATH_STANDALONE
42 #define UNUSED __attribute__((unused))
43 #define xmalloc malloc
45 grub_util_error (const char *fmt
, ...)
49 fprintf (stderr
, "ofpath: error: ");
51 vfprintf (stderr
, fmt
, ap
);
60 kill_trailing_dir(char *path
)
62 char *end
= path
+ strlen(path
) - 1;
77 trim_newline (char *path
)
79 char *end
= path
+ strlen(path
) - 1;
85 #define OF_PATH_MAX 256
88 find_obppath(char *of_path
, const char *sysfs_path_orig
)
90 char *sysfs_path
, *path
;
92 sysfs_path
= xmalloc (PATH_MAX
);
93 path
= xmalloc (PATH_MAX
);
95 strcpy(sysfs_path
, sysfs_path_orig
);
100 snprintf(path
, PATH_MAX
, "%s/obppath", sysfs_path
);
102 printf("Trying %s\n", path
);
105 fd
= open(path
, O_RDONLY
);
108 kill_trailing_dir(sysfs_path
);
109 if (!strcmp(sysfs_path
, "/sys"))
110 grub_util_error("'obppath' not found in parent dirs of %s",
114 memset(of_path
, 0, OF_PATH_MAX
);
115 read(fd
, of_path
, OF_PATH_MAX
);
118 trim_newline(of_path
);
127 block_device_get_sysfs_path_and_link(const char *devicenode
,
128 char *sysfs_path
, int sysfs_path_len
)
130 char *rpath
= xmalloc (PATH_MAX
);
132 snprintf(sysfs_path
, sysfs_path_len
, "/sys/block/%s", devicenode
);
134 if (!realpath (sysfs_path
, rpath
))
135 grub_util_error ("Cannot get the real path of `%s'", sysfs_path
);
137 strcat(rpath
, "/device");
139 if (!realpath (rpath
, sysfs_path
))
140 grub_util_error ("Cannot get the real path of `%s'", rpath
);
146 trailing_digits (const char *p
)
150 end
= p
+ strlen(p
) - 1;
162 __of_path_common(char *of_path
, char *sysfs_path
,
163 const char *device
, int devno
)
165 const char *digit_string
;
168 find_obppath(of_path
, sysfs_path
);
170 digit_string
= trailing_digits (device
);
171 if (*digit_string
== '\0')
173 sprintf(disk
, "/disk@%d", devno
);
179 sscanf(digit_string
, "%d", &part
);
180 sprintf(disk
, "/disk@%d:%c", devno
, 'a' + (part
- 1));
182 strcat(of_path
, disk
);
186 get_basename(char *p
)
201 of_path_of_vdisk(char *of_path
,
202 const char *devname UNUSED
, const char *device
,
203 const char *devnode UNUSED
, const char *devicenode
)
205 char *sysfs_path
, *p
;
208 sysfs_path
= xmalloc (PATH_MAX
);
209 block_device_get_sysfs_path_and_link(devicenode
,
210 sysfs_path
, PATH_MAX
);
211 p
= get_basename (sysfs_path
);
212 sscanf(p
, "vdc-port-%d-%d", &devno
, &junk
);
213 __of_path_common(of_path
, sysfs_path
, device
, devno
);
219 of_path_of_ide(char *of_path
,
220 const char *devname UNUSED
, const char *device
,
221 const char *devnode UNUSED
, const char *devicenode
)
223 char *sysfs_path
, *p
;
226 sysfs_path
= xmalloc (PATH_MAX
);
227 block_device_get_sysfs_path_and_link(devicenode
,
228 sysfs_path
, PATH_MAX
);
229 p
= get_basename (sysfs_path
);
230 sscanf(p
, "%d.%d", &chan
, &devno
);
232 __of_path_common(of_path
, sysfs_path
, device
, devno
);
238 vendor_is_ATA(const char *path
)
243 buf
= xmalloc (PATH_MAX
);
245 snprintf(buf
, PATH_MAX
, "%s/vendor", path
);
246 fd
= open(buf
, O_RDONLY
);
248 grub_util_error ("Cannot open 'vendor' node of `%s'", path
);
250 memset(buf
, 0, PATH_MAX
);
251 err
= read(fd
, buf
, PATH_MAX
);
253 grub_util_error ("Cannot read 'vendor' node of `%s'", path
);
259 if (!strncmp(buf
, "ATA", 3))
265 check_sas (char *sysfs_path
, int *tgt
)
267 char *ed
= strstr (sysfs_path
, "end_device");
275 /* SAS devices are identified using disk@$PHY_ID */
276 p
= strdup (sysfs_path
);
277 ed
= strstr(p
, "end_device");
280 while (*q
&& *q
!= '/')
284 path
= xmalloc (PATH_MAX
);
285 sprintf (path
, "%s/sas_device:%s/phy_identifier", p
, ed
);
287 fd
= open(path
, O_RDONLY
);
289 grub_util_error("Cannot open SAS PHY ID '%s'\n", path
);
291 memset (phy
, 0, sizeof (phy
));
292 read (fd
, phy
, sizeof (phy
));
294 sscanf (phy
, "%d", tgt
);
301 of_path_of_scsi(char *of_path
,
302 const char *devname UNUSED
, const char *device
,
303 const char *devnode UNUSED
, const char *devicenode
)
305 const char *p
, *digit_string
, *disk_name
;
306 int host
, bus
, tgt
, lun
;
307 char *sysfs_path
, disk
[64];
309 sysfs_path
= xmalloc (PATH_MAX
);
311 block_device_get_sysfs_path_and_link(devicenode
,
312 sysfs_path
, PATH_MAX
);
313 p
= get_basename (sysfs_path
);
314 sscanf(p
, "%d:%d:%d:%d", &host
, &bus
, &tgt
, &lun
);
315 check_sas (sysfs_path
, &tgt
);
317 if (vendor_is_ATA(sysfs_path
))
319 __of_path_common(of_path
, sysfs_path
, device
, tgt
);
324 find_obppath(of_path
, sysfs_path
);
327 if (strstr (of_path
, "qlc"))
328 strcat (of_path
, "/fp@0,0");
330 if (strstr (of_path
, "sbus"))
335 digit_string
= trailing_digits (device
);
336 if (*digit_string
== '\0')
338 sprintf(disk
, "/%s@%x,%d", disk_name
, tgt
, lun
);
344 sscanf(digit_string
, "%d", &part
);
345 sprintf(disk
, "/%s@%x,%d:%c", disk_name
, tgt
, lun
, 'a' + (part
- 1));
347 strcat(of_path
, disk
);
351 strip_trailing_digits (const char *p
)
356 end
= new + strlen(new) - 1;
368 grub_util_devname_to_ofpath (char *devname
)
370 char *name_buf
, *device
, *devnode
, *devicenode
, *ofpath
;
372 name_buf
= xmalloc (PATH_MAX
);
373 name_buf
= realpath (devname
, name_buf
);
375 grub_util_error ("Cannot get the real path of `%s'", devname
);
377 device
= get_basename (devname
);
378 devnode
= strip_trailing_digits (devname
);
379 devicenode
= strip_trailing_digits (device
);
381 ofpath
= xmalloc (OF_PATH_MAX
);
383 if (device
[0] == 'h' && device
[1] == 'd')
384 of_path_of_ide(ofpath
, name_buf
, device
, devnode
, devicenode
);
385 else if (device
[0] == 's'
386 && (device
[1] == 'd' || device
[1] == 'r'))
387 of_path_of_scsi(ofpath
, name_buf
, device
, devnode
, devicenode
);
388 else if (device
[0] == 'v' && device
[1] == 'd' && device
[2] == 'i'
389 && device
[3] == 's' && device
[4] == 'k')
390 of_path_of_vdisk(ofpath
, name_buf
, device
, devnode
, devicenode
);
399 #ifdef OFPATH_STANDALONE
400 int main(int argc
, char **argv
)
406 printf("Usage: grub-ofpathname DEVICE\n");
410 of_path
= grub_util_devname_to_ofpath (argv
[1]);
411 printf("%s\n", of_path
);