devfsinfo.c revision b6f77fef621cd73a859ec20b62be03bf2ea78c81
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <thread.h>
#include <synch.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/openpromio.h>
#include <ftw.h>
#include <limits.h>
#include "device_info.h"
/*
* #define's
*/
/* alias node searching return values */
#define NO_MATCH -1
#define EXACT_MATCH 1
#define INEXACT_MATCH 2
/* for prom io operations */
#define BUFSIZE 4096
#define MAXPROPSIZE 256
/* prom_obp_vers() return values */
/* for nftw call */
#define FT_DEPTH 15
/* default logical and physical device name space */
#define DEV "/dev"
#define DEVICES "/devices"
/* for boot device identification on x86 */
#define CREATE_DISKMAP "/boot/solaris/bin/create_diskmap"
#define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
/*
* internal structure declarations
*/
/* for prom io functions */
typedef union {
struct openpromio opp;
} Oppbuf;
/* used to manage lists of devices and aliases */
struct name_list {
char *name;
};
/*
* internal global data
*/
/* global since nftw does not let you pass args to be updated */
/* global since nftw does not let you pass args to be updated */
static struct boot_dev **bootdev_list;
/* mutex to protect bootdev_list and dev_list */
/*
* internal function prototypes
*/
static int prom_open(int);
static void prom_close(int);
static int is_openprom(int);
static int prom_srch_aliases_by_def(char *, struct name_list **,
struct name_list **, int);
static int prom_find_aliases_node(int fd);
static int prom_obp_vers(void);
static void parse_name(char *, char **, char **, char **);
static int process_bootdev(const char *, const char *, struct boot_dev ***);
const int array_size, const char *default_root);
static int check_logical_dev(const char *, const struct stat *, int,
struct FTW *);
static struct boot_dev *alloc_bootdev(char *);
char *alias_name);
/*
* frees a list of paths from devfs_get_prom_name_list
*/
static void
prom_list_free(char **prom_list)
{
int i = 0;
if (!prom_list)
return;
while (prom_list[i]) {
i++;
}
}
static int
{
int count = 0; /* # of slots we will need in prom_list */
char **list;
char *ptr;
return (DEVFS_INVAL);
if (*dev_name != '/')
return (DEVFS_INVAL);
return (DEVFS_INVAL);
/*
* make sure we are on a machine which supports a prom
*/
if ((ret = prom_obp_vers()) < 0)
return (ret);
return (DEVFS_NOMEM);
/*
* get the prom path name
*/
if (ret < 0) {
return (ret);
}
/* deal with list of names */
for (i = 0; i < ret; i++)
if (prom_path[i] == '\0')
count++;
return (DEVFS_NOMEM);
}
for (i = 0; i < count; i++) {
return (DEVFS_NOMEM);
}
}
return (0);
}
/*
* retrieve the list of prom representations for a given device name
* the list will be sorted in the following order: exact aliases,
* inexact aliases, prom device path name. If multiple matches occur
* for exact or inexact aliases, then these are sorted in collating
* order. The list is returned in prom_list
*
* the list may be restricted by specifying the correct flags in options.
*/
int
{
int count = 0; /* # of slots we will need in prom_list */
char **alias_list = NULL;
char **list;
int ret;
return (DEVFS_INVAL);
}
if (*dev_name != '/') {
return (DEVFS_INVAL);
}
return (DEVFS_INVAL);
}
/*
* make sure we are on a machine which supports a prom
*/
if ((ret = prom_obp_vers()) < 0) {
return (ret);
}
return (DEVFS_NOMEM);
}
/*
* get the prom path name
*/
if (ret < 0) {
return (ret);
}
/* get the list of aliases (exact and inexact) */
return (ret);
}
/* now figure out how big the return array must be */
if (alias_list != NULL) {
count++;
}
}
if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
count++; /* # of slots we will need in prom_list */
}
count++; /* for the null terminator */
/* allocate space for the list */
count = 0;
count++;
}
return (DEVFS_NOMEM);
}
/* fill in the array and free the name list of aliases. */
count = 0;
count++;
}
if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
}
if (alias_list != NULL) {
}
return (0);
}
/*
* Get a list prom-path translations for a solaris device.
*
* Returns the number of and all OBP paths and alias variants that
* reference the Solaris device path passed in.
*/
int
struct devfs_prom_path **paths)
{
if ((ret = prom_obp_vers()) < 0)
return (ret);
return (DEVFS_NOMEM);
prom_path, MAXVALSIZE)) < 0) {
return (ret);
}
for (i = 0; i < ret; i++)
if (prom_path[i] == '\0')
count++;
for (i = 0; i < count; i++) {
return (DEVFS_NOMEM);
}
else
return (DEVFS_NOMEM);
}
&(cur->alias_list))) < 0) {
return (ret);
}
}
return (count);
}
void
{
int i;
return;
}
}
/*
* Accepts a device name as an input argument. Uses this to set the
* boot-device (or like) variable
*
* By default, this routine prepends to the list and converts the
* logical device name to its most compact prom representation.
* Available options include: converting the device name to a prom
* path name (but not an alias) or performing no conversion at all;
* overwriting the existing contents of boot-device rather than
* prepending.
*/
int
{
char *prom_path;
char *new_bootdev;
char *ptr;
char **alias_list = NULL;
if (devfs_bootdev_modifiable() != 0) {
return (DEVFS_NOTSUP);
}
return (DEVFS_INVAL);
}
return (DEVFS_INVAL);
return (DEVFS_INVAL);
}
return (DEVFS_INVAL);
}
/*
* if we are prepending, make sure that this obp rev
* supports multiple boot device entries.
*/
ret = prom_obp_vers();
if (ret < 0) {
return (ret);
}
return (DEVFS_NOMEM);
}
if (options & BOOTDEV_LITERAL) {
} else {
/* need to convert to prom representation */
if (ret < 0) {
return (ret);
}
len = MAXVALSIZE;
i = 0;
if (!(options & BOOTDEV_PROMDEV)) {
&alias_list);
if (ret < 0) {
return (ret);
}
if ((alias_list != NULL) &&
(alias_list[0] != NULL)) {
alias_list[0]);
ret++)
} else {
prom_list[i]);
}
if (alias_list != NULL)
} else {
}
len -= j;
ptr += j;
i++;
}
ptr--;
}
if (options & BOOTDEV_OVERWRITE) {
} else {
/* retrieve the current value of boot-device */
if (ret < 0) {
return (ret);
}
/* prepend new entry - deal with duplicates */
if (new_bootdev == NULL) {
return (DEVFS_NOMEM);
}
if (opp->oprom_size > 0) {
/* we strip out duplicates */
continue;
}
}
}
}
/* now set the new value */
if (options & BOOTDEV_OVERWRITE) {
} else {
}
return (ret);
}
/*
* sets the string bootdev as the new value for boot-device
*/
static int
{
int prom_fd;
int i;
int ret;
char *valbuf;
char *save_bootdev;
char *bootdev_variables[] = {
"boot-device",
"bootdev",
"boot-from",
};
int found = 0;
/* query the prom */
if (prom_fd < 0) {
return (prom_fd);
}
/* get the diagnostic-mode? property */
if ((opp->oprom_size > 0) &&
return (DEVFS_ERR);
}
}
/* get the diag-switch? property */
if ((opp->oprom_size > 0) &&
return (DEVFS_ERR);
}
}
/*
* look for one of the following properties in order:
* boot-device
* bootdev
* boot-from
*
* Use the first one that we find.
*/
*ip = 0;
break;
}
for (i = 0; bootdev_variables[i] != NULL; i++) {
== 0) {
found = 1;
break;
}
}
}
if (found) {
return (DEVFS_NOTSUP);
}
} else {
return (DEVFS_NOTSUP);
}
/* save the old copy in case we fail */
return (DEVFS_NOMEM);
}
/* set up the new value of boot-device */
return (DEVFS_ERR);
}
/*
* now read it back to make sure it took
*/
/* success */
return (0);
}
/* deal with setting it to "" */
/* success */
return (0);
}
}
/*
* something did not take - write out the old value and
* hope that we can restore things...
*
* unfortunately, there is no way for us to differentiate
* whether we exceeded the maximum number of characters
* allowable. The limit varies from prom rev to prom
* rev, and on some proms, when the limit is
* exceeded, whatever was in the
* boot-device variable becomes unreadable.
*
* so if we fail, we will assume we ran out of room. If we
* not able to restore the original setting, then we will
* return DEVFS_ERR instead.
*/
ret = DEVFS_LIMIT;
}
return (ret);
}
/*
* retrieve the current value for boot-device
*/
static int
{
int prom_fd;
int i;
char *bootdev_variables[] = {
"boot-device",
"bootdev",
"boot-from",
};
int found = 0;
/* query the prom */
if (prom_fd < 0) {
return (prom_fd);
}
/* get the diagnostic-mode? property */
if ((opp->oprom_size > 0) &&
return (DEVFS_ERR);
}
}
/* get the diag-switch? property */
if ((opp->oprom_size > 0) &&
return (DEVFS_ERR);
}
}
/*
* look for one of the following properties in order:
* boot-device
* bootdev
* boot-from
*
* Use the first one that we find.
*/
*ip = 0;
break;
}
for (i = 0; bootdev_variables[i] != NULL; i++) {
== 0) {
found = 1;
break;
}
}
}
if (found) {
return (DEVFS_ERR);
}
/* boot-device exists but contains nothing */
if (opp->oprom_size == 0) {
}
} else {
return (DEVFS_NOTSUP);
}
return (0);
}
#ifndef __sparc
static FILE *
open_diskmap(void)
{
/* make sure we have a map file */
"%s > /dev/null", CREATE_DISKMAP);
}
return (fp);
}
static int
{
file = open_diskmap();
return (DEVFS_ERR);
continue;
/* drop new-line */
/*
* an x86 BIOS only boots a disk, not a partition
* or a slice, so hard-code :q (p0)
*/
break;
ret = 0;
break;
}
return (ret);
}
#endif /* ndef __sparc */
/*
* retrieve the list of entries in the boot-device configuration
* variable. An array of boot_dev structs will be created, one entry
* for each device name in the boot-device variable. Each entry
* in the array will contain the logical device representation of the
* boot-device entry, if any.
*
* default_root. if set, is used to locate logical device entries in
* directories other than /dev
*/
int
devfs_bootdev_get_list(const char *default_root,
struct boot_dev ***bootdev_list)
{
int i;
if (default_root == NULL) {
default_root = "";
} else if (*default_root != '/') {
return (DEVFS_INVAL);
}
if (bootdev_list == NULL) {
return (DEVFS_INVAL);
}
/* get the boot-device variable */
#if defined(sparc)
i = get_boot_dev_var(opp);
#else
i = find_x86_boot_device(opp);
#endif
if (i < 0) {
return (i);
}
/* now try to translate each entry to a logical device. */
if (i == 0) {
*bootdev_list = tmp_list;
return (0);
} else {
return (i);
}
}
/*
* loop thru the list of entries in a boot-device configuration
* variable.
*/
static int
{
int i;
char prom_path[MAXPATHLEN];
char ret_buf[MAXPATHLEN];
struct boot_dev **bootdev_array;
int num_entries = 0;
int found = 0;
int vers;
return (DEVFS_NOMEM);
}
/* count the number of entries */
num_entries++;
}
bootdev_array = (struct boot_dev **)
if (bootdev_array == NULL) {
return (DEVFS_NOMEM);
}
vers = prom_obp_vers();
if (vers < 0) {
return (vers);
}
/* for each entry in boot-device, do... */
return (DEVFS_NOMEM);
}
/*
* prom boot-device may be aliased, so we need to do
* the necessary prom alias to dev translation.
*/
if (*ptr != '/') {
continue;
}
} else {
}
/* now we have a prom device path - convert to a devfs name */
continue;
}
/* append any default minor names necessary */
continue;
}
found = 1;
/*
* store the physical device path for now - when
* we are all done with the entries, we will convert
* these to their logical device name equivalents
*/
}
/*
* Convert all of the boot-device entries that translated to a
* physical device path in /devices to a logical device path
* in /dev (note that there may be several logical device paths
* associated with a single physical device path - return them all
*/
if (found) {
default_root) < 0) {
}
}
*list = bootdev_array;
return (0);
}
/*
* We may get a device path from the prom that has no minor name
* information included in it. Since this device name will not
* correspond directly to a physical device in /devices, we do our
* best to append what the default minor name should be and try this.
*
* For sparc: we append slice 0 (:a).
* For x86: we append fdisk partition 0 (:q).
*/
static int
{
char *cp;
#if defined(sparc)
const char *default_minor_name = "a";
#else
const char *default_minor_name = "q";
#endif
int n;
char path[MAXPATHLEN];
/*
* if the device file already exists as given to us, there
* is nothing to do but return.
*/
return (0);
}
/*
* if there is no ':' after the last '/' character, or if there is
* a ':' with no specifier, append the default segment specifier
* ; if there is a ':' followed by a digit, this indicates
* a partition number (which does not map into the /devices name
* space), so strip the number and replace it with the letter
* that represents the partition index
*/
} else if (*++cp == '\0') {
/* make sure to squash the digit */
*cp = '\0';
switch (n) {
break;
break;
break;
break;
break;
break;
}
}
}
/*
* see if we can find something now.
*/
return (0);
} else {
return (-1);
}
}
/*
* for each entry in bootdev_array, convert the physical device
* representation of the boot-device entry to one or more logical device
* entries. We use the hammer method - walk through the logical device
* name space looking for matches (/dev). We use nftw to do this.
*/
static int
const char *default_root)
{
char *full_path;
int count, i;
char **dev_name_array;
int len;
if (array_size < 0) {
return (-1);
}
if (bootdev_array == NULL) {
return (-1);
}
if (default_root == NULL) {
return (-1);
}
return (-1);
}
/* short cut for an empty array */
if (*bootdev_array == NULL) {
return (0);
}
/* tell nftw where to start (default: /dev) */
return (-1);
}
/*
* if the default root path is terminated with a /, we have to
* make sure we don't end up with one too many slashes in the
* path we are building.
*/
if ((default_root_len > (size_t)0) &&
&dev_dir[1]);
} else {
}
/*
* we need to muck with global data to make nftw work
* so single thread access
*/
(void) mutex_lock(&dev_lists_lk);
/*
* set the global vars bootdev_list and dev_list for use by nftw
* dev_list is an array of lists - one for each boot-device
* entry. The nftw function will create a list of logical device
* entries for each boot-device and put all of the lists in
* dev_list.
*/
(void) mutex_unlock(&dev_lists_lk);
return (-1);
}
bootdev_list = NULL;
for (i = 0; i < array_size; i++) {
}
/* don't free dev_list here because it's been handed off */
(void) mutex_unlock(&dev_lists_lk);
return (-1);
}
/*
* now we have a filled in dev_list. So for each logical device
* list in dev_list, count the number of entries in the list,
* create an array of strings of logical devices, and save in the
* corresponding boot_dev structure.
*/
for (i = 0; i < array_size; i++) {
/* get the next list */
count = 0;
/* count the number of entries in the list */
count++;
}
if ((dev_name_array =
== NULL) {
continue;
}
count = 0;
/* fill in the array */
count++;
}
/*
* null terminate the array
*/
bootdev_trans[0] != NULL)) {
}
if (bootdev_array[i] != NULL) {
}
}
bootdev_list = NULL;
for (i = 0; i < array_size; i++) {
free_name_list(dev_list[i], 0);
}
(void) mutex_unlock(&dev_lists_lk);
return (0);
}
/*
* nftw function
* for a logical dev entry, it walks the list of boot-devices and
* sees if there are any matches. If so, it saves the logical device
* name off in the appropriate list in dev_list
*/
/* ARGSUSED */
static int
{
char link_buf[MAXPATHLEN];
int link_buf_len;
char *name;
char *physdev;
int i;
return (0);
}
== -1) {
return (0);
}
return (0);
}
for (i = 0; bootdev_list[i] != NULL; i++) {
continue;
}
/*
* compare the contents of the link with the physical
* device representation of this boot device
*/
return (-1);
}
return (-1);
}
} else {
}
}
}
return (0);
}
/*
* frees a list of boot_dev struct pointers
*/
void
{
int i = 0;
int j;
return;
}
j = 0;
}
i++;
}
}
/*
* allocates a boot_dev struct and fills in the bootdev_element portion
*/
static struct boot_dev *
alloc_bootdev(char *entry_name)
{
return (NULL);
}
return (NULL);
}
/*
* Allocate room for 1 name and a null terminator - the caller of
* this function will need the first slot right away.
*/
== NULL) {
return (NULL);
}
return (entry);
}
/*
* will come back with a concatenated list of paths
*/
int
{
int prom_fd;
int ret = DEVFS_INVAL;
int i;
return (DEVFS_INVAL);
}
return (DEVFS_INVAL);
}
return (DEVFS_INVAL);
if (*dev_path != '/')
return (DEVFS_INVAL);
if (prom_fd < 0) {
return (prom_fd);
}
/* query the prom */
/* return the prom path in prom_path */
if (i < 0) {
return (len);
} else {
return (opp->oprom_size);
}
}
/*
* either the prom does not support this ioctl or the argument
* was invalid.
*/
ret = DEVFS_NOTSUP;
}
return (ret);
}
/*
* Convert a physical or logical device name to a name the prom would
* understand. Fail if this platform does not support a prom or if
* the device does not correspond to a valid prom device.
* dev_path should be the name of a device in the logical or
* physical device namespace.
* prom_path is the prom version of the device name
* prom_path must be large enough to contain the result and is
* supplied by the user.
*
* This routine only supports converting leaf device paths
*/
int
{
int rval;
if (rval < 0)
return (rval);
else
return (0);
}
/*
* Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs
* path to a driver name.
* devfs_path - the pathname of interest. This must be the physcical device
* path with the mount point prefix (ie. /devices) stripped off.
* drv_buf - user supplied buffer - the driver name will be stored here.
*
* If the prom lookup fails, we return the name of the last component in
* the pathname. This routine is useful for looking up driver names
* associated with generically named devices.
*
* This routine returns driver names that have aliases resolved.
*/
int
{
char driver_path[MAXPATHLEN];
int prom_fd;
return (-1);
}
if (devfs_path == NULL) {
return (-1);
}
return (-1);
if (*devfs_path != '/')
return (-1);
/* strip off any minor node info at the end of the path */
return (-1);
*colon = '\0';
/* query the prom */
/* return the driver name in drv_buf */
return (0);
}
} else if (prom_fd != DEVFS_NOTSUP)
return (-1);
/*
* If we get here, then either:
* 1. this platform does not support an openprom driver
* 2. we were asked to look up a device the prom does
* not know about (e.g. a pseudo device)
* In this case, we use the last component of the devfs path
* name and try to derive the driver name
*/
/* use the last component of devfs_path as the driver name */
*dev_addr = '\0';
slash++;
/* use opp->oprom_array as a buffer */
return (-1);
return (0);
}
/*
* These modctl calls do the equivalent of:
* ddi_name_to_major()
* ddi_major_to_name()
* This results in two things:
* - the driver name must be a valid one
* - any driver aliases are resolved.
* drv is overwritten with the resulting name.
*/
char *
devfs_resolve_aliases(char *drv)
{
return (NULL);
}
return (NULL);
< 0) {
return (NULL);
} else {
return (drv);
}
}
/*
* open the openprom device. and verify that we are on an
* OBP/1275 OF machine. If the prom does not exist, then we
* return an error
*/
static int
{
int prom_fd = -1;
while (prom_fd < 0) {
(void) sleep(5);
continue;
}
return (DEVFS_NOTSUP);
}
return (DEVFS_PERM);
}
return (DEVFS_ERR);
} else
break;
}
if (is_openprom(prom_fd))
return (prom_fd);
else {
return (DEVFS_ERR);
}
}
static void
prom_close(int prom_fd)
{
}
/*
* is this an OBP/1275 OF machine?
*/
static int
is_openprom(int prom_fd)
{
unsigned int i;
return (0);
i = (unsigned int)((unsigned char)opp->oprom_array[0]);
return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
}
/*
* convert a prom device path name to an equivalent physical device
* path in the kernel.
*/
static int
{
int prom_fd;
int ret = DEVFS_INVAL;
return (DEVFS_INVAL);
}
return (DEVFS_INVAL);
}
return (DEVFS_INVAL);
if (*prom_path != '/') {
return (DEVFS_INVAL);
}
/* query the prom */
if (prom_fd < 0) {
return (prom_fd);
}
/*
* success
* return the prom path in prom_path
*/
return (0);
}
/*
* either the argument was not a valid name or the openprom
* driver does not support this ioctl.
*/
ret = DEVFS_NOTSUP;
}
return (ret);
}
/*
* convert a prom device path to a list of equivalent alias names
* If there is no alias node, or there are no aliases that correspond
* to dev, we return empty lists.
*/
static int
{
struct name_list *exact_list;
struct name_list *inexact_list;
char *ptr;
char **array;
int prom_fd;
int count;
int vers;
vers = prom_obp_vers();
if (vers < 0) {
return (vers);
}
return (DEVFS_INVAL);
}
if (*dev != '/')
return (DEVFS_INVAL);
return (DEVFS_INVAL);
return (DEVFS_INVAL);
}
return (DEVFS_INVAL);
}
if (prom_fd < 0) {
return (prom_fd);
}
&inexact_list, prom_fd);
if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) {
exact_list = NULL;
}
if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) {
inexact_list = NULL;
}
count = 0;
list = exact_list;
count++;
}
list = inexact_list;
count++;
}
== NULL) {
return (DEVFS_NOMEM);
}
count = 0;
list = exact_list;
count++;
}
list = inexact_list;
count++;
}
free_name_list(exact_list, 0);
return (0);
}
/*
* determine the version of prom we are running on.
* Also include any prom revision specific information.
*/
static int
prom_obp_vers(void)
{
int prom_fd;
static int version = 0;
/* cache version */
if (version > 0) {
return (version);
}
if (prom_fd < 0) {
return (prom_fd);
}
return (DEVFS_ERR);
}
return (version);
}
/*
* search the aliases node by definition - compile a list of
* alias names that are both exact and inexact matches.
*/
static int
{
int ret;
char alias_buf[MAXNAMELEN];
int found = 0;
*ip = 0;
return (0);
if (opp->oprom_size == 0)
return (0);
(propdef_opp->oprom_size == 0)) {
continue;
}
if (ret == EXACT_MATCH) {
found++;
!= 0) {
return (-1);
}
}
if (ret == INEXACT_MATCH) {
found++;
!= 0) {
return (-1);
}
}
}
if (found) {
return (0);
} else {
return (-1);
}
}
/*
* free a list of name_list structs and optionally
* free the strings they contain.
*/
static void
{
if (free_name)
}
}
/*
* insert a new alias in a list of aliases - the list is sorted
* in collating order (ignoring anything that comes after the
* ':' in the name).
*/
static int
{
int ret;
if ((new_entry =
== NULL) {
return (-1);
}
return (-1);
}
return (0);
}
*colon1 = '\0';
}
prev_entry = NULL;
*colon2 = '\0';
}
*colon2 = ':';
}
/* duplicate */
if (ret == 0) {
*colon1 = ':';
}
return (0);
}
if (ret < 0) {
if (prev_entry == NULL) {
/* in beginning of list */
} else {
/* in middle of list */
}
*colon1 = ':';
}
return (0);
}
prev_entry = entry;
}
/* at end of list */
*colon1 = ':';
}
return (0);
}
/*
* append :x to alias_name to override any default minor name options
*/
static void
{
char *colon;
/*
* XXX - should alias names in /aliases ever have a
* : embedded in them?
* If so we ignore it.
*/
*colon = '\0';
}
}
}
/*
* compare to prom device names.
* if the device names are not fully qualified. we convert them -
* we only do this as a last resort though since it requires
* jumping into the kernel.
*/
static int
{
int unqualified_name = 0;
int error = EXACT_MATCH;
char *wildcard = ",0";
return (NO_MATCH);
}
return (NO_MATCH);
}
/*
* compare device names one component at a time.
*/
*ptr1 = '\0';
*ptr2 = '\0';
break;
}
break;
}
break;
}
/*
* a possible name is driver_name@address. The address
* portion is optional (i.e. the name is not fully
* qualified.). We have to deal with the case where
* the component name is either driver_name or
* driver_name@address
*/
unqualified_name = 1;
} else if (addrname1 &&
/*
* check to see if appending a ",0" to the
* shorter address causes a match to occur.
* If so succeed.
*/
continue;
continue;
}
break;
}
}
/*
* if either of the two device paths still has more components,
* then we do not have a match.
*/
*ptr1 = '/';
}
*ptr2 = '/';
}
return (error);
}
/*
* OK - we found a possible match but one or more of the
* path components was not fully qualified (did not have any
* address information. So we need to convert it to a form
* that is fully qualified and then compare the resulting
* strings.
*/
if (unqualified_name != 0) {
return (NO_MATCH);
}
*dev1 = '\0';
}
*dev2 = '\0';
}
return (NO_MATCH);
}
}
/*
* the resulting strings matched. If the minorname information
* matches, then we have an exact match, otherwise an inexact match
*/
return (EXACT_MATCH);
} else {
return (INEXACT_MATCH);
}
}
/*
* wrapper or strcmp - deals with null strings.
*/
static int
{
return (0);
return (-1);
}
return (1);
}
}
/*
* break device@a,b:minor into components
*/
static void
{
if (*name == '@')
if (ch == '@')
else if (ch == ':')
++cp;
}
if (*addrname) {
}
if (*minorname) {
}
}
/*
* converts a prom alias to a prom device name.
* if we find no matching device, then we fail since if were
* given a valid alias, then by definition, there must be a
* device pathname associated with it in the /aliases node.
*/
static int
{
char *options_ptr;
char alias_buf[MAXNAMELEN];
char alias_def[MAXPATHLEN];
int prom_fd = -1;
int ret;
int found = 0;
int i;
return (DEVFS_INVAL);
return (DEVFS_INVAL);
return (DEVFS_INVAL);
}
if (prom_fd < 0) {
return (prom_fd);
}
/*
* save off any options (minor name info) that is
* explicitly called out in the alias name
*/
*options_ptr = '\0';
}
*alias_def = '\0';
if (ret == 0) {
/*
* we loop because one alias may define another... we have
* to work our way down to an actual device definition.
*/
for (i = 0; i <= 10; i++) {
if (ret == -1) {
break;
}
sizeof (alias_buf));
if (*alias_def == '/') {
break;
}
/*
* save off any explicit options (minor name info)
* if none has been encountered yet
*/
if (options_ptr == NULL) {
if (options_ptr != NULL) {
*options_ptr = '\0';
sizeof (options));
}
}
}
}
/* error */
if (ret == -1) {
return (ret);
}
/* override minor name information */
if (options_ptr != NULL) {
} else {
*(++options_ptr) = '\0';
}
}
return (0);
}
/*
* search a prom node for a property name
*/
static int
{
*ip = 0;
return (-1);
if (opp->oprom_size == 0)
return (-1);
return (-1);
if (opp->oprom_size == 0)
return (-1);
}
return (-1);
if (opp->oprom_size == 0)
return (-1);
return (0);
}
/*
* return the aliases node.
*/
static int
prom_find_aliases_node(int fd)
{
char buf[MAXNAMELEN];
return (-1);
return (-1);
while (child_id != 0) {
return (0);
}
}
}
return (-1);
}
/*
* get sibling
*/
static uint_t
{
return (0);
}
/*
* get child
*/
static uint_t
{
return (0);
}
/*
* only on sparc for now
*/
int
devfs_bootdev_modifiable(void)
{
#if defined(sparc)
return (0);
#else
return (DEVFS_NOTSUP);
#endif
}