6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libdevinfo / devfsinfo.c
bloba5e6915721b88d2b3a62d49025946c9d962418a4
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <stdio.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <thread.h>
34 #include <synch.h>
35 #include <sys/types.h>
36 #include <ctype.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <sys/modctl.h>
40 #include <errno.h>
41 #include <sys/openpromio.h>
42 #include <ftw.h>
43 #include <sys/ddi.h>
44 #include <sys/sunddi.h>
45 #include <limits.h>
47 #include "device_info.h"
50 * #define's
53 /* alias node searching return values */
54 #define NO_MATCH -1
55 #define EXACT_MATCH 1
56 #define INEXACT_MATCH 2
58 /* for prom io operations */
59 #define BUFSIZE 4096
60 #define MAXPROPSIZE 256
61 #define MAXVALSIZE (BUFSIZE - MAXPROPSIZE - sizeof (uint_t))
63 /* prom_obp_vers() return values */
64 #define OBP_OF 0x4 /* versions OBP 3.x */
65 #define OBP_NO_ALIAS_NODE 0x8 /* No alias node */
67 /* for nftw call */
68 #define FT_DEPTH 15
70 /* default logical and physical device name space */
71 #define DEV "/dev"
72 #define DEVICES "/devices"
74 /* for boot device identification on x86 */
75 #define CREATE_DISKMAP "/boot/solaris/bin/create_diskmap"
76 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
79 * internal structure declarations
82 /* for prom io functions */
83 typedef union {
84 char buf[BUFSIZE];
85 struct openpromio opp;
86 } Oppbuf;
88 /* used to manage lists of devices and aliases */
89 struct name_list {
90 char *name;
91 struct name_list *next;
95 * internal global data
98 /* global since nftw does not let you pass args to be updated */
99 static struct name_list **dev_list;
101 /* global since nftw does not let you pass args to be updated */
102 static struct boot_dev **bootdev_list;
104 /* mutex to protect bootdev_list and dev_list */
105 static mutex_t dev_lists_lk = DEFAULTMUTEX;
108 * internal function prototypes
111 static int prom_open(int);
112 static void prom_close(int);
113 static int is_openprom(int);
115 static int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf);
116 static int alias_to_prom_dev(char *alias, char *ret_buf);
117 static int prom_srch_aliases_by_def(char *, struct name_list **,
118 struct name_list **, int);
119 static int prom_find_aliases_node(int fd);
120 static int prom_compare_devs(char *prom_dev1, char *prom_dev2);
121 static int _prom_strcmp(char *s1, char *s2);
122 static int prom_srch_node(int fd, char *prop_name, char *ret_buf);
123 static uint_t prom_next_node(int fd, uint_t node_id);
124 static uint_t prom_child_node(int fd, uint_t node_id);
126 static int prom_obp_vers(void);
128 static void parse_name(char *, char **, char **, char **);
129 static int process_bootdev(const char *, const char *, struct boot_dev ***);
130 static int process_minor_name(char *dev_path, const char *default_root);
131 static void options_override(char *prom_path, char *alias_name);
132 static int devfs_phys_to_logical(struct boot_dev **bootdev_array,
133 const int array_size, const char *default_root);
134 static int check_logical_dev(const char *, const struct stat *, int,
135 struct FTW *);
136 static struct boot_dev *alloc_bootdev(char *);
137 static void free_name_list(struct name_list *list, int free_name);
138 static int insert_alias_list(struct name_list **list,
139 char *alias_name);
140 static int get_boot_dev_var(struct openpromio *opp);
141 static int set_boot_dev_var(struct openpromio *opp, char *bootdev);
142 static int devfs_prom_to_dev_name(char *prom_path, char *dev_path);
143 static int devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len);
146 * frees a list of paths from devfs_get_prom_name_list
148 static void
149 prom_list_free(char **prom_list)
151 int i = 0;
153 if (!prom_list)
154 return;
156 while (prom_list[i]) {
157 free(prom_list[i]);
158 i++;
160 free(prom_list);
163 static int
164 devfs_get_prom_name_list(const char *dev_name, char ***prom_list)
166 char *prom_path = NULL;
167 int count = 0; /* # of slots we will need in prom_list */
168 int ret, i, len;
169 char **list;
170 char *ptr;
172 if (dev_name == NULL)
173 return (DEVFS_INVAL);
174 if (*dev_name != '/')
175 return (DEVFS_INVAL);
176 if (prom_list == NULL)
177 return (DEVFS_INVAL);
180 * make sure we are on a machine which supports a prom
181 * and we have permission to use /dev/openprom
183 if ((ret = prom_obp_vers()) < 0)
184 return (ret);
185 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
186 return (DEVFS_NOMEM);
188 * get the prom path name
190 ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE);
191 if (ret < 0) {
192 free(prom_path);
193 return (ret);
195 /* deal with list of names */
196 for (i = 0; i < ret; i++)
197 if (prom_path[i] == '\0')
198 count++;
200 if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) {
201 free(prom_path);
202 return (DEVFS_NOMEM);
205 ptr = prom_path;
206 for (i = 0; i < count; i++) {
207 len = strlen(ptr) + 1;
208 if ((list[i] = (char *)malloc(len)) == NULL) {
209 free(prom_path);
210 free(list);
211 return (DEVFS_NOMEM);
213 (void) snprintf(list[i], len, "%s", ptr);
214 ptr += len;
217 free(prom_path);
219 *prom_list = list;
220 return (0);
224 * retrieve the list of prom representations for a given device name
225 * the list will be sorted in the following order: exact aliases,
226 * inexact aliases, prom device path name. If multiple matches occur
227 * for exact or inexact aliases, then these are sorted in collating
228 * order. The list is returned in prom_list
230 * the list may be restricted by specifying the correct flags in options.
233 devfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list)
235 char *prom_path = NULL;
236 int count = 0; /* # of slots we will need in prom_list */
237 char **alias_list = NULL;
238 char **list;
239 int ret;
241 if (dev_name == NULL) {
242 return (DEVFS_INVAL);
244 if (*dev_name != '/') {
245 return (DEVFS_INVAL);
247 if (prom_list == NULL) {
248 return (DEVFS_INVAL);
251 * make sure we are on a machine which supports a prom
252 * and we have permission to use /dev/openprom
254 if ((ret = prom_obp_vers()) < 0) {
255 return (ret);
257 if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) {
258 return (DEVFS_NOMEM);
261 * get the prom path name
263 ret = devfs_dev_to_prom_name((char *)dev_name, prom_path);
264 if (ret < 0) {
265 free(prom_path);
266 return (ret);
268 /* get the list of aliases (exact and inexact) */
269 if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) {
270 free(prom_path);
271 return (ret);
273 /* now figure out how big the return array must be */
274 if (alias_list != NULL) {
275 while (alias_list[count] != NULL) {
276 count++;
279 if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
280 count++; /* # of slots we will need in prom_list */
282 count++; /* for the null terminator */
284 /* allocate space for the list */
285 if ((list = (char **)calloc(count, sizeof (char *))) == NULL) {
286 count = 0;
287 while ((alias_list) && (alias_list[count] != NULL)) {
288 free(alias_list[count]);
289 count++;
291 free(alias_list);
292 free(prom_path);
293 return (DEVFS_NOMEM);
295 /* fill in the array and free the name list of aliases. */
296 count = 0;
297 while ((alias_list) && (alias_list[count] != NULL)) {
298 list[count] = alias_list[count];
299 count++;
301 if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
302 list[count] = prom_path;
304 if (alias_list != NULL) {
305 free(alias_list);
307 *prom_list = list;
308 return (0);
312 * Get a list prom-path translations for a solaris device.
314 * Returns the number of and all OBP paths and alias variants that
315 * reference the Solaris device path passed in.
318 devfs_get_all_prom_names(const char *solaris_path, uint_t flags,
319 struct devfs_prom_path **paths)
321 int ret, len, i, count = 0;
322 char *ptr, *prom_path;
323 struct devfs_prom_path *cur = NULL, *new;
325 if ((ret = prom_obp_vers()) < 0)
326 return (ret);
327 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
328 return (DEVFS_NOMEM);
330 if ((ret = devfs_dev_to_prom_names((char *)solaris_path,
331 prom_path, MAXVALSIZE)) < 0) {
332 free(prom_path);
333 return (ret);
336 for (i = 0; i < ret; i++)
337 if (prom_path[i] == '\0')
338 count++;
340 *paths = NULL;
341 ptr = prom_path;
342 for (i = 0; i < count; i++) {
343 if ((new = (struct devfs_prom_path *)calloc(
344 sizeof (struct devfs_prom_path), 1)) == NULL) {
345 free(prom_path);
346 devfs_free_all_prom_names(*paths);
347 return (DEVFS_NOMEM);
350 if (cur == NULL)
351 *paths = new;
352 else
353 cur->next = new;
354 cur = new;
356 len = strlen(ptr) + 1;
357 if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) {
358 free(prom_path);
359 devfs_free_all_prom_names(*paths);
360 return (DEVFS_NOMEM);
363 (void) snprintf(cur->obp_path, len, "%s", ptr);
364 ptr += len;
365 if ((ret = prom_dev_to_alias(cur->obp_path, flags,
366 &(cur->alias_list))) < 0) {
367 free(prom_path);
368 devfs_free_all_prom_names(*paths);
369 return (ret);
373 free(prom_path);
374 return (count);
377 void
378 devfs_free_all_prom_names(struct devfs_prom_path *paths)
380 int i;
382 if (paths == NULL)
383 return;
385 devfs_free_all_prom_names(paths->next);
387 if (paths->obp_path != NULL)
388 free(paths->obp_path);
390 if (paths->alias_list != NULL) {
391 for (i = 0; paths->alias_list[i] != NULL; i++)
392 if (paths->alias_list[i] != NULL)
393 free(paths->alias_list[i]);
395 free(paths->alias_list);
398 free(paths);
402 * Accepts a device name as an input argument. Uses this to set the
403 * boot-device (or like) variable
405 * By default, this routine prepends to the list and converts the
406 * logical device name to its most compact prom representation.
407 * Available options include: converting the device name to a prom
408 * path name (but not an alias) or performing no conversion at all;
409 * overwriting the existing contents of boot-device rather than
410 * prepending.
413 devfs_bootdev_set_list(const char *dev_name, const uint_t options)
415 char *prom_path;
416 char *new_bootdev;
417 char *ptr;
418 char **alias_list = NULL;
419 char **prom_list = NULL;
420 Oppbuf oppbuf;
421 struct openpromio *opp = &(oppbuf.opp);
422 int ret, len, i, j;
424 if (devfs_bootdev_modifiable() != 0) {
425 return (DEVFS_NOTSUP);
427 if (dev_name == NULL) {
428 return (DEVFS_INVAL);
430 if (strlen(dev_name) >= MAXPATHLEN)
431 return (DEVFS_INVAL);
433 if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) {
434 return (DEVFS_INVAL);
436 if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) {
437 return (DEVFS_INVAL);
440 * if we are prepending, make sure that this obp rev
441 * supports multiple boot device entries.
443 ret = prom_obp_vers();
444 if (ret < 0) {
445 return (ret);
448 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) {
449 return (DEVFS_NOMEM);
451 if (options & BOOTDEV_LITERAL) {
452 (void) strcpy(prom_path, dev_name);
453 } else {
454 /* need to convert to prom representation */
455 ret = devfs_get_prom_name_list(dev_name, &prom_list);
456 if (ret < 0) {
457 free(prom_path);
458 return (ret);
461 len = MAXVALSIZE;
462 i = 0;
463 ptr = prom_path;
464 while (prom_list && prom_list[i]) {
465 if (!(options & BOOTDEV_PROMDEV)) {
466 ret = prom_dev_to_alias(prom_list[i], 0,
467 &alias_list);
468 if (ret < 0) {
469 free(prom_path);
470 prom_list_free(prom_list);
471 return (ret);
473 if ((alias_list != NULL) &&
474 (alias_list[0] != NULL)) {
475 (void) snprintf(ptr, len, "%s ",
476 alias_list[0]);
477 for (ret = 0; alias_list[ret] != NULL;
478 ret++)
479 free(alias_list[ret]);
480 } else {
481 (void) snprintf(ptr, len, "%s ",
482 prom_list[i]);
484 if (alias_list != NULL)
485 free(alias_list);
486 } else {
487 (void) snprintf(ptr, len, "%s ", prom_list[i]);
489 j = strlen(ptr);
490 len -= j;
491 ptr += j;
492 i++;
494 ptr--;
495 *ptr = NULL;
497 prom_list_free(prom_list);
499 if (options & BOOTDEV_OVERWRITE) {
500 new_bootdev = prom_path;
501 } else {
502 /* retrieve the current value of boot-device */
503 ret = get_boot_dev_var(opp);
504 if (ret < 0) {
505 free(prom_path);
506 return (ret);
508 /* prepend new entry - deal with duplicates */
509 new_bootdev = (char *)malloc(strlen(opp->oprom_array)
510 + strlen(prom_path) + 2);
511 if (new_bootdev == NULL) {
512 free(prom_path);
513 return (DEVFS_NOMEM);
515 (void) strcpy(new_bootdev, prom_path);
516 if (opp->oprom_size > 0) {
517 for (ptr = strtok(opp->oprom_array, " "); ptr != NULL;
518 ptr = strtok(NULL, " ")) {
519 /* we strip out duplicates */
520 if (strcmp(prom_path, ptr) == 0) {
521 continue;
523 (void) strcat(new_bootdev, " ");
524 (void) strcat(new_bootdev, ptr);
529 /* now set the new value */
530 ret = set_boot_dev_var(opp, new_bootdev);
532 if (options & BOOTDEV_OVERWRITE) {
533 free(prom_path);
534 } else {
535 free(new_bootdev);
536 free(prom_path);
539 return (ret);
543 * sets the string bootdev as the new value for boot-device
545 static int
546 set_boot_dev_var(struct openpromio *opp, char *bootdev)
548 int prom_fd;
549 int i;
550 int ret;
551 char *valbuf;
552 char *save_bootdev;
553 char *bootdev_variables[] = {
554 "boot-device",
555 "bootdev",
556 "boot-from",
557 NULL
559 int found = 0;
560 int *ip = (int *)((void *)opp->oprom_array);
562 /* query the prom */
563 prom_fd = prom_open(O_RDWR);
564 if (prom_fd < 0) {
565 return (prom_fd);
568 /* get the diagnostic-mode? property */
569 (void) strcpy(opp->oprom_array, "diagnostic-mode?");
570 opp->oprom_size = MAXVALSIZE;
571 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
572 if ((opp->oprom_size > 0) &&
573 (strcmp(opp->oprom_array, "true") == 0)) {
574 prom_close(prom_fd);
575 return (DEVFS_ERR);
578 /* get the diag-switch? property */
579 (void) strcpy(opp->oprom_array, "diag-switch?");
580 opp->oprom_size = MAXVALSIZE;
581 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
582 if ((opp->oprom_size > 0) &&
583 (strcmp(opp->oprom_array, "true") == 0)) {
584 prom_close(prom_fd);
585 return (DEVFS_ERR);
589 * look for one of the following properties in order:
590 * boot-device
591 * bootdev
592 * boot-from
594 * Use the first one that we find.
596 *ip = 0;
597 opp->oprom_size = MAXPROPSIZE;
598 while ((opp->oprom_size != 0) && (!found)) {
599 opp->oprom_size = MAXPROPSIZE;
600 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
601 break;
603 for (i = 0; bootdev_variables[i] != NULL; i++) {
604 if (strcmp(opp->oprom_array, bootdev_variables[i])
605 == 0) {
606 found = 1;
607 break;
611 if (found) {
612 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
613 opp->oprom_size = MAXVALSIZE;
614 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
615 prom_close(prom_fd);
616 return (DEVFS_NOTSUP);
618 } else {
619 prom_close(prom_fd);
620 return (DEVFS_NOTSUP);
623 /* save the old copy in case we fail */
624 if ((save_bootdev = strdup(opp->oprom_array)) == NULL) {
625 prom_close(prom_fd);
626 return (DEVFS_NOMEM);
628 /* set up the new value of boot-device */
629 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
630 valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
631 (void) strcpy(valbuf, bootdev);
633 opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
635 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
636 free(save_bootdev);
637 prom_close(prom_fd);
638 return (DEVFS_ERR);
642 * now read it back to make sure it took
644 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
645 opp->oprom_size = MAXVALSIZE;
646 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
647 if (_prom_strcmp(opp->oprom_array, bootdev) == 0) {
648 /* success */
649 free(save_bootdev);
650 prom_close(prom_fd);
651 return (0);
653 /* deal with setting it to "" */
654 if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) {
655 /* success */
656 free(save_bootdev);
657 prom_close(prom_fd);
658 return (0);
662 * something did not take - write out the old value and
663 * hope that we can restore things...
665 * unfortunately, there is no way for us to differentiate
666 * whether we exceeded the maximum number of characters
667 * allowable. The limit varies from prom rev to prom
668 * rev, and on some proms, when the limit is
669 * exceeded, whatever was in the
670 * boot-device variable becomes unreadable.
672 * so if we fail, we will assume we ran out of room. If we
673 * not able to restore the original setting, then we will
674 * return DEVFS_ERR instead.
676 ret = DEVFS_LIMIT;
677 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
678 valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
679 (void) strcpy(valbuf, save_bootdev);
681 opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
683 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
684 ret = DEVFS_ERR;
686 free(save_bootdev);
687 prom_close(prom_fd);
688 return (ret);
691 * retrieve the current value for boot-device
693 static int
694 get_boot_dev_var(struct openpromio *opp)
696 int prom_fd;
697 int i;
698 char *bootdev_variables[] = {
699 "boot-device",
700 "bootdev",
701 "boot-from",
702 NULL
704 int found = 0;
705 int *ip = (int *)((void *)opp->oprom_array);
707 /* query the prom */
708 prom_fd = prom_open(O_RDONLY);
709 if (prom_fd < 0) {
710 return (prom_fd);
713 /* get the diagnostic-mode? property */
714 (void) strcpy(opp->oprom_array, "diagnostic-mode?");
715 opp->oprom_size = MAXVALSIZE;
716 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
717 if ((opp->oprom_size > 0) &&
718 (strcmp(opp->oprom_array, "true") == 0)) {
719 prom_close(prom_fd);
720 return (DEVFS_ERR);
723 /* get the diag-switch? property */
724 (void) strcpy(opp->oprom_array, "diag-switch?");
725 opp->oprom_size = MAXVALSIZE;
726 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
727 if ((opp->oprom_size > 0) &&
728 (strcmp(opp->oprom_array, "true") == 0)) {
729 prom_close(prom_fd);
730 return (DEVFS_ERR);
734 * look for one of the following properties in order:
735 * boot-device
736 * bootdev
737 * boot-from
739 * Use the first one that we find.
741 *ip = 0;
742 opp->oprom_size = MAXPROPSIZE;
743 while ((opp->oprom_size != 0) && (!found)) {
744 opp->oprom_size = MAXPROPSIZE;
745 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
746 break;
748 for (i = 0; bootdev_variables[i] != NULL; i++) {
749 if (strcmp(opp->oprom_array, bootdev_variables[i])
750 == 0) {
751 found = 1;
752 break;
756 if (found) {
757 (void) strcpy(opp->oprom_array, bootdev_variables[i]);
758 opp->oprom_size = MAXVALSIZE;
759 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
760 prom_close(prom_fd);
761 return (DEVFS_ERR);
763 /* boot-device exists but contains nothing */
764 if (opp->oprom_size == 0) {
765 *opp->oprom_array = '\0';
767 } else {
768 prom_close(prom_fd);
769 return (DEVFS_NOTSUP);
771 prom_close(prom_fd);
772 return (0);
775 #ifndef __sparc
776 static FILE *
777 open_diskmap(void)
779 FILE *fp;
780 char cmd[PATH_MAX];
782 /* make sure we have a map file */
783 fp = fopen(GRUBDISK_MAP, "r");
784 if (fp == NULL) {
785 (void) snprintf(cmd, sizeof (cmd),
786 "%s > /dev/null", CREATE_DISKMAP);
787 (void) system(cmd);
788 fp = fopen(GRUBDISK_MAP, "r");
790 return (fp);
793 static int
794 find_x86_boot_device(struct openpromio *opp)
796 int ret = DEVFS_ERR;
797 char *cp, line[MAXVALSIZE + 6];
798 FILE *file;
800 file = open_diskmap();
801 if (file == NULL)
802 return (DEVFS_ERR);
804 while (fgets(line, MAXVALSIZE + 6, file)) {
805 if (strncmp(line, "0 ", 2) != 0)
806 continue;
807 /* drop new-line */
808 line[strlen(line) - 1] = '\0';
810 * an x86 BIOS only boots a disk, not a partition
811 * or a slice, so hard-code :q (p0)
813 cp = strchr(line + 2, ' ');
814 if (cp == NULL)
815 break;
816 (void) snprintf(opp->oprom_array, MAXVALSIZE,
817 "%s:q", cp + 1);
818 opp->oprom_size = MAXVALSIZE;
819 ret = 0;
820 break;
822 (void) fclose(file);
823 return (ret);
825 #endif /* ndef __sparc */
828 * retrieve the list of entries in the boot-device configuration
829 * variable. An array of boot_dev structs will be created, one entry
830 * for each device name in the boot-device variable. Each entry
831 * in the array will contain the logical device representation of the
832 * boot-device entry, if any.
834 * default_root. if set, is used to locate logical device entries in
835 * directories other than /dev
838 devfs_bootdev_get_list(const char *default_root,
839 struct boot_dev ***bootdev_list)
841 Oppbuf oppbuf;
842 struct openpromio *opp = &(oppbuf.opp);
843 int i;
844 struct boot_dev **tmp_list;
846 if (default_root == NULL) {
847 default_root = "";
848 } else if (*default_root != '/') {
849 return (DEVFS_INVAL);
852 if (bootdev_list == NULL) {
853 return (DEVFS_INVAL);
856 /* get the boot-device variable */
857 #if defined(sparc)
858 i = get_boot_dev_var(opp);
859 #else
860 i = find_x86_boot_device(opp);
861 #endif
862 if (i < 0) {
863 return (i);
865 /* now try to translate each entry to a logical device. */
866 i = process_bootdev(opp->oprom_array, default_root, &tmp_list);
867 if (i == 0) {
868 *bootdev_list = tmp_list;
869 return (0);
870 } else {
871 return (i);
876 * loop thru the list of entries in a boot-device configuration
877 * variable.
879 static int
880 process_bootdev(const char *bootdevice, const char *default_root,
881 struct boot_dev ***list)
883 int i;
884 char *entry, *ptr;
885 char prom_path[MAXPATHLEN];
886 char ret_buf[MAXPATHLEN];
887 struct boot_dev **bootdev_array;
888 int num_entries = 0;
889 int found = 0;
890 int vers;
892 if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) {
893 return (DEVFS_NOMEM);
895 /* count the number of entries */
896 (void) strcpy(entry, bootdevice);
897 for (ptr = strtok(entry, " "); ptr != NULL;
898 ptr = strtok(NULL, " ")) {
899 num_entries++;
901 (void) strcpy(entry, bootdevice);
903 bootdev_array = (struct boot_dev **)
904 calloc((size_t)num_entries + 1, sizeof (struct boot_dev *));
906 if (bootdev_array == NULL) {
907 free(entry);
908 return (DEVFS_NOMEM);
911 vers = prom_obp_vers();
912 if (vers < 0) {
913 free(entry);
914 return (vers);
917 /* for each entry in boot-device, do... */
918 for (ptr = strtok(entry, " "), i = 0; ptr != NULL;
919 ptr = strtok(NULL, " "), i++) {
921 if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) {
922 devfs_bootdev_free_list(bootdev_array);
923 free(entry);
924 return (DEVFS_NOMEM);
928 * prom boot-device may be aliased, so we need to do
929 * the necessary prom alias to dev translation.
931 if (*ptr != '/') {
932 if (alias_to_prom_dev(ptr, prom_path) < 0) {
933 continue;
935 } else {
936 (void) strcpy(prom_path, ptr);
939 /* now we have a prom device path - convert to a devfs name */
940 if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) {
941 continue;
944 /* append any default minor names necessary */
945 if (process_minor_name(ret_buf, default_root) < 0) {
946 continue;
948 found = 1;
951 * store the physical device path for now - when
952 * we are all done with the entries, we will convert
953 * these to their logical device name equivalents
955 bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf);
958 * Convert all of the boot-device entries that translated to a
959 * physical device path in /devices to a logical device path
960 * in /dev (note that there may be several logical device paths
961 * associated with a single physical device path - return them all
963 if (found) {
964 if (devfs_phys_to_logical(bootdev_array, num_entries,
965 default_root) < 0) {
966 devfs_bootdev_free_list(bootdev_array);
967 bootdev_array = NULL;
970 free(entry);
971 *list = bootdev_array;
972 return (0);
976 * We may get a device path from the prom that has no minor name
977 * information included in it. Since this device name will not
978 * correspond directly to a physical device in /devices, we do our
979 * best to append what the default minor name should be and try this.
981 * For sparc: we append slice 0 (:a).
982 * For x86: we append fdisk partition 0 (:q).
984 static int
985 process_minor_name(char *dev_path, const char *root)
987 char *cp;
988 #if defined(sparc)
989 const char *default_minor_name = "a";
990 #else
991 const char *default_minor_name = "q";
992 #endif
993 int n;
994 struct stat stat_buf;
995 char path[MAXPATHLEN];
997 (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
999 * if the device file already exists as given to us, there
1000 * is nothing to do but return.
1002 if (stat(path, &stat_buf) == 0) {
1003 return (0);
1006 * if there is no ':' after the last '/' character, or if there is
1007 * a ':' with no specifier, append the default segment specifier
1008 * ; if there is a ':' followed by a digit, this indicates
1009 * a partition number (which does not map into the /devices name
1010 * space), so strip the number and replace it with the letter
1011 * that represents the partition index
1013 if ((cp = strrchr(dev_path, '/')) != NULL) {
1014 if ((cp = strchr(cp, ':')) == NULL) {
1015 (void) strcat(dev_path, ":");
1016 (void) strcat(dev_path, default_minor_name);
1017 } else if (*++cp == '\0') {
1018 (void) strcat(dev_path, default_minor_name);
1019 } else if (isdigit(*cp)) {
1020 n = atoi(cp);
1021 /* make sure to squash the digit */
1022 *cp = '\0';
1023 switch (n) {
1024 case 0: (void) strcat(dev_path, "q");
1025 break;
1026 case 1: (void) strcat(dev_path, "r");
1027 break;
1028 case 2: (void) strcat(dev_path, "s");
1029 break;
1030 case 3: (void) strcat(dev_path, "t");
1031 break;
1032 case 4: (void) strcat(dev_path, "u");
1033 break;
1034 default: (void) strcat(dev_path, "a");
1035 break;
1040 * see if we can find something now.
1042 (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
1044 if (stat(path, &stat_buf) == 0) {
1045 return (0);
1046 } else {
1047 return (-1);
1052 * for each entry in bootdev_array, convert the physical device
1053 * representation of the boot-device entry to one or more logical device
1054 * entries. We use the hammer method - walk through the logical device
1055 * name space looking for matches (/dev). We use nftw to do this.
1057 static int
1058 devfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size,
1059 const char *default_root)
1061 int walk_flags = FTW_PHYS | FTW_MOUNT;
1062 char *full_path;
1063 struct name_list *list;
1064 int count, i;
1065 char **dev_name_array;
1066 size_t default_root_len;
1067 char *dev_dir = DEV;
1068 int len;
1070 if (array_size < 0) {
1071 return (-1);
1074 if (bootdev_array == NULL) {
1075 return (-1);
1077 if (default_root == NULL) {
1078 return (-1);
1080 default_root_len = strlen(default_root);
1081 if ((default_root_len != 0) && (*default_root != '/')) {
1082 return (-1);
1085 /* short cut for an empty array */
1086 if (*bootdev_array == NULL) {
1087 return (0);
1090 /* tell nftw where to start (default: /dev) */
1091 len = default_root_len + strlen(dev_dir) + 1;
1092 if ((full_path = (char *)malloc(len)) == NULL) {
1093 return (-1);
1097 * if the default root path is terminated with a /, we have to
1098 * make sure we don't end up with one too many slashes in the
1099 * path we are building.
1101 if ((default_root_len > (size_t)0) &&
1102 (default_root[default_root_len - 1] == '/')) {
1103 (void) snprintf(full_path, len, "%s%s", default_root,
1104 &dev_dir[1]);
1105 } else {
1106 (void) snprintf(full_path, len, "%s%s", default_root, dev_dir);
1110 * we need to muck with global data to make nftw work
1111 * so single thread access
1113 (void) mutex_lock(&dev_lists_lk);
1116 * set the global vars bootdev_list and dev_list for use by nftw
1117 * dev_list is an array of lists - one for each boot-device
1118 * entry. The nftw function will create a list of logical device
1119 * entries for each boot-device and put all of the lists in
1120 * dev_list.
1122 dev_list = (struct name_list **)
1123 calloc(array_size, sizeof (struct name_list *));
1124 if (dev_list == NULL) {
1125 free(full_path);
1126 (void) mutex_unlock(&dev_lists_lk);
1127 return (-1);
1129 bootdev_list = bootdev_array;
1131 if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) {
1132 bootdev_list = NULL;
1133 free(full_path);
1134 for (i = 0; i < array_size; i++) {
1135 free_name_list(dev_list[i], 1);
1137 /* don't free dev_list here because it's been handed off */
1138 dev_list = NULL;
1139 (void) mutex_unlock(&dev_lists_lk);
1140 return (-1);
1144 * now we have a filled in dev_list. So for each logical device
1145 * list in dev_list, count the number of entries in the list,
1146 * create an array of strings of logical devices, and save in the
1147 * corresponding boot_dev structure.
1149 for (i = 0; i < array_size; i++) {
1150 /* get the next list */
1151 list = dev_list[i];
1152 count = 0;
1154 /* count the number of entries in the list */
1155 while (list != NULL) {
1156 count++;
1157 list = list->next;
1159 if ((dev_name_array =
1160 (char **)malloc((count + 1) * sizeof (char *)))
1161 == NULL) {
1162 continue;
1164 list = dev_list[i];
1165 count = 0;
1167 /* fill in the array */
1168 while (list != NULL) {
1169 dev_name_array[count] = list->name;
1170 count++;
1171 list = list->next;
1175 * null terminate the array
1177 dev_name_array[count] = NULL;
1178 if ((bootdev_array[i] != NULL) && (bootdev_array[i]->
1179 bootdev_trans[0] != NULL)) {
1180 free(bootdev_array[i]->bootdev_trans[0]);
1182 if (bootdev_array[i] != NULL) {
1183 free(bootdev_array[i]->bootdev_trans);
1184 bootdev_array[i]->bootdev_trans = dev_name_array;
1187 bootdev_list = NULL;
1188 free(full_path);
1189 for (i = 0; i < array_size; i++) {
1190 free_name_list(dev_list[i], 0);
1192 free(dev_list);
1193 dev_list = NULL;
1194 (void) mutex_unlock(&dev_lists_lk);
1195 return (0);
1198 * nftw function
1199 * for a logical dev entry, it walks the list of boot-devices and
1200 * sees if there are any matches. If so, it saves the logical device
1201 * name off in the appropriate list in dev_list
1203 /* ARGSUSED */
1204 static int
1205 check_logical_dev(const char *node, const struct stat *node_stat, int flags,
1206 struct FTW *ftw_info)
1208 char link_buf[MAXPATHLEN];
1209 int link_buf_len;
1210 char *name;
1211 struct name_list *dev;
1212 char *physdev;
1213 int i;
1215 if (flags != FTW_SL) {
1216 return (0);
1219 if ((link_buf_len = readlink(node, (void *)link_buf, MAXPATHLEN))
1220 == -1) {
1221 return (0);
1223 link_buf[link_buf_len] = '\0';
1224 if ((name = strstr(link_buf, DEVICES)) == NULL) {
1225 return (0);
1227 name = (char *)(name + strlen(DEVICES));
1229 for (i = 0; bootdev_list[i] != NULL; i++) {
1230 if (bootdev_list[i]->bootdev_trans[0] == NULL) {
1231 continue;
1234 * compare the contents of the link with the physical
1235 * device representation of this boot device
1237 physdev = bootdev_list[i]->bootdev_trans[0];
1238 if ((strcmp(name, physdev) == 0) &&
1239 (strlen(name) == strlen(physdev))) {
1240 if ((dev = (struct name_list *)
1241 malloc(sizeof (struct name_list))) == NULL) {
1242 return (-1);
1244 if ((dev->name = strdup(node)) == NULL) {
1245 free(dev);
1246 return (-1);
1248 if (dev_list[i] == NULL) {
1249 dev_list[i] = dev;
1250 dev_list[i]->next = NULL;
1251 } else {
1252 dev->next = dev_list[i];
1253 dev_list[i] = dev;
1257 return (0);
1261 * frees a list of boot_dev struct pointers
1263 void
1264 devfs_bootdev_free_list(struct boot_dev **array)
1266 int i = 0;
1267 int j;
1269 if (array == NULL) {
1270 return;
1273 while (array[i] != NULL) {
1274 free(array[i]->bootdev_element);
1275 j = 0;
1276 while (array[i]->bootdev_trans[j] != NULL) {
1277 free(array[i]->bootdev_trans[j++]);
1279 free(array[i]->bootdev_trans);
1280 free(array[i]);
1281 i++;
1283 free(array);
1286 * allocates a boot_dev struct and fills in the bootdev_element portion
1288 static struct boot_dev *
1289 alloc_bootdev(char *entry_name)
1291 struct boot_dev *entry;
1293 entry = (struct boot_dev *)calloc(1, sizeof (struct boot_dev));
1295 if (entry == NULL) {
1296 return (NULL);
1298 if ((entry->bootdev_element = strdup(entry_name)) == NULL) {
1299 free(entry);
1300 return (NULL);
1303 * Allocate room for 1 name and a null terminator - the caller of
1304 * this function will need the first slot right away.
1306 if ((entry->bootdev_trans = (char **)calloc(2, sizeof (char *)))
1307 == NULL) {
1308 free(entry->bootdev_element);
1309 free(entry);
1310 return (NULL);
1312 return (entry);
1316 * will come back with a concatenated list of paths
1319 devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len)
1321 Oppbuf oppbuf;
1322 struct openpromio *opp = &(oppbuf.opp);
1323 int prom_fd;
1324 int ret = DEVFS_INVAL;
1325 int i;
1327 if (prom_path == NULL) {
1328 return (DEVFS_INVAL);
1330 if (dev_path == NULL) {
1331 return (DEVFS_INVAL);
1333 if (strlen(dev_path) >= MAXPATHLEN)
1334 return (DEVFS_INVAL);
1336 if (*dev_path != '/')
1337 return (DEVFS_INVAL);
1339 prom_fd = prom_open(O_RDONLY);
1340 if (prom_fd < 0) {
1341 return (prom_fd);
1344 /* query the prom */
1345 (void) snprintf(opp->oprom_array, MAXVALSIZE, "%s", dev_path);
1346 opp->oprom_size = MAXVALSIZE;
1348 if (ioctl(prom_fd, OPROMDEV2PROMNAME, opp) == 0) {
1349 prom_close(prom_fd);
1351 /* return the prom path in prom_path */
1353 i = len - opp->oprom_size;
1354 if (i < 0) {
1355 bcopy(opp->oprom_array, prom_path, len);
1356 prom_path[len - 1] = NULL;
1357 return (len);
1358 } else {
1359 bcopy(opp->oprom_array, prom_path, len);
1360 return (opp->oprom_size);
1364 * either the prom does not support this ioctl or the argument
1365 * was invalid.
1367 if (errno == ENXIO) {
1368 ret = DEVFS_NOTSUP;
1370 prom_close(prom_fd);
1371 return (ret);
1375 * Convert a physical or logical device name to a name the prom would
1376 * understand. Fail if this platform does not support a prom or if
1377 * the device does not correspond to a valid prom device.
1378 * dev_path should be the name of a device in the logical or
1379 * physical device namespace.
1380 * prom_path is the prom version of the device name
1381 * prom_path must be large enough to contain the result and is
1382 * supplied by the user.
1384 * This routine only supports converting leaf device paths
1387 devfs_dev_to_prom_name(char *dev_path, char *prom_path)
1389 int rval;
1391 rval = devfs_dev_to_prom_names(dev_path, prom_path, MAXPATHLEN);
1393 if (rval < 0)
1394 return (rval);
1395 else
1396 return (0);
1400 * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs
1401 * path to a driver name.
1402 * devfs_path - the pathname of interest. This must be the physcical device
1403 * path with the mount point prefix (ie. /devices) stripped off.
1404 * drv_buf - user supplied buffer - the driver name will be stored here.
1406 * If the prom lookup fails, we return the name of the last component in
1407 * the pathname. This routine is useful for looking up driver names
1408 * associated with generically named devices.
1410 * This routine returns driver names that have aliases resolved.
1413 devfs_path_to_drv(char *devfs_path, char *drv_buf)
1415 Oppbuf oppbuf;
1416 struct openpromio *opp = &(oppbuf.opp);
1417 char *slash, *colon, *dev_addr;
1418 char driver_path[MAXPATHLEN];
1419 int prom_fd;
1421 if (drv_buf == NULL) {
1422 return (-1);
1424 if (devfs_path == NULL) {
1425 return (-1);
1428 if (strlen(devfs_path) >= MAXPATHLEN)
1429 return (-1);
1431 if (*devfs_path != '/')
1432 return (-1);
1435 /* strip off any minor node info at the end of the path */
1436 (void) strcpy(driver_path, devfs_path);
1437 slash = strrchr(driver_path, '/');
1438 if (slash == NULL)
1439 return (-1);
1440 colon = strrchr(slash, ':');
1441 if (colon != NULL)
1442 *colon = '\0';
1444 /* query the prom */
1445 if ((prom_fd = prom_open(O_RDONLY)) >= 0) {
1446 (void) strcpy(opp->oprom_array, driver_path);
1447 opp->oprom_size = MAXVALSIZE;
1449 if (ioctl(prom_fd, OPROMPATH2DRV, opp) == 0) {
1450 prom_close(prom_fd);
1451 /* return the driver name in drv_buf */
1452 (void) strcpy(drv_buf, opp->oprom_array);
1453 return (0);
1455 prom_close(prom_fd);
1456 } else if (prom_fd != DEVFS_NOTSUP)
1457 return (-1);
1459 * If we get here, then either:
1460 * 1. this platform does not support an openprom driver
1461 * 2. we were asked to look up a device the prom does
1462 * not know about (e.g. a pseudo device)
1463 * In this case, we use the last component of the devfs path
1464 * name and try to derive the driver name
1467 /* use the last component of devfs_path as the driver name */
1468 if ((dev_addr = strrchr(slash, '@')) != NULL)
1469 *dev_addr = '\0';
1470 slash++;
1472 /* use opp->oprom_array as a buffer */
1473 (void) strcpy(opp->oprom_array, slash);
1474 if (devfs_resolve_aliases(opp->oprom_array) == NULL)
1475 return (-1);
1476 (void) strcpy(drv_buf, opp->oprom_array);
1477 return (0);
1481 * These modctl calls do the equivalent of:
1482 * ddi_name_to_major()
1483 * ddi_major_to_name()
1484 * This results in two things:
1485 * - the driver name must be a valid one
1486 * - any driver aliases are resolved.
1487 * drv is overwritten with the resulting name.
1489 char *
1490 devfs_resolve_aliases(char *drv)
1492 major_t maj;
1493 char driver_name[MAXNAMELEN + 1];
1495 if (drv == NULL) {
1496 return (NULL);
1499 if (modctl(MODGETMAJBIND, drv, strlen(drv) + 1, &maj) < 0)
1500 return (NULL);
1501 else if (modctl(MODGETNAME, driver_name, sizeof (driver_name), &maj)
1502 < 0) {
1503 return (NULL);
1504 } else {
1505 (void) strcpy(drv, driver_name);
1506 return (drv);
1511 * open the openprom device. and verify that we are on an
1512 * OBP/1275 OF machine. If the prom does not exist, then we
1513 * return an error
1515 static int
1516 prom_open(int oflag)
1518 int prom_fd = -1;
1519 char *promdev = "/dev/openprom";
1521 while (prom_fd < 0) {
1522 if ((prom_fd = open(promdev, oflag)) < 0) {
1523 if (errno == EAGAIN) {
1524 (void) sleep(5);
1525 continue;
1527 if ((errno == ENXIO) || (errno == ENOENT)) {
1528 return (DEVFS_NOTSUP);
1530 if ((errno == EPERM) || (errno == EACCES)) {
1531 return (DEVFS_PERM);
1533 return (DEVFS_ERR);
1534 } else
1535 break;
1537 if (is_openprom(prom_fd))
1538 return (prom_fd);
1539 else {
1540 prom_close(prom_fd);
1541 return (DEVFS_ERR);
1545 static void
1546 prom_close(int prom_fd)
1548 (void) close(prom_fd);
1552 * is this an OBP/1275 OF machine?
1554 static int
1555 is_openprom(int prom_fd)
1557 Oppbuf oppbuf;
1558 struct openpromio *opp = &(oppbuf.opp);
1559 unsigned int i;
1561 opp->oprom_size = MAXVALSIZE;
1562 if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
1563 return (0);
1565 i = (unsigned int)((unsigned char)opp->oprom_array[0]);
1566 return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
1570 * convert a prom device path name to an equivalent physical device
1571 * path in the kernel.
1573 static int
1574 devfs_prom_to_dev_name(char *prom_path, char *dev_path)
1576 Oppbuf oppbuf;
1577 struct openpromio *opp = &(oppbuf.opp);
1578 int prom_fd;
1579 int ret = DEVFS_INVAL;
1581 if (dev_path == NULL) {
1582 return (DEVFS_INVAL);
1584 if (prom_path == NULL) {
1585 return (DEVFS_INVAL);
1587 if (strlen(prom_path) >= MAXPATHLEN)
1588 return (DEVFS_INVAL);
1590 if (*prom_path != '/') {
1591 return (DEVFS_INVAL);
1594 /* query the prom */
1595 prom_fd = prom_open(O_RDONLY);
1596 if (prom_fd < 0) {
1597 return (prom_fd);
1599 (void) strcpy(opp->oprom_array, prom_path);
1600 opp->oprom_size = MAXVALSIZE;
1602 if (ioctl(prom_fd, OPROMPROM2DEVNAME, opp) == 0) {
1603 prom_close(prom_fd);
1605 * success
1606 * return the prom path in prom_path
1608 (void) strcpy(dev_path, opp->oprom_array);
1609 return (0);
1612 * either the argument was not a valid name or the openprom
1613 * driver does not support this ioctl.
1615 if (errno == ENXIO) {
1616 ret = DEVFS_NOTSUP;
1618 prom_close(prom_fd);
1619 return (ret);
1622 * convert a prom device path to a list of equivalent alias names
1623 * If there is no alias node, or there are no aliases that correspond
1624 * to dev, we return empty lists.
1626 static int
1627 prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf)
1629 struct name_list *exact_list;
1630 struct name_list *inexact_list;
1631 struct name_list *list;
1632 char *ptr;
1633 char **array;
1634 int prom_fd;
1635 int count;
1636 int vers;
1638 vers = prom_obp_vers();
1639 if (vers < 0) {
1640 return (vers);
1643 if (dev == NULL) {
1644 return (DEVFS_INVAL);
1647 if (*dev != '/')
1648 return (DEVFS_INVAL);
1650 if (strlen(dev) >= MAXPATHLEN)
1651 return (DEVFS_INVAL);
1653 if ((ptr = strchr(dev, ':')) != NULL) {
1654 if (strchr(ptr, '/') != NULL)
1655 return (DEVFS_INVAL);
1657 if (ret_buf == NULL) {
1658 return (DEVFS_INVAL);
1661 prom_fd = prom_open(O_RDONLY);
1662 if (prom_fd < 0) {
1663 return (prom_fd);
1666 (void) prom_srch_aliases_by_def(dev, &exact_list,
1667 &inexact_list, prom_fd);
1669 prom_close(prom_fd);
1671 if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) {
1672 free_name_list(exact_list, 1);
1673 exact_list = NULL;
1676 if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) {
1677 free_name_list(inexact_list, 1);
1678 inexact_list = NULL;
1681 count = 0;
1682 list = exact_list;
1683 while (list != NULL) {
1684 list = list->next;
1685 count++;
1687 list = inexact_list;
1688 while (list != NULL) {
1689 list = list->next;
1690 count++;
1693 if ((*ret_buf = (char **)malloc((count + 1) * sizeof (char *)))
1694 == NULL) {
1695 free_name_list(inexact_list, 1);
1696 free_name_list(exact_list, 1);
1697 return (DEVFS_NOMEM);
1700 array = *ret_buf;
1701 count = 0;
1702 list = exact_list;
1703 while (list != NULL) {
1704 array[count] = list->name;
1705 list = list->next;
1706 count++;
1708 list = inexact_list;
1709 while (list != NULL) {
1710 array[count] = list->name;
1711 list = list->next;
1712 count++;
1714 array[count] = NULL;
1715 free_name_list(inexact_list, 0);
1716 free_name_list(exact_list, 0);
1718 return (0);
1722 * determine the version of prom we are running on.
1723 * Also include any prom revision specific information.
1725 static int
1726 prom_obp_vers(void)
1728 Oppbuf oppbuf;
1729 struct openpromio *opp = &(oppbuf.opp);
1730 int prom_fd;
1731 static int version = 0;
1733 /* cache version */
1734 if (version > 0) {
1735 return (version);
1738 prom_fd = prom_open(O_RDONLY);
1739 if (prom_fd < 0) {
1740 return (prom_fd);
1743 opp->oprom_size = MAXVALSIZE;
1745 if ((ioctl(prom_fd, OPROMGETVERSION, opp)) < 0) {
1746 prom_close(prom_fd);
1747 return (DEVFS_ERR);
1749 prom_close(prom_fd);
1751 version |= OBP_OF;
1753 return (version);
1756 * search the aliases node by definition - compile a list of
1757 * alias names that are both exact and inexact matches.
1759 static int
1760 prom_srch_aliases_by_def(char *promdev_def, struct name_list **exact_list,
1761 struct name_list **inexact_list, int prom_fd)
1763 Oppbuf oppbuf;
1764 Oppbuf propdef_oppbuf;
1765 struct openpromio *opp = &(oppbuf.opp);
1766 struct openpromio *propdef_opp = &(propdef_oppbuf.opp);
1767 int *ip = (int *)((void *)opp->oprom_array);
1768 int ret;
1769 struct name_list *inexact_match = *inexact_list = NULL;
1770 struct name_list *exact_match = *exact_list = NULL;
1771 char alias_buf[MAXNAMELEN];
1772 int found = 0;
1774 (void) memset(oppbuf.buf, 0, BUFSIZE);
1775 opp->oprom_size = MAXPROPSIZE;
1776 *ip = 0;
1778 if ((ret = ioctl(prom_fd, OPROMNXTPROP, opp)) < 0)
1779 return (0);
1780 if (opp->oprom_size == 0)
1781 return (0);
1783 while ((ret >= 0) && (opp->oprom_size > 0)) {
1784 (void) strcpy(propdef_opp->oprom_array, opp->oprom_array);
1785 opp->oprom_size = MAXPROPSIZE;
1786 propdef_opp->oprom_size = MAXVALSIZE;
1787 if ((ioctl(prom_fd, OPROMGETPROP, propdef_opp) < 0) ||
1788 (propdef_opp->oprom_size == 0)) {
1789 ret = ioctl(prom_fd, OPROMNXTPROP, opp);
1790 continue;
1792 ret = prom_compare_devs(promdev_def, propdef_opp->oprom_array);
1793 if (ret == EXACT_MATCH) {
1794 found++;
1795 if (insert_alias_list(exact_list, opp->oprom_array)
1796 != 0) {
1797 free_name_list(exact_match, 1);
1798 free_name_list(inexact_match, 1);
1799 return (-1);
1802 if (ret == INEXACT_MATCH) {
1803 found++;
1804 (void) strcpy(alias_buf, opp->oprom_array);
1805 options_override(promdev_def, alias_buf);
1806 if (insert_alias_list(inexact_list, alias_buf)
1807 != 0) {
1808 free_name_list(exact_match, 1);
1809 free_name_list(inexact_match, 1);
1810 return (-1);
1813 ret = ioctl(prom_fd, OPROMNXTPROP, opp);
1815 if (found) {
1816 return (0);
1817 } else {
1818 return (-1);
1823 * free a list of name_list structs and optionally
1824 * free the strings they contain.
1826 static void
1827 free_name_list(struct name_list *list, int free_name)
1829 struct name_list *next = list;
1831 while (next != NULL) {
1832 list = list->next;
1833 if (free_name)
1834 free(next->name);
1835 free(next);
1836 next = list;
1841 * insert a new alias in a list of aliases - the list is sorted
1842 * in collating order (ignoring anything that comes after the
1843 * ':' in the name).
1845 static int
1846 insert_alias_list(struct name_list **list, char *alias_name)
1848 struct name_list *entry = *list;
1849 struct name_list *new_entry, *prev_entry;
1850 int ret;
1851 char *colon1, *colon2;
1853 if ((new_entry =
1854 (struct name_list *)malloc(sizeof (struct name_list)))
1855 == NULL) {
1856 return (-1);
1858 if ((new_entry->name = strdup(alias_name)) == NULL) {
1859 free(new_entry);
1860 return (-1);
1862 new_entry->next = NULL;
1864 if (entry == NULL) {
1865 *list = new_entry;
1866 return (0);
1869 if ((colon1 = strchr(alias_name, ':')) != NULL) {
1870 *colon1 = '\0';
1872 prev_entry = NULL;
1873 while (entry != NULL) {
1874 if ((colon2 = strchr(entry->name, ':')) != NULL) {
1875 *colon2 = '\0';
1877 ret = strcmp(alias_name, entry->name);
1878 if (colon2 != NULL) {
1879 *colon2 = ':';
1881 /* duplicate */
1882 if (ret == 0) {
1883 free(new_entry->name);
1884 free(new_entry);
1885 if (colon1 != NULL) {
1886 *colon1 = ':';
1888 return (0);
1890 if (ret < 0) {
1891 new_entry->next = entry;
1892 if (prev_entry == NULL) {
1893 /* in beginning of list */
1894 *list = new_entry;
1895 } else {
1896 /* in middle of list */
1897 prev_entry->next = new_entry;
1899 if (colon1 != NULL) {
1900 *colon1 = ':';
1902 return (0);
1904 prev_entry = entry;
1905 entry = entry->next;
1907 /* at end of list */
1908 prev_entry->next = new_entry;
1909 new_entry->next = NULL;
1910 if (colon1 != NULL) {
1911 *colon1 = ':';
1913 return (0);
1916 * append :x to alias_name to override any default minor name options
1918 static void
1919 options_override(char *prom_path, char *alias_name)
1921 char *colon;
1923 if ((colon = strrchr(alias_name, ':')) != NULL) {
1925 * XXX - should alias names in /aliases ever have a
1926 * : embedded in them?
1927 * If so we ignore it.
1929 *colon = '\0';
1932 if ((colon = strrchr(prom_path, ':')) != NULL) {
1933 (void) strcat(alias_name, colon);
1938 * compare to prom device names.
1939 * if the device names are not fully qualified. we convert them -
1940 * we only do this as a last resort though since it requires
1941 * jumping into the kernel.
1943 static int
1944 prom_compare_devs(char *prom_dev1, char *prom_dev2)
1946 char *dev1, *dev2;
1947 char *ptr1, *ptr2;
1948 char *drvname1, *addrname1, *minorname1;
1949 char *drvname2, *addrname2, *minorname2;
1950 char component1[MAXNAMELEN], component2[MAXNAMELEN];
1951 char devname1[MAXPATHLEN], devname2[MAXPATHLEN];
1952 int unqualified_name = 0;
1953 int error = EXACT_MATCH;
1954 int len1, len2;
1955 char *wildcard = ",0";
1957 ptr1 = prom_dev1;
1958 ptr2 = prom_dev2;
1960 if ((ptr1 == NULL) || (*ptr1 != '/')) {
1961 return (NO_MATCH);
1963 if ((ptr2 == NULL) || (*ptr2 != '/')) {
1964 return (NO_MATCH);
1968 * compare device names one component at a time.
1970 while ((ptr1 != NULL) && (ptr2 != NULL)) {
1971 *ptr1 = *ptr2 = '/';
1972 dev1 = ptr1 + 1;
1973 dev2 = ptr2 + 1;
1974 if ((ptr1 = strchr(dev1, '/')) != NULL)
1975 *ptr1 = '\0';
1976 if ((ptr2 = strchr(dev2, '/')) != NULL)
1977 *ptr2 = '\0';
1979 (void) strcpy(component1, dev1);
1980 (void) strcpy(component2, dev2);
1982 parse_name(component1, &drvname1, &addrname1, &minorname1);
1983 parse_name(component2, &drvname2, &addrname2, &minorname2);
1985 if ((drvname1 == NULL) && (addrname1 == NULL)) {
1986 error = NO_MATCH;
1987 break;
1990 if ((drvname2 == NULL) && (addrname2 == NULL)) {
1991 error = NO_MATCH;
1992 break;
1995 if (_prom_strcmp(drvname1, drvname2) != 0) {
1996 error = NO_MATCH;
1997 break;
2001 * a possible name is driver_name@address. The address
2002 * portion is optional (i.e. the name is not fully
2003 * qualified.). We have to deal with the case where
2004 * the component name is either driver_name or
2005 * driver_name@address
2007 if ((addrname1 == NULL) ^ (addrname2 == NULL)) {
2008 unqualified_name = 1;
2009 } else if (addrname1 &&
2010 (_prom_strcmp(addrname1, addrname2) != 0)) {
2012 * check to see if appending a ",0" to the
2013 * shorter address causes a match to occur.
2014 * If so succeed.
2016 len1 = strlen(addrname1);
2017 len2 = strlen(addrname2);
2018 if ((len1 < len2) &&
2019 (strncmp(addrname1, addrname2, len1) == 0) &&
2020 (strcmp(wildcard, &addrname2[len1]) == 0)) {
2021 continue;
2022 } else if ((len2 < len1) &&
2023 (strncmp(addrname1, addrname2, len2) == 0) &&
2024 (strcmp(wildcard, &addrname1[len2]) == 0)) {
2025 continue;
2027 error = NO_MATCH;
2028 break;
2033 * if either of the two device paths still has more components,
2034 * then we do not have a match.
2036 if (ptr1 != NULL) {
2037 *ptr1 = '/';
2038 error = NO_MATCH;
2040 if (ptr2 != NULL) {
2041 *ptr2 = '/';
2042 error = NO_MATCH;
2044 if (error == NO_MATCH) {
2045 return (error);
2049 * OK - we found a possible match but one or more of the
2050 * path components was not fully qualified (did not have any
2051 * address information. So we need to convert it to a form
2052 * that is fully qualified and then compare the resulting
2053 * strings.
2055 if (unqualified_name != 0) {
2056 if ((devfs_prom_to_dev_name(prom_dev1, devname1) < 0) ||
2057 (devfs_prom_to_dev_name(prom_dev2, devname2) < 0)) {
2058 return (NO_MATCH);
2060 if ((dev1 = strrchr(devname1, ':')) != NULL) {
2061 *dev1 = '\0';
2063 if ((dev2 = strrchr(devname2, ':')) != NULL) {
2064 *dev2 = '\0';
2066 if (strcmp(devname1, devname2) != 0) {
2067 return (NO_MATCH);
2071 * the resulting strings matched. If the minorname information
2072 * matches, then we have an exact match, otherwise an inexact match
2074 if (_prom_strcmp(minorname1, minorname2) == 0) {
2075 return (EXACT_MATCH);
2076 } else {
2077 return (INEXACT_MATCH);
2082 * wrapper or strcmp - deals with null strings.
2084 static int
2085 _prom_strcmp(char *s1, char *s2)
2087 if ((s1 == NULL) && (s2 == NULL))
2088 return (0);
2089 if ((s1 == NULL) && (s2 != NULL)) {
2090 return (-1);
2092 if ((s1 != NULL) && (s2 == NULL)) {
2093 return (1);
2095 return (strcmp(s1, s2));
2098 * break device@a,b:minor into components
2100 static void
2101 parse_name(char *name, char **drvname, char **addrname, char **minorname)
2103 char *cp, ch;
2105 cp = *drvname = name;
2106 *addrname = *minorname = NULL;
2107 if (*name == '@')
2108 *drvname = NULL;
2110 while ((ch = *cp) != '\0') {
2111 if (ch == '@')
2112 *addrname = ++cp;
2113 else if (ch == ':')
2114 *minorname = ++cp;
2115 ++cp;
2117 if (*addrname) {
2118 *((*addrname)-1) = '\0';
2120 if (*minorname) {
2121 *((*minorname)-1) = '\0';
2126 * converts a prom alias to a prom device name.
2127 * if we find no matching device, then we fail since if were
2128 * given a valid alias, then by definition, there must be a
2129 * device pathname associated with it in the /aliases node.
2131 static int
2132 alias_to_prom_dev(char *alias, char *ret_buf)
2134 char *options_ptr;
2135 char alias_buf[MAXNAMELEN];
2136 char alias_def[MAXPATHLEN];
2137 char options[16] = "";
2138 int prom_fd = -1;
2139 int ret;
2140 int i;
2142 if (strchr(alias, '/') != NULL)
2143 return (DEVFS_INVAL);
2145 if (strlen(alias) > (MAXNAMELEN - 1))
2146 return (DEVFS_INVAL);
2148 if (ret_buf == NULL) {
2149 return (DEVFS_INVAL);
2152 prom_fd = prom_open(O_RDONLY);
2153 if (prom_fd < 0) {
2154 return (prom_fd);
2157 (void) strlcpy(alias_buf, alias, sizeof (alias_buf));
2160 * save off any options (minor name info) that is
2161 * explicitly called out in the alias name
2163 if ((options_ptr = strchr(alias_buf, ':')) != NULL) {
2164 *options_ptr = '\0';
2165 (void) strlcpy(options, ++options_ptr, sizeof (options));
2168 *alias_def = '\0';
2170 ret = prom_find_aliases_node(prom_fd);
2171 if (ret == 0) {
2173 * we loop because one alias may define another... we have
2174 * to work our way down to an actual device definition.
2176 for (i = 0; i <= 10; i++) {
2177 ret = prom_srch_node(prom_fd, alias_buf, alias_def);
2178 if (ret == -1) {
2179 break;
2181 (void) strlcpy(alias_buf, alias_def,
2182 sizeof (alias_buf));
2183 if (*alias_def == '/') {
2184 break;
2188 * save off any explicit options (minor name info)
2189 * if none has been encountered yet
2191 if (options_ptr == NULL) {
2192 options_ptr = strchr(alias_buf, ':');
2193 if (options_ptr != NULL) {
2194 *options_ptr = '\0';
2195 (void) strlcpy(options, ++options_ptr,
2196 sizeof (options));
2201 prom_close(prom_fd);
2203 /* error */
2204 if (ret == -1) {
2205 return (ret);
2208 (void) strlcpy(ret_buf, alias_def, MAXPATHLEN);
2210 /* override minor name information */
2211 if (options_ptr != NULL) {
2212 if ((options_ptr = strrchr(ret_buf, ':')) == NULL) {
2213 (void) strcat(ret_buf, ":");
2214 } else {
2215 *(++options_ptr) = '\0';
2217 (void) strcat(ret_buf, options);
2219 return (0);
2223 * search a prom node for a property name
2225 static int
2226 prom_srch_node(int fd, char *prop_name, char *ret_buf)
2228 Oppbuf oppbuf;
2229 struct openpromio *opp = &(oppbuf.opp);
2230 int *ip = (int *)((void *)opp->oprom_array);
2232 (void) memset(oppbuf.buf, 0, BUFSIZE);
2233 opp->oprom_size = MAXPROPSIZE;
2234 *ip = 0;
2236 if (ioctl(fd, OPROMNXTPROP, opp) < 0)
2237 return (-1);
2238 if (opp->oprom_size == 0)
2239 return (-1);
2241 while (strcmp(prop_name, opp->oprom_array) != 0) {
2242 opp->oprom_size = MAXPROPSIZE;
2243 if (ioctl(fd, OPROMNXTPROP, opp) < 0)
2244 return (-1);
2245 if (opp->oprom_size == 0)
2246 return (-1);
2248 opp->oprom_size = MAXVALSIZE;
2249 if (ioctl(fd, OPROMGETPROP, opp) < 0)
2250 return (-1);
2252 if (opp->oprom_size == 0)
2253 return (-1);
2254 (void) strlcpy(ret_buf, opp->oprom_array, MAXPATHLEN);
2255 return (0);
2259 * return the aliases node.
2261 static int
2262 prom_find_aliases_node(int fd)
2264 uint_t child_id;
2265 char buf[MAXPATHLEN];
2267 if ((child_id = prom_next_node(fd, 0)) == 0)
2268 return (-1);
2269 if ((child_id = prom_child_node(fd, child_id)) == 0)
2270 return (-1);
2272 while (child_id != 0) {
2273 if (prom_srch_node(fd, "name", buf) == 0) {
2274 if (strcmp(buf, "aliases") == 0) {
2275 return (0);
2278 child_id = prom_next_node(fd, child_id);
2280 return (-1);
2284 * get sibling
2286 static uint_t
2287 prom_next_node(int fd, uint_t node_id)
2289 Oppbuf oppbuf;
2290 struct openpromio *opp = &(oppbuf.opp);
2291 uint_t *ip = (uint_t *)((void *)opp->oprom_array);
2293 (void) memset(oppbuf.buf, 0, BUFSIZE);
2294 opp->oprom_size = MAXVALSIZE;
2295 *ip = node_id;
2297 if (ioctl(fd, OPROMNEXT, opp) < 0)
2298 return (0);
2300 return (*(uint_t *)((void *)opp->oprom_array));
2304 * get child
2306 static uint_t
2307 prom_child_node(int fd, uint_t node_id)
2309 Oppbuf oppbuf;
2310 struct openpromio *opp = &(oppbuf.opp);
2311 uint_t *ip = (uint_t *)((void *)opp->oprom_array);
2313 (void) memset(oppbuf.buf, 0, BUFSIZE);
2314 opp->oprom_size = MAXVALSIZE;
2315 *ip = node_id;
2317 if (ioctl(fd, OPROMCHILD, opp) < 0)
2318 return (0);
2320 return (*(uint_t *)((void *)opp->oprom_array));
2324 * only on sparc for now
2327 devfs_bootdev_modifiable(void)
2329 #if defined(sparc)
2330 return (0);
2331 #else
2332 return (DEVFS_NOTSUP);
2333 #endif