1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <thread.h>
33 #include <synch.h>
34 #include <sys/types.h>
35 #include <ctype.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <sys/modctl.h>
39 #include <errno.h>
40 #include <sys/openpromio.h>
41 #include <ftw.h>
42 #include <sys/ddi.h>
43 #include <sys/sunddi.h>
44 #include <limits.h>
45
46 #include "device_info.h"
47
48 /*
49 * #define's
50 */
51
52 /* alias node searching return values */
53 #define NO_MATCH -1
54 #define EXACT_MATCH 1
55 #define INEXACT_MATCH 2
56
57 /* for prom io operations */
58 #define BUFSIZE 4096
59 #define MAXPROPSIZE 256
60 #define MAXVALSIZE (BUFSIZE - MAXPROPSIZE - sizeof (uint_t))
61
62 /* prom_obp_vers() return values */
63 #define OBP_OF 0x4 /* versions OBP 3.x */
64 #define OBP_NO_ALIAS_NODE 0x8 /* No alias node */
65
66 /* for nftw call */
67 #define FT_DEPTH 15
68
69 /* default logical and physical device name space */
70 #define DEV "/dev"
71 #define DEVICES "/devices"
72
73 /* for boot device identification on x86 */
74 #define CREATE_DISKMAP "/boot/solaris/bin/create_diskmap"
75 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
76
77 /*
78 * internal structure declarations
79 */
80
81 /* for prom io functions */
82 typedef union {
83 char buf[BUFSIZE];
84 struct openpromio opp;
85 } Oppbuf;
86
87 /* used to manage lists of devices and aliases */
88 struct name_list {
89 char *name;
90 struct name_list *next;
91 };
92
93 /*
94 * internal global data
95 */
96
97 /* global since nftw does not let you pass args to be updated */
98 static struct name_list **dev_list;
99
100 /* global since nftw does not let you pass args to be updated */
101 static struct boot_dev **bootdev_list;
102
103 /* mutex to protect bootdev_list and dev_list */
104 static mutex_t dev_lists_lk = DEFAULTMUTEX;
105
106 /*
107 * internal function prototypes
108 */
109
110 static int prom_open(int);
111 static void prom_close(int);
112 static int is_openprom(int);
113
114 static int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf);
115 static int alias_to_prom_dev(char *alias, char *ret_buf);
116 static int prom_srch_aliases_by_def(char *, struct name_list **,
117 struct name_list **, int);
118 static int prom_find_aliases_node(int fd);
119 static int prom_compare_devs(char *prom_dev1, char *prom_dev2);
120 static int _prom_strcmp(char *s1, char *s2);
121 static int prom_srch_node(int fd, char *prop_name, char *ret_buf);
122 static uint_t prom_next_node(int fd, uint_t node_id);
123 static uint_t prom_child_node(int fd, uint_t node_id);
124
125 static int prom_obp_vers(void);
126
127 static void parse_name(char *, char **, char **, char **);
128 static int process_bootdev(const char *, const char *, struct boot_dev ***);
129 static int process_minor_name(char *dev_path, const char *default_root);
130 static void options_override(char *prom_path, char *alias_name);
131 static int devfs_phys_to_logical(struct boot_dev **bootdev_array,
132 const int array_size, const char *default_root);
133 static int check_logical_dev(const char *, const struct stat *, int,
134 struct FTW *);
135 static struct boot_dev *alloc_bootdev(char *);
136 static void free_name_list(struct name_list *list, int free_name);
137 static int insert_alias_list(struct name_list **list,
138 char *alias_name);
139 static int get_boot_dev_var(struct openpromio *opp);
140 static int set_boot_dev_var(struct openpromio *opp, char *bootdev);
141 static int devfs_prom_to_dev_name(char *prom_path, char *dev_path);
142 static int devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len);
143
144 /*
145 * frees a list of paths from devfs_get_prom_name_list
146 */
147 static void
prom_list_free(char ** prom_list)148 prom_list_free(char **prom_list)
149 {
150 int i = 0;
151
152 if (!prom_list)
153 return;
154
155 while (prom_list[i]) {
156 free(prom_list[i]);
157 i++;
158 }
159 free(prom_list);
160 }
161
162 static int
devfs_get_prom_name_list(const char * dev_name,char *** prom_list)163 devfs_get_prom_name_list(const char *dev_name, char ***prom_list)
164 {
165 char *prom_path = NULL;
166 int count = 0; /* # of slots we will need in prom_list */
167 int ret, i, len;
168 char **list;
169 char *ptr;
170
171 if (dev_name == NULL)
172 return (DEVFS_INVAL);
173 if (*dev_name != '/')
174 return (DEVFS_INVAL);
175 if (prom_list == NULL)
176 return (DEVFS_INVAL);
177
178 /*
179 * make sure we are on a machine which supports a prom
180 * and we have permission to use /dev/openprom
181 */
182 if ((ret = prom_obp_vers()) < 0)
183 return (ret);
184 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
185 return (DEVFS_NOMEM);
186 /*
187 * get the prom path name
188 */
189 ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE);
190 if (ret < 0) {
191 free(prom_path);
192 return (ret);
193 }
194 /* deal with list of names */
195 for (i = 0; i < ret; i++)
196 if (prom_path[i] == '\0')
197 count++;
198
199 if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) {
200 free(prom_path);
201 return (DEVFS_NOMEM);
202 }
203
204 ptr = prom_path;
205 for (i = 0; i < count; i++) {
206 len = strlen(ptr) + 1;
207 if ((list[i] = (char *)malloc(len)) == NULL) {
208 free(prom_path);
209 free(list);
210 return (DEVFS_NOMEM);
211 }
212 (void) snprintf(list[i], len, "%s", ptr);
213 ptr += len;
214 }
215
216 free(prom_path);
217
218 *prom_list = list;
219 return (0);
220 }
221
222 /*
223 * retrieve the list of prom representations for a given device name
224 * the list will be sorted in the following order: exact aliases,
225 * inexact aliases, prom device path name. If multiple matches occur
226 * for exact or inexact aliases, then these are sorted in collating
227 * order. The list is returned in prom_list
228 *
229 * the list may be restricted by specifying the correct flags in options.
230 */
231 int
devfs_get_prom_names(const char * dev_name,uint_t options,char *** prom_list)232 devfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list)
233 {
234 char *prom_path = NULL;
235 int count = 0; /* # of slots we will need in prom_list */
236 char **alias_list = NULL;
237 char **list;
238 int ret;
239
240 if (dev_name == NULL) {
241 return (DEVFS_INVAL);
242 }
243 if (*dev_name != '/') {
244 return (DEVFS_INVAL);
245 }
246 if (prom_list == NULL) {
247 return (DEVFS_INVAL);
248 }
249 /*
250 * make sure we are on a machine which supports a prom
251 * and we have permission to use /dev/openprom
252 */
253 if ((ret = prom_obp_vers()) < 0) {
254 return (ret);
255 }
256 if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) {
257 return (DEVFS_NOMEM);
258 }
259 /*
260 * get the prom path name
261 */
262 ret = devfs_dev_to_prom_name((char *)dev_name, prom_path);
263 if (ret < 0) {
264 free(prom_path);
265 return (ret);
266 }
267 /* get the list of aliases (exact and inexact) */
268 if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) {
269 free(prom_path);
270 return (ret);
271 }
272 /* now figure out how big the return array must be */
273 if (alias_list != NULL) {
274 while (alias_list[count] != NULL) {
275 count++;
276 }
277 }
278 if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
279 count++; /* # of slots we will need in prom_list */
280 }
281 count++; /* for the null terminator */
282
283 /* allocate space for the list */
284 if ((list = (char **)calloc(count, sizeof (char *))) == NULL) {
285 count = 0;
286 while ((alias_list) && (alias_list[count] != NULL)) {
287 free(alias_list[count]);
288 count++;
289 }
290 free(alias_list);
291 free(prom_path);
292 return (DEVFS_NOMEM);
293 }
294 /* fill in the array and free the name list of aliases. */
295 count = 0;
296 while ((alias_list) && (alias_list[count] != NULL)) {
297 list[count] = alias_list[count];
298 count++;
299 }
300 if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
301 list[count] = prom_path;
302 }
303 if (alias_list != NULL) {
304 free(alias_list);
305 }
306 *prom_list = list;
307 return (0);
308 }
309
310 /*
311 * Get a list prom-path translations for a solaris device.
312 *
313 * Returns the number of and all OBP paths and alias variants that
314 * reference the Solaris device path passed in.
315 */
316 int
devfs_get_all_prom_names(const char * solaris_path,uint_t flags,struct devfs_prom_path ** paths)317 devfs_get_all_prom_names(const char *solaris_path, uint_t flags,
318 struct devfs_prom_path **paths)
319 {
320 int ret, len, i, count = 0;
321 char *ptr, *prom_path;
322 struct devfs_prom_path *cur = NULL, *new;
323
324 if ((ret = prom_obp_vers()) < 0)
325 return (ret);
326 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
327 return (DEVFS_NOMEM);
328
329 if ((ret = devfs_dev_to_prom_names((char *)solaris_path,
330 prom_path, MAXVALSIZE)) < 0) {
331 free(prom_path);
332 return (ret);
333 }
334
335 for (i = 0; i < ret; i++)
336 if (prom_path[i] == '\0')
337 count++;
338
339 *paths = NULL;
340 ptr = prom_path;
341 for (i = 0; i < count; i++) {
342 if ((new = (struct devfs_prom_path *)calloc(
343 sizeof (struct devfs_prom_path), 1)) == NULL) {
344 free(prom_path);
345 devfs_free_all_prom_names(*paths);
346 return (DEVFS_NOMEM);
347 }
348
349 if (cur == NULL)
350 *paths = new;
351 else
352 cur->next = new;
353 cur = new;
354
355 len = strlen(ptr) + 1;
356 if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) {
357 free(prom_path);
358 devfs_free_all_prom_names(*paths);
359 return (DEVFS_NOMEM);
360 }
361
362 (void) snprintf(cur->obp_path, len, "%s", ptr);
363 ptr += len;
364 if ((ret = prom_dev_to_alias(cur->obp_path, flags,
365 &(cur->alias_list))) < 0) {
366 free(prom_path);
367 devfs_free_all_prom_names(*paths);
368 return (ret);
369 }
370 }
371
372 free(prom_path);
373 return (count);
374 }
375
376 void
devfs_free_all_prom_names(struct devfs_prom_path * paths)377 devfs_free_all_prom_names(struct devfs_prom_path *paths)
378 {
379 int i;
380
381 if (paths == NULL)
382 return;
383
384 devfs_free_all_prom_names(paths->next);
385
386 if (paths->obp_path != NULL)
387 free(paths->obp_path);
388
389 if (paths->alias_list != NULL) {
390 for (i = 0; paths->alias_list[i] != NULL; i++)
391 if (paths->alias_list[i] != NULL)
392 free(paths->alias_list[i]);
393
394 free(paths->alias_list);
395 }
396
397 free(paths);
398 }
399
400 /*
401 * Accepts a device name as an input argument. Uses this to set the
402 * boot-device (or like) variable
403 *
404 * By default, this routine prepends to the list and converts the
405 * logical device name to its most compact prom representation.
406 * Available options include: converting the device name to a prom
407 * path name (but not an alias) or performing no conversion at all;
408 * overwriting the existing contents of boot-device rather than
409 * prepending.
410 */
411 int
devfs_bootdev_set_list(const char * dev_name,const uint_t options)412 devfs_bootdev_set_list(const char *dev_name, const uint_t options)
413 {
414 char *prom_path;
415 char *new_bootdev;
416 char *ptr;
417 char **alias_list = NULL;
418 char **prom_list = NULL;
419 Oppbuf oppbuf;
420 struct openpromio *opp = &(oppbuf.opp);
421 int ret, len, i, j;
422
423 if (devfs_bootdev_modifiable() != 0) {
424 return (DEVFS_NOTSUP);
425 }
426 if (dev_name == NULL) {
427 return (DEVFS_INVAL);
428 }
429 if (strlen(dev_name) >= MAXPATHLEN)
430 return (DEVFS_INVAL);
431
432 if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) {
433 return (DEVFS_INVAL);
434 }
435 if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) {
436 return (DEVFS_INVAL);
437 }
438 /*
439 * if we are prepending, make sure that this obp rev
440 * supports multiple boot device entries.
441 */
442 ret = prom_obp_vers();
443 if (ret < 0) {
444 return (ret);
445 }
446
447 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) {
448 return (DEVFS_NOMEM);
449 }
450 if (options & BOOTDEV_LITERAL) {
451 (void) strcpy(prom_path, dev_name);
452 } else {
453 /* need to convert to prom representation */
454 ret = devfs_get_prom_name_list(dev_name, &prom_list);
455 if (ret < 0) {
456 free(prom_path);
457 return (ret);
458 }
459
460 len = MAXVALSIZE;
461 i = 0;
462 ptr = prom_path;
463 while (prom_list && prom_list[i]) {
464 if (!(options & BOOTDEV_PROMDEV)) {
465 ret = prom_dev_to_alias(prom_list[i], 0,
466 &alias_list);
467 if (ret < 0) {
468 free(prom_path);
469 prom_list_free(prom_list);
470 return (ret);
471 }
472 if ((alias_list != NULL) &&
473 (alias_list[0] != NULL)) {
474 (void) snprintf(ptr, len, "%s ",
475 alias_list[0]);
476 for (ret = 0; alias_list[ret] != NULL;
477 ret++)
478 free(alias_list[ret]);
479 } else {
480 (void) snprintf(ptr, len, "%s ",
481 prom_list[i]);
482 }
483 if (alias_list != NULL)
484 free(alias_list);
485 } else {
486 (void) snprintf(ptr, len, "%s ", prom_list[i]);
487 }
488 j = strlen(ptr);
489 len -= j;
490 ptr += j;
491 i++;
492 }
493 ptr--;
494 *ptr = NULL;
495
496 prom_list_free(prom_list);
497 }
498 if (options & BOOTDEV_OVERWRITE) {
499 new_bootdev = prom_path;
500 } else {
501 /* retrieve the current value of boot-device */
502 ret = get_boot_dev_var(opp);
503 if (ret < 0) {
504 free(prom_path);
505 return (ret);
506 }
507 /* prepend new entry - deal with duplicates */
508 new_bootdev = (char *)malloc(strlen(opp->oprom_array)
509 + strlen(prom_path) + 2);
510 if (new_bootdev == NULL) {
511 free(prom_path);
512 return (DEVFS_NOMEM);
513 }
514 (void) strcpy(new_bootdev, prom_path);
515 if (opp->oprom_size > 0) {
516 for (ptr = strtok(opp->oprom_array, " "); ptr != NULL;
517 ptr = strtok(NULL, " ")) {
518 /* we strip out duplicates */
519 if (strcmp(prom_path, ptr) == 0) {
520 continue;
521 }
522 (void) strcat(new_bootdev, " ");
523 (void) strcat(new_bootdev, ptr);
524 }
525 }
526 }
527
528 /* now set the new value */
529 ret = set_boot_dev_var(opp, new_bootdev);
530
531 if (options & BOOTDEV_OVERWRITE) {
532 free(prom_path);
533 } else {
534 free(new_bootdev);
535 free(prom_path);
536 }
537
538 return (ret);
539 }
540
541 /*
542 * sets the string bootdev as the new value for boot-device
543 */
544 static int
set_boot_dev_var(struct openpromio * opp,char * bootdev)545 set_boot_dev_var(struct openpromio *opp, char *bootdev)
546 {
547 int prom_fd;
548 int i;
549 int ret;
550 char *valbuf;
551 char *save_bootdev;
552 char *bootdev_variables[] = {
553 "boot-device",
554 "bootdev",
555 "boot-from",
556 NULL
557 };
558 int found = 0;
559 int *ip = (int *)((void *)opp->oprom_array);
560
561 /* query the prom */
562 prom_fd = prom_open(O_RDWR);
563 if (prom_fd < 0) {
564 return (prom_fd);
565 }
566
567 /* get the diagnostic-mode? property */
568 (void) strcpy(opp->oprom_array, "diagnostic-mode?");
569 opp->oprom_size = MAXVALSIZE;
570 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
571 if ((opp->oprom_size > 0) &&
572 (strcmp(opp->oprom_array, "true") == 0)) {
573 prom_close(prom_fd);
574 return (DEVFS_ERR);
575 }
576 }
577 /* get the diag-switch? property */
578 (void) strcpy(opp->oprom_array, "diag-switch?");
579 opp->oprom_size = MAXVALSIZE;
580 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
581 if ((opp->oprom_size > 0) &&
582 (strcmp(opp->oprom_array, "true") == 0)) {
583 prom_close(prom_fd);
584 return (DEVFS_ERR);
585 }
586 }
587 /*
588 * look for one of the following properties in order:
589 * boot-device
590 * bootdev
591 * boot-from
592 *
593 * Use the first one that we find.
594 */
595 *ip = 0;
596 opp->oprom_size = MAXPROPSIZE;
597 while ((opp->oprom_size != 0) && (!found)) {
598 opp->oprom_size = MAXPROPSIZE;
599 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
600 break;
601 }
602 for (i = 0; bootdev_variables[i] != NULL; i++) {
603 if (strcmp(opp->oprom_array, bootdev_variables[i])
604 == 0) {
605 found = 1;
606 break;
607 }
608 }
609 }
610 if (found) {
611 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
612 opp->oprom_size = MAXVALSIZE;
613 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
614 prom_close(prom_fd);
615 return (DEVFS_NOTSUP);
616 }
617 } else {
618 prom_close(prom_fd);
619 return (DEVFS_NOTSUP);
620 }
621
622 /* save the old copy in case we fail */
623 if ((save_bootdev = strdup(opp->oprom_array)) == NULL) {
624 prom_close(prom_fd);
625 return (DEVFS_NOMEM);
626 }
627 /* set up the new value of boot-device */
628 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
629 valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
630 (void) strcpy(valbuf, bootdev);
631
632 opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
633
634 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
635 free(save_bootdev);
636 prom_close(prom_fd);
637 return (DEVFS_ERR);
638 }
639
640 /*
641 * now read it back to make sure it took
642 */
643 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
644 opp->oprom_size = MAXVALSIZE;
645 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
646 if (_prom_strcmp(opp->oprom_array, bootdev) == 0) {
647 /* success */
648 free(save_bootdev);
649 prom_close(prom_fd);
650 return (0);
651 }
652 /* deal with setting it to "" */
653 if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) {
654 /* success */
655 free(save_bootdev);
656 prom_close(prom_fd);
657 return (0);
658 }
659 }
660 /*
661 * something did not take - write out the old value and
662 * hope that we can restore things...
663 *
664 * unfortunately, there is no way for us to differentiate
665 * whether we exceeded the maximum number of characters
666 * allowable. The limit varies from prom rev to prom
667 * rev, and on some proms, when the limit is
668 * exceeded, whatever was in the
669 * boot-device variable becomes unreadable.
670 *
671 * so if we fail, we will assume we ran out of room. If we
672 * not able to restore the original setting, then we will
673 * return DEVFS_ERR instead.
674 */
675 ret = DEVFS_LIMIT;
676 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
677 valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
678 (void) strcpy(valbuf, save_bootdev);
679
680 opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
681
682 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
683 ret = DEVFS_ERR;
684 }
685 free(save_bootdev);
686 prom_close(prom_fd);
687 return (ret);
688 }
689 /*
690 * retrieve the current value for boot-device
691 */
692 static int
get_boot_dev_var(struct openpromio * opp)693 get_boot_dev_var(struct openpromio *opp)
694 {
695 int prom_fd;
696 int i;
697 char *bootdev_variables[] = {
698 "boot-device",
699 "bootdev",
700 "boot-from",
701 NULL
702 };
703 int found = 0;
704 int *ip = (int *)((void *)opp->oprom_array);
705
706 /* query the prom */
707 prom_fd = prom_open(O_RDONLY);
708 if (prom_fd < 0) {
709 return (prom_fd);
710 }
711
712 /* get the diagnostic-mode? property */
713 (void) strcpy(opp->oprom_array, "diagnostic-mode?");
714 opp->oprom_size = MAXVALSIZE;
715 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
716 if ((opp->oprom_size > 0) &&
717 (strcmp(opp->oprom_array, "true") == 0)) {
718 prom_close(prom_fd);
719 return (DEVFS_ERR);
720 }
721 }
722 /* get the diag-switch? property */
723 (void) strcpy(opp->oprom_array, "diag-switch?");
724 opp->oprom_size = MAXVALSIZE;
725 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
726 if ((opp->oprom_size > 0) &&
727 (strcmp(opp->oprom_array, "true") == 0)) {
728 prom_close(prom_fd);
729 return (DEVFS_ERR);
730 }
731 }
732 /*
733 * look for one of the following properties in order:
734 * boot-device
735 * bootdev
736 * boot-from
737 *
738 * Use the first one that we find.
739 */
740 *ip = 0;
741 opp->oprom_size = MAXPROPSIZE;
742 while ((opp->oprom_size != 0) && (!found)) {
743 opp->oprom_size = MAXPROPSIZE;
744 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
745 break;
746 }
747 for (i = 0; bootdev_variables[i] != NULL; i++) {
748 if (strcmp(opp->oprom_array, bootdev_variables[i])
749 == 0) {
750 found = 1;
751 break;
752 }
753 }
754 }
755 if (found) {
756 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
757 opp->oprom_size = MAXVALSIZE;
758 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
759 prom_close(prom_fd);
760 return (DEVFS_ERR);
761 }
762 /* boot-device exists but contains nothing */
763 if (opp->oprom_size == 0) {
764 *opp->oprom_array = '\0';
765 }
766 } else {
767 prom_close(prom_fd);
768 return (DEVFS_NOTSUP);
769 }
770 prom_close(prom_fd);
771 return (0);
772 }
773
774 #ifndef __sparc
775 static FILE *
open_diskmap(void)776 open_diskmap(void)
777 {
778 FILE *fp;
779 char cmd[PATH_MAX];
780
781 /* make sure we have a map file */
782 fp = fopen(GRUBDISK_MAP, "r");
783 if (fp == NULL) {
784 (void) snprintf(cmd, sizeof (cmd),
785 "%s > /dev/null", CREATE_DISKMAP);
786 (void) system(cmd);
787 fp = fopen(GRUBDISK_MAP, "r");
788 }
789 return (fp);
790 }
791
792 static int
find_x86_boot_device(struct openpromio * opp)793 find_x86_boot_device(struct openpromio *opp)
794 {
795 int ret = DEVFS_ERR;
796 char *cp, line[MAXVALSIZE + 6];
797 FILE *file;
798
799 file = open_diskmap();
800 if (file == NULL)
801 return (DEVFS_ERR);
802
803 while (fgets(line, MAXVALSIZE + 6, file)) {
804 if (strncmp(line, "0 ", 2) != 0)
805 continue;
806 /* drop new-line */
807 line[strlen(line) - 1] = '\0';
808 /*
809 * an x86 BIOS only boots a disk, not a partition
810 * or a slice, so hard-code :q (p0)
811 */
812 cp = strchr(line + 2, ' ');
813 if (cp == NULL)
814 break;
815 (void) snprintf(opp->oprom_array, MAXVALSIZE,
816 "%s:q", cp + 1);
817 opp->oprom_size = MAXVALSIZE;
818 ret = 0;
819 break;
820 }
821 (void) fclose(file);
822 return (ret);
823 }
824 #endif /* ndef __sparc */
825
826 /*
827 * retrieve the list of entries in the boot-device configuration
828 * variable. An array of boot_dev structs will be created, one entry
829 * for each device name in the boot-device variable. Each entry
830 * in the array will contain the logical device representation of the
831 * boot-device entry, if any.
832 *
833 * default_root. if set, is used to locate logical device entries in
834 * directories other than /dev
835 */
836 int
devfs_bootdev_get_list(const char * default_root,struct boot_dev *** bootdev_list)837 devfs_bootdev_get_list(const char *default_root,
838 struct boot_dev ***bootdev_list)
839 {
840 Oppbuf oppbuf;
841 struct openpromio *opp = &(oppbuf.opp);
842 int i;
843 struct boot_dev **tmp_list;
844
845 if (default_root == NULL) {
846 default_root = "";
847 } else if (*default_root != '/') {
848 return (DEVFS_INVAL);
849 }
850
851 if (bootdev_list == NULL) {
852 return (DEVFS_INVAL);
853 }
854
855 /* get the boot-device variable */
856 #if defined(sparc)
857 i = get_boot_dev_var(opp);
858 #else
859 i = find_x86_boot_device(opp);
860 #endif
861 if (i < 0) {
862 return (i);
863 }
864 /* now try to translate each entry to a logical device. */
865 i = process_bootdev(opp->oprom_array, default_root, &tmp_list);
866 if (i == 0) {
867 *bootdev_list = tmp_list;
868 return (0);
869 } else {
870 return (i);
871 }
872 }
873
874 /*
875 * loop thru the list of entries in a boot-device configuration
876 * variable.
877 */
878 static int
process_bootdev(const char * bootdevice,const char * default_root,struct boot_dev *** list)879 process_bootdev(const char *bootdevice, const char *default_root,
880 struct boot_dev ***list)
881 {
882 int i;
883 char *entry, *ptr;
884 char prom_path[MAXPATHLEN];
885 char ret_buf[MAXPATHLEN];
886 struct boot_dev **bootdev_array;
887 int num_entries = 0;
888 int found = 0;
889 int vers;
890
891 if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) {
892 return (DEVFS_NOMEM);
893 }
894 /* count the number of entries */
895 (void) strcpy(entry, bootdevice);
896 for (ptr = strtok(entry, " "); ptr != NULL;
897 ptr = strtok(NULL, " ")) {
898 num_entries++;
899 }
900 (void) strcpy(entry, bootdevice);
901
902 bootdev_array = (struct boot_dev **)
903 calloc((size_t)num_entries + 1, sizeof (struct boot_dev *));
904
905 if (bootdev_array == NULL) {
906 free(entry);
907 return (DEVFS_NOMEM);
908 }
909
910 vers = prom_obp_vers();
911 if (vers < 0) {
912 free(entry);
913 return (vers);
914 }
915
916 /* for each entry in boot-device, do... */
917 for (ptr = strtok(entry, " "), i = 0; ptr != NULL;
918 ptr = strtok(NULL, " "), i++) {
919
920 if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) {
921 devfs_bootdev_free_list(bootdev_array);
922 free(entry);
923 return (DEVFS_NOMEM);
924 }
925
926 /*
927 * prom boot-device may be aliased, so we need to do
928 * the necessary prom alias to dev translation.
929 */
930 if (*ptr != '/') {
931 if (alias_to_prom_dev(ptr, prom_path) < 0) {
932 continue;
933 }
934 } else {
935 (void) strcpy(prom_path, ptr);
936 }
937
938 /* now we have a prom device path - convert to a devfs name */
939 if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) {
940 continue;
941 }
942
943 /* append any default minor names necessary */
944 if (process_minor_name(ret_buf, default_root) < 0) {
945 continue;
946 }
947 found = 1;
948
949 /*
950 * store the physical device path for now - when
951 * we are all done with the entries, we will convert
952 * these to their logical device name equivalents
953 */
954 bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf);
955 }
956 /*
957 * Convert all of the boot-device entries that translated to a
958 * physical device path in /devices to a logical device path
959 * in /dev (note that there may be several logical device paths
960 * associated with a single physical device path - return them all
961 */
962 if (found) {
963 if (devfs_phys_to_logical(bootdev_array, num_entries,
964 default_root) < 0) {
965 devfs_bootdev_free_list(bootdev_array);
966 bootdev_array = NULL;
967 }
968 }
969 free(entry);
970 *list = bootdev_array;
971 return (0);
972 }
973
974 /*
975 * We may get a device path from the prom that has no minor name
976 * information included in it. Since this device name will not
977 * correspond directly to a physical device in /devices, we do our
978 * best to append what the default minor name should be and try this.
979 *
980 * For sparc: we append slice 0 (:a).
981 * For x86: we append fdisk partition 0 (:q).
982 */
983 static int
process_minor_name(char * dev_path,const char * root)984 process_minor_name(char *dev_path, const char *root)
985 {
986 char *cp;
987 #if defined(sparc)
988 const char *default_minor_name = "a";
989 #else
990 const char *default_minor_name = "q";
991 #endif
992 int n;
993 struct stat stat_buf;
994 char path[MAXPATHLEN];
995
996 (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
997 /*
998 * if the device file already exists as given to us, there
999 * is nothing to do but return.
1000 */
1001 if (stat(path, &stat_buf) == 0) {
1002 return (0);
1003 }
1004 /*
1005 * if there is no ':' after the last '/' character, or if there is
1006 * a ':' with no specifier, append the default segment specifier
1007 * ; if there is a ':' followed by a digit, this indicates
1008 * a partition number (which does not map into the /devices name
1009 * space), so strip the number and replace it with the letter
1010 * that represents the partition index
1011 */
1012 if ((cp = strrchr(dev_path, '/')) != NULL) {
1013 if ((cp = strchr(cp, ':')) == NULL) {
1014 (void) strcat(dev_path, ":");
1015 (void) strcat(dev_path, default_minor_name);
1016 } else if (*++cp == '\0') {
1017 (void) strcat(dev_path, default_minor_name);
1018 } else if (isdigit(*cp)) {
1019 n = atoi(cp);
1020 /* make sure to squash the digit */
1021 *cp = '\0';
1022 switch (n) {
1023 case 0: (void) strcat(dev_path, "q");
1024 break;
1025 case 1: (void) strcat(dev_path, "r");
1026 break;
1027 case 2: (void) strcat(dev_path, "s");
1028 break;
1029 case 3: (void) strcat(dev_path, "t");
1030 break;
1031 case 4: (void) strcat(dev_path, "u");
1032 break;
1033 default: (void) strcat(dev_path, "a");
1034 break;
1035 }
1036 }
1037 }
1038 /*
1039 * see if we can find something now.
1040 */
1041 (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
1042
1043 if (stat(path, &stat_buf) == 0) {
1044 return (0);
1045 } else {
1046 return (-1);
1047 }
1048 }
1049
1050 /*
1051 * for each entry in bootdev_array, convert the physical device
1052 * representation of the boot-device entry to one or more logical device
1053 * entries. We use the hammer method - walk through the logical device
1054 * name space looking for matches (/dev). We use nftw to do this.
1055 */
1056 static int
devfs_phys_to_logical(struct boot_dev ** bootdev_array,const int array_size,const char * default_root)1057 devfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size,
1058 const char *default_root)
1059 {
1060 int walk_flags = FTW_PHYS | FTW_MOUNT;
1061 char *full_path;
1062 struct name_list *list;
1063 int count, i;
1064 char **dev_name_array;
1065 size_t default_root_len;
1066 char *dev_dir = DEV;
1067 int len;
1068
1069 if (array_size < 0) {
1070 return (-1);
1071 }
1072
1073 if (bootdev_array == NULL) {
1074 return (-1);
1075 }
1076 if (default_root == NULL) {
1077 return (-1);
1078 }
1079 default_root_len = strlen(default_root);
1080 if ((default_root_len != 0) && (*default_root != '/')) {
1081 return (-1);
1082 }
1083
1084 /* short cut for an empty array */
1085 if (*bootdev_array == NULL) {
1086 return (0);
1087 }
1088
1089 /* tell nftw where to start (default: /dev) */
1090 len = default_root_len + strlen(dev_dir) + 1;
1091 if ((full_path = (char *)malloc(len)) == NULL) {
1092 return (-1);
1093 }
1094
1095 /*
1096 * if the default root path is terminated with a /, we have to
1097 * make sure we don't end up with one too many slashes in the
1098 * path we are building.
1099 */
1100 if ((default_root_len > (size_t)0) &&
1101 (default_root[default_root_len - 1] == '/')) {
1102 (void) snprintf(full_path, len, "%s%s", default_root,
1103 &dev_dir[1]);
1104 } else {
1105 (void) snprintf(full_path, len, "%s%s", default_root, dev_dir);
1106 }
1107
1108 /*
1109 * we need to muck with global data to make nftw work
1110 * so single thread access
1111 */
1112 (void) mutex_lock(&dev_lists_lk);
1113
1114 /*
1115 * set the global vars bootdev_list and dev_list for use by nftw
1116 * dev_list is an array of lists - one for each boot-device
1117 * entry. The nftw function will create a list of logical device
1118 * entries for each boot-device and put all of the lists in
1119 * dev_list.
1120 */
1121 dev_list = (struct name_list **)
1122 calloc(array_size, sizeof (struct name_list *));
1123 if (dev_list == NULL) {
1124 free(full_path);
1125 (void) mutex_unlock(&dev_lists_lk);
1126 return (-1);
1127 }
1128 bootdev_list = bootdev_array;
1129
1130 if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) {
1131 bootdev_list = NULL;
1132 free(full_path);
1133 for (i = 0; i < array_size; i++) {
1134 free_name_list(dev_list[i], 1);
1135 }
1136 /* don't free dev_list here because it's been handed off */
1137 dev_list = NULL;
1138 (void) mutex_unlock(&dev_lists_lk);
1139 return (-1);
1140 }
1141
1142 /*
1143 * now we have a filled in dev_list. So for each logical device
1144 * list in dev_list, count the number of entries in the list,
1145 * create an array of strings of logical devices, and save in the
1146 * corresponding boot_dev structure.
1147 */
1148 for (i = 0; i < array_size; i++) {
1149 /* get the next list */
1150 list = dev_list[i];
1151 count = 0;
1152
1153 /* count the number of entries in the list */
1154 while (list != NULL) {
1155 count++;
1156 list = list->next;
1157 }
1158 if ((dev_name_array =
1159 (char **)malloc((count + 1) * sizeof (char *)))
1160 == NULL) {
1161 continue;
1162 }
1163 list = dev_list[i];
1164 count = 0;
1165
1166 /* fill in the array */
1167 while (list != NULL) {
1168 dev_name_array[count] = list->name;
1169 count++;
1170 list = list->next;
1171 }
1172
1173 /*
1174 * null terminate the array
1175 */
1176 dev_name_array[count] = NULL;
1177 if ((bootdev_array[i] != NULL) && (bootdev_array[i]->
1178 bootdev_trans[0] != NULL)) {
1179 free(bootdev_array[i]->bootdev_trans[0]);
1180 }
1181 if (bootdev_array[i] != NULL) {
1182 free(bootdev_array[i]->bootdev_trans);
1183 bootdev_array[i]->bootdev_trans = dev_name_array;
1184 }
1185 }
1186 bootdev_list = NULL;
1187 free(full_path);
1188 for (i = 0; i < array_size; i++) {
1189 free_name_list(dev_list[i], 0);
1190 }
1191 free(dev_list);
1192 dev_list = NULL;
1193 (void) mutex_unlock(&dev_lists_lk);
1194 return (0);
1195 }
1196 /*
1197 * nftw function
1198 * for a logical dev entry, it walks the list of boot-devices and
1199 * sees if there are any matches. If so, it saves the logical device
1200 * name off in the appropriate list in dev_list
1201 */
1202 /* ARGSUSED */
1203 static int
check_logical_dev(const char * node,const struct stat * node_stat,int flags,struct FTW * ftw_info)1204 check_logical_dev(const char *node, const struct stat *node_stat, int flags,
1205 struct FTW *ftw_info)
1206 {
1207 char link_buf[MAXPATHLEN];
1208 int link_buf_len;
1209 char *name;
1210 struct name_list *dev;
1211 char *physdev;
1212 int i;
1213
1214 if (flags != FTW_SL) {
1215 return (0);
1216 }
1217
1218 if ((link_buf_len = readlink(node, (void *)link_buf, MAXPATHLEN))
1219 == -1) {
1220 return (0);
1221 }
1222 link_buf[link_buf_len] = '\0';
1223 if ((name = strstr(link_buf, DEVICES)) == NULL) {
1224 return (0);
1225 }
1226 name = (char *)(name + strlen(DEVICES));
1227
1228 for (i = 0; bootdev_list[i] != NULL; i++) {
1229 if (bootdev_list[i]->bootdev_trans[0] == NULL) {
1230 continue;
1231 }
1232 /*
1233 * compare the contents of the link with the physical
1234 * device representation of this boot device
1235 */
1236 physdev = bootdev_list[i]->bootdev_trans[0];
1237 if ((strcmp(name, physdev) == 0) &&
1238 (strlen(name) == strlen(physdev))) {
1239 if ((dev = (struct name_list *)
1240 malloc(sizeof (struct name_list))) == NULL) {
1241 return (-1);
1242 }
1243 if ((dev->name = strdup(node)) == NULL) {
1244 free(dev);
1245 return (-1);
1246 }
1247 if (dev_list[i] == NULL) {
1248 dev_list[i] = dev;
1249 dev_list[i]->next = NULL;
1250 } else {
1251 dev->next = dev_list[i];
1252 dev_list[i] = dev;
1253 }
1254 }
1255 }
1256 return (0);
1257 }
1258
1259 /*
1260 * frees a list of boot_dev struct pointers
1261 */
1262 void
devfs_bootdev_free_list(struct boot_dev ** array)1263 devfs_bootdev_free_list(struct boot_dev **array)
1264 {
1265 int i = 0;
1266 int j;
1267
1268 if (array == NULL) {
1269 return;
1270 }
1271
1272 while (array[i] != NULL) {
1273 free(array[i]->bootdev_element);
1274 j = 0;
1275 while (array[i]->bootdev_trans[j] != NULL) {
1276 free(array[i]->bootdev_trans[j++]);
1277 }
1278 free(array[i]->bootdev_trans);
1279 free(array[i]);
1280 i++;
1281 }
1282 free(array);
1283 }
1284 /*
1285 * allocates a boot_dev struct and fills in the bootdev_element portion
1286 */
1287 static struct boot_dev *
alloc_bootdev(char * entry_name)1288 alloc_bootdev(char *entry_name)
1289 {
1290 struct boot_dev *entry;
1291
1292 entry = (struct boot_dev *)calloc(1, sizeof (struct boot_dev));
1293
1294 if (entry == NULL) {
1295 return (NULL);
1296 }
1297 if ((entry->bootdev_element = strdup(entry_name)) == NULL) {
1298 free(entry);
1299 return (NULL);
1300 }
1301 /*
1302 * Allocate room for 1 name and a null terminator - the caller of
1303 * this function will need the first slot right away.
1304 */
1305 if ((entry->bootdev_trans = (char **)calloc(2, sizeof (char *)))
1306 == NULL) {
1307 free(entry->bootdev_element);
1308 free(entry);
1309 return (NULL);
1310 }
1311 return (entry);
1312 }
1313
1314 /*
1315 * will come back with a concatenated list of paths
1316 */
1317 int
devfs_dev_to_prom_names(char * dev_path,char * prom_path,size_t len)1318 devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len)
1319 {
1320 Oppbuf oppbuf;
1321 struct openpromio *opp = &(oppbuf.opp);
1322 int prom_fd;
1323 int ret = DEVFS_INVAL;
1324 int i;
1325
1326 if (prom_path == NULL) {
1327 return (DEVFS_INVAL);
1328 }
1329 if (dev_path == NULL) {
1330 return (DEVFS_INVAL);
1331 }
1332 if (strlen(dev_path) >= MAXPATHLEN)
1333 return (DEVFS_INVAL);
1334
1335 if (*dev_path != '/')
1336 return (DEVFS_INVAL);
1337
1338 prom_fd = prom_open(O_RDONLY);
1339 if (prom_fd < 0) {
1340 return (prom_fd);
1341 }
1342
1343 /* query the prom */
1344 (void) snprintf(opp->oprom_array, MAXVALSIZE, "%s", dev_path);
1345 opp->oprom_size = MAXVALSIZE;
1346
1347 if (ioctl(prom_fd, OPROMDEV2PROMNAME, opp) == 0) {
1348 prom_close(prom_fd);
1349
1350 /* return the prom path in prom_path */
1351
1352 i = len - opp->oprom_size;
1353 if (i < 0) {
1354 bcopy(opp->oprom_array, prom_path, len);
1355 prom_path[len - 1] = NULL;
1356 return (len);
1357 } else {
1358 bcopy(opp->oprom_array, prom_path, len);
1359 return (opp->oprom_size);
1360 }
1361 }
1362 /*
1363 * either the prom does not support this ioctl or the argument
1364 * was invalid.
1365 */
1366 if (errno == ENXIO) {
1367 ret = DEVFS_NOTSUP;
1368 }
1369 prom_close(prom_fd);
1370 return (ret);
1371 }
1372
1373 /*
1374 * Convert a physical or logical device name to a name the prom would
1375 * understand. Fail if this platform does not support a prom or if
1376 * the device does not correspond to a valid prom device.
1377 * dev_path should be the name of a device in the logical or
1378 * physical device namespace.
1379 * prom_path is the prom version of the device name
1380 * prom_path must be large enough to contain the result and is
1381 * supplied by the user.
1382 *
1383 * This routine only supports converting leaf device paths
1384 */
1385 int
devfs_dev_to_prom_name(char * dev_path,char * prom_path)1386 devfs_dev_to_prom_name(char *dev_path, char *prom_path)
1387 {
1388 int rval;
1389
1390 rval = devfs_dev_to_prom_names(dev_path, prom_path, MAXPATHLEN);
1391
1392 if (rval < 0)
1393 return (rval);
1394 else
1395 return (0);
1396 }
1397
1398 /*
1399 * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs
1400 * path to a driver name.
1401 * devfs_path - the pathname of interest. This must be the physcical device
1402 * path with the mount point prefix (ie. /devices) stripped off.
1403 * drv_buf - user supplied buffer - the driver name will be stored here.
1404 *
1405 * If the prom lookup fails, we return the name of the last component in
1406 * the pathname. This routine is useful for looking up driver names
1407 * associated with generically named devices.
1408 *
1409 * This routine returns driver names that have aliases resolved.
1410 */
1411 int
devfs_path_to_drv(char * devfs_path,char * drv_buf)1412 devfs_path_to_drv(char *devfs_path, char *drv_buf)
1413 {
1414 Oppbuf oppbuf;
1415 struct openpromio *opp = &(oppbuf.opp);
1416 char *slash, *colon, *dev_addr;
1417 char driver_path[MAXPATHLEN];
1418 int prom_fd;
1419
1420 if (drv_buf == NULL) {
1421 return (-1);
1422 }
1423 if (devfs_path == NULL) {
1424 return (-1);
1425 }
1426
1427 if (strlen(devfs_path) >= MAXPATHLEN)
1428 return (-1);
1429
1430 if (*devfs_path != '/')
1431 return (-1);
1432
1433
1434 /* strip off any minor node info at the end of the path */
1435 (void) strcpy(driver_path, devfs_path);
1436 slash = strrchr(driver_path, '/');
1437 if (slash == NULL)
1438 return (-1);
1439 colon = strrchr(slash, ':');
1440 if (colon != NULL)
1441 *colon = '\0';
1442
1443 /* query the prom */
1444 if ((prom_fd = prom_open(O_RDONLY)) >= 0) {
1445 (void) strcpy(opp->oprom_array, driver_path);
1446 opp->oprom_size = MAXVALSIZE;
1447
1448 if (ioctl(prom_fd, OPROMPATH2DRV, opp) == 0) {
1449 prom_close(prom_fd);
1450 /* return the driver name in drv_buf */
1451 (void) strcpy(drv_buf, opp->oprom_array);
1452 return (0);
1453 }
1454 prom_close(prom_fd);
1455 } else if (prom_fd != DEVFS_NOTSUP)
1456 return (-1);
1457 /*
1458 * If we get here, then either:
1459 * 1. this platform does not support an openprom driver
1460 * 2. we were asked to look up a device the prom does
1461 * not know about (e.g. a pseudo device)
1462 * In this case, we use the last component of the devfs path
1463 * name and try to derive the driver name
1464 */
1465
1466 /* use the last component of devfs_path as the driver name */
1467 if ((dev_addr = strrchr(slash, '@')) != NULL)
1468 *dev_addr = '\0';
1469 slash++;
1470
1471 /* use opp->oprom_array as a buffer */
1472 (void) strcpy(opp->oprom_array, slash);
1473 if (devfs_resolve_aliases(opp->oprom_array) == NULL)
1474 return (-1);
1475 (void) strcpy(drv_buf, opp->oprom_array);
1476 return (0);
1477 }
1478
1479 /*
1480 * These modctl calls do the equivalent of:
1481 * ddi_name_to_major()
1482 * ddi_major_to_name()
1483 * This results in two things:
1484 * - the driver name must be a valid one
1485 * - any driver aliases are resolved.
1486 * drv is overwritten with the resulting name.
1487 */
1488 char *
devfs_resolve_aliases(char * drv)1489 devfs_resolve_aliases(char *drv)
1490 {
1491 major_t maj;
1492 char driver_name[MAXNAMELEN + 1];
1493
1494 if (drv == NULL) {
1495 return (NULL);
1496 }
1497
1498 if (modctl(MODGETMAJBIND, drv, strlen(drv) + 1, &maj) < 0)
1499 return (NULL);
1500 else if (modctl(MODGETNAME, driver_name, sizeof (driver_name), &maj)
1501 < 0) {
1502 return (NULL);
1503 } else {
1504 (void) strcpy(drv, driver_name);
1505 return (drv);
1506 }
1507 }
1508
1509 /*
1510 * open the openprom device. and verify that we are on an
1511 * OBP/1275 OF machine. If the prom does not exist, then we
1512 * return an error
1513 */
1514 static int
prom_open(int oflag)1515 prom_open(int oflag)
1516 {
1517 int prom_fd = -1;
1518 char *promdev = "/dev/openprom";
1519
1520 while (prom_fd < 0) {
1521 if ((prom_fd = open(promdev, oflag)) < 0) {
1522 if (errno == EAGAIN) {
1523 (void) sleep(5);
1524 continue;
1525 }
1526 if ((errno == ENXIO) || (errno == ENOENT)) {
1527 return (DEVFS_NOTSUP);
1528 }
1529 if ((errno == EPERM) || (errno == EACCES)) {
1530 return (DEVFS_PERM);
1531 }
1532 return (DEVFS_ERR);
1533 } else
1534 break;
1535 }
1536 if (is_openprom(prom_fd))
1537 return (prom_fd);
1538 else {
1539 prom_close(prom_fd);
1540 return (DEVFS_ERR);
1541 }
1542 }
1543
1544 static void
prom_close(int prom_fd)1545 prom_close(int prom_fd)
1546 {
1547 (void) close(prom_fd);
1548 }
1549
1550 /*
1551 * is this an OBP/1275 OF machine?
1552 */
1553 static int
is_openprom(int prom_fd)1554 is_openprom(int prom_fd)
1555 {
1556 Oppbuf oppbuf;
1557 struct openpromio *opp = &(oppbuf.opp);
1558 unsigned int i;
1559
1560 opp->oprom_size = MAXVALSIZE;
1561 if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
1562 return (0);
1563
1564 i = (unsigned int)((unsigned char)opp->oprom_array[0]);
1565 return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
1566 }
1567
1568 /*
1569 * convert a prom device path name to an equivalent physical device
1570 * path in the kernel.
1571 */
1572 static int
devfs_prom_to_dev_name(char * prom_path,char * dev_path)1573 devfs_prom_to_dev_name(char *prom_path, char *dev_path)
1574 {
1575 Oppbuf oppbuf;
1576 struct openpromio *opp = &(oppbuf.opp);
1577 int prom_fd;
1578 int ret = DEVFS_INVAL;
1579
1580 if (dev_path == NULL) {
1581 return (DEVFS_INVAL);
1582 }
1583 if (prom_path == NULL) {
1584 return (DEVFS_INVAL);
1585 }
1586 if (strlen(prom_path) >= MAXPATHLEN)
1587 return (DEVFS_INVAL);
1588
1589 if (*prom_path != '/') {
1590 return (DEVFS_INVAL);
1591 }
1592
1593 /* query the prom */
1594 prom_fd = prom_open(O_RDONLY);
1595 if (prom_fd < 0) {
1596 return (prom_fd);
1597 }
1598 (void) strcpy(opp->oprom_array, prom_path);
1599 opp->oprom_size = MAXVALSIZE;
1600
1601 if (ioctl(prom_fd, OPROMPROM2DEVNAME, opp) == 0) {
1602 prom_close(prom_fd);
1603 /*
1604 * success
1605 * return the prom path in prom_path
1606 */
1607 (void) strcpy(dev_path, opp->oprom_array);
1608 return (0);
1609 }
1610 /*
1611 * either the argument was not a valid name or the openprom
1612 * driver does not support this ioctl.
1613 */
1614 if (errno == ENXIO) {
1615 ret = DEVFS_NOTSUP;
1616 }
1617 prom_close(prom_fd);
1618 return (ret);
1619 }
1620 /*
1621 * convert a prom device path to a list of equivalent alias names
1622 * If there is no alias node, or there are no aliases that correspond
1623 * to dev, we return empty lists.
1624 */
1625 static int
prom_dev_to_alias(char * dev,uint_t options,char *** ret_buf)1626 prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf)
1627 {
1628 struct name_list *exact_list;
1629 struct name_list *inexact_list;
1630 struct name_list *list;
1631 char *ptr;
1632 char **array;
1633 int prom_fd;
1634 int count;
1635 int vers;
1636
1637 vers = prom_obp_vers();
1638 if (vers < 0) {
1639 return (vers);
1640 }
1641
1642 if (dev == NULL) {
1643 return (DEVFS_INVAL);
1644 }
1645
1646 if (*dev != '/')
1647 return (DEVFS_INVAL);
1648
1649 if (strlen(dev) >= MAXPATHLEN)
1650 return (DEVFS_INVAL);
1651
1652 if ((ptr = strchr(dev, ':')) != NULL) {
1653 if (strchr(ptr, '/') != NULL)
1654 return (DEVFS_INVAL);
1655 }
1656 if (ret_buf == NULL) {
1657 return (DEVFS_INVAL);
1658 }
1659
1660 prom_fd = prom_open(O_RDONLY);
1661 if (prom_fd < 0) {
1662 return (prom_fd);
1663 }
1664
1665 (void) prom_srch_aliases_by_def(dev, &exact_list,
1666 &inexact_list, prom_fd);
1667
1668 prom_close(prom_fd);
1669
1670 if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) {
1671 free_name_list(exact_list, 1);
1672 exact_list = NULL;
1673 }
1674
1675 if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) {
1676 free_name_list(inexact_list, 1);
1677 inexact_list = NULL;
1678 }
1679
1680 count = 0;
1681 list = exact_list;
1682 while (list != NULL) {
1683 list = list->next;
1684 count++;
1685 }
1686 list = inexact_list;
1687 while (list != NULL) {
1688 list = list->next;
1689 count++;
1690 }
1691
1692 if ((*ret_buf = (char **)malloc((count + 1) * sizeof (char *)))
1693 == NULL) {
1694 free_name_list(inexact_list, 1);
1695 free_name_list(exact_list, 1);
1696 return (DEVFS_NOMEM);
1697 }
1698
1699 array = *ret_buf;
1700 count = 0;
1701 list = exact_list;
1702 while (list != NULL) {
1703 array[count] = list->name;
1704 list = list->next;
1705 count++;
1706 }
1707 list = inexact_list;
1708 while (list != NULL) {
1709 array[count] = list->name;
1710 list = list->next;
1711 count++;
1712 }
1713 array[count] = NULL;
1714 free_name_list(inexact_list, 0);
1715 free_name_list(exact_list, 0);
1716
1717 return (0);
1718 }
1719
1720 /*
1721 * determine the version of prom we are running on.
1722 * Also include any prom revision specific information.
1723 */
1724 static int
prom_obp_vers(void)1725 prom_obp_vers(void)
1726 {
1727 Oppbuf oppbuf;
1728 struct openpromio *opp = &(oppbuf.opp);
1729 int prom_fd;
1730 static int version = 0;
1731
1732 /* cache version */
1733 if (version > 0) {
1734 return (version);
1735 }
1736
1737 prom_fd = prom_open(O_RDONLY);
1738 if (prom_fd < 0) {
1739 return (prom_fd);
1740 }
1741
1742 opp->oprom_size = MAXVALSIZE;
1743
1744 if ((ioctl(prom_fd, OPROMGETVERSION, opp)) < 0) {
1745 prom_close(prom_fd);
1746 return (DEVFS_ERR);
1747 }
1748 prom_close(prom_fd);
1749
1750 version |= OBP_OF;
1751
1752 return (version);
1753 }
1754 /*
1755 * search the aliases node by definition - compile a list of
1756 * alias names that are both exact and inexact matches.
1757 */
1758 static int
prom_srch_aliases_by_def(char * promdev_def,struct name_list ** exact_list,struct name_list ** inexact_list,int prom_fd)1759 prom_srch_aliases_by_def(char *promdev_def, struct name_list **exact_list,
1760 struct name_list **inexact_list, int prom_fd)
1761 {
1762 Oppbuf oppbuf;
1763 Oppbuf propdef_oppbuf;
1764 struct openpromio *opp = &(oppbuf.opp);
1765 struct openpromio *propdef_opp = &(propdef_oppbuf.opp);
1766 int *ip = (int *)((void *)opp->oprom_array);
1767 int ret;
1768 struct name_list *inexact_match = *inexact_list = NULL;
1769 struct name_list *exact_match = *exact_list = NULL;
1770 char alias_buf[MAXNAMELEN];
1771 int found = 0;
1772
1773 if ((ret = prom_find_aliases_node(prom_fd)) < 0)
1774 return (0);
1775
1776 (void) memset(oppbuf.buf, 0, BUFSIZE);
1777 opp->oprom_size = MAXPROPSIZE;
1778 *ip = 0;
1779
1780 if ((ret = ioctl(prom_fd, OPROMNXTPROP, opp)) < 0)
1781 return (0);
1782 if (opp->oprom_size == 0)
1783 return (0);
1784
1785 while ((ret >= 0) && (opp->oprom_size > 0)) {
1786 (void) strcpy(propdef_opp->oprom_array, opp->oprom_array);
1787 opp->oprom_size = MAXPROPSIZE;
1788 propdef_opp->oprom_size = MAXVALSIZE;
1789 if ((ioctl(prom_fd, OPROMGETPROP, propdef_opp) < 0) ||
1790 (propdef_opp->oprom_size == 0)) {
1791 ret = ioctl(prom_fd, OPROMNXTPROP, opp);
1792 continue;
1793 }
1794 ret = prom_compare_devs(promdev_def, propdef_opp->oprom_array);
1795 if (ret == EXACT_MATCH) {
1796 found++;
1797 if (insert_alias_list(exact_list, opp->oprom_array)
1798 != 0) {
1799 free_name_list(exact_match, 1);
1800 free_name_list(inexact_match, 1);
1801 return (-1);
1802 }
1803 }
1804 if (ret == INEXACT_MATCH) {
1805 found++;
1806 (void) strcpy(alias_buf, opp->oprom_array);
1807 options_override(promdev_def, alias_buf);
1808 if (insert_alias_list(inexact_list, alias_buf)
1809 != 0) {
1810 free_name_list(exact_match, 1);
1811 free_name_list(inexact_match, 1);
1812 return (-1);
1813 }
1814 }
1815 ret = ioctl(prom_fd, OPROMNXTPROP, opp);
1816 }
1817 if (found) {
1818 return (0);
1819 } else {
1820 return (-1);
1821 }
1822 }
1823
1824 /*
1825 * free a list of name_list structs and optionally
1826 * free the strings they contain.
1827 */
1828 static void
free_name_list(struct name_list * list,int free_name)1829 free_name_list(struct name_list *list, int free_name)
1830 {
1831 struct name_list *next = list;
1832
1833 while (next != NULL) {
1834 list = list->next;
1835 if (free_name)
1836 free(next->name);
1837 free(next);
1838 next = list;
1839 }
1840 }
1841
1842 /*
1843 * insert a new alias in a list of aliases - the list is sorted
1844 * in collating order (ignoring anything that comes after the
1845 * ':' in the name).
1846 */
1847 static int
insert_alias_list(struct name_list ** list,char * alias_name)1848 insert_alias_list(struct name_list **list, char *alias_name)
1849 {
1850 struct name_list *entry = *list;
1851 struct name_list *new_entry, *prev_entry;
1852 int ret;
1853 char *colon1, *colon2;
1854
1855 if ((new_entry =
1856 (struct name_list *)malloc(sizeof (struct name_list)))
1857 == NULL) {
1858 return (-1);
1859 }
1860 if ((new_entry->name = strdup(alias_name)) == NULL) {
1861 free(new_entry);
1862 return (-1);
1863 }
1864 new_entry->next = NULL;
1865
1866 if (entry == NULL) {
1867 *list = new_entry;
1868 return (0);
1869 }
1870
1871 if ((colon1 = strchr(alias_name, ':')) != NULL) {
1872 *colon1 = '\0';
1873 }
1874 prev_entry = NULL;
1875 while (entry != NULL) {
1876 if ((colon2 = strchr(entry->name, ':')) != NULL) {
1877 *colon2 = '\0';
1878 }
1879 ret = strcmp(alias_name, entry->name);
1880 if (colon2 != NULL) {
1881 *colon2 = ':';
1882 }
1883 /* duplicate */
1884 if (ret == 0) {
1885 free(new_entry->name);
1886 free(new_entry);
1887 if (colon1 != NULL) {
1888 *colon1 = ':';
1889 }
1890 return (0);
1891 }
1892 if (ret < 0) {
1893 new_entry->next = entry;
1894 if (prev_entry == NULL) {
1895 /* in beginning of list */
1896 *list = new_entry;
1897 } else {
1898 /* in middle of list */
1899 prev_entry->next = new_entry;
1900 }
1901 if (colon1 != NULL) {
1902 *colon1 = ':';
1903 }
1904 return (0);
1905 }
1906 prev_entry = entry;
1907 entry = entry->next;
1908 }
1909 /* at end of list */
1910 prev_entry->next = new_entry;
1911 new_entry->next = NULL;
1912 if (colon1 != NULL) {
1913 *colon1 = ':';
1914 }
1915 return (0);
1916 }
1917 /*
1918 * append :x to alias_name to override any default minor name options
1919 */
1920 static void
options_override(char * prom_path,char * alias_name)1921 options_override(char *prom_path, char *alias_name)
1922 {
1923 char *colon;
1924
1925 if ((colon = strrchr(alias_name, ':')) != NULL) {
1926 /*
1927 * XXX - should alias names in /aliases ever have a
1928 * : embedded in them?
1929 * If so we ignore it.
1930 */
1931 *colon = '\0';
1932 }
1933
1934 if ((colon = strrchr(prom_path, ':')) != NULL) {
1935 (void) strcat(alias_name, colon);
1936 }
1937 }
1938
1939 /*
1940 * compare to prom device names.
1941 * if the device names are not fully qualified. we convert them -
1942 * we only do this as a last resort though since it requires
1943 * jumping into the kernel.
1944 */
1945 static int
prom_compare_devs(char * prom_dev1,char * prom_dev2)1946 prom_compare_devs(char *prom_dev1, char *prom_dev2)
1947 {
1948 char *dev1, *dev2;
1949 char *ptr1, *ptr2;
1950 char *drvname1, *addrname1, *minorname1;
1951 char *drvname2, *addrname2, *minorname2;
1952 char component1[MAXNAMELEN], component2[MAXNAMELEN];
1953 char devname1[MAXPATHLEN], devname2[MAXPATHLEN];
1954 int unqualified_name = 0;
1955 int error = EXACT_MATCH;
1956 int len1, len2;
1957 char *wildcard = ",0";
1958
1959 ptr1 = prom_dev1;
1960 ptr2 = prom_dev2;
1961
1962 if ((ptr1 == NULL) || (*ptr1 != '/')) {
1963 return (NO_MATCH);
1964 }
1965 if ((ptr2 == NULL) || (*ptr2 != '/')) {
1966 return (NO_MATCH);
1967 }
1968
1969 /*
1970 * compare device names one component at a time.
1971 */
1972 while ((ptr1 != NULL) && (ptr2 != NULL)) {
1973 *ptr1 = *ptr2 = '/';
1974 dev1 = ptr1 + 1;
1975 dev2 = ptr2 + 1;
1976 if ((ptr1 = strchr(dev1, '/')) != NULL)
1977 *ptr1 = '\0';
1978 if ((ptr2 = strchr(dev2, '/')) != NULL)
1979 *ptr2 = '\0';
1980
1981 (void) strcpy(component1, dev1);
1982 (void) strcpy(component2, dev2);
1983
1984 parse_name(component1, &drvname1, &addrname1, &minorname1);
1985 parse_name(component2, &drvname2, &addrname2, &minorname2);
1986
1987 if ((drvname1 == NULL) && (addrname1 == NULL)) {
1988 error = NO_MATCH;
1989 break;
1990 }
1991
1992 if ((drvname2 == NULL) && (addrname2 == NULL)) {
1993 error = NO_MATCH;
1994 break;
1995 }
1996
1997 if (_prom_strcmp(drvname1, drvname2) != 0) {
1998 error = NO_MATCH;
1999 break;
2000 }
2001
2002 /*
2003 * a possible name is driver_name@address. The address
2004 * portion is optional (i.e. the name is not fully
2005 * qualified.). We have to deal with the case where
2006 * the component name is either driver_name or
2007 * driver_name@address
2008 */
2009 if ((addrname1 == NULL) ^ (addrname2 == NULL)) {
2010 unqualified_name = 1;
2011 } else if (addrname1 &&
2012 (_prom_strcmp(addrname1, addrname2) != 0)) {
2013 /*
2014 * check to see if appending a ",0" to the
2015 * shorter address causes a match to occur.
2016 * If so succeed.
2017 */
2018 len1 = strlen(addrname1);
2019 len2 = strlen(addrname2);
2020 if ((len1 < len2) &&
2021 (strncmp(addrname1, addrname2, len1) == 0) &&
2022 (strcmp(wildcard, &addrname2[len1]) == 0)) {
2023 continue;
2024 } else if ((len2 < len1) &&
2025 (strncmp(addrname1, addrname2, len2) == 0) &&
2026 (strcmp(wildcard, &addrname1[len2]) == 0)) {
2027 continue;
2028 }
2029 error = NO_MATCH;
2030 break;
2031 }
2032 }
2033
2034 /*
2035 * if either of the two device paths still has more components,
2036 * then we do not have a match.
2037 */
2038 if (ptr1 != NULL) {
2039 *ptr1 = '/';
2040 error = NO_MATCH;
2041 }
2042 if (ptr2 != NULL) {
2043 *ptr2 = '/';
2044 error = NO_MATCH;
2045 }
2046 if (error == NO_MATCH) {
2047 return (error);
2048 }
2049
2050 /*
2051 * OK - we found a possible match but one or more of the
2052 * path components was not fully qualified (did not have any
2053 * address information. So we need to convert it to a form
2054 * that is fully qualified and then compare the resulting
2055 * strings.
2056 */
2057 if (unqualified_name != 0) {
2058 if ((devfs_prom_to_dev_name(prom_dev1, devname1) < 0) ||
2059 (devfs_prom_to_dev_name(prom_dev2, devname2) < 0)) {
2060 return (NO_MATCH);
2061 }
2062 if ((dev1 = strrchr(devname1, ':')) != NULL) {
2063 *dev1 = '\0';
2064 }
2065 if ((dev2 = strrchr(devname2, ':')) != NULL) {
2066 *dev2 = '\0';
2067 }
2068 if (strcmp(devname1, devname2) != 0) {
2069 return (NO_MATCH);
2070 }
2071 }
2072 /*
2073 * the resulting strings matched. If the minorname information
2074 * matches, then we have an exact match, otherwise an inexact match
2075 */
2076 if (_prom_strcmp(minorname1, minorname2) == 0) {
2077 return (EXACT_MATCH);
2078 } else {
2079 return (INEXACT_MATCH);
2080 }
2081 }
2082
2083 /*
2084 * wrapper or strcmp - deals with null strings.
2085 */
2086 static int
_prom_strcmp(char * s1,char * s2)2087 _prom_strcmp(char *s1, char *s2)
2088 {
2089 if ((s1 == NULL) && (s2 == NULL))
2090 return (0);
2091 if ((s1 == NULL) && (s2 != NULL)) {
2092 return (-1);
2093 }
2094 if ((s1 != NULL) && (s2 == NULL)) {
2095 return (1);
2096 }
2097 return (strcmp(s1, s2));
2098 }
2099 /*
2100 * break device@a,b:minor into components
2101 */
2102 static void
parse_name(char * name,char ** drvname,char ** addrname,char ** minorname)2103 parse_name(char *name, char **drvname, char **addrname, char **minorname)
2104 {
2105 char *cp, ch;
2106
2107 cp = *drvname = name;
2108 *addrname = *minorname = NULL;
2109 if (*name == '@')
2110 *drvname = NULL;
2111
2112 while ((ch = *cp) != '\0') {
2113 if (ch == '@')
2114 *addrname = ++cp;
2115 else if (ch == ':')
2116 *minorname = ++cp;
2117 ++cp;
2118 }
2119 if (*addrname) {
2120 *((*addrname)-1) = '\0';
2121 }
2122 if (*minorname) {
2123 *((*minorname)-1) = '\0';
2124 }
2125 }
2126
2127 /*
2128 * converts a prom alias to a prom device name.
2129 * if we find no matching device, then we fail since if were
2130 * given a valid alias, then by definition, there must be a
2131 * device pathname associated with it in the /aliases node.
2132 */
2133 static int
alias_to_prom_dev(char * alias,char * ret_buf)2134 alias_to_prom_dev(char *alias, char *ret_buf)
2135 {
2136 char *options_ptr;
2137 char alias_buf[MAXNAMELEN];
2138 char alias_def[MAXPATHLEN];
2139 char options[16] = "";
2140 int prom_fd = -1;
2141 int ret;
2142 int i;
2143
2144 if (strchr(alias, '/') != NULL)
2145 return (DEVFS_INVAL);
2146
2147 if (strlen(alias) > (MAXNAMELEN - 1))
2148 return (DEVFS_INVAL);
2149
2150 if (ret_buf == NULL) {
2151 return (DEVFS_INVAL);
2152 }
2153
2154 prom_fd = prom_open(O_RDONLY);
2155 if (prom_fd < 0) {
2156 return (prom_fd);
2157 }
2158
2159 (void) strlcpy(alias_buf, alias, sizeof (alias_buf));
2160
2161 /*
2162 * save off any options (minor name info) that is
2163 * explicitly called out in the alias name
2164 */
2165 if ((options_ptr = strchr(alias_buf, ':')) != NULL) {
2166 *options_ptr = '\0';
2167 (void) strlcpy(options, ++options_ptr, sizeof (options));
2168 }
2169
2170 *alias_def = '\0';
2171
2172 ret = prom_find_aliases_node(prom_fd);
2173 if (ret == 0) {
2174 /*
2175 * we loop because one alias may define another... we have
2176 * to work our way down to an actual device definition.
2177 */
2178 for (i = 0; i <= 10; i++) {
2179 ret = prom_srch_node(prom_fd, alias_buf, alias_def);
2180 if (ret == -1) {
2181 break;
2182 }
2183 (void) strlcpy(alias_buf, alias_def,
2184 sizeof (alias_buf));
2185 if (*alias_def == '/') {
2186 break;
2187 }
2188
2189 /*
2190 * save off any explicit options (minor name info)
2191 * if none has been encountered yet
2192 */
2193 if (options_ptr == NULL) {
2194 options_ptr = strchr(alias_buf, ':');
2195 if (options_ptr != NULL) {
2196 *options_ptr = '\0';
2197 (void) strlcpy(options, ++options_ptr,
2198 sizeof (options));
2199 }
2200 }
2201 }
2202 }
2203 prom_close(prom_fd);
2204
2205 /* error */
2206 if (ret == -1) {
2207 return (ret);
2208 }
2209
2210 (void) strlcpy(ret_buf, alias_def, MAXPATHLEN);
2211
2212 /* override minor name information */
2213 if (options_ptr != NULL) {
2214 if ((options_ptr = strrchr(ret_buf, ':')) == NULL) {
2215 (void) strcat(ret_buf, ":");
2216 } else {
2217 *(++options_ptr) = '\0';
2218 }
2219 (void) strcat(ret_buf, options);
2220 }
2221 return (0);
2222 }
2223
2224 /*
2225 * search a prom node for a property name
2226 */
2227 static int
prom_srch_node(int fd,char * prop_name,char * ret_buf)2228 prom_srch_node(int fd, char *prop_name, char *ret_buf)
2229 {
2230 Oppbuf oppbuf;
2231 struct openpromio *opp = &(oppbuf.opp);
2232 int *ip = (int *)((void *)opp->oprom_array);
2233
2234 (void) memset(oppbuf.buf, 0, BUFSIZE);
2235 opp->oprom_size = MAXPROPSIZE;
2236 *ip = 0;
2237
2238 if (ioctl(fd, OPROMNXTPROP, opp) < 0)
2239 return (-1);
2240 if (opp->oprom_size == 0)
2241 return (-1);
2242
2243 while (strcmp(prop_name, opp->oprom_array) != 0) {
2244 opp->oprom_size = MAXPROPSIZE;
2245 if (ioctl(fd, OPROMNXTPROP, opp) < 0)
2246 return (-1);
2247 if (opp->oprom_size == 0)
2248 return (-1);
2249 }
2250 opp->oprom_size = MAXVALSIZE;
2251 if (ioctl(fd, OPROMGETPROP, opp) < 0)
2252 return (-1);
2253
2254 if (opp->oprom_size == 0)
2255 return (-1);
2256 (void) strlcpy(ret_buf, opp->oprom_array, MAXPATHLEN);
2257 return (0);
2258 }
2259
2260 /*
2261 * return the aliases node.
2262 */
2263 static int
prom_find_aliases_node(int fd)2264 prom_find_aliases_node(int fd)
2265 {
2266 uint_t child_id;
2267 char buf[MAXPATHLEN];
2268
2269 if ((child_id = prom_next_node(fd, 0)) == 0)
2270 return (-1);
2271 if ((child_id = prom_child_node(fd, child_id)) == 0)
2272 return (-1);
2273
2274 while (child_id != 0) {
2275 if (prom_srch_node(fd, "name", buf) == 0) {
2276 if (strcmp(buf, "aliases") == 0) {
2277 return (0);
2278 }
2279 }
2280 child_id = prom_next_node(fd, child_id);
2281 }
2282 return (-1);
2283 }
2284
2285 /*
2286 * get sibling
2287 */
2288 static uint_t
prom_next_node(int fd,uint_t node_id)2289 prom_next_node(int fd, uint_t node_id)
2290 {
2291 Oppbuf oppbuf;
2292 struct openpromio *opp = &(oppbuf.opp);
2293 uint_t *ip = (uint_t *)((void *)opp->oprom_array);
2294
2295 (void) memset(oppbuf.buf, 0, BUFSIZE);
2296 opp->oprom_size = MAXVALSIZE;
2297 *ip = node_id;
2298
2299 if (ioctl(fd, OPROMNEXT, opp) < 0)
2300 return (0);
2301
2302 return (*(uint_t *)((void *)opp->oprom_array));
2303 }
2304
2305 /*
2306 * get child
2307 */
2308 static uint_t
prom_child_node(int fd,uint_t node_id)2309 prom_child_node(int fd, uint_t node_id)
2310 {
2311 Oppbuf oppbuf;
2312 struct openpromio *opp = &(oppbuf.opp);
2313 uint_t *ip = (uint_t *)((void *)opp->oprom_array);
2314
2315 (void) memset(oppbuf.buf, 0, BUFSIZE);
2316 opp->oprom_size = MAXVALSIZE;
2317 *ip = node_id;
2318
2319 if (ioctl(fd, OPROMCHILD, opp) < 0)
2320 return (0);
2321
2322 return (*(uint_t *)((void *)opp->oprom_array));
2323 }
2324
2325 /*
2326 * only on sparc for now
2327 */
2328 int
devfs_bootdev_modifiable(void)2329 devfs_bootdev_modifiable(void)
2330 {
2331 #if defined(sparc)
2332 return (0);
2333 #else
2334 return (DEVFS_NOTSUP);
2335 #endif
2336 }
2337