2009-11-01 Felix Zielcke <fzielcke@z-51.de>
[grub2/phcoder/solaris.git] / util / ieee1275 / ofpath.c
blob7b464bf093f1d6fa5603b4de2a4306f490a9778a
1 /* ofpath.c - calculate OpenFirmware path names given an OS device */
2 /*
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>
26 #endif
28 #include <limits.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <malloc.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <ctype.h>
41 #ifdef OFPATH_STANDALONE
42 #define UNUSED __attribute__((unused))
43 #define xmalloc malloc
44 void
45 grub_util_error (const char *fmt, ...)
47 va_list ap;
49 fprintf (stderr, "ofpath: error: ");
50 va_start (ap, fmt);
51 vfprintf (stderr, fmt, ap);
52 va_end (ap);
53 fputc ('\n', stderr);
54 exit (1);
57 #endif
59 static void
60 kill_trailing_dir(char *path)
62 char *end = path + strlen(path) - 1;
64 while (end >= path)
66 if (*end != '/')
68 end--;
69 continue;
71 *end = '\0';
72 break;
76 static void
77 trim_newline (char *path)
79 char *end = path + strlen(path) - 1;
81 while (*end == '\n')
82 *end-- = '\0';
85 #define OF_PATH_MAX 256
87 static void
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);
96 while (1)
98 int fd;
100 snprintf(path, PATH_MAX, "%s/obppath", sysfs_path);
101 #if 0
102 printf("Trying %s\n", path);
103 #endif
105 fd = open(path, O_RDONLY);
106 if (fd < 0)
108 kill_trailing_dir(sysfs_path);
109 if (!strcmp(sysfs_path, "/sys"))
110 grub_util_error("'obppath' not found in parent dirs of %s",
111 sysfs_path_orig);
112 continue;
114 memset(of_path, 0, OF_PATH_MAX);
115 read(fd, of_path, OF_PATH_MAX);
116 close(fd);
118 trim_newline(of_path);
119 break;
122 free (path);
123 free (sysfs_path);
126 static void
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);
142 free (rpath);
145 static const char *
146 trailing_digits (const char *p)
148 const char *end;
150 end = p + strlen(p) - 1;
151 while (end >= p)
153 if (! isdigit(*end))
154 break;
155 end--;
158 return end + 1;
161 static void
162 __of_path_common(char *of_path, char *sysfs_path,
163 const char *device, int devno)
165 const char *digit_string;
166 char disk[64];
168 find_obppath(of_path, sysfs_path);
170 digit_string = trailing_digits (device);
171 if (*digit_string == '\0')
173 sprintf(disk, "/disk@%d", devno);
175 else
177 int part;
179 sscanf(digit_string, "%d", &part);
180 sprintf(disk, "/disk@%d:%c", devno, 'a' + (part - 1));
182 strcat(of_path, disk);
185 static char *
186 get_basename(char *p)
188 char *ret = p;
190 while (*p)
192 if (*p == '/')
193 ret = p + 1;
194 p++;
197 return ret;
200 static void
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;
206 int devno, junk;
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);
215 free (sysfs_path);
218 static void
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;
224 int chan, devno;
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);
234 free (sysfs_path);
237 static int
238 vendor_is_ATA(const char *path)
240 int fd, err;
241 char *buf;
243 buf = xmalloc (PATH_MAX);
245 snprintf(buf, PATH_MAX, "%s/vendor", path);
246 fd = open(buf, O_RDONLY);
247 if (fd < 0)
248 grub_util_error ("Cannot open 'vendor' node of `%s'", path);
250 memset(buf, 0, PATH_MAX);
251 err = read(fd, buf, PATH_MAX);
252 if (err < 0)
253 grub_util_error ("Cannot read 'vendor' node of `%s'", path);
255 close(fd);
257 free (buf);
259 if (!strncmp(buf, "ATA", 3))
260 return 1;
261 return 0;
264 static void
265 check_sas (char *sysfs_path, int *tgt)
267 char *ed = strstr (sysfs_path, "end_device");
268 char *p, *q, *path;
269 char phy[16];
270 int fd;
272 if (!ed)
273 return;
275 /* SAS devices are identified using disk@$PHY_ID */
276 p = strdup (sysfs_path);
277 ed = strstr(p, "end_device");
279 q = ed;
280 while (*q && *q != '/')
281 q++;
282 *q = '\0';
284 path = xmalloc (PATH_MAX);
285 sprintf (path, "%s/sas_device:%s/phy_identifier", p, ed);
287 fd = open(path, O_RDONLY);
288 if (fd < 0)
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);
296 free (path);
297 free (p);
300 static void
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);
320 free (sysfs_path);
321 return;
324 find_obppath(of_path, sysfs_path);
325 free (sysfs_path);
327 if (strstr (of_path, "qlc"))
328 strcat (of_path, "/fp@0,0");
330 if (strstr (of_path, "sbus"))
331 disk_name = "sd";
332 else
333 disk_name = "disk";
335 digit_string = trailing_digits (device);
336 if (*digit_string == '\0')
338 sprintf(disk, "/%s@%x,%d", disk_name, tgt, lun);
340 else
342 int part;
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);
350 static char *
351 strip_trailing_digits (const char *p)
353 char *new, *end;
355 new = strdup (p);
356 end = new + strlen(new) - 1;
357 while (end >= new)
359 if (! isdigit(*end))
360 break;
361 *end-- = '\0';
364 return new;
367 char *
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);
374 if (! 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);
392 free (devnode);
393 free (devicenode);
394 free (name_buf);
396 return ofpath;
399 #ifdef OFPATH_STANDALONE
400 int main(int argc, char **argv)
402 char *of_path;
404 if (argc != 2)
406 printf("Usage: grub-ofpathname DEVICE\n");
407 return 1;
410 of_path = grub_util_devname_to_ofpath (argv[1]);
411 printf("%s\n", of_path);
413 return 0;
415 #endif