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