10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53337Sas158974 * Common Development and Distribution License (the "License").
63337Sas158974 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*9735SSriman.Bhavanam@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <stdio.h>
280Sstevel@tonic-gate #include <string.h>
290Sstevel@tonic-gate #include <strings.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <thread.h>
330Sstevel@tonic-gate #include <synch.h>
340Sstevel@tonic-gate #include <sys/types.h>
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include <fcntl.h>
380Sstevel@tonic-gate #include <sys/modctl.h>
390Sstevel@tonic-gate #include <errno.h>
400Sstevel@tonic-gate #include <sys/openpromio.h>
410Sstevel@tonic-gate #include <ftw.h>
420Sstevel@tonic-gate #include <sys/ddi.h>
430Sstevel@tonic-gate #include <sys/sunddi.h>
440Sstevel@tonic-gate #include <limits.h>
450Sstevel@tonic-gate
460Sstevel@tonic-gate #include "device_info.h"
470Sstevel@tonic-gate
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate * #define's
500Sstevel@tonic-gate */
510Sstevel@tonic-gate
520Sstevel@tonic-gate /* alias node searching return values */
530Sstevel@tonic-gate #define NO_MATCH -1
540Sstevel@tonic-gate #define EXACT_MATCH 1
550Sstevel@tonic-gate #define INEXACT_MATCH 2
560Sstevel@tonic-gate
570Sstevel@tonic-gate /* for prom io operations */
580Sstevel@tonic-gate #define BUFSIZE 4096
590Sstevel@tonic-gate #define MAXPROPSIZE 256
600Sstevel@tonic-gate #define MAXVALSIZE (BUFSIZE - MAXPROPSIZE - sizeof (uint_t))
610Sstevel@tonic-gate
623337Sas158974 /* prom_obp_vers() return values */
630Sstevel@tonic-gate #define OBP_OF 0x4 /* versions OBP 3.x */
643337Sas158974 #define OBP_NO_ALIAS_NODE 0x8 /* No alias node */
650Sstevel@tonic-gate
660Sstevel@tonic-gate /* for nftw call */
670Sstevel@tonic-gate #define FT_DEPTH 15
680Sstevel@tonic-gate
690Sstevel@tonic-gate /* default logical and physical device name space */
700Sstevel@tonic-gate #define DEV "/dev"
710Sstevel@tonic-gate #define DEVICES "/devices"
720Sstevel@tonic-gate
730Sstevel@tonic-gate /* for boot device identification on x86 */
740Sstevel@tonic-gate #define CREATE_DISKMAP "/boot/solaris/bin/create_diskmap"
750Sstevel@tonic-gate #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
760Sstevel@tonic-gate
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate * internal structure declarations
790Sstevel@tonic-gate */
800Sstevel@tonic-gate
810Sstevel@tonic-gate /* for prom io functions */
820Sstevel@tonic-gate typedef union {
830Sstevel@tonic-gate char buf[BUFSIZE];
840Sstevel@tonic-gate struct openpromio opp;
850Sstevel@tonic-gate } Oppbuf;
860Sstevel@tonic-gate
870Sstevel@tonic-gate /* used to manage lists of devices and aliases */
880Sstevel@tonic-gate struct name_list {
890Sstevel@tonic-gate char *name;
900Sstevel@tonic-gate struct name_list *next;
910Sstevel@tonic-gate };
920Sstevel@tonic-gate
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate * internal global data
950Sstevel@tonic-gate */
960Sstevel@tonic-gate
970Sstevel@tonic-gate /* global since nftw does not let you pass args to be updated */
980Sstevel@tonic-gate static struct name_list **dev_list;
990Sstevel@tonic-gate
1000Sstevel@tonic-gate /* global since nftw does not let you pass args to be updated */
1010Sstevel@tonic-gate static struct boot_dev **bootdev_list;
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate /* mutex to protect bootdev_list and dev_list */
1040Sstevel@tonic-gate static mutex_t dev_lists_lk = DEFAULTMUTEX;
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate /*
1070Sstevel@tonic-gate * internal function prototypes
1080Sstevel@tonic-gate */
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate static int prom_open(int);
1110Sstevel@tonic-gate static void prom_close(int);
1120Sstevel@tonic-gate static int is_openprom(int);
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate static int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf);
1153337Sas158974 static int alias_to_prom_dev(char *alias, char *ret_buf);
1160Sstevel@tonic-gate static int prom_srch_aliases_by_def(char *, struct name_list **,
1170Sstevel@tonic-gate struct name_list **, int);
1183337Sas158974 static int prom_find_aliases_node(int fd);
1190Sstevel@tonic-gate static int prom_compare_devs(char *prom_dev1, char *prom_dev2);
1200Sstevel@tonic-gate static int _prom_strcmp(char *s1, char *s2);
1213337Sas158974 static int prom_srch_node(int fd, char *prop_name, char *ret_buf);
1223337Sas158974 static uint_t prom_next_node(int fd, uint_t node_id);
1233337Sas158974 static uint_t prom_child_node(int fd, uint_t node_id);
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate static int prom_obp_vers(void);
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate static void parse_name(char *, char **, char **, char **);
1280Sstevel@tonic-gate static int process_bootdev(const char *, const char *, struct boot_dev ***);
1290Sstevel@tonic-gate static int process_minor_name(char *dev_path, const char *default_root);
1300Sstevel@tonic-gate static void options_override(char *prom_path, char *alias_name);
1310Sstevel@tonic-gate static int devfs_phys_to_logical(struct boot_dev **bootdev_array,
1320Sstevel@tonic-gate const int array_size, const char *default_root);
1330Sstevel@tonic-gate static int check_logical_dev(const char *, const struct stat *, int,
1340Sstevel@tonic-gate struct FTW *);
1350Sstevel@tonic-gate static struct boot_dev *alloc_bootdev(char *);
1360Sstevel@tonic-gate static void free_name_list(struct name_list *list, int free_name);
1370Sstevel@tonic-gate static int insert_alias_list(struct name_list **list,
1380Sstevel@tonic-gate char *alias_name);
1390Sstevel@tonic-gate static int get_boot_dev_var(struct openpromio *opp);
1400Sstevel@tonic-gate static int set_boot_dev_var(struct openpromio *opp, char *bootdev);
1410Sstevel@tonic-gate static int devfs_prom_to_dev_name(char *prom_path, char *dev_path);
1420Sstevel@tonic-gate static int devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len);
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate /*
1450Sstevel@tonic-gate * frees a list of paths from devfs_get_prom_name_list
1460Sstevel@tonic-gate */
1470Sstevel@tonic-gate static void
prom_list_free(char ** prom_list)1480Sstevel@tonic-gate prom_list_free(char **prom_list)
1490Sstevel@tonic-gate {
1500Sstevel@tonic-gate int i = 0;
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate if (!prom_list)
1530Sstevel@tonic-gate return;
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate while (prom_list[i]) {
1560Sstevel@tonic-gate free(prom_list[i]);
1570Sstevel@tonic-gate i++;
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate free(prom_list);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate static int
devfs_get_prom_name_list(const char * dev_name,char *** prom_list)1630Sstevel@tonic-gate devfs_get_prom_name_list(const char *dev_name, char ***prom_list)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate char *prom_path = NULL;
1660Sstevel@tonic-gate int count = 0; /* # of slots we will need in prom_list */
1670Sstevel@tonic-gate int ret, i, len;
1680Sstevel@tonic-gate char **list;
1690Sstevel@tonic-gate char *ptr;
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate if (dev_name == NULL)
1720Sstevel@tonic-gate return (DEVFS_INVAL);
1730Sstevel@tonic-gate if (*dev_name != '/')
1740Sstevel@tonic-gate return (DEVFS_INVAL);
1750Sstevel@tonic-gate if (prom_list == NULL)
1760Sstevel@tonic-gate return (DEVFS_INVAL);
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate /*
1790Sstevel@tonic-gate * make sure we are on a machine which supports a prom
1800Sstevel@tonic-gate * and we have permission to use /dev/openprom
1810Sstevel@tonic-gate */
1820Sstevel@tonic-gate if ((ret = prom_obp_vers()) < 0)
1830Sstevel@tonic-gate return (ret);
1840Sstevel@tonic-gate if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
1850Sstevel@tonic-gate return (DEVFS_NOMEM);
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate * get the prom path name
1880Sstevel@tonic-gate */
1890Sstevel@tonic-gate ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE);
1900Sstevel@tonic-gate if (ret < 0) {
1910Sstevel@tonic-gate free(prom_path);
1920Sstevel@tonic-gate return (ret);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate /* deal with list of names */
1950Sstevel@tonic-gate for (i = 0; i < ret; i++)
1960Sstevel@tonic-gate if (prom_path[i] == '\0')
1970Sstevel@tonic-gate count++;
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) {
2000Sstevel@tonic-gate free(prom_path);
2010Sstevel@tonic-gate return (DEVFS_NOMEM);
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate ptr = prom_path;
2050Sstevel@tonic-gate for (i = 0; i < count; i++) {
2060Sstevel@tonic-gate len = strlen(ptr) + 1;
2070Sstevel@tonic-gate if ((list[i] = (char *)malloc(len)) == NULL) {
2080Sstevel@tonic-gate free(prom_path);
2090Sstevel@tonic-gate free(list);
2100Sstevel@tonic-gate return (DEVFS_NOMEM);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate (void) snprintf(list[i], len, "%s", ptr);
2130Sstevel@tonic-gate ptr += len;
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate free(prom_path);
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate *prom_list = list;
2190Sstevel@tonic-gate return (0);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate /*
2230Sstevel@tonic-gate * retrieve the list of prom representations for a given device name
2240Sstevel@tonic-gate * the list will be sorted in the following order: exact aliases,
2250Sstevel@tonic-gate * inexact aliases, prom device path name. If multiple matches occur
2260Sstevel@tonic-gate * for exact or inexact aliases, then these are sorted in collating
2270Sstevel@tonic-gate * order. The list is returned in prom_list
2280Sstevel@tonic-gate *
2290Sstevel@tonic-gate * the list may be restricted by specifying the correct flags in options.
2300Sstevel@tonic-gate */
2310Sstevel@tonic-gate int
devfs_get_prom_names(const char * dev_name,uint_t options,char *** prom_list)2320Sstevel@tonic-gate devfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate char *prom_path = NULL;
2350Sstevel@tonic-gate int count = 0; /* # of slots we will need in prom_list */
2360Sstevel@tonic-gate char **alias_list = NULL;
2370Sstevel@tonic-gate char **list;
2380Sstevel@tonic-gate int ret;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate if (dev_name == NULL) {
2410Sstevel@tonic-gate return (DEVFS_INVAL);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate if (*dev_name != '/') {
2440Sstevel@tonic-gate return (DEVFS_INVAL);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate if (prom_list == NULL) {
2470Sstevel@tonic-gate return (DEVFS_INVAL);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate /*
2500Sstevel@tonic-gate * make sure we are on a machine which supports a prom
2510Sstevel@tonic-gate * and we have permission to use /dev/openprom
2520Sstevel@tonic-gate */
2530Sstevel@tonic-gate if ((ret = prom_obp_vers()) < 0) {
2540Sstevel@tonic-gate return (ret);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) {
2570Sstevel@tonic-gate return (DEVFS_NOMEM);
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate /*
2600Sstevel@tonic-gate * get the prom path name
2610Sstevel@tonic-gate */
2620Sstevel@tonic-gate ret = devfs_dev_to_prom_name((char *)dev_name, prom_path);
2630Sstevel@tonic-gate if (ret < 0) {
2640Sstevel@tonic-gate free(prom_path);
2650Sstevel@tonic-gate return (ret);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate /* get the list of aliases (exact and inexact) */
2680Sstevel@tonic-gate if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) {
2690Sstevel@tonic-gate free(prom_path);
2700Sstevel@tonic-gate return (ret);
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate /* now figure out how big the return array must be */
2730Sstevel@tonic-gate if (alias_list != NULL) {
2740Sstevel@tonic-gate while (alias_list[count] != NULL) {
2750Sstevel@tonic-gate count++;
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
2790Sstevel@tonic-gate count++; /* # of slots we will need in prom_list */
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate count++; /* for the null terminator */
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate /* allocate space for the list */
2840Sstevel@tonic-gate if ((list = (char **)calloc(count, sizeof (char *))) == NULL) {
2850Sstevel@tonic-gate count = 0;
2860Sstevel@tonic-gate while ((alias_list) && (alias_list[count] != NULL)) {
2870Sstevel@tonic-gate free(alias_list[count]);
2880Sstevel@tonic-gate count++;
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate free(alias_list);
2910Sstevel@tonic-gate free(prom_path);
2920Sstevel@tonic-gate return (DEVFS_NOMEM);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate /* fill in the array and free the name list of aliases. */
2950Sstevel@tonic-gate count = 0;
2960Sstevel@tonic-gate while ((alias_list) && (alias_list[count] != NULL)) {
2970Sstevel@tonic-gate list[count] = alias_list[count];
2980Sstevel@tonic-gate count++;
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
3010Sstevel@tonic-gate list[count] = prom_path;
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate if (alias_list != NULL) {
3040Sstevel@tonic-gate free(alias_list);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate *prom_list = list;
3070Sstevel@tonic-gate return (0);
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate /*
3110Sstevel@tonic-gate * Get a list prom-path translations for a solaris device.
3120Sstevel@tonic-gate *
3130Sstevel@tonic-gate * Returns the number of and all OBP paths and alias variants that
3140Sstevel@tonic-gate * reference the Solaris device path passed in.
3150Sstevel@tonic-gate */
3160Sstevel@tonic-gate int
devfs_get_all_prom_names(const char * solaris_path,uint_t flags,struct devfs_prom_path ** paths)3170Sstevel@tonic-gate devfs_get_all_prom_names(const char *solaris_path, uint_t flags,
3180Sstevel@tonic-gate struct devfs_prom_path **paths)
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate int ret, len, i, count = 0;
3210Sstevel@tonic-gate char *ptr, *prom_path;
3220Sstevel@tonic-gate struct devfs_prom_path *cur = NULL, *new;
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate if ((ret = prom_obp_vers()) < 0)
3250Sstevel@tonic-gate return (ret);
3260Sstevel@tonic-gate if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
3270Sstevel@tonic-gate return (DEVFS_NOMEM);
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate if ((ret = devfs_dev_to_prom_names((char *)solaris_path,
3300Sstevel@tonic-gate prom_path, MAXVALSIZE)) < 0) {
3310Sstevel@tonic-gate free(prom_path);
3320Sstevel@tonic-gate return (ret);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate for (i = 0; i < ret; i++)
3360Sstevel@tonic-gate if (prom_path[i] == '\0')
3370Sstevel@tonic-gate count++;
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate *paths = NULL;
3400Sstevel@tonic-gate ptr = prom_path;
3410Sstevel@tonic-gate for (i = 0; i < count; i++) {
3420Sstevel@tonic-gate if ((new = (struct devfs_prom_path *)calloc(
3430Sstevel@tonic-gate sizeof (struct devfs_prom_path), 1)) == NULL) {
3440Sstevel@tonic-gate free(prom_path);
3450Sstevel@tonic-gate devfs_free_all_prom_names(*paths);
3460Sstevel@tonic-gate return (DEVFS_NOMEM);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate if (cur == NULL)
3500Sstevel@tonic-gate *paths = new;
3510Sstevel@tonic-gate else
3520Sstevel@tonic-gate cur->next = new;
3530Sstevel@tonic-gate cur = new;
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate len = strlen(ptr) + 1;
3560Sstevel@tonic-gate if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) {
3570Sstevel@tonic-gate free(prom_path);
3580Sstevel@tonic-gate devfs_free_all_prom_names(*paths);
3590Sstevel@tonic-gate return (DEVFS_NOMEM);
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate (void) snprintf(cur->obp_path, len, "%s", ptr);
3630Sstevel@tonic-gate ptr += len;
3640Sstevel@tonic-gate if ((ret = prom_dev_to_alias(cur->obp_path, flags,
3650Sstevel@tonic-gate &(cur->alias_list))) < 0) {
3660Sstevel@tonic-gate free(prom_path);
3670Sstevel@tonic-gate devfs_free_all_prom_names(*paths);
3680Sstevel@tonic-gate return (ret);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate free(prom_path);
3730Sstevel@tonic-gate return (count);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate void
devfs_free_all_prom_names(struct devfs_prom_path * paths)3770Sstevel@tonic-gate devfs_free_all_prom_names(struct devfs_prom_path *paths)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate int i;
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate if (paths == NULL)
3820Sstevel@tonic-gate return;
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate devfs_free_all_prom_names(paths->next);
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate if (paths->obp_path != NULL)
3870Sstevel@tonic-gate free(paths->obp_path);
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate if (paths->alias_list != NULL) {
3900Sstevel@tonic-gate for (i = 0; paths->alias_list[i] != NULL; i++)
3910Sstevel@tonic-gate if (paths->alias_list[i] != NULL)
3920Sstevel@tonic-gate free(paths->alias_list[i]);
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate free(paths->alias_list);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate free(paths);
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate /*
4010Sstevel@tonic-gate * Accepts a device name as an input argument. Uses this to set the
4020Sstevel@tonic-gate * boot-device (or like) variable
4030Sstevel@tonic-gate *
4040Sstevel@tonic-gate * By default, this routine prepends to the list and converts the
4050Sstevel@tonic-gate * logical device name to its most compact prom representation.
4060Sstevel@tonic-gate * Available options include: converting the device name to a prom
4070Sstevel@tonic-gate * path name (but not an alias) or performing no conversion at all;
4080Sstevel@tonic-gate * overwriting the existing contents of boot-device rather than
4090Sstevel@tonic-gate * prepending.
4100Sstevel@tonic-gate */
4110Sstevel@tonic-gate int
devfs_bootdev_set_list(const char * dev_name,const uint_t options)4120Sstevel@tonic-gate devfs_bootdev_set_list(const char *dev_name, const uint_t options)
4130Sstevel@tonic-gate {
4140Sstevel@tonic-gate char *prom_path;
4150Sstevel@tonic-gate char *new_bootdev;
4160Sstevel@tonic-gate char *ptr;
4170Sstevel@tonic-gate char **alias_list = NULL;
4180Sstevel@tonic-gate char **prom_list = NULL;
4190Sstevel@tonic-gate Oppbuf oppbuf;
4200Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
4210Sstevel@tonic-gate int ret, len, i, j;
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate if (devfs_bootdev_modifiable() != 0) {
4240Sstevel@tonic-gate return (DEVFS_NOTSUP);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate if (dev_name == NULL) {
4270Sstevel@tonic-gate return (DEVFS_INVAL);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate if (strlen(dev_name) >= MAXPATHLEN)
4300Sstevel@tonic-gate return (DEVFS_INVAL);
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) {
4330Sstevel@tonic-gate return (DEVFS_INVAL);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) {
4360Sstevel@tonic-gate return (DEVFS_INVAL);
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate /*
4390Sstevel@tonic-gate * if we are prepending, make sure that this obp rev
4400Sstevel@tonic-gate * supports multiple boot device entries.
4410Sstevel@tonic-gate */
4420Sstevel@tonic-gate ret = prom_obp_vers();
4430Sstevel@tonic-gate if (ret < 0) {
4440Sstevel@tonic-gate return (ret);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) {
4480Sstevel@tonic-gate return (DEVFS_NOMEM);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate if (options & BOOTDEV_LITERAL) {
4510Sstevel@tonic-gate (void) strcpy(prom_path, dev_name);
4520Sstevel@tonic-gate } else {
4530Sstevel@tonic-gate /* need to convert to prom representation */
4540Sstevel@tonic-gate ret = devfs_get_prom_name_list(dev_name, &prom_list);
4550Sstevel@tonic-gate if (ret < 0) {
4560Sstevel@tonic-gate free(prom_path);
4570Sstevel@tonic-gate return (ret);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate len = MAXVALSIZE;
4610Sstevel@tonic-gate i = 0;
4620Sstevel@tonic-gate ptr = prom_path;
4630Sstevel@tonic-gate while (prom_list && prom_list[i]) {
4640Sstevel@tonic-gate if (!(options & BOOTDEV_PROMDEV)) {
4650Sstevel@tonic-gate ret = prom_dev_to_alias(prom_list[i], 0,
466*9735SSriman.Bhavanam@Sun.COM &alias_list);
4670Sstevel@tonic-gate if (ret < 0) {
4680Sstevel@tonic-gate free(prom_path);
4690Sstevel@tonic-gate prom_list_free(prom_list);
4700Sstevel@tonic-gate return (ret);
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate if ((alias_list != NULL) &&
4730Sstevel@tonic-gate (alias_list[0] != NULL)) {
4740Sstevel@tonic-gate (void) snprintf(ptr, len, "%s ",
4750Sstevel@tonic-gate alias_list[0]);
4760Sstevel@tonic-gate for (ret = 0; alias_list[ret] != NULL;
4770Sstevel@tonic-gate ret++)
4780Sstevel@tonic-gate free(alias_list[ret]);
4790Sstevel@tonic-gate } else {
4800Sstevel@tonic-gate (void) snprintf(ptr, len, "%s ",
4810Sstevel@tonic-gate prom_list[i]);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate if (alias_list != NULL)
4840Sstevel@tonic-gate free(alias_list);
4850Sstevel@tonic-gate } else {
4860Sstevel@tonic-gate (void) snprintf(ptr, len, "%s ", prom_list[i]);
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate j = strlen(ptr);
4890Sstevel@tonic-gate len -= j;
4900Sstevel@tonic-gate ptr += j;
4910Sstevel@tonic-gate i++;
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate ptr--;
4940Sstevel@tonic-gate *ptr = NULL;
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate prom_list_free(prom_list);
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate if (options & BOOTDEV_OVERWRITE) {
4990Sstevel@tonic-gate new_bootdev = prom_path;
5000Sstevel@tonic-gate } else {
5010Sstevel@tonic-gate /* retrieve the current value of boot-device */
5020Sstevel@tonic-gate ret = get_boot_dev_var(opp);
5030Sstevel@tonic-gate if (ret < 0) {
5040Sstevel@tonic-gate free(prom_path);
5050Sstevel@tonic-gate return (ret);
5060Sstevel@tonic-gate }
5070Sstevel@tonic-gate /* prepend new entry - deal with duplicates */
5080Sstevel@tonic-gate new_bootdev = (char *)malloc(strlen(opp->oprom_array)
5090Sstevel@tonic-gate + strlen(prom_path) + 2);
5100Sstevel@tonic-gate if (new_bootdev == NULL) {
5110Sstevel@tonic-gate free(prom_path);
5120Sstevel@tonic-gate return (DEVFS_NOMEM);
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate (void) strcpy(new_bootdev, prom_path);
5150Sstevel@tonic-gate if (opp->oprom_size > 0) {
5160Sstevel@tonic-gate for (ptr = strtok(opp->oprom_array, " "); ptr != NULL;
5170Sstevel@tonic-gate ptr = strtok(NULL, " ")) {
5180Sstevel@tonic-gate /* we strip out duplicates */
5190Sstevel@tonic-gate if (strcmp(prom_path, ptr) == 0) {
5200Sstevel@tonic-gate continue;
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate (void) strcat(new_bootdev, " ");
5230Sstevel@tonic-gate (void) strcat(new_bootdev, ptr);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate /* now set the new value */
5290Sstevel@tonic-gate ret = set_boot_dev_var(opp, new_bootdev);
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate if (options & BOOTDEV_OVERWRITE) {
5320Sstevel@tonic-gate free(prom_path);
5330Sstevel@tonic-gate } else {
5340Sstevel@tonic-gate free(new_bootdev);
5350Sstevel@tonic-gate free(prom_path);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate return (ret);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate /*
5420Sstevel@tonic-gate * sets the string bootdev as the new value for boot-device
5430Sstevel@tonic-gate */
5440Sstevel@tonic-gate static int
set_boot_dev_var(struct openpromio * opp,char * bootdev)5450Sstevel@tonic-gate set_boot_dev_var(struct openpromio *opp, char *bootdev)
5460Sstevel@tonic-gate {
5470Sstevel@tonic-gate int prom_fd;
5480Sstevel@tonic-gate int i;
5490Sstevel@tonic-gate int ret;
5500Sstevel@tonic-gate char *valbuf;
5510Sstevel@tonic-gate char *save_bootdev;
5520Sstevel@tonic-gate char *bootdev_variables[] = {
5530Sstevel@tonic-gate "boot-device",
5540Sstevel@tonic-gate "bootdev",
5550Sstevel@tonic-gate "boot-from",
5560Sstevel@tonic-gate NULL
5570Sstevel@tonic-gate };
5580Sstevel@tonic-gate int found = 0;
5590Sstevel@tonic-gate int *ip = (int *)((void *)opp->oprom_array);
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate /* query the prom */
5620Sstevel@tonic-gate prom_fd = prom_open(O_RDWR);
5630Sstevel@tonic-gate if (prom_fd < 0) {
5640Sstevel@tonic-gate return (prom_fd);
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate /* get the diagnostic-mode? property */
5680Sstevel@tonic-gate (void) strcpy(opp->oprom_array, "diagnostic-mode?");
5690Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
5700Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
5710Sstevel@tonic-gate if ((opp->oprom_size > 0) &&
5720Sstevel@tonic-gate (strcmp(opp->oprom_array, "true") == 0)) {
5730Sstevel@tonic-gate prom_close(prom_fd);
5740Sstevel@tonic-gate return (DEVFS_ERR);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate /* get the diag-switch? property */
5780Sstevel@tonic-gate (void) strcpy(opp->oprom_array, "diag-switch?");
5790Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
5800Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
5810Sstevel@tonic-gate if ((opp->oprom_size > 0) &&
5820Sstevel@tonic-gate (strcmp(opp->oprom_array, "true") == 0)) {
5830Sstevel@tonic-gate prom_close(prom_fd);
5840Sstevel@tonic-gate return (DEVFS_ERR);
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate /*
5880Sstevel@tonic-gate * look for one of the following properties in order:
5890Sstevel@tonic-gate * boot-device
5900Sstevel@tonic-gate * bootdev
5910Sstevel@tonic-gate * boot-from
5920Sstevel@tonic-gate *
5930Sstevel@tonic-gate * Use the first one that we find.
5940Sstevel@tonic-gate */
5950Sstevel@tonic-gate *ip = 0;
5960Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE;
5970Sstevel@tonic-gate while ((opp->oprom_size != 0) && (!found)) {
5980Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE;
5990Sstevel@tonic-gate if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
6000Sstevel@tonic-gate break;
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate for (i = 0; bootdev_variables[i] != NULL; i++) {
6030Sstevel@tonic-gate if (strcmp(opp->oprom_array, bootdev_variables[i])
6040Sstevel@tonic-gate == 0) {
6050Sstevel@tonic-gate found = 1;
6060Sstevel@tonic-gate break;
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate if (found) {
6110Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]);
6120Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
6130Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
6140Sstevel@tonic-gate prom_close(prom_fd);
6150Sstevel@tonic-gate return (DEVFS_NOTSUP);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate } else {
6180Sstevel@tonic-gate prom_close(prom_fd);
6190Sstevel@tonic-gate return (DEVFS_NOTSUP);
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate /* save the old copy in case we fail */
6230Sstevel@tonic-gate if ((save_bootdev = strdup(opp->oprom_array)) == NULL) {
6240Sstevel@tonic-gate prom_close(prom_fd);
6250Sstevel@tonic-gate return (DEVFS_NOMEM);
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate /* set up the new value of boot-device */
6280Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]);
6290Sstevel@tonic-gate valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
6300Sstevel@tonic-gate (void) strcpy(valbuf, bootdev);
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
6350Sstevel@tonic-gate free(save_bootdev);
6360Sstevel@tonic-gate prom_close(prom_fd);
6370Sstevel@tonic-gate return (DEVFS_ERR);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate /*
6410Sstevel@tonic-gate * now read it back to make sure it took
6420Sstevel@tonic-gate */
6430Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]);
6440Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
6450Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
6460Sstevel@tonic-gate if (_prom_strcmp(opp->oprom_array, bootdev) == 0) {
6470Sstevel@tonic-gate /* success */
6480Sstevel@tonic-gate free(save_bootdev);
6490Sstevel@tonic-gate prom_close(prom_fd);
6500Sstevel@tonic-gate return (0);
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate /* deal with setting it to "" */
6530Sstevel@tonic-gate if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) {
6540Sstevel@tonic-gate /* success */
6550Sstevel@tonic-gate free(save_bootdev);
6560Sstevel@tonic-gate prom_close(prom_fd);
6570Sstevel@tonic-gate return (0);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate /*
6610Sstevel@tonic-gate * something did not take - write out the old value and
6620Sstevel@tonic-gate * hope that we can restore things...
6630Sstevel@tonic-gate *
6640Sstevel@tonic-gate * unfortunately, there is no way for us to differentiate
6650Sstevel@tonic-gate * whether we exceeded the maximum number of characters
6660Sstevel@tonic-gate * allowable. The limit varies from prom rev to prom
6670Sstevel@tonic-gate * rev, and on some proms, when the limit is
6680Sstevel@tonic-gate * exceeded, whatever was in the
6690Sstevel@tonic-gate * boot-device variable becomes unreadable.
6700Sstevel@tonic-gate *
6710Sstevel@tonic-gate * so if we fail, we will assume we ran out of room. If we
6720Sstevel@tonic-gate * not able to restore the original setting, then we will
6730Sstevel@tonic-gate * return DEVFS_ERR instead.
6740Sstevel@tonic-gate */
6750Sstevel@tonic-gate ret = DEVFS_LIMIT;
6760Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]);
6770Sstevel@tonic-gate valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
6780Sstevel@tonic-gate (void) strcpy(valbuf, save_bootdev);
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
6830Sstevel@tonic-gate ret = DEVFS_ERR;
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate free(save_bootdev);
6860Sstevel@tonic-gate prom_close(prom_fd);
6870Sstevel@tonic-gate return (ret);
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate /*
6900Sstevel@tonic-gate * retrieve the current value for boot-device
6910Sstevel@tonic-gate */
6920Sstevel@tonic-gate static int
get_boot_dev_var(struct openpromio * opp)6930Sstevel@tonic-gate get_boot_dev_var(struct openpromio *opp)
6940Sstevel@tonic-gate {
6950Sstevel@tonic-gate int prom_fd;
6960Sstevel@tonic-gate int i;
6970Sstevel@tonic-gate char *bootdev_variables[] = {
6980Sstevel@tonic-gate "boot-device",
6990Sstevel@tonic-gate "bootdev",
7000Sstevel@tonic-gate "boot-from",
7010Sstevel@tonic-gate NULL
7020Sstevel@tonic-gate };
7030Sstevel@tonic-gate int found = 0;
7040Sstevel@tonic-gate int *ip = (int *)((void *)opp->oprom_array);
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate /* query the prom */
7070Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY);
7080Sstevel@tonic-gate if (prom_fd < 0) {
7090Sstevel@tonic-gate return (prom_fd);
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate /* get the diagnostic-mode? property */
7130Sstevel@tonic-gate (void) strcpy(opp->oprom_array, "diagnostic-mode?");
7140Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
7150Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
7160Sstevel@tonic-gate if ((opp->oprom_size > 0) &&
7170Sstevel@tonic-gate (strcmp(opp->oprom_array, "true") == 0)) {
7180Sstevel@tonic-gate prom_close(prom_fd);
7190Sstevel@tonic-gate return (DEVFS_ERR);
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate /* get the diag-switch? property */
7230Sstevel@tonic-gate (void) strcpy(opp->oprom_array, "diag-switch?");
7240Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
7250Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
7260Sstevel@tonic-gate if ((opp->oprom_size > 0) &&
7270Sstevel@tonic-gate (strcmp(opp->oprom_array, "true") == 0)) {
7280Sstevel@tonic-gate prom_close(prom_fd);
7290Sstevel@tonic-gate return (DEVFS_ERR);
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate /*
7330Sstevel@tonic-gate * look for one of the following properties in order:
7340Sstevel@tonic-gate * boot-device
7350Sstevel@tonic-gate * bootdev
7360Sstevel@tonic-gate * boot-from
7370Sstevel@tonic-gate *
7380Sstevel@tonic-gate * Use the first one that we find.
7390Sstevel@tonic-gate */
7400Sstevel@tonic-gate *ip = 0;
7410Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE;
7420Sstevel@tonic-gate while ((opp->oprom_size != 0) && (!found)) {
7430Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE;
7440Sstevel@tonic-gate if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
7450Sstevel@tonic-gate break;
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate for (i = 0; bootdev_variables[i] != NULL; i++) {
7480Sstevel@tonic-gate if (strcmp(opp->oprom_array, bootdev_variables[i])
7490Sstevel@tonic-gate == 0) {
7500Sstevel@tonic-gate found = 1;
7510Sstevel@tonic-gate break;
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate if (found) {
7560Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]);
7570Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
7580Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
7590Sstevel@tonic-gate prom_close(prom_fd);
7600Sstevel@tonic-gate return (DEVFS_ERR);
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate /* boot-device exists but contains nothing */
7630Sstevel@tonic-gate if (opp->oprom_size == 0) {
7640Sstevel@tonic-gate *opp->oprom_array = '\0';
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate } else {
7670Sstevel@tonic-gate prom_close(prom_fd);
7680Sstevel@tonic-gate return (DEVFS_NOTSUP);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate prom_close(prom_fd);
7710Sstevel@tonic-gate return (0);
7720Sstevel@tonic-gate }
7730Sstevel@tonic-gate
7740Sstevel@tonic-gate #ifndef __sparc
7750Sstevel@tonic-gate static FILE *
open_diskmap(void)7760Sstevel@tonic-gate open_diskmap(void)
7770Sstevel@tonic-gate {
7780Sstevel@tonic-gate FILE *fp;
7790Sstevel@tonic-gate char cmd[PATH_MAX];
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate /* make sure we have a map file */
7820Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r");
7830Sstevel@tonic-gate if (fp == NULL) {
7840Sstevel@tonic-gate (void) snprintf(cmd, sizeof (cmd),
7850Sstevel@tonic-gate "%s > /dev/null", CREATE_DISKMAP);
7860Sstevel@tonic-gate (void) system(cmd);
7870Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r");
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate return (fp);
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate static int
find_x86_boot_device(struct openpromio * opp)7930Sstevel@tonic-gate find_x86_boot_device(struct openpromio *opp)
7940Sstevel@tonic-gate {
7950Sstevel@tonic-gate int ret = DEVFS_ERR;
7960Sstevel@tonic-gate char *cp, line[MAXVALSIZE + 6];
7970Sstevel@tonic-gate FILE *file;
7980Sstevel@tonic-gate
7990Sstevel@tonic-gate file = open_diskmap();
8000Sstevel@tonic-gate if (file == NULL)
8010Sstevel@tonic-gate return (DEVFS_ERR);
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate while (fgets(line, MAXVALSIZE + 6, file)) {
8040Sstevel@tonic-gate if (strncmp(line, "0 ", 2) != 0)
8050Sstevel@tonic-gate continue;
8060Sstevel@tonic-gate /* drop new-line */
8070Sstevel@tonic-gate line[strlen(line) - 1] = '\0';
8080Sstevel@tonic-gate /*
8090Sstevel@tonic-gate * an x86 BIOS only boots a disk, not a partition
8100Sstevel@tonic-gate * or a slice, so hard-code :q (p0)
8110Sstevel@tonic-gate */
8120Sstevel@tonic-gate cp = strchr(line + 2, ' ');
8130Sstevel@tonic-gate if (cp == NULL)
8140Sstevel@tonic-gate break;
8150Sstevel@tonic-gate (void) snprintf(opp->oprom_array, MAXVALSIZE,
8160Sstevel@tonic-gate "%s:q", cp + 1);
8170Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
8180Sstevel@tonic-gate ret = 0;
8190Sstevel@tonic-gate break;
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate (void) fclose(file);
8220Sstevel@tonic-gate return (ret);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate #endif /* ndef __sparc */
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate /*
8270Sstevel@tonic-gate * retrieve the list of entries in the boot-device configuration
8280Sstevel@tonic-gate * variable. An array of boot_dev structs will be created, one entry
8290Sstevel@tonic-gate * for each device name in the boot-device variable. Each entry
8300Sstevel@tonic-gate * in the array will contain the logical device representation of the
8310Sstevel@tonic-gate * boot-device entry, if any.
8320Sstevel@tonic-gate *
8330Sstevel@tonic-gate * default_root. if set, is used to locate logical device entries in
8340Sstevel@tonic-gate * directories other than /dev
8350Sstevel@tonic-gate */
8360Sstevel@tonic-gate int
devfs_bootdev_get_list(const char * default_root,struct boot_dev *** bootdev_list)8370Sstevel@tonic-gate devfs_bootdev_get_list(const char *default_root,
8380Sstevel@tonic-gate struct boot_dev ***bootdev_list)
8390Sstevel@tonic-gate {
8400Sstevel@tonic-gate Oppbuf oppbuf;
8410Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
8420Sstevel@tonic-gate int i;
8430Sstevel@tonic-gate struct boot_dev **tmp_list;
8440Sstevel@tonic-gate
8450Sstevel@tonic-gate if (default_root == NULL) {
8460Sstevel@tonic-gate default_root = "";
8470Sstevel@tonic-gate } else if (*default_root != '/') {
8480Sstevel@tonic-gate return (DEVFS_INVAL);
8490Sstevel@tonic-gate }
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate if (bootdev_list == NULL) {
8520Sstevel@tonic-gate return (DEVFS_INVAL);
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate
8550Sstevel@tonic-gate /* get the boot-device variable */
8560Sstevel@tonic-gate #if defined(sparc)
8570Sstevel@tonic-gate i = get_boot_dev_var(opp);
8580Sstevel@tonic-gate #else
8590Sstevel@tonic-gate i = find_x86_boot_device(opp);
8600Sstevel@tonic-gate #endif
8610Sstevel@tonic-gate if (i < 0) {
8620Sstevel@tonic-gate return (i);
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate /* now try to translate each entry to a logical device. */
8650Sstevel@tonic-gate i = process_bootdev(opp->oprom_array, default_root, &tmp_list);
8660Sstevel@tonic-gate if (i == 0) {
8670Sstevel@tonic-gate *bootdev_list = tmp_list;
8680Sstevel@tonic-gate return (0);
8690Sstevel@tonic-gate } else {
8700Sstevel@tonic-gate return (i);
8710Sstevel@tonic-gate }
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate
8740Sstevel@tonic-gate /*
8750Sstevel@tonic-gate * loop thru the list of entries in a boot-device configuration
8760Sstevel@tonic-gate * variable.
8770Sstevel@tonic-gate */
8780Sstevel@tonic-gate static int
process_bootdev(const char * bootdevice,const char * default_root,struct boot_dev *** list)8790Sstevel@tonic-gate process_bootdev(const char *bootdevice, const char *default_root,
8800Sstevel@tonic-gate struct boot_dev ***list)
8810Sstevel@tonic-gate {
8820Sstevel@tonic-gate int i;
8830Sstevel@tonic-gate char *entry, *ptr;
8840Sstevel@tonic-gate char prom_path[MAXPATHLEN];
8850Sstevel@tonic-gate char ret_buf[MAXPATHLEN];
8860Sstevel@tonic-gate struct boot_dev **bootdev_array;
8870Sstevel@tonic-gate int num_entries = 0;
8880Sstevel@tonic-gate int found = 0;
8890Sstevel@tonic-gate int vers;
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) {
8920Sstevel@tonic-gate return (DEVFS_NOMEM);
8930Sstevel@tonic-gate }
8940Sstevel@tonic-gate /* count the number of entries */
8950Sstevel@tonic-gate (void) strcpy(entry, bootdevice);
8960Sstevel@tonic-gate for (ptr = strtok(entry, " "); ptr != NULL;
8970Sstevel@tonic-gate ptr = strtok(NULL, " ")) {
8980Sstevel@tonic-gate num_entries++;
8990Sstevel@tonic-gate }
9000Sstevel@tonic-gate (void) strcpy(entry, bootdevice);
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate bootdev_array = (struct boot_dev **)
9030Sstevel@tonic-gate calloc((size_t)num_entries + 1, sizeof (struct boot_dev *));
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate if (bootdev_array == NULL) {
9060Sstevel@tonic-gate free(entry);
9070Sstevel@tonic-gate return (DEVFS_NOMEM);
9080Sstevel@tonic-gate }
9090Sstevel@tonic-gate
9100Sstevel@tonic-gate vers = prom_obp_vers();
9110Sstevel@tonic-gate if (vers < 0) {
9120Sstevel@tonic-gate free(entry);
9130Sstevel@tonic-gate return (vers);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate /* for each entry in boot-device, do... */
9170Sstevel@tonic-gate for (ptr = strtok(entry, " "), i = 0; ptr != NULL;
9180Sstevel@tonic-gate ptr = strtok(NULL, " "), i++) {
9190Sstevel@tonic-gate
9200Sstevel@tonic-gate if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) {
9210Sstevel@tonic-gate devfs_bootdev_free_list(bootdev_array);
9220Sstevel@tonic-gate free(entry);
9230Sstevel@tonic-gate return (DEVFS_NOMEM);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate
9263337Sas158974 /*
9273337Sas158974 * prom boot-device may be aliased, so we need to do
9283337Sas158974 * the necessary prom alias to dev translation.
9293337Sas158974 */
9303337Sas158974 if (*ptr != '/') {
9313337Sas158974 if (alias_to_prom_dev(ptr, prom_path) < 0) {
9323337Sas158974 continue;
9333337Sas158974 }
9343337Sas158974 } else {
9353337Sas158974 (void) strcpy(prom_path, ptr);
9363337Sas158974 }
9373337Sas158974
9380Sstevel@tonic-gate /* now we have a prom device path - convert to a devfs name */
9390Sstevel@tonic-gate if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) {
940*9735SSriman.Bhavanam@Sun.COM continue;
9410Sstevel@tonic-gate }
9423337Sas158974
9430Sstevel@tonic-gate /* append any default minor names necessary */
9440Sstevel@tonic-gate if (process_minor_name(ret_buf, default_root) < 0) {
945*9735SSriman.Bhavanam@Sun.COM continue;
9460Sstevel@tonic-gate }
9473337Sas158974 found = 1;
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate /*
9500Sstevel@tonic-gate * store the physical device path for now - when
9510Sstevel@tonic-gate * we are all done with the entries, we will convert
9520Sstevel@tonic-gate * these to their logical device name equivalents
9530Sstevel@tonic-gate */
9540Sstevel@tonic-gate bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf);
9550Sstevel@tonic-gate }
9560Sstevel@tonic-gate /*
9570Sstevel@tonic-gate * Convert all of the boot-device entries that translated to a
9580Sstevel@tonic-gate * physical device path in /devices to a logical device path
9590Sstevel@tonic-gate * in /dev (note that there may be several logical device paths
9600Sstevel@tonic-gate * associated with a single physical device path - return them all
9610Sstevel@tonic-gate */
9620Sstevel@tonic-gate if (found) {
9630Sstevel@tonic-gate if (devfs_phys_to_logical(bootdev_array, num_entries,
9640Sstevel@tonic-gate default_root) < 0) {
9650Sstevel@tonic-gate devfs_bootdev_free_list(bootdev_array);
9660Sstevel@tonic-gate bootdev_array = NULL;
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate free(entry);
9700Sstevel@tonic-gate *list = bootdev_array;
9710Sstevel@tonic-gate return (0);
9720Sstevel@tonic-gate }
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate /*
9750Sstevel@tonic-gate * We may get a device path from the prom that has no minor name
9760Sstevel@tonic-gate * information included in it. Since this device name will not
9770Sstevel@tonic-gate * correspond directly to a physical device in /devices, we do our
9780Sstevel@tonic-gate * best to append what the default minor name should be and try this.
9790Sstevel@tonic-gate *
9800Sstevel@tonic-gate * For sparc: we append slice 0 (:a).
9810Sstevel@tonic-gate * For x86: we append fdisk partition 0 (:q).
9820Sstevel@tonic-gate */
9830Sstevel@tonic-gate static int
process_minor_name(char * dev_path,const char * root)9840Sstevel@tonic-gate process_minor_name(char *dev_path, const char *root)
9850Sstevel@tonic-gate {
9860Sstevel@tonic-gate char *cp;
9870Sstevel@tonic-gate #if defined(sparc)
9880Sstevel@tonic-gate const char *default_minor_name = "a";
9890Sstevel@tonic-gate #else
9900Sstevel@tonic-gate const char *default_minor_name = "q";
9910Sstevel@tonic-gate #endif
9920Sstevel@tonic-gate int n;
9930Sstevel@tonic-gate struct stat stat_buf;
9940Sstevel@tonic-gate char path[MAXPATHLEN];
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
9970Sstevel@tonic-gate /*
9980Sstevel@tonic-gate * if the device file already exists as given to us, there
9990Sstevel@tonic-gate * is nothing to do but return.
10000Sstevel@tonic-gate */
10010Sstevel@tonic-gate if (stat(path, &stat_buf) == 0) {
10020Sstevel@tonic-gate return (0);
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate /*
10050Sstevel@tonic-gate * if there is no ':' after the last '/' character, or if there is
10060Sstevel@tonic-gate * a ':' with no specifier, append the default segment specifier
10070Sstevel@tonic-gate * ; if there is a ':' followed by a digit, this indicates
10080Sstevel@tonic-gate * a partition number (which does not map into the /devices name
10090Sstevel@tonic-gate * space), so strip the number and replace it with the letter
10100Sstevel@tonic-gate * that represents the partition index
10110Sstevel@tonic-gate */
10120Sstevel@tonic-gate if ((cp = strrchr(dev_path, '/')) != NULL) {
10130Sstevel@tonic-gate if ((cp = strchr(cp, ':')) == NULL) {
10140Sstevel@tonic-gate (void) strcat(dev_path, ":");
10150Sstevel@tonic-gate (void) strcat(dev_path, default_minor_name);
10160Sstevel@tonic-gate } else if (*++cp == '\0') {
10170Sstevel@tonic-gate (void) strcat(dev_path, default_minor_name);
10180Sstevel@tonic-gate } else if (isdigit(*cp)) {
10190Sstevel@tonic-gate n = atoi(cp);
10200Sstevel@tonic-gate /* make sure to squash the digit */
10210Sstevel@tonic-gate *cp = '\0';
10220Sstevel@tonic-gate switch (n) {
1023*9735SSriman.Bhavanam@Sun.COM case 0: (void) strcat(dev_path, "q");
10240Sstevel@tonic-gate break;
1025*9735SSriman.Bhavanam@Sun.COM case 1: (void) strcat(dev_path, "r");
10260Sstevel@tonic-gate break;
1027*9735SSriman.Bhavanam@Sun.COM case 2: (void) strcat(dev_path, "s");
10280Sstevel@tonic-gate break;
1029*9735SSriman.Bhavanam@Sun.COM case 3: (void) strcat(dev_path, "t");
10300Sstevel@tonic-gate break;
1031*9735SSriman.Bhavanam@Sun.COM case 4: (void) strcat(dev_path, "u");
10320Sstevel@tonic-gate break;
1033*9735SSriman.Bhavanam@Sun.COM default: (void) strcat(dev_path, "a");
10340Sstevel@tonic-gate break;
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate }
10370Sstevel@tonic-gate }
10380Sstevel@tonic-gate /*
10390Sstevel@tonic-gate * see if we can find something now.
10400Sstevel@tonic-gate */
10410Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate if (stat(path, &stat_buf) == 0) {
10440Sstevel@tonic-gate return (0);
10450Sstevel@tonic-gate } else {
10460Sstevel@tonic-gate return (-1);
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate /*
10510Sstevel@tonic-gate * for each entry in bootdev_array, convert the physical device
10520Sstevel@tonic-gate * representation of the boot-device entry to one or more logical device
10530Sstevel@tonic-gate * entries. We use the hammer method - walk through the logical device
10540Sstevel@tonic-gate * name space looking for matches (/dev). We use nftw to do this.
10550Sstevel@tonic-gate */
10560Sstevel@tonic-gate static int
devfs_phys_to_logical(struct boot_dev ** bootdev_array,const int array_size,const char * default_root)10570Sstevel@tonic-gate devfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size,
10580Sstevel@tonic-gate const char *default_root)
10590Sstevel@tonic-gate {
10600Sstevel@tonic-gate int walk_flags = FTW_PHYS | FTW_MOUNT;
10610Sstevel@tonic-gate char *full_path;
10620Sstevel@tonic-gate struct name_list *list;
10630Sstevel@tonic-gate int count, i;
10640Sstevel@tonic-gate char **dev_name_array;
10650Sstevel@tonic-gate size_t default_root_len;
10660Sstevel@tonic-gate char *dev_dir = DEV;
10670Sstevel@tonic-gate int len;
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate if (array_size < 0) {
10700Sstevel@tonic-gate return (-1);
10710Sstevel@tonic-gate }
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate if (bootdev_array == NULL) {
10740Sstevel@tonic-gate return (-1);
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate if (default_root == NULL) {
10770Sstevel@tonic-gate return (-1);
10780Sstevel@tonic-gate }
10790Sstevel@tonic-gate default_root_len = strlen(default_root);
10800Sstevel@tonic-gate if ((default_root_len != 0) && (*default_root != '/')) {
10810Sstevel@tonic-gate return (-1);
10820Sstevel@tonic-gate }
10833337Sas158974
10840Sstevel@tonic-gate /* short cut for an empty array */
10850Sstevel@tonic-gate if (*bootdev_array == NULL) {
10860Sstevel@tonic-gate return (0);
10870Sstevel@tonic-gate }
10880Sstevel@tonic-gate
10890Sstevel@tonic-gate /* tell nftw where to start (default: /dev) */
10900Sstevel@tonic-gate len = default_root_len + strlen(dev_dir) + 1;
10910Sstevel@tonic-gate if ((full_path = (char *)malloc(len)) == NULL) {
10920Sstevel@tonic-gate return (-1);
10930Sstevel@tonic-gate }
10943337Sas158974
10950Sstevel@tonic-gate /*
10960Sstevel@tonic-gate * if the default root path is terminated with a /, we have to
10970Sstevel@tonic-gate * make sure we don't end up with one too many slashes in the
10980Sstevel@tonic-gate * path we are building.
10990Sstevel@tonic-gate */
11000Sstevel@tonic-gate if ((default_root_len > (size_t)0) &&
11010Sstevel@tonic-gate (default_root[default_root_len - 1] == '/')) {
11020Sstevel@tonic-gate (void) snprintf(full_path, len, "%s%s", default_root,
11030Sstevel@tonic-gate &dev_dir[1]);
11040Sstevel@tonic-gate } else {
11050Sstevel@tonic-gate (void) snprintf(full_path, len, "%s%s", default_root, dev_dir);
11060Sstevel@tonic-gate }
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate /*
11090Sstevel@tonic-gate * we need to muck with global data to make nftw work
11100Sstevel@tonic-gate * so single thread access
11110Sstevel@tonic-gate */
11120Sstevel@tonic-gate (void) mutex_lock(&dev_lists_lk);
11130Sstevel@tonic-gate
11140Sstevel@tonic-gate /*
11150Sstevel@tonic-gate * set the global vars bootdev_list and dev_list for use by nftw
11160Sstevel@tonic-gate * dev_list is an array of lists - one for each boot-device
11170Sstevel@tonic-gate * entry. The nftw function will create a list of logical device
11180Sstevel@tonic-gate * entries for each boot-device and put all of the lists in
11190Sstevel@tonic-gate * dev_list.
11200Sstevel@tonic-gate */
11210Sstevel@tonic-gate dev_list = (struct name_list **)
11220Sstevel@tonic-gate calloc(array_size, sizeof (struct name_list *));
11230Sstevel@tonic-gate if (dev_list == NULL) {
11240Sstevel@tonic-gate free(full_path);
11250Sstevel@tonic-gate (void) mutex_unlock(&dev_lists_lk);
11260Sstevel@tonic-gate return (-1);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate bootdev_list = bootdev_array;
11290Sstevel@tonic-gate
11300Sstevel@tonic-gate if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) {
11310Sstevel@tonic-gate bootdev_list = NULL;
11320Sstevel@tonic-gate free(full_path);
11330Sstevel@tonic-gate for (i = 0; i < array_size; i++) {
11340Sstevel@tonic-gate free_name_list(dev_list[i], 1);
11350Sstevel@tonic-gate }
11360Sstevel@tonic-gate /* don't free dev_list here because it's been handed off */
11370Sstevel@tonic-gate dev_list = NULL;
11380Sstevel@tonic-gate (void) mutex_unlock(&dev_lists_lk);
11390Sstevel@tonic-gate return (-1);
11400Sstevel@tonic-gate }
11413337Sas158974
11420Sstevel@tonic-gate /*
11430Sstevel@tonic-gate * now we have a filled in dev_list. So for each logical device
11440Sstevel@tonic-gate * list in dev_list, count the number of entries in the list,
11450Sstevel@tonic-gate * create an array of strings of logical devices, and save in the
11460Sstevel@tonic-gate * corresponding boot_dev structure.
11470Sstevel@tonic-gate */
11480Sstevel@tonic-gate for (i = 0; i < array_size; i++) {
11490Sstevel@tonic-gate /* get the next list */
11500Sstevel@tonic-gate list = dev_list[i];
11510Sstevel@tonic-gate count = 0;
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate /* count the number of entries in the list */
11540Sstevel@tonic-gate while (list != NULL) {
11550Sstevel@tonic-gate count++;
11560Sstevel@tonic-gate list = list->next;
11570Sstevel@tonic-gate }
11580Sstevel@tonic-gate if ((dev_name_array =
11590Sstevel@tonic-gate (char **)malloc((count + 1) * sizeof (char *)))
11600Sstevel@tonic-gate == NULL) {
11610Sstevel@tonic-gate continue;
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate list = dev_list[i];
11640Sstevel@tonic-gate count = 0;
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate /* fill in the array */
11670Sstevel@tonic-gate while (list != NULL) {
11680Sstevel@tonic-gate dev_name_array[count] = list->name;
11690Sstevel@tonic-gate count++;
11700Sstevel@tonic-gate list = list->next;
11710Sstevel@tonic-gate }
11723337Sas158974
11730Sstevel@tonic-gate /*
11740Sstevel@tonic-gate * null terminate the array
11750Sstevel@tonic-gate */
11760Sstevel@tonic-gate dev_name_array[count] = NULL;
11773337Sas158974 if ((bootdev_array[i] != NULL) && (bootdev_array[i]->
11783337Sas158974 bootdev_trans[0] != NULL)) {
11790Sstevel@tonic-gate free(bootdev_array[i]->bootdev_trans[0]);
11800Sstevel@tonic-gate }
11813337Sas158974 if (bootdev_array[i] != NULL) {
11823337Sas158974 free(bootdev_array[i]->bootdev_trans);
11833337Sas158974 bootdev_array[i]->bootdev_trans = dev_name_array;
11843337Sas158974 }
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate bootdev_list = NULL;
11870Sstevel@tonic-gate free(full_path);
11880Sstevel@tonic-gate for (i = 0; i < array_size; i++) {
11890Sstevel@tonic-gate free_name_list(dev_list[i], 0);
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate free(dev_list);
11920Sstevel@tonic-gate dev_list = NULL;
11930Sstevel@tonic-gate (void) mutex_unlock(&dev_lists_lk);
11940Sstevel@tonic-gate return (0);
11950Sstevel@tonic-gate }
11960Sstevel@tonic-gate /*
11970Sstevel@tonic-gate * nftw function
11980Sstevel@tonic-gate * for a logical dev entry, it walks the list of boot-devices and
11990Sstevel@tonic-gate * sees if there are any matches. If so, it saves the logical device
12000Sstevel@tonic-gate * name off in the appropriate list in dev_list
12010Sstevel@tonic-gate */
12020Sstevel@tonic-gate /* ARGSUSED */
12030Sstevel@tonic-gate static int
check_logical_dev(const char * node,const struct stat * node_stat,int flags,struct FTW * ftw_info)12040Sstevel@tonic-gate check_logical_dev(const char *node, const struct stat *node_stat, int flags,
12050Sstevel@tonic-gate struct FTW *ftw_info)
12060Sstevel@tonic-gate {
12070Sstevel@tonic-gate char link_buf[MAXPATHLEN];
12080Sstevel@tonic-gate int link_buf_len;
12090Sstevel@tonic-gate char *name;
12100Sstevel@tonic-gate struct name_list *dev;
12110Sstevel@tonic-gate char *physdev;
12120Sstevel@tonic-gate int i;
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate if (flags != FTW_SL) {
12150Sstevel@tonic-gate return (0);
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate
12180Sstevel@tonic-gate if ((link_buf_len = readlink(node, (void *)link_buf, MAXPATHLEN))
12190Sstevel@tonic-gate == -1) {
12200Sstevel@tonic-gate return (0);
12210Sstevel@tonic-gate }
12220Sstevel@tonic-gate link_buf[link_buf_len] = '\0';
12230Sstevel@tonic-gate if ((name = strstr(link_buf, DEVICES)) == NULL) {
12240Sstevel@tonic-gate return (0);
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate name = (char *)(name + strlen(DEVICES));
12270Sstevel@tonic-gate
12280Sstevel@tonic-gate for (i = 0; bootdev_list[i] != NULL; i++) {
12290Sstevel@tonic-gate if (bootdev_list[i]->bootdev_trans[0] == NULL) {
12300Sstevel@tonic-gate continue;
12310Sstevel@tonic-gate }
12320Sstevel@tonic-gate /*
12330Sstevel@tonic-gate * compare the contents of the link with the physical
12340Sstevel@tonic-gate * device representation of this boot device
12350Sstevel@tonic-gate */
12360Sstevel@tonic-gate physdev = bootdev_list[i]->bootdev_trans[0];
12370Sstevel@tonic-gate if ((strcmp(name, physdev) == 0) &&
12380Sstevel@tonic-gate (strlen(name) == strlen(physdev))) {
12390Sstevel@tonic-gate if ((dev = (struct name_list *)
12400Sstevel@tonic-gate malloc(sizeof (struct name_list))) == NULL) {
12410Sstevel@tonic-gate return (-1);
12420Sstevel@tonic-gate }
12430Sstevel@tonic-gate if ((dev->name = strdup(node)) == NULL) {
12440Sstevel@tonic-gate free(dev);
12450Sstevel@tonic-gate return (-1);
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate if (dev_list[i] == NULL) {
12480Sstevel@tonic-gate dev_list[i] = dev;
12490Sstevel@tonic-gate dev_list[i]->next = NULL;
12500Sstevel@tonic-gate } else {
12510Sstevel@tonic-gate dev->next = dev_list[i];
12520Sstevel@tonic-gate dev_list[i] = dev;
12530Sstevel@tonic-gate }
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate }
12560Sstevel@tonic-gate return (0);
12570Sstevel@tonic-gate }
12580Sstevel@tonic-gate
12590Sstevel@tonic-gate /*
12600Sstevel@tonic-gate * frees a list of boot_dev struct pointers
12610Sstevel@tonic-gate */
12620Sstevel@tonic-gate void
devfs_bootdev_free_list(struct boot_dev ** array)12630Sstevel@tonic-gate devfs_bootdev_free_list(struct boot_dev **array)
12640Sstevel@tonic-gate {
12650Sstevel@tonic-gate int i = 0;
12660Sstevel@tonic-gate int j;
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate if (array == NULL) {
12690Sstevel@tonic-gate return;
12700Sstevel@tonic-gate }
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate while (array[i] != NULL) {
12730Sstevel@tonic-gate free(array[i]->bootdev_element);
12740Sstevel@tonic-gate j = 0;
12750Sstevel@tonic-gate while (array[i]->bootdev_trans[j] != NULL) {
12760Sstevel@tonic-gate free(array[i]->bootdev_trans[j++]);
12770Sstevel@tonic-gate }
12780Sstevel@tonic-gate free(array[i]->bootdev_trans);
12790Sstevel@tonic-gate free(array[i]);
12800Sstevel@tonic-gate i++;
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate free(array);
12830Sstevel@tonic-gate }
12840Sstevel@tonic-gate /*
12850Sstevel@tonic-gate * allocates a boot_dev struct and fills in the bootdev_element portion
12860Sstevel@tonic-gate */
12870Sstevel@tonic-gate static struct boot_dev *
alloc_bootdev(char * entry_name)12880Sstevel@tonic-gate alloc_bootdev(char *entry_name)
12890Sstevel@tonic-gate {
12900Sstevel@tonic-gate struct boot_dev *entry;
12910Sstevel@tonic-gate
12920Sstevel@tonic-gate entry = (struct boot_dev *)calloc(1, sizeof (struct boot_dev));
12930Sstevel@tonic-gate
12940Sstevel@tonic-gate if (entry == NULL) {
12950Sstevel@tonic-gate return (NULL);
12960Sstevel@tonic-gate }
12970Sstevel@tonic-gate if ((entry->bootdev_element = strdup(entry_name)) == NULL) {
12980Sstevel@tonic-gate free(entry);
12990Sstevel@tonic-gate return (NULL);
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate /*
13020Sstevel@tonic-gate * Allocate room for 1 name and a null terminator - the caller of
13030Sstevel@tonic-gate * this function will need the first slot right away.
13040Sstevel@tonic-gate */
13050Sstevel@tonic-gate if ((entry->bootdev_trans = (char **)calloc(2, sizeof (char *)))
13060Sstevel@tonic-gate == NULL) {
13070Sstevel@tonic-gate free(entry->bootdev_element);
13080Sstevel@tonic-gate free(entry);
13090Sstevel@tonic-gate return (NULL);
13100Sstevel@tonic-gate }
13110Sstevel@tonic-gate return (entry);
13120Sstevel@tonic-gate }
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate /*
13150Sstevel@tonic-gate * will come back with a concatenated list of paths
13160Sstevel@tonic-gate */
13170Sstevel@tonic-gate int
devfs_dev_to_prom_names(char * dev_path,char * prom_path,size_t len)13180Sstevel@tonic-gate devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len)
13190Sstevel@tonic-gate {
13200Sstevel@tonic-gate Oppbuf oppbuf;
13210Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
13220Sstevel@tonic-gate int prom_fd;
13230Sstevel@tonic-gate int ret = DEVFS_INVAL;
13240Sstevel@tonic-gate int i;
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate if (prom_path == NULL) {
13270Sstevel@tonic-gate return (DEVFS_INVAL);
13280Sstevel@tonic-gate }
13290Sstevel@tonic-gate if (dev_path == NULL) {
13300Sstevel@tonic-gate return (DEVFS_INVAL);
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate if (strlen(dev_path) >= MAXPATHLEN)
13330Sstevel@tonic-gate return (DEVFS_INVAL);
13340Sstevel@tonic-gate
13350Sstevel@tonic-gate if (*dev_path != '/')
13360Sstevel@tonic-gate return (DEVFS_INVAL);
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY);
13390Sstevel@tonic-gate if (prom_fd < 0) {
13400Sstevel@tonic-gate return (prom_fd);
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate
13430Sstevel@tonic-gate /* query the prom */
13440Sstevel@tonic-gate (void) snprintf(opp->oprom_array, MAXVALSIZE, "%s", dev_path);
13450Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
13460Sstevel@tonic-gate
13470Sstevel@tonic-gate if (ioctl(prom_fd, OPROMDEV2PROMNAME, opp) == 0) {
13480Sstevel@tonic-gate prom_close(prom_fd);
13490Sstevel@tonic-gate
13500Sstevel@tonic-gate /* return the prom path in prom_path */
13510Sstevel@tonic-gate
13520Sstevel@tonic-gate i = len - opp->oprom_size;
13530Sstevel@tonic-gate if (i < 0) {
13540Sstevel@tonic-gate bcopy(opp->oprom_array, prom_path, len);
13550Sstevel@tonic-gate prom_path[len - 1] = NULL;
13560Sstevel@tonic-gate return (len);
13570Sstevel@tonic-gate } else {
13580Sstevel@tonic-gate bcopy(opp->oprom_array, prom_path, len);
13590Sstevel@tonic-gate return (opp->oprom_size);
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate /*
13630Sstevel@tonic-gate * either the prom does not support this ioctl or the argument
13640Sstevel@tonic-gate * was invalid.
13650Sstevel@tonic-gate */
13660Sstevel@tonic-gate if (errno == ENXIO) {
13670Sstevel@tonic-gate ret = DEVFS_NOTSUP;
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate prom_close(prom_fd);
13700Sstevel@tonic-gate return (ret);
13710Sstevel@tonic-gate }
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate /*
13740Sstevel@tonic-gate * Convert a physical or logical device name to a name the prom would
13750Sstevel@tonic-gate * understand. Fail if this platform does not support a prom or if
13760Sstevel@tonic-gate * the device does not correspond to a valid prom device.
13770Sstevel@tonic-gate * dev_path should be the name of a device in the logical or
13780Sstevel@tonic-gate * physical device namespace.
13790Sstevel@tonic-gate * prom_path is the prom version of the device name
13800Sstevel@tonic-gate * prom_path must be large enough to contain the result and is
13810Sstevel@tonic-gate * supplied by the user.
13820Sstevel@tonic-gate *
13830Sstevel@tonic-gate * This routine only supports converting leaf device paths
13840Sstevel@tonic-gate */
13850Sstevel@tonic-gate int
devfs_dev_to_prom_name(char * dev_path,char * prom_path)13860Sstevel@tonic-gate devfs_dev_to_prom_name(char *dev_path, char *prom_path)
13870Sstevel@tonic-gate {
13880Sstevel@tonic-gate int rval;
13890Sstevel@tonic-gate
13900Sstevel@tonic-gate rval = devfs_dev_to_prom_names(dev_path, prom_path, MAXPATHLEN);
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate if (rval < 0)
13930Sstevel@tonic-gate return (rval);
13940Sstevel@tonic-gate else
13950Sstevel@tonic-gate return (0);
13960Sstevel@tonic-gate }
13970Sstevel@tonic-gate
13980Sstevel@tonic-gate /*
13990Sstevel@tonic-gate * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs
14000Sstevel@tonic-gate * path to a driver name.
14010Sstevel@tonic-gate * devfs_path - the pathname of interest. This must be the physcical device
14020Sstevel@tonic-gate * path with the mount point prefix (ie. /devices) stripped off.
14030Sstevel@tonic-gate * drv_buf - user supplied buffer - the driver name will be stored here.
14040Sstevel@tonic-gate *
14050Sstevel@tonic-gate * If the prom lookup fails, we return the name of the last component in
14060Sstevel@tonic-gate * the pathname. This routine is useful for looking up driver names
14070Sstevel@tonic-gate * associated with generically named devices.
14080Sstevel@tonic-gate *
14090Sstevel@tonic-gate * This routine returns driver names that have aliases resolved.
14100Sstevel@tonic-gate */
14110Sstevel@tonic-gate int
devfs_path_to_drv(char * devfs_path,char * drv_buf)14120Sstevel@tonic-gate devfs_path_to_drv(char *devfs_path, char *drv_buf)
14130Sstevel@tonic-gate {
14140Sstevel@tonic-gate Oppbuf oppbuf;
14150Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
14160Sstevel@tonic-gate char *slash, *colon, *dev_addr;
14170Sstevel@tonic-gate char driver_path[MAXPATHLEN];
14180Sstevel@tonic-gate int prom_fd;
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate if (drv_buf == NULL) {
14210Sstevel@tonic-gate return (-1);
14220Sstevel@tonic-gate }
14230Sstevel@tonic-gate if (devfs_path == NULL) {
14240Sstevel@tonic-gate return (-1);
14250Sstevel@tonic-gate }
14260Sstevel@tonic-gate
14270Sstevel@tonic-gate if (strlen(devfs_path) >= MAXPATHLEN)
14280Sstevel@tonic-gate return (-1);
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate if (*devfs_path != '/')
14310Sstevel@tonic-gate return (-1);
14320Sstevel@tonic-gate
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate /* strip off any minor node info at the end of the path */
14350Sstevel@tonic-gate (void) strcpy(driver_path, devfs_path);
14360Sstevel@tonic-gate slash = strrchr(driver_path, '/');
14370Sstevel@tonic-gate if (slash == NULL)
14380Sstevel@tonic-gate return (-1);
14390Sstevel@tonic-gate colon = strrchr(slash, ':');
14400Sstevel@tonic-gate if (colon != NULL)
14410Sstevel@tonic-gate *colon = '\0';
14420Sstevel@tonic-gate
14430Sstevel@tonic-gate /* query the prom */
14440Sstevel@tonic-gate if ((prom_fd = prom_open(O_RDONLY)) >= 0) {
14450Sstevel@tonic-gate (void) strcpy(opp->oprom_array, driver_path);
14460Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
14470Sstevel@tonic-gate
14480Sstevel@tonic-gate if (ioctl(prom_fd, OPROMPATH2DRV, opp) == 0) {
14490Sstevel@tonic-gate prom_close(prom_fd);
14500Sstevel@tonic-gate /* return the driver name in drv_buf */
14510Sstevel@tonic-gate (void) strcpy(drv_buf, opp->oprom_array);
14520Sstevel@tonic-gate return (0);
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate prom_close(prom_fd);
14550Sstevel@tonic-gate } else if (prom_fd != DEVFS_NOTSUP)
14560Sstevel@tonic-gate return (-1);
14570Sstevel@tonic-gate /*
14580Sstevel@tonic-gate * If we get here, then either:
14590Sstevel@tonic-gate * 1. this platform does not support an openprom driver
14600Sstevel@tonic-gate * 2. we were asked to look up a device the prom does
14610Sstevel@tonic-gate * not know about (e.g. a pseudo device)
14620Sstevel@tonic-gate * In this case, we use the last component of the devfs path
14630Sstevel@tonic-gate * name and try to derive the driver name
14640Sstevel@tonic-gate */
14650Sstevel@tonic-gate
14660Sstevel@tonic-gate /* use the last component of devfs_path as the driver name */
14670Sstevel@tonic-gate if ((dev_addr = strrchr(slash, '@')) != NULL)
14680Sstevel@tonic-gate *dev_addr = '\0';
14690Sstevel@tonic-gate slash++;
14700Sstevel@tonic-gate
14710Sstevel@tonic-gate /* use opp->oprom_array as a buffer */
14720Sstevel@tonic-gate (void) strcpy(opp->oprom_array, slash);
14730Sstevel@tonic-gate if (devfs_resolve_aliases(opp->oprom_array) == NULL)
14740Sstevel@tonic-gate return (-1);
14750Sstevel@tonic-gate (void) strcpy(drv_buf, opp->oprom_array);
14760Sstevel@tonic-gate return (0);
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate * These modctl calls do the equivalent of:
14810Sstevel@tonic-gate * ddi_name_to_major()
14820Sstevel@tonic-gate * ddi_major_to_name()
14830Sstevel@tonic-gate * This results in two things:
14840Sstevel@tonic-gate * - the driver name must be a valid one
14850Sstevel@tonic-gate * - any driver aliases are resolved.
14860Sstevel@tonic-gate * drv is overwritten with the resulting name.
14870Sstevel@tonic-gate */
14880Sstevel@tonic-gate char *
devfs_resolve_aliases(char * drv)14890Sstevel@tonic-gate devfs_resolve_aliases(char *drv)
14900Sstevel@tonic-gate {
14910Sstevel@tonic-gate major_t maj;
14920Sstevel@tonic-gate char driver_name[MAXNAMELEN + 1];
14930Sstevel@tonic-gate
14940Sstevel@tonic-gate if (drv == NULL) {
14950Sstevel@tonic-gate return (NULL);
14960Sstevel@tonic-gate }
14970Sstevel@tonic-gate
14980Sstevel@tonic-gate if (modctl(MODGETMAJBIND, drv, strlen(drv) + 1, &maj) < 0)
14990Sstevel@tonic-gate return (NULL);
15000Sstevel@tonic-gate else if (modctl(MODGETNAME, driver_name, sizeof (driver_name), &maj)
15010Sstevel@tonic-gate < 0) {
15020Sstevel@tonic-gate return (NULL);
15030Sstevel@tonic-gate } else {
15040Sstevel@tonic-gate (void) strcpy(drv, driver_name);
15050Sstevel@tonic-gate return (drv);
15060Sstevel@tonic-gate }
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate
15090Sstevel@tonic-gate /*
15100Sstevel@tonic-gate * open the openprom device. and verify that we are on an
15110Sstevel@tonic-gate * OBP/1275 OF machine. If the prom does not exist, then we
15120Sstevel@tonic-gate * return an error
15130Sstevel@tonic-gate */
15140Sstevel@tonic-gate static int
prom_open(int oflag)15150Sstevel@tonic-gate prom_open(int oflag)
15160Sstevel@tonic-gate {
15170Sstevel@tonic-gate int prom_fd = -1;
15180Sstevel@tonic-gate char *promdev = "/dev/openprom";
15190Sstevel@tonic-gate
15200Sstevel@tonic-gate while (prom_fd < 0) {
15210Sstevel@tonic-gate if ((prom_fd = open(promdev, oflag)) < 0) {
15220Sstevel@tonic-gate if (errno == EAGAIN) {
15230Sstevel@tonic-gate (void) sleep(5);
15240Sstevel@tonic-gate continue;
15250Sstevel@tonic-gate }
15260Sstevel@tonic-gate if ((errno == ENXIO) || (errno == ENOENT)) {
15270Sstevel@tonic-gate return (DEVFS_NOTSUP);
15280Sstevel@tonic-gate }
15290Sstevel@tonic-gate if ((errno == EPERM) || (errno == EACCES)) {
15300Sstevel@tonic-gate return (DEVFS_PERM);
15310Sstevel@tonic-gate }
15320Sstevel@tonic-gate return (DEVFS_ERR);
15330Sstevel@tonic-gate } else
15340Sstevel@tonic-gate break;
15350Sstevel@tonic-gate }
15360Sstevel@tonic-gate if (is_openprom(prom_fd))
15370Sstevel@tonic-gate return (prom_fd);
15380Sstevel@tonic-gate else {
15390Sstevel@tonic-gate prom_close(prom_fd);
15400Sstevel@tonic-gate return (DEVFS_ERR);
15410Sstevel@tonic-gate }
15420Sstevel@tonic-gate }
15430Sstevel@tonic-gate
15440Sstevel@tonic-gate static void
prom_close(int prom_fd)15450Sstevel@tonic-gate prom_close(int prom_fd)
15460Sstevel@tonic-gate {
15470Sstevel@tonic-gate (void) close(prom_fd);
15480Sstevel@tonic-gate }
15490Sstevel@tonic-gate
15500Sstevel@tonic-gate /*
15510Sstevel@tonic-gate * is this an OBP/1275 OF machine?
15520Sstevel@tonic-gate */
15530Sstevel@tonic-gate static int
is_openprom(int prom_fd)15540Sstevel@tonic-gate is_openprom(int prom_fd)
15550Sstevel@tonic-gate {
15560Sstevel@tonic-gate Oppbuf oppbuf;
15570Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
15580Sstevel@tonic-gate unsigned int i;
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
15610Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
15620Sstevel@tonic-gate return (0);
15630Sstevel@tonic-gate
15640Sstevel@tonic-gate i = (unsigned int)((unsigned char)opp->oprom_array[0]);
15650Sstevel@tonic-gate return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
15660Sstevel@tonic-gate }
15670Sstevel@tonic-gate
15680Sstevel@tonic-gate /*
15690Sstevel@tonic-gate * convert a prom device path name to an equivalent physical device
15700Sstevel@tonic-gate * path in the kernel.
15710Sstevel@tonic-gate */
15720Sstevel@tonic-gate static int
devfs_prom_to_dev_name(char * prom_path,char * dev_path)15730Sstevel@tonic-gate devfs_prom_to_dev_name(char *prom_path, char *dev_path)
15740Sstevel@tonic-gate {
15750Sstevel@tonic-gate Oppbuf oppbuf;
15760Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
15770Sstevel@tonic-gate int prom_fd;
15780Sstevel@tonic-gate int ret = DEVFS_INVAL;
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate if (dev_path == NULL) {
15810Sstevel@tonic-gate return (DEVFS_INVAL);
15820Sstevel@tonic-gate }
15830Sstevel@tonic-gate if (prom_path == NULL) {
15840Sstevel@tonic-gate return (DEVFS_INVAL);
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate if (strlen(prom_path) >= MAXPATHLEN)
15870Sstevel@tonic-gate return (DEVFS_INVAL);
15880Sstevel@tonic-gate
15890Sstevel@tonic-gate if (*prom_path != '/') {
15900Sstevel@tonic-gate return (DEVFS_INVAL);
15910Sstevel@tonic-gate }
15920Sstevel@tonic-gate
15930Sstevel@tonic-gate /* query the prom */
15940Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY);
15950Sstevel@tonic-gate if (prom_fd < 0) {
15960Sstevel@tonic-gate return (prom_fd);
15970Sstevel@tonic-gate }
15980Sstevel@tonic-gate (void) strcpy(opp->oprom_array, prom_path);
15990Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
16000Sstevel@tonic-gate
16010Sstevel@tonic-gate if (ioctl(prom_fd, OPROMPROM2DEVNAME, opp) == 0) {
16020Sstevel@tonic-gate prom_close(prom_fd);
16030Sstevel@tonic-gate /*
16040Sstevel@tonic-gate * success
16050Sstevel@tonic-gate * return the prom path in prom_path
16060Sstevel@tonic-gate */
16070Sstevel@tonic-gate (void) strcpy(dev_path, opp->oprom_array);
16080Sstevel@tonic-gate return (0);
16090Sstevel@tonic-gate }
16100Sstevel@tonic-gate /*
16110Sstevel@tonic-gate * either the argument was not a valid name or the openprom
16120Sstevel@tonic-gate * driver does not support this ioctl.
16130Sstevel@tonic-gate */
16140Sstevel@tonic-gate if (errno == ENXIO) {
16150Sstevel@tonic-gate ret = DEVFS_NOTSUP;
16160Sstevel@tonic-gate }
16170Sstevel@tonic-gate prom_close(prom_fd);
16180Sstevel@tonic-gate return (ret);
16190Sstevel@tonic-gate }
16200Sstevel@tonic-gate /*
16210Sstevel@tonic-gate * convert a prom device path to a list of equivalent alias names
16220Sstevel@tonic-gate * If there is no alias node, or there are no aliases that correspond
16230Sstevel@tonic-gate * to dev, we return empty lists.
16240Sstevel@tonic-gate */
16250Sstevel@tonic-gate static int
prom_dev_to_alias(char * dev,uint_t options,char *** ret_buf)16260Sstevel@tonic-gate prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf)
16270Sstevel@tonic-gate {
16280Sstevel@tonic-gate struct name_list *exact_list;
16290Sstevel@tonic-gate struct name_list *inexact_list;
16300Sstevel@tonic-gate struct name_list *list;
16310Sstevel@tonic-gate char *ptr;
16320Sstevel@tonic-gate char **array;
16330Sstevel@tonic-gate int prom_fd;
16340Sstevel@tonic-gate int count;
16350Sstevel@tonic-gate int vers;
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate vers = prom_obp_vers();
16380Sstevel@tonic-gate if (vers < 0) {
16390Sstevel@tonic-gate return (vers);
16400Sstevel@tonic-gate }
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate if (dev == NULL) {
16430Sstevel@tonic-gate return (DEVFS_INVAL);
16440Sstevel@tonic-gate }
16450Sstevel@tonic-gate
16460Sstevel@tonic-gate if (*dev != '/')
16470Sstevel@tonic-gate return (DEVFS_INVAL);
16480Sstevel@tonic-gate
16490Sstevel@tonic-gate if (strlen(dev) >= MAXPATHLEN)
16500Sstevel@tonic-gate return (DEVFS_INVAL);
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate if ((ptr = strchr(dev, ':')) != NULL) {
16530Sstevel@tonic-gate if (strchr(ptr, '/') != NULL)
16540Sstevel@tonic-gate return (DEVFS_INVAL);
16550Sstevel@tonic-gate }
16560Sstevel@tonic-gate if (ret_buf == NULL) {
16570Sstevel@tonic-gate return (DEVFS_INVAL);
16580Sstevel@tonic-gate }
16590Sstevel@tonic-gate
16600Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY);
16610Sstevel@tonic-gate if (prom_fd < 0) {
16620Sstevel@tonic-gate return (prom_fd);
16630Sstevel@tonic-gate }
16640Sstevel@tonic-gate
16650Sstevel@tonic-gate (void) prom_srch_aliases_by_def(dev, &exact_list,
16660Sstevel@tonic-gate &inexact_list, prom_fd);
16670Sstevel@tonic-gate
16680Sstevel@tonic-gate prom_close(prom_fd);
16690Sstevel@tonic-gate
16700Sstevel@tonic-gate if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) {
16710Sstevel@tonic-gate free_name_list(exact_list, 1);
16720Sstevel@tonic-gate exact_list = NULL;
16730Sstevel@tonic-gate }
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) {
16760Sstevel@tonic-gate free_name_list(inexact_list, 1);
16770Sstevel@tonic-gate inexact_list = NULL;
16780Sstevel@tonic-gate }
16790Sstevel@tonic-gate
16800Sstevel@tonic-gate count = 0;
16810Sstevel@tonic-gate list = exact_list;
16820Sstevel@tonic-gate while (list != NULL) {
16830Sstevel@tonic-gate list = list->next;
16840Sstevel@tonic-gate count++;
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate list = inexact_list;
16870Sstevel@tonic-gate while (list != NULL) {
16880Sstevel@tonic-gate list = list->next;
16890Sstevel@tonic-gate count++;
16900Sstevel@tonic-gate }
16910Sstevel@tonic-gate
16920Sstevel@tonic-gate if ((*ret_buf = (char **)malloc((count + 1) * sizeof (char *)))
16930Sstevel@tonic-gate == NULL) {
16940Sstevel@tonic-gate free_name_list(inexact_list, 1);
16950Sstevel@tonic-gate free_name_list(exact_list, 1);
16960Sstevel@tonic-gate return (DEVFS_NOMEM);
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate
16990Sstevel@tonic-gate array = *ret_buf;
17000Sstevel@tonic-gate count = 0;
17010Sstevel@tonic-gate list = exact_list;
17020Sstevel@tonic-gate while (list != NULL) {
17030Sstevel@tonic-gate array[count] = list->name;
17040Sstevel@tonic-gate list = list->next;
17050Sstevel@tonic-gate count++;
17060Sstevel@tonic-gate }
17070Sstevel@tonic-gate list = inexact_list;
17080Sstevel@tonic-gate while (list != NULL) {
17090Sstevel@tonic-gate array[count] = list->name;
17100Sstevel@tonic-gate list = list->next;
17110Sstevel@tonic-gate count++;
17120Sstevel@tonic-gate }
17130Sstevel@tonic-gate array[count] = NULL;
17140Sstevel@tonic-gate free_name_list(inexact_list, 0);
17150Sstevel@tonic-gate free_name_list(exact_list, 0);
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate return (0);
17180Sstevel@tonic-gate }
17190Sstevel@tonic-gate
17200Sstevel@tonic-gate /*
17210Sstevel@tonic-gate * determine the version of prom we are running on.
17220Sstevel@tonic-gate * Also include any prom revision specific information.
17230Sstevel@tonic-gate */
17240Sstevel@tonic-gate static int
prom_obp_vers(void)17250Sstevel@tonic-gate prom_obp_vers(void)
17260Sstevel@tonic-gate {
17270Sstevel@tonic-gate Oppbuf oppbuf;
17280Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
17290Sstevel@tonic-gate int prom_fd;
17300Sstevel@tonic-gate static int version = 0;
17310Sstevel@tonic-gate
17320Sstevel@tonic-gate /* cache version */
17330Sstevel@tonic-gate if (version > 0) {
17340Sstevel@tonic-gate return (version);
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY);
17380Sstevel@tonic-gate if (prom_fd < 0) {
17390Sstevel@tonic-gate return (prom_fd);
17400Sstevel@tonic-gate }
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
17430Sstevel@tonic-gate
17440Sstevel@tonic-gate if ((ioctl(prom_fd, OPROMGETVERSION, opp)) < 0) {
17450Sstevel@tonic-gate prom_close(prom_fd);
17460Sstevel@tonic-gate return (DEVFS_ERR);
17470Sstevel@tonic-gate }
17480Sstevel@tonic-gate prom_close(prom_fd);
17490Sstevel@tonic-gate
17500Sstevel@tonic-gate version |= OBP_OF;
17510Sstevel@tonic-gate
17520Sstevel@tonic-gate return (version);
17530Sstevel@tonic-gate }
17540Sstevel@tonic-gate /*
17550Sstevel@tonic-gate * search the aliases node by definition - compile a list of
17560Sstevel@tonic-gate * alias names that are both exact and inexact matches.
17570Sstevel@tonic-gate */
17580Sstevel@tonic-gate static int
prom_srch_aliases_by_def(char * promdev_def,struct name_list ** exact_list,struct name_list ** inexact_list,int prom_fd)17590Sstevel@tonic-gate prom_srch_aliases_by_def(char *promdev_def, struct name_list **exact_list,
17600Sstevel@tonic-gate struct name_list **inexact_list, int prom_fd)
17610Sstevel@tonic-gate {
17620Sstevel@tonic-gate Oppbuf oppbuf;
17630Sstevel@tonic-gate Oppbuf propdef_oppbuf;
17640Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
17650Sstevel@tonic-gate struct openpromio *propdef_opp = &(propdef_oppbuf.opp);
17660Sstevel@tonic-gate int *ip = (int *)((void *)opp->oprom_array);
17670Sstevel@tonic-gate int ret;
17680Sstevel@tonic-gate struct name_list *inexact_match = *inexact_list = NULL;
17690Sstevel@tonic-gate struct name_list *exact_match = *exact_list = NULL;
17700Sstevel@tonic-gate char alias_buf[MAXNAMELEN];
17710Sstevel@tonic-gate int found = 0;
17720Sstevel@tonic-gate
1773*9735SSriman.Bhavanam@Sun.COM if ((ret = prom_find_aliases_node(prom_fd)) < 0)
1774*9735SSriman.Bhavanam@Sun.COM return (0);
1775*9735SSriman.Bhavanam@Sun.COM
17760Sstevel@tonic-gate (void) memset(oppbuf.buf, 0, BUFSIZE);
17770Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE;
17780Sstevel@tonic-gate *ip = 0;
17790Sstevel@tonic-gate
17800Sstevel@tonic-gate if ((ret = ioctl(prom_fd, OPROMNXTPROP, opp)) < 0)
17810Sstevel@tonic-gate return (0);
17820Sstevel@tonic-gate if (opp->oprom_size == 0)
17830Sstevel@tonic-gate return (0);
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate while ((ret >= 0) && (opp->oprom_size > 0)) {
17860Sstevel@tonic-gate (void) strcpy(propdef_opp->oprom_array, opp->oprom_array);
17870Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE;
17880Sstevel@tonic-gate propdef_opp->oprom_size = MAXVALSIZE;
17890Sstevel@tonic-gate if ((ioctl(prom_fd, OPROMGETPROP, propdef_opp) < 0) ||
17900Sstevel@tonic-gate (propdef_opp->oprom_size == 0)) {
17910Sstevel@tonic-gate ret = ioctl(prom_fd, OPROMNXTPROP, opp);
17920Sstevel@tonic-gate continue;
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate ret = prom_compare_devs(promdev_def, propdef_opp->oprom_array);
17950Sstevel@tonic-gate if (ret == EXACT_MATCH) {
17960Sstevel@tonic-gate found++;
17970Sstevel@tonic-gate if (insert_alias_list(exact_list, opp->oprom_array)
17980Sstevel@tonic-gate != 0) {
17990Sstevel@tonic-gate free_name_list(exact_match, 1);
18000Sstevel@tonic-gate free_name_list(inexact_match, 1);
18010Sstevel@tonic-gate return (-1);
18020Sstevel@tonic-gate }
18030Sstevel@tonic-gate }
18040Sstevel@tonic-gate if (ret == INEXACT_MATCH) {
18050Sstevel@tonic-gate found++;
18060Sstevel@tonic-gate (void) strcpy(alias_buf, opp->oprom_array);
18070Sstevel@tonic-gate options_override(promdev_def, alias_buf);
18080Sstevel@tonic-gate if (insert_alias_list(inexact_list, alias_buf)
18090Sstevel@tonic-gate != 0) {
18100Sstevel@tonic-gate free_name_list(exact_match, 1);
18110Sstevel@tonic-gate free_name_list(inexact_match, 1);
18120Sstevel@tonic-gate return (-1);
18130Sstevel@tonic-gate }
18140Sstevel@tonic-gate }
18150Sstevel@tonic-gate ret = ioctl(prom_fd, OPROMNXTPROP, opp);
18160Sstevel@tonic-gate }
18170Sstevel@tonic-gate if (found) {
18180Sstevel@tonic-gate return (0);
18190Sstevel@tonic-gate } else {
18200Sstevel@tonic-gate return (-1);
18210Sstevel@tonic-gate }
18220Sstevel@tonic-gate }
18230Sstevel@tonic-gate
18240Sstevel@tonic-gate /*
18250Sstevel@tonic-gate * free a list of name_list structs and optionally
18260Sstevel@tonic-gate * free the strings they contain.
18270Sstevel@tonic-gate */
18280Sstevel@tonic-gate static void
free_name_list(struct name_list * list,int free_name)18290Sstevel@tonic-gate free_name_list(struct name_list *list, int free_name)
18300Sstevel@tonic-gate {
18310Sstevel@tonic-gate struct name_list *next = list;
18320Sstevel@tonic-gate
18330Sstevel@tonic-gate while (next != NULL) {
18340Sstevel@tonic-gate list = list->next;
18350Sstevel@tonic-gate if (free_name)
18360Sstevel@tonic-gate free(next->name);
18370Sstevel@tonic-gate free(next);
18380Sstevel@tonic-gate next = list;
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate
18420Sstevel@tonic-gate /*
18430Sstevel@tonic-gate * insert a new alias in a list of aliases - the list is sorted
18440Sstevel@tonic-gate * in collating order (ignoring anything that comes after the
18450Sstevel@tonic-gate * ':' in the name).
18460Sstevel@tonic-gate */
18470Sstevel@tonic-gate static int
insert_alias_list(struct name_list ** list,char * alias_name)18480Sstevel@tonic-gate insert_alias_list(struct name_list **list, char *alias_name)
18490Sstevel@tonic-gate {
18500Sstevel@tonic-gate struct name_list *entry = *list;
18510Sstevel@tonic-gate struct name_list *new_entry, *prev_entry;
18520Sstevel@tonic-gate int ret;
18530Sstevel@tonic-gate char *colon1, *colon2;
18540Sstevel@tonic-gate
18550Sstevel@tonic-gate if ((new_entry =
18560Sstevel@tonic-gate (struct name_list *)malloc(sizeof (struct name_list)))
18570Sstevel@tonic-gate == NULL) {
18580Sstevel@tonic-gate return (-1);
18590Sstevel@tonic-gate }
18600Sstevel@tonic-gate if ((new_entry->name = strdup(alias_name)) == NULL) {
18610Sstevel@tonic-gate free(new_entry);
18620Sstevel@tonic-gate return (-1);
18630Sstevel@tonic-gate }
18640Sstevel@tonic-gate new_entry->next = NULL;
18650Sstevel@tonic-gate
18660Sstevel@tonic-gate if (entry == NULL) {
18670Sstevel@tonic-gate *list = new_entry;
18680Sstevel@tonic-gate return (0);
18690Sstevel@tonic-gate }
18700Sstevel@tonic-gate
18710Sstevel@tonic-gate if ((colon1 = strchr(alias_name, ':')) != NULL) {
18720Sstevel@tonic-gate *colon1 = '\0';
18730Sstevel@tonic-gate }
18740Sstevel@tonic-gate prev_entry = NULL;
18750Sstevel@tonic-gate while (entry != NULL) {
18760Sstevel@tonic-gate if ((colon2 = strchr(entry->name, ':')) != NULL) {
18770Sstevel@tonic-gate *colon2 = '\0';
18780Sstevel@tonic-gate }
18790Sstevel@tonic-gate ret = strcmp(alias_name, entry->name);
18800Sstevel@tonic-gate if (colon2 != NULL) {
18810Sstevel@tonic-gate *colon2 = ':';
18820Sstevel@tonic-gate }
18830Sstevel@tonic-gate /* duplicate */
18840Sstevel@tonic-gate if (ret == 0) {
18850Sstevel@tonic-gate free(new_entry->name);
18860Sstevel@tonic-gate free(new_entry);
18870Sstevel@tonic-gate if (colon1 != NULL) {
18880Sstevel@tonic-gate *colon1 = ':';
18890Sstevel@tonic-gate }
18900Sstevel@tonic-gate return (0);
18910Sstevel@tonic-gate }
18920Sstevel@tonic-gate if (ret < 0) {
18930Sstevel@tonic-gate new_entry->next = entry;
18940Sstevel@tonic-gate if (prev_entry == NULL) {
18950Sstevel@tonic-gate /* in beginning of list */
18960Sstevel@tonic-gate *list = new_entry;
18970Sstevel@tonic-gate } else {
18980Sstevel@tonic-gate /* in middle of list */
18990Sstevel@tonic-gate prev_entry->next = new_entry;
19000Sstevel@tonic-gate }
19010Sstevel@tonic-gate if (colon1 != NULL) {
19020Sstevel@tonic-gate *colon1 = ':';
19030Sstevel@tonic-gate }
19040Sstevel@tonic-gate return (0);
19050Sstevel@tonic-gate }
19060Sstevel@tonic-gate prev_entry = entry;
19070Sstevel@tonic-gate entry = entry->next;
19080Sstevel@tonic-gate }
19090Sstevel@tonic-gate /* at end of list */
19100Sstevel@tonic-gate prev_entry->next = new_entry;
19110Sstevel@tonic-gate new_entry->next = NULL;
19120Sstevel@tonic-gate if (colon1 != NULL) {
19130Sstevel@tonic-gate *colon1 = ':';
19140Sstevel@tonic-gate }
19150Sstevel@tonic-gate return (0);
19160Sstevel@tonic-gate }
19170Sstevel@tonic-gate /*
19180Sstevel@tonic-gate * append :x to alias_name to override any default minor name options
19190Sstevel@tonic-gate */
19200Sstevel@tonic-gate static void
options_override(char * prom_path,char * alias_name)19210Sstevel@tonic-gate options_override(char *prom_path, char *alias_name)
19220Sstevel@tonic-gate {
19230Sstevel@tonic-gate char *colon;
19240Sstevel@tonic-gate
19250Sstevel@tonic-gate if ((colon = strrchr(alias_name, ':')) != NULL) {
19260Sstevel@tonic-gate /*
19270Sstevel@tonic-gate * XXX - should alias names in /aliases ever have a
19280Sstevel@tonic-gate * : embedded in them?
19290Sstevel@tonic-gate * If so we ignore it.
19300Sstevel@tonic-gate */
19310Sstevel@tonic-gate *colon = '\0';
19320Sstevel@tonic-gate }
19330Sstevel@tonic-gate
19340Sstevel@tonic-gate if ((colon = strrchr(prom_path, ':')) != NULL) {
19350Sstevel@tonic-gate (void) strcat(alias_name, colon);
19360Sstevel@tonic-gate }
19370Sstevel@tonic-gate }
19380Sstevel@tonic-gate
19390Sstevel@tonic-gate /*
19400Sstevel@tonic-gate * compare to prom device names.
19410Sstevel@tonic-gate * if the device names are not fully qualified. we convert them -
19420Sstevel@tonic-gate * we only do this as a last resort though since it requires
19430Sstevel@tonic-gate * jumping into the kernel.
19440Sstevel@tonic-gate */
19450Sstevel@tonic-gate static int
prom_compare_devs(char * prom_dev1,char * prom_dev2)19460Sstevel@tonic-gate prom_compare_devs(char *prom_dev1, char *prom_dev2)
19470Sstevel@tonic-gate {
19480Sstevel@tonic-gate char *dev1, *dev2;
19490Sstevel@tonic-gate char *ptr1, *ptr2;
19500Sstevel@tonic-gate char *drvname1, *addrname1, *minorname1;
19510Sstevel@tonic-gate char *drvname2, *addrname2, *minorname2;
19520Sstevel@tonic-gate char component1[MAXNAMELEN], component2[MAXNAMELEN];
19530Sstevel@tonic-gate char devname1[MAXPATHLEN], devname2[MAXPATHLEN];
19540Sstevel@tonic-gate int unqualified_name = 0;
19550Sstevel@tonic-gate int error = EXACT_MATCH;
19560Sstevel@tonic-gate int len1, len2;
19570Sstevel@tonic-gate char *wildcard = ",0";
19580Sstevel@tonic-gate
19590Sstevel@tonic-gate ptr1 = prom_dev1;
19600Sstevel@tonic-gate ptr2 = prom_dev2;
19610Sstevel@tonic-gate
19620Sstevel@tonic-gate if ((ptr1 == NULL) || (*ptr1 != '/')) {
19630Sstevel@tonic-gate return (NO_MATCH);
19640Sstevel@tonic-gate }
19650Sstevel@tonic-gate if ((ptr2 == NULL) || (*ptr2 != '/')) {
19660Sstevel@tonic-gate return (NO_MATCH);
19670Sstevel@tonic-gate }
19680Sstevel@tonic-gate
19690Sstevel@tonic-gate /*
19700Sstevel@tonic-gate * compare device names one component at a time.
19710Sstevel@tonic-gate */
19720Sstevel@tonic-gate while ((ptr1 != NULL) && (ptr2 != NULL)) {
19730Sstevel@tonic-gate *ptr1 = *ptr2 = '/';
19740Sstevel@tonic-gate dev1 = ptr1 + 1;
19750Sstevel@tonic-gate dev2 = ptr2 + 1;
19760Sstevel@tonic-gate if ((ptr1 = strchr(dev1, '/')) != NULL)
19770Sstevel@tonic-gate *ptr1 = '\0';
19780Sstevel@tonic-gate if ((ptr2 = strchr(dev2, '/')) != NULL)
19790Sstevel@tonic-gate *ptr2 = '\0';
19800Sstevel@tonic-gate
19810Sstevel@tonic-gate (void) strcpy(component1, dev1);
19820Sstevel@tonic-gate (void) strcpy(component2, dev2);
19830Sstevel@tonic-gate
19840Sstevel@tonic-gate parse_name(component1, &drvname1, &addrname1, &minorname1);
19850Sstevel@tonic-gate parse_name(component2, &drvname2, &addrname2, &minorname2);
19860Sstevel@tonic-gate
19870Sstevel@tonic-gate if ((drvname1 == NULL) && (addrname1 == NULL)) {
19880Sstevel@tonic-gate error = NO_MATCH;
19890Sstevel@tonic-gate break;
19900Sstevel@tonic-gate }
19910Sstevel@tonic-gate
19920Sstevel@tonic-gate if ((drvname2 == NULL) && (addrname2 == NULL)) {
19930Sstevel@tonic-gate error = NO_MATCH;
19940Sstevel@tonic-gate break;
19950Sstevel@tonic-gate }
19960Sstevel@tonic-gate
19970Sstevel@tonic-gate if (_prom_strcmp(drvname1, drvname2) != 0) {
19980Sstevel@tonic-gate error = NO_MATCH;
19990Sstevel@tonic-gate break;
20000Sstevel@tonic-gate }
20010Sstevel@tonic-gate
20020Sstevel@tonic-gate /*
20030Sstevel@tonic-gate * a possible name is driver_name@address. The address
20040Sstevel@tonic-gate * portion is optional (i.e. the name is not fully
20050Sstevel@tonic-gate * qualified.). We have to deal with the case where
20060Sstevel@tonic-gate * the component name is either driver_name or
20070Sstevel@tonic-gate * driver_name@address
20080Sstevel@tonic-gate */
20090Sstevel@tonic-gate if ((addrname1 == NULL) ^ (addrname2 == NULL)) {
20100Sstevel@tonic-gate unqualified_name = 1;
20110Sstevel@tonic-gate } else if (addrname1 &&
20120Sstevel@tonic-gate (_prom_strcmp(addrname1, addrname2) != 0)) {
20130Sstevel@tonic-gate /*
20140Sstevel@tonic-gate * check to see if appending a ",0" to the
20150Sstevel@tonic-gate * shorter address causes a match to occur.
20160Sstevel@tonic-gate * If so succeed.
20170Sstevel@tonic-gate */
20180Sstevel@tonic-gate len1 = strlen(addrname1);
20190Sstevel@tonic-gate len2 = strlen(addrname2);
20200Sstevel@tonic-gate if ((len1 < len2) &&
20210Sstevel@tonic-gate (strncmp(addrname1, addrname2, len1) == 0) &&
20220Sstevel@tonic-gate (strcmp(wildcard, &addrname2[len1]) == 0)) {
20230Sstevel@tonic-gate continue;
20240Sstevel@tonic-gate } else if ((len2 < len1) &&
20250Sstevel@tonic-gate (strncmp(addrname1, addrname2, len2) == 0) &&
20260Sstevel@tonic-gate (strcmp(wildcard, &addrname1[len2]) == 0)) {
20270Sstevel@tonic-gate continue;
20280Sstevel@tonic-gate }
20290Sstevel@tonic-gate error = NO_MATCH;
20300Sstevel@tonic-gate break;
20310Sstevel@tonic-gate }
20320Sstevel@tonic-gate }
20330Sstevel@tonic-gate
20340Sstevel@tonic-gate /*
20350Sstevel@tonic-gate * if either of the two device paths still has more components,
20360Sstevel@tonic-gate * then we do not have a match.
20370Sstevel@tonic-gate */
20380Sstevel@tonic-gate if (ptr1 != NULL) {
20390Sstevel@tonic-gate *ptr1 = '/';
20400Sstevel@tonic-gate error = NO_MATCH;
20410Sstevel@tonic-gate }
20420Sstevel@tonic-gate if (ptr2 != NULL) {
20430Sstevel@tonic-gate *ptr2 = '/';
20440Sstevel@tonic-gate error = NO_MATCH;
20450Sstevel@tonic-gate }
20460Sstevel@tonic-gate if (error == NO_MATCH) {
20470Sstevel@tonic-gate return (error);
20480Sstevel@tonic-gate }
20490Sstevel@tonic-gate
20500Sstevel@tonic-gate /*
20510Sstevel@tonic-gate * OK - we found a possible match but one or more of the
20520Sstevel@tonic-gate * path components was not fully qualified (did not have any
20530Sstevel@tonic-gate * address information. So we need to convert it to a form
20540Sstevel@tonic-gate * that is fully qualified and then compare the resulting
20550Sstevel@tonic-gate * strings.
20560Sstevel@tonic-gate */
20570Sstevel@tonic-gate if (unqualified_name != 0) {
20580Sstevel@tonic-gate if ((devfs_prom_to_dev_name(prom_dev1, devname1) < 0) ||
20590Sstevel@tonic-gate (devfs_prom_to_dev_name(prom_dev2, devname2) < 0)) {
20600Sstevel@tonic-gate return (NO_MATCH);
20610Sstevel@tonic-gate }
20620Sstevel@tonic-gate if ((dev1 = strrchr(devname1, ':')) != NULL) {
20630Sstevel@tonic-gate *dev1 = '\0';
20640Sstevel@tonic-gate }
20650Sstevel@tonic-gate if ((dev2 = strrchr(devname2, ':')) != NULL) {
20660Sstevel@tonic-gate *dev2 = '\0';
20670Sstevel@tonic-gate }
20680Sstevel@tonic-gate if (strcmp(devname1, devname2) != 0) {
20690Sstevel@tonic-gate return (NO_MATCH);
20700Sstevel@tonic-gate }
20710Sstevel@tonic-gate }
20720Sstevel@tonic-gate /*
20730Sstevel@tonic-gate * the resulting strings matched. If the minorname information
20740Sstevel@tonic-gate * matches, then we have an exact match, otherwise an inexact match
20750Sstevel@tonic-gate */
20760Sstevel@tonic-gate if (_prom_strcmp(minorname1, minorname2) == 0) {
20770Sstevel@tonic-gate return (EXACT_MATCH);
20780Sstevel@tonic-gate } else {
20790Sstevel@tonic-gate return (INEXACT_MATCH);
20800Sstevel@tonic-gate }
20810Sstevel@tonic-gate }
20820Sstevel@tonic-gate
20830Sstevel@tonic-gate /*
20840Sstevel@tonic-gate * wrapper or strcmp - deals with null strings.
20850Sstevel@tonic-gate */
20860Sstevel@tonic-gate static int
_prom_strcmp(char * s1,char * s2)20870Sstevel@tonic-gate _prom_strcmp(char *s1, char *s2)
20880Sstevel@tonic-gate {
20890Sstevel@tonic-gate if ((s1 == NULL) && (s2 == NULL))
20900Sstevel@tonic-gate return (0);
20910Sstevel@tonic-gate if ((s1 == NULL) && (s2 != NULL)) {
20920Sstevel@tonic-gate return (-1);
20930Sstevel@tonic-gate }
20940Sstevel@tonic-gate if ((s1 != NULL) && (s2 == NULL)) {
20950Sstevel@tonic-gate return (1);
20960Sstevel@tonic-gate }
20970Sstevel@tonic-gate return (strcmp(s1, s2));
20980Sstevel@tonic-gate }
20990Sstevel@tonic-gate /*
21000Sstevel@tonic-gate * break device@a,b:minor into components
21010Sstevel@tonic-gate */
21020Sstevel@tonic-gate static void
parse_name(char * name,char ** drvname,char ** addrname,char ** minorname)21030Sstevel@tonic-gate parse_name(char *name, char **drvname, char **addrname, char **minorname)
21040Sstevel@tonic-gate {
21050Sstevel@tonic-gate char *cp, ch;
21060Sstevel@tonic-gate
21070Sstevel@tonic-gate cp = *drvname = name;
21080Sstevel@tonic-gate *addrname = *minorname = NULL;
21090Sstevel@tonic-gate if (*name == '@')
21100Sstevel@tonic-gate *drvname = NULL;
21110Sstevel@tonic-gate
21120Sstevel@tonic-gate while ((ch = *cp) != '\0') {
21130Sstevel@tonic-gate if (ch == '@')
21140Sstevel@tonic-gate *addrname = ++cp;
21150Sstevel@tonic-gate else if (ch == ':')
21160Sstevel@tonic-gate *minorname = ++cp;
21170Sstevel@tonic-gate ++cp;
21180Sstevel@tonic-gate }
21190Sstevel@tonic-gate if (*addrname) {
21200Sstevel@tonic-gate *((*addrname)-1) = '\0';
21210Sstevel@tonic-gate }
21220Sstevel@tonic-gate if (*minorname) {
21230Sstevel@tonic-gate *((*minorname)-1) = '\0';
21240Sstevel@tonic-gate }
21250Sstevel@tonic-gate }
21260Sstevel@tonic-gate
21270Sstevel@tonic-gate /*
21283337Sas158974 * converts a prom alias to a prom device name.
21293337Sas158974 * if we find no matching device, then we fail since if were
21303337Sas158974 * given a valid alias, then by definition, there must be a
21313337Sas158974 * device pathname associated with it in the /aliases node.
21323337Sas158974 */
21333337Sas158974 static int
alias_to_prom_dev(char * alias,char * ret_buf)21343337Sas158974 alias_to_prom_dev(char *alias, char *ret_buf)
21353337Sas158974 {
21363337Sas158974 char *options_ptr;
21373337Sas158974 char alias_buf[MAXNAMELEN];
21383337Sas158974 char alias_def[MAXPATHLEN];
21393337Sas158974 char options[16] = "";
21403337Sas158974 int prom_fd = -1;
21413337Sas158974 int ret;
21423337Sas158974 int i;
21433337Sas158974
21443337Sas158974 if (strchr(alias, '/') != NULL)
21453337Sas158974 return (DEVFS_INVAL);
21463337Sas158974
21473337Sas158974 if (strlen(alias) > (MAXNAMELEN - 1))
21483337Sas158974 return (DEVFS_INVAL);
21493337Sas158974
21503337Sas158974 if (ret_buf == NULL) {
21513337Sas158974 return (DEVFS_INVAL);
21523337Sas158974 }
21533337Sas158974
21543337Sas158974 prom_fd = prom_open(O_RDONLY);
21553337Sas158974 if (prom_fd < 0) {
21563337Sas158974 return (prom_fd);
21573337Sas158974 }
21583337Sas158974
21593337Sas158974 (void) strlcpy(alias_buf, alias, sizeof (alias_buf));
21603337Sas158974
21613337Sas158974 /*
21623337Sas158974 * save off any options (minor name info) that is
21633337Sas158974 * explicitly called out in the alias name
21643337Sas158974 */
21653337Sas158974 if ((options_ptr = strchr(alias_buf, ':')) != NULL) {
21663337Sas158974 *options_ptr = '\0';
21673337Sas158974 (void) strlcpy(options, ++options_ptr, sizeof (options));
21683337Sas158974 }
21693337Sas158974
21703337Sas158974 *alias_def = '\0';
21713337Sas158974
21723337Sas158974 ret = prom_find_aliases_node(prom_fd);
21733337Sas158974 if (ret == 0) {
21743337Sas158974 /*
21753337Sas158974 * we loop because one alias may define another... we have
21763337Sas158974 * to work our way down to an actual device definition.
21773337Sas158974 */
21783337Sas158974 for (i = 0; i <= 10; i++) {
21793337Sas158974 ret = prom_srch_node(prom_fd, alias_buf, alias_def);
21803337Sas158974 if (ret == -1) {
21813337Sas158974 break;
21823337Sas158974 }
21833337Sas158974 (void) strlcpy(alias_buf, alias_def,
21843337Sas158974 sizeof (alias_buf));
21853337Sas158974 if (*alias_def == '/') {
21863337Sas158974 break;
21873337Sas158974 }
21883337Sas158974
21893337Sas158974 /*
21903337Sas158974 * save off any explicit options (minor name info)
21913337Sas158974 * if none has been encountered yet
21923337Sas158974 */
21933337Sas158974 if (options_ptr == NULL) {
21943337Sas158974 options_ptr = strchr(alias_buf, ':');
21953337Sas158974 if (options_ptr != NULL) {
2196*9735SSriman.Bhavanam@Sun.COM *options_ptr = '\0';
2197*9735SSriman.Bhavanam@Sun.COM (void) strlcpy(options, ++options_ptr,
21983337Sas158974 sizeof (options));
21993337Sas158974 }
22003337Sas158974 }
22013337Sas158974 }
22023337Sas158974 }
22033337Sas158974 prom_close(prom_fd);
22043337Sas158974
22053337Sas158974 /* error */
22063337Sas158974 if (ret == -1) {
22073337Sas158974 return (ret);
22083337Sas158974 }
22093337Sas158974
22103931Sas158974 (void) strlcpy(ret_buf, alias_def, MAXPATHLEN);
22113337Sas158974
22123337Sas158974 /* override minor name information */
22133337Sas158974 if (options_ptr != NULL) {
22143337Sas158974 if ((options_ptr = strrchr(ret_buf, ':')) == NULL) {
22153337Sas158974 (void) strcat(ret_buf, ":");
22163337Sas158974 } else {
22173337Sas158974 *(++options_ptr) = '\0';
22183337Sas158974 }
22193337Sas158974 (void) strcat(ret_buf, options);
22203337Sas158974 }
22213337Sas158974 return (0);
22223337Sas158974 }
22233337Sas158974
22243337Sas158974 /*
22253337Sas158974 * search a prom node for a property name
22263337Sas158974 */
22273337Sas158974 static int
prom_srch_node(int fd,char * prop_name,char * ret_buf)22283337Sas158974 prom_srch_node(int fd, char *prop_name, char *ret_buf)
22293337Sas158974 {
22303337Sas158974 Oppbuf oppbuf;
22313337Sas158974 struct openpromio *opp = &(oppbuf.opp);
22323337Sas158974 int *ip = (int *)((void *)opp->oprom_array);
22333337Sas158974
22343337Sas158974 (void) memset(oppbuf.buf, 0, BUFSIZE);
22353337Sas158974 opp->oprom_size = MAXPROPSIZE;
22363337Sas158974 *ip = 0;
22373337Sas158974
22383337Sas158974 if (ioctl(fd, OPROMNXTPROP, opp) < 0)
22393337Sas158974 return (-1);
22403337Sas158974 if (opp->oprom_size == 0)
22413337Sas158974 return (-1);
22423337Sas158974
22433337Sas158974 while (strcmp(prop_name, opp->oprom_array) != 0) {
22443337Sas158974 opp->oprom_size = MAXPROPSIZE;
22453337Sas158974 if (ioctl(fd, OPROMNXTPROP, opp) < 0)
22463337Sas158974 return (-1);
22473337Sas158974 if (opp->oprom_size == 0)
22483337Sas158974 return (-1);
22493337Sas158974 }
22503337Sas158974 opp->oprom_size = MAXVALSIZE;
22513337Sas158974 if (ioctl(fd, OPROMGETPROP, opp) < 0)
22523337Sas158974 return (-1);
22533337Sas158974
22543337Sas158974 if (opp->oprom_size == 0)
22553337Sas158974 return (-1);
22563931Sas158974 (void) strlcpy(ret_buf, opp->oprom_array, MAXPATHLEN);
22573337Sas158974 return (0);
22583337Sas158974 }
22593337Sas158974
22603337Sas158974 /*
22613337Sas158974 * return the aliases node.
22623337Sas158974 */
22633337Sas158974 static int
prom_find_aliases_node(int fd)22643337Sas158974 prom_find_aliases_node(int fd)
22653337Sas158974 {
22663337Sas158974 uint_t child_id;
22673931Sas158974 char buf[MAXPATHLEN];
22683337Sas158974
22693337Sas158974 if ((child_id = prom_next_node(fd, 0)) == 0)
22703337Sas158974 return (-1);
22713337Sas158974 if ((child_id = prom_child_node(fd, child_id)) == 0)
22723337Sas158974 return (-1);
22733337Sas158974
22743337Sas158974 while (child_id != 0) {
22753337Sas158974 if (prom_srch_node(fd, "name", buf) == 0) {
22763337Sas158974 if (strcmp(buf, "aliases") == 0) {
22773337Sas158974 return (0);
22783337Sas158974 }
22793337Sas158974 }
22803337Sas158974 child_id = prom_next_node(fd, child_id);
22813337Sas158974 }
22823337Sas158974 return (-1);
22833337Sas158974 }
22843337Sas158974
22853337Sas158974 /*
22863337Sas158974 * get sibling
22873337Sas158974 */
22883337Sas158974 static uint_t
prom_next_node(int fd,uint_t node_id)22893337Sas158974 prom_next_node(int fd, uint_t node_id)
22903337Sas158974 {
22913337Sas158974 Oppbuf oppbuf;
22923337Sas158974 struct openpromio *opp = &(oppbuf.opp);
22933337Sas158974 uint_t *ip = (uint_t *)((void *)opp->oprom_array);
22943337Sas158974
22953337Sas158974 (void) memset(oppbuf.buf, 0, BUFSIZE);
22963337Sas158974 opp->oprom_size = MAXVALSIZE;
22973337Sas158974 *ip = node_id;
22983337Sas158974
22993337Sas158974 if (ioctl(fd, OPROMNEXT, opp) < 0)
23003337Sas158974 return (0);
23013337Sas158974
23023337Sas158974 return (*(uint_t *)((void *)opp->oprom_array));
23033337Sas158974 }
23043337Sas158974
23053337Sas158974 /*
23063337Sas158974 * get child
23073337Sas158974 */
23083337Sas158974 static uint_t
prom_child_node(int fd,uint_t node_id)23093337Sas158974 prom_child_node(int fd, uint_t node_id)
23103337Sas158974 {
23113337Sas158974 Oppbuf oppbuf;
23123337Sas158974 struct openpromio *opp = &(oppbuf.opp);
23133337Sas158974 uint_t *ip = (uint_t *)((void *)opp->oprom_array);
23143337Sas158974
23153337Sas158974 (void) memset(oppbuf.buf, 0, BUFSIZE);
23163337Sas158974 opp->oprom_size = MAXVALSIZE;
23173337Sas158974 *ip = node_id;
23183337Sas158974
23193337Sas158974 if (ioctl(fd, OPROMCHILD, opp) < 0)
23203337Sas158974 return (0);
23213337Sas158974
23223337Sas158974 return (*(uint_t *)((void *)opp->oprom_array));
23233337Sas158974 }
23243337Sas158974
23253337Sas158974 /*
23260Sstevel@tonic-gate * only on sparc for now
23270Sstevel@tonic-gate */
23280Sstevel@tonic-gate int
devfs_bootdev_modifiable(void)23290Sstevel@tonic-gate devfs_bootdev_modifiable(void)
23300Sstevel@tonic-gate {
23310Sstevel@tonic-gate #if defined(sparc)
23320Sstevel@tonic-gate return (0);
23330Sstevel@tonic-gate #else
23340Sstevel@tonic-gate return (DEVFS_NOTSUP);
23350Sstevel@tonic-gate #endif
23360Sstevel@tonic-gate }
2337