int dev_list_gather(topo_mod_t *mod, topo_list_t *listp) { di_node_t devtree; di_devlink_handle_t devhdl; disk_cbdata_t dcb; if ((devtree = topo_mod_devinfo(mod)) == DI_NODE_NIL) { topo_mod_dprintf(mod, "disk_list_gather: " "topo_mod_devinfo() failed"); return (-1); } if ((devhdl = di_devlink_init(NULL, 0)) == DI_NODE_NIL) { topo_mod_dprintf(mod, "disk_list_gather: " "di_devlink_init() failed"); return (-1); } dcb.dcb_mod = mod; dcb.dcb_list = listp; dcb.dcb_devhdl = devhdl; /* walk the devinfo snapshot looking for disk nodes */ (void) di_walk_node(devtree, DI_WALK_CLDFIRST, &dcb, dev_walk_di_nodes); (void) di_devlink_fini(&devhdl); return (0); }
/* * The functions in this file do a dev tree walk to build up a model of the * disks, controllers and paths on the system. This model is returned in the * args->disk_listp and args->controller_listp members of the args param. * There is no global data for this file so it is thread safe. It is up to * the caller to merge the resulting model with any existing model that is * cached. The caller must also free the memory for this model when it is * no longer needed. */ void findevs(struct search_args *args) { di_node_t di_root; args->bus_listp = NULL; args->controller_listp = NULL; args->disk_listp = NULL; args->dev_walk_status = 0; args->handle = di_devlink_init(NULL, 0); /* * Have to make several passes at this with the new devfs caching. * First, we find non-mpxio devices. Then we find mpxio/multipath * devices. */ di_root = di_init("/", DINFOCACHE); args->ph = di_prom_init(); (void) di_walk_minor(di_root, NULL, 0, args, add_devs); di_fini(di_root); di_root = di_init("/", DINFOCPYALL|DINFOPATH); (void) di_walk_minor(di_root, NULL, 0, args, add_devs); di_fini(di_root); (void) di_devlink_fini(&(args->handle)); clean_paths(args); }
int sunos_get_device_list(struct libusb_context * ctx, struct discovered_devs **discdevs) { di_node_t root_node; struct node_args args; di_devlink_handle_t devlink_hdl; args.ctx = ctx; args.discdevs = discdevs; args.last_ugenpath = NULL; if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { usbi_dbg("di_int() failed: %s", strerror(errno)); return (LIBUSB_ERROR_IO); } if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) { di_fini(root_node); usbi_dbg("di_devlink_init() failed: %s", strerror(errno)); return (LIBUSB_ERROR_IO); } args.dlink_hdl = devlink_hdl; /* walk each node to find USB devices */ if (di_walk_node(root_node, DI_WALK_SIBFIRST, &args, sunos_walk_minor_node_link) == -1) { usbi_dbg("di_walk_node() failed: %s", strerror(errno)); di_fini(root_node); return (LIBUSB_ERROR_IO); } di_fini(root_node); di_devlink_fini(&devlink_hdl); usbi_dbg("%d devices", (*discdevs)->len); return ((*discdevs)->len); }
char *getDeviceFileName(MP_UINT64 objectSequenceNumber) { char *deviceFileName = NULL; di_node_t root_node = DI_NODE_NIL; di_node_t cur_node = DI_NODE_NIL; int instNum; int majorNum; MP_UINT64 osn; char *pathName = NULL; char *minorName = "c,raw"; char *devLink = NULL; char fullName[512]; walk_devlink_t warg; di_devlink_handle_t dlHandle = NULL; int diStatus = 0; log(LOG_INFO, "getDeviceFileName()", " - enter"); log(LOG_INFO, "getDeviceFileName()", " - objectSequenceNumber: %llx", objectSequenceNumber); root_node = di_init("/", DINFOCACHE); if (DI_NODE_NIL == root_node) { log(LOG_INFO, "MP_GetMultipathLusPlugin()", " - $ERROR, di_init() failed"); return (NULL); } cur_node = di_drv_first_node("scsi_vhci", root_node); if (DI_NODE_NIL == cur_node) { log(LOG_INFO, "getDeviceFileName()", " - $ERROR, di_drv_first_node() failed"); di_fini(root_node); return (NULL); } cur_node = di_child_node(cur_node); while (DI_NODE_NIL != cur_node) { instNum = di_instance(cur_node); majorNum = di_driver_major(cur_node); osn = 0; osn = MP_STORE_INST_TO_ID(instNum, osn); osn = MP_STORE_MAJOR_TO_ID(majorNum, osn); if (osn == objectSequenceNumber) { log(LOG_INFO, "getDeviceFileName()", " - found node."); break; } cur_node = di_sibling_node(cur_node); } if (DI_NODE_NIL != cur_node) { dlHandle = di_devlink_init(NULL, 0); if (NULL == dlHandle) { log(LOG_INFO, "getDeviceFileName()", " - $ERROR, di_devlink_init() failed."); di_fini(root_node); return (NULL); } pathName = di_devfs_path(cur_node); (void) snprintf(fullName, 511, "%s:%s", pathName, minorName); log(LOG_INFO, "getDeviceFileName()", " - fullName: {%s]", fullName); (void) memset(&warg, 0, sizeof (walk_devlink_t)); devLink = NULL; warg.linkpp = &devLink; diStatus = di_devlink_walk(dlHandle, NULL, fullName, DI_PRIMARY_LINK, (void *)&warg, get_devlink); if (diStatus != 0) { log(LOG_INFO, "getDeviceFileName()", "diStatus: %d", diStatus); if (diStatus < 0) { diStatus = errno; } log(LOG_INFO, "getDeviceFileName()", "diStatus: %d", diStatus); log(LOG_INFO, "getDeviceFileName()", "strerror(diStatus): %s", strerror(diStatus)); } if (NULL != devLink) { deviceFileName = (char *)calloc(1, strlen(devLink) + 1); (void) strncpy(deviceFileName, devLink, strlen(devLink)); } else { log(LOG_INFO, "getDeviceFileName()", " - $ERROR, devLink is NULL."); deviceFileName = (char *)calloc(1, 256); (void) strncpy(deviceFileName, pathName, 255); } di_devfs_path_free(pathName); (void) di_devlink_fini(&dlHandle); } di_fini(root_node); free(devLink); log(LOG_INFO, "getDeviceFileName()", " - exit"); return (deviceFileName); }
static int init_zfd_devs(zlog_t *zlogp, zlog_mode_t mode) { devctl_hdl_t bus_hdl = NULL; di_devlink_handle_t dl = NULL; int rv = -1; int ndevs; int reqdevs; int i; /* * Three zfd devices are required for log mode. * Interactive mode needs only one. */ reqdevs = (mode != ZLOG_INTERACTIVE) ? 3 : 1; /* * Don't re-setup zone fd devs if they already exist; just * skip ahead to making devlinks, which we do for sanity's sake. */ ndevs = count_zfd_devs(zlogp); if (ndevs == reqdevs) goto devlinks; if (ndevs > 0 || ndevs == -1) { if (destroy_zfd_devs(zlogp) == -1) goto error; } /* * Time to make the devices. */ if ((bus_hdl = devctl_bus_acquire(ZFDNEX_FILEPATH, 0)) == NULL) { zerror(zlogp, B_TRUE, "devctl_bus_acquire failed"); goto error; } for (i = 0; i < reqdevs; i++) { if (init_zfd_dev(zlogp, bus_hdl, i) != 0) goto error; } devlinks: if ((dl = di_devlink_init("zfd", DI_MAKE_LINK)) == NULL) { zerror(zlogp, B_TRUE, "failed to create devlinks"); goto error; } (void) di_devlink_fini(&dl); rv = 0; if (mode == ZLOG_INTERACTIVE) { /* We want to look like a tty. */ make_tty(zlogp, 0); } error: if (bus_hdl) devctl_release(bus_hdl); return (rv); }
static char * find_link(di_node_t cnode) { di_minor_t devminor = DI_MINOR_NIL; di_devlink_handle_t hdl; char *devfspath = NULL; char *minorpath = NULL; char *linkname = NULL; char *cbresult = NULL; devfspath = di_devfs_path(cnode); if (cnode == DI_NODE_NIL) { logmsg(MSG_ERROR, gettext("find_ctrl must be called with non-null " "di_node_t\n")); return (NULL); } logmsg(MSG_INFO, "find_link: devfspath %s\n", devfspath); if (((cbresult = calloc(1, MAXPATHLEN)) == NULL) || ((minorpath = calloc(1, MAXPATHLEN)) == NULL) || ((linkname = calloc(1, MAXPATHLEN)) == NULL)) { logmsg(MSG_ERROR, "unable to allocate space for dev link\n"); return (NULL); } devminor = di_minor_next(cnode, devminor); hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK); if (hdl == NULL) { logmsg((readonlyroot ? MSG_INFO : MSG_ERROR), gettext("unable to take devlink snapshot: %s\n"), strerror(errno)); return (NULL); } linkname = "^dsk/"; (void) snprintf(minorpath, MAXPATHLEN, "%s:c", devfspath); errno = 0; if (di_devlink_walk(hdl, linkname, minorpath, DI_PRIMARY_LINK, (void *)cbresult, link_cb) < 0) { logmsg(MSG_ERROR, gettext("Unable to walk devlink snapshot for %s: %s\n"), minorpath, strerror(errno)); return (NULL); } if (di_devlink_fini(&hdl) < 0) { logmsg(MSG_ERROR, gettext("Unable to close devlink snapshot: %s\n"), strerror(errno)); } if (strstr(cbresult, "dsk/") == NULL) return (devfspath); bzero(minorpath, MAXPATHLEN); /* strip off the trailing "s2" */ bcopy(cbresult, minorpath, strlen(cbresult) - 1); /* Now strip off the /dev/dsk/ prefix for output flexibility */ linkname = strrchr(minorpath, '/'); return (++linkname); }
/* * init_console_dev() drives the device-tree configuration of the zone * console device. The general strategy is to use the libdevice (devctl) * interfaces to instantiate a new zone console node. We do a lot of * sanity checking, and are careful to reuse a console if one exists. * * Once the device is in the device tree, we kick devfsadm via di_devlink_init() * to ensure that the appropriate symlinks (to the master and slave console * devices) are placed in /dev in the global zone. */ static int init_console_dev(zlog_t *zlogp) { char conspath[MAXPATHLEN]; devctl_hdl_t bus_hdl = NULL; devctl_hdl_t dev_hdl = NULL; devctl_ddef_t ddef_hdl = NULL; di_devlink_handle_t dl = NULL; int rv = -1; int ndevs; int masterfd; int slavefd; int i; /* * Don't re-setup console if it is working and ready already; just * skip ahead to making devlinks, which we do for sanity's sake. */ ndevs = count_console_devs(zlogp); if (ndevs == 1) { goto devlinks; } else if (ndevs > 1 || ndevs == -1) { /* * For now, this seems like a reasonable but harsh punishment. * If needed, we could try to get clever and delete all but * the console which is pointed at by the current symlink. */ if (destroy_console_devs(zlogp) == -1) { goto error; } } /* * Time to make the consoles! */ if ((bus_hdl = devctl_bus_acquire(ZCONSNEX_FILEPATH, 0)) == NULL) { zerror(zlogp, B_TRUE, "%s failed", "devctl_bus_acquire"); goto error; } if ((ddef_hdl = devctl_ddef_alloc("zcons", 0)) == NULL) { zerror(zlogp, B_TRUE, "failed to allocate ddef handle"); goto error; } /* * Set three properties on this node; the first is the name of the * zone; the second is a flag which lets pseudo know that it is * OK to automatically allocate an instance # for this device; * the third tells the device framework not to auto-detach this * node-- we need the node to still be there when we ask devfsadmd * to make links, and when we need to open it. */ if (devctl_ddef_string(ddef_hdl, "zonename", zone_name) == -1) { zerror(zlogp, B_TRUE, "failed to create zonename property"); goto error; } if (devctl_ddef_int(ddef_hdl, "auto-assign-instance", 1) == -1) { zerror(zlogp, B_TRUE, "failed to create auto-assign-instance " "property"); goto error; } if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) { zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach " "property"); goto error; } if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) { zerror(zlogp, B_TRUE, "failed to create console node"); goto error; } devlinks: if ((dl = di_devlink_init("zcons", DI_MAKE_LINK)) != NULL) { (void) di_devlink_fini(&dl); } else { zerror(zlogp, B_TRUE, "failed to create devlinks"); goto error; } /* * Open the master side of the console and issue the ZC_HOLDSLAVE ioctl, * which will cause the master to retain a reference to the slave. * This prevents ttymon from blowing through the slave's STREAMS anchor. * * In very rare cases the open returns ENOENT if devfs doesn't have * everything setup yet due to heavy zone startup load. Wait for * 1 sec. and retry a few times. Even if we can't setup the zone's * console, we still go ahead and boot the zone. */ (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME); for (i = 0; i < ZCONS_RETRY; i++) { masterfd = open(conspath, O_RDWR | O_NOCTTY); if (masterfd >= 0 || errno != ENOENT) break; (void) sleep(1); } if (masterfd == -1) { zerror(zlogp, B_TRUE, "ERROR: could not open master side of " "zone console for %s to acquire slave handle", zone_name); master_zcons_failed = B_TRUE; } (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s", zone_name, ZCONS_SLAVE_NAME); for (i = 0; i < ZCONS_RETRY; i++) { slavefd = open(conspath, O_RDWR | O_NOCTTY); if (slavefd >= 0 || errno != ENOENT) break; (void) sleep(1); } if (slavefd == -1) zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone" " console for %s to acquire slave handle", zone_name); /* * This ioctl can occasionally return ENXIO if devfs doesn't have * everything plumbed up yet due to heavy zone startup load. Wait for * 1 sec. and retry a few times before we fail to boot the zone. */ if (masterfd != -1 && slavefd != -1) { for (i = 0; i < ZCONS_RETRY; i++) { if (ioctl(masterfd, ZC_HOLDSLAVE, (caddr_t)(intptr_t)slavefd) == 0) { rv = 0; break; } else if (errno != ENXIO) { break; } (void) sleep(1); } if (rv != 0) zerror(zlogp, B_TRUE, "ERROR: error while acquiring " "slave handle of zone console for %s", zone_name); } if (slavefd != -1) (void) close(slavefd); if (masterfd != -1) (void) close(masterfd); error: if (ddef_hdl) devctl_ddef_free(ddef_hdl); if (bus_hdl) devctl_release(bus_hdl); if (dev_hdl) devctl_release(dev_hdl); return (rv); }
/* * Convert the specified devid/minor_name into a devid_nmlist_t array * with names that resolve into /devices or /dev depending on search_path. * * The man page indicates that: * * This function traverses the file tree, starting at search_path. * * This is not true, we reverse engineer the paths relative to * the specified search path to avoid attaching all devices. */ int devid_deviceid_to_nmlist( char *search_path, ddi_devid_t devid, char *minor_name, devid_nmlist_t **retlist) { char *cp; int dev; char *paths = NULL; char *path; int lens; #ifndef __APPLE__ di_devlink_handle_t dlh = NULL; #endif int ret = -1; #ifndef __APPLE__ struct devlink_cbinfo cbi; #endif struct nmlist *nlh = NULL; struct nmlist *nl; devid_nmlist_t *rl; int nret; int nagain = 0; int err = 0; *retlist = NULL; /* verify valid search path starts with "/devices" or "/dev" */ if ((strcmp(search_path, "/devices") == 0) || (strncmp(search_path, "/devices/", 9) == 0)) dev = 0; else if ((strcmp(search_path, "/dev") == 0) || (strncmp(search_path, "/dev/", 5) == 0)) dev = 1; else { errno = EINVAL; return (-1); } #ifndef __APPLE__ /* translate devid/minor_name to /devices paths */ again: if (modctl(MODDEVID2PATHS, devid, minor_name, 0, &lens, NULL) != 0) goto out; if ((paths = (char *)malloc(lens)) == NULL) goto out; if (modctl(MODDEVID2PATHS, devid, minor_name, 0, &lens, paths) != 0) { if ((errno == EAGAIN) && (nagain++ < DEVICEID_NMLIST_NRETRY)) { free(paths); paths = NULL; goto again; } goto out; } /* * initialize for /devices path to /dev path translation. To reduce * overhead we reuse the last snapshot if DEVICEID_NMLIST_SLINK is set. */ if (dev) { dlh = devid_deviceid_to_nmlist_dlh; if (dlh && !(devid_deviceid_to_nmlist_flg & DEVICEID_NMLIST_SLINK)) { (void) di_devlink_fini(&dlh); dlh = devid_deviceid_to_nmlist_dlh = NULL; } if ((dlh == NULL) && ((dlh = di_devlink_init(NULL, 0)) == NULL)) goto out; } /* * iterate over all the devtspectype resolutions of the devid and * convert them into the appropriate path form and add items to return * to the nmlist list; */ for (path = paths; *path; path += strlen(path) + 1) { if (dev) { /* add /dev entries */ cbi.cbi_nlhp = &nlh; cbi.cbi_search_path = search_path; cbi.cbi_error = 0; (void) di_devlink_walk(dlh, NULL, path, devid_deviceid_to_nmlist_link, (void *)&cbi, devlink_callback); if (cbi.cbi_error) goto out; } else { /* add /devices entry */ cp = malloc(strlen("/devices") + strlen(path) + 1); (void) strcpy(cp, "/devices"); (void) strcat(cp, path); if (strncmp(cp, search_path, strlen(search_path)) == 0) { if (nmlist_add(&nlh, cp) == NULL) { free(cp); goto out; } } free(cp); } } /* convert from nmlist to retlist array */ for (nl = nlh, nret = 0; nl; nl = nl->nl_next) nret++; if (nret == 0) { err = ENODEV; goto out; } if ((*retlist = calloc(nret + 1, sizeof (devid_nmlist_t))) == NULL) { err = ENOMEM; goto out; } for (nl = nlh, rl = *retlist; nl; nl = nl->nl_next, rl++) { rl->devname = nl->nl_devname; rl->dev = nl->nl_dev; } rl->devname = NULL; rl->dev = NODEV; ret = 0; out: while ((nl = nlh) != NULL) { /* free the nmlist */ nlh = nl->nl_next; free(nl); } if (paths) free(paths); if (dlh) { if ((ret == 0) && (devid_deviceid_to_nmlist_flg & DEVICEID_NMLIST_SLINK)) devid_deviceid_to_nmlist_dlh = dlh; else (void) di_devlink_fini(&dlh); } if (ret && *retlist) free(*retlist); if (ret && err != 0) errno = err; #endif return (ret); }