static int offline_device(char *path) { devctl_hdl_t dcp; if ((dcp = devctl_device_acquire(path, 0)) == NULL) { return (-1); } if ((devctl_device_offline(dcp)) == -1) { devctl_release(dcp); return (-1); } devctl_release(dcp); return (0); }
/* * Pair of routines to set up for/clean up after a devctl_ap_* lib call. */ static void cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist) { if (user_nvlist != NULL) { nvlist_free(user_nvlist); } if (devctl_hdl != NULL) { devctl_release(devctl_hdl); } }
/* * init_zfd_devs() drives the device-tree configuration of the zone fd devices. * The general strategy is to use the libdevice (devctl) interfaces to * instantiate 3 new zone fd nodes. We do a lot of sanity checking, and * are careful to reuse a dev if one exists. * * Once the devices are in the device tree, we kick devfsadm via * di_devlink_init() to ensure that the appropriate symlinks (to the master and * slave fd devices) are placed in /dev in the global zone. */ static int init_zfd_dev(zlog_t *zlogp, devctl_hdl_t bus_hdl, int id) { int rv = -1; devctl_ddef_t ddef_hdl = NULL; devctl_hdl_t dev_hdl = NULL; if ((ddef_hdl = devctl_ddef_alloc("zfd", 0)) == NULL) { zerror(zlogp, B_TRUE, "failed to allocate ddef handle"); goto error; } /* * Set four 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, "zfd_zname", zone_name) == -1) { zerror(zlogp, B_TRUE, "failed to create zfd_zname property"); goto error; } if (devctl_ddef_int(ddef_hdl, "zfd_id", id) == -1) { zerror(zlogp, B_TRUE, "failed to create zfd_id 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 zfd node"); goto error; } rv = 0; error: if (ddef_hdl) devctl_ddef_free(ddef_hdl); if (dev_hdl) devctl_release(dev_hdl); return (rv); }
static int getstate_device(char *path) { devctl_hdl_t dcp; uint_t state = 0; if ((dcp = devctl_device_acquire(path, 0)) == NULL) { (void) printf("%s unknown unknown\n", path); return (-1); } if ((devctl_device_getstate(dcp, &state)) == -1) { (void) printf("%s unknown unknown\n", path); devctl_release(dcp); return (-1); } devctl_release(dcp); switch (state) { case DEVICE_DOWN: (void) printf("%s down not_busy\n", path); break; case DEVICE_OFFLINE: (void) printf("%s offline not_busy\n", path); break; case DEVICE_ONLINE: (void) printf("%s online not_busy\n", path); break; case (DEVICE_ONLINE | DEVICE_BUSY): (void) printf("%s online busy\n", path); break; case (DEVICE_DOWN | DEVICE_BUSY): (void) printf("%s down busy\n", path); break; default: (void) printf("%s unknown unknown\n", path); break; } return (0); }
/* * destroy_zfd_devs() and its helper destroy_cb() tears down any zfd instances * associated with this zone. If things went very wrong, we might have an * incorrect number of instances hanging around. This routine hunts down and * tries to remove all of them. Of course, if the fd is open, the instance will * not detach, which is a potential issue. */ static int destroy_cb(di_node_t node, void *arg) { struct cb_data *cb = (struct cb_data *)arg; char *prop_data; char *tmp; char devpath[MAXPATHLEN]; devctl_hdl_t hdl; if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zfd_zname", &prop_data) == -1) return (DI_WALK_CONTINUE); assert(prop_data != NULL); if (strcmp(prop_data, zone_name) != 0) { /* this is a zfd for a different zone */ return (DI_WALK_CONTINUE); } cb->found++; tmp = di_devfs_path(node); (void) snprintf(devpath, sizeof (devpath), "/devices/%s", tmp); di_devfs_path_free(tmp); if ((hdl = devctl_device_acquire(devpath, 0)) == NULL) { zerror(cb->zlogp, B_TRUE, "WARNING: zfd %s found, " "but it could not be controlled.", devpath); return (DI_WALK_CONTINUE); } if (devctl_device_remove(hdl) == 0) { cb->killed++; } else { zerror(cb->zlogp, B_TRUE, "WARNING: zfd %s found, " "but it could not be removed.", devpath); } devctl_release(hdl); return (DI_WALK_CONTINUE); }
/* * allocate and initalize the devctl_hdl structure for the * particular handle type. */ static devctl_hdl_t dc_mkhndl(dc_type_t type, char *path, uint_t oflags, devctl_hdl_t pc) { struct devctl_hdl *dcp; struct stat sb; char iocpath[MAXPATHLEN]; char *nodename, *unitsep, *minorsep, *chop; char *minorname; size_t strlcpy_size; char *iocpath_dup; char *tok; if ((path == NULL) || (strlen(path) > MAXPATHLEN - 1)) { errno = EINVAL; return (NULL); } /* * allocate handle and make a copy of the original path */ if ((dcp = calloc(1, sizeof (*dcp))) == NULL) { errno = ENOMEM; return (NULL); } if ((dcp->opath = strdup(path)) == NULL) { devctl_release((devctl_hdl_t)dcp); errno = ENOMEM; return (NULL); } (void) strcpy(iocpath, path); dcp->hdltype = type; dcp->fd = -1; /* * break apart the pathname according to the type handle */ switch (type) { case DEVCTL_PM_BUS: /* * chop off any minor name and concatenate the * ":devctl" minor node name string. */ if ((chop = strrchr(iocpath, ':')) != NULL) *chop = '\0'; if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >= MAXPATHLEN) { devctl_release((devctl_hdl_t)dcp); errno = EINVAL; return (NULL); } else if (_libdevice_debug) { (void) printf("DEVCTL_PM_BUS: iocpath %s\n", iocpath); } break; case DEVCTL_PM_DEV: /* * Chop up the last device component in the pathname. * Concatenate either the device name itself, or the * "a,raw" string, as the minor node name, to the iocpath. */ if ((iocpath_dup = strdup(iocpath)) == NULL) { devctl_release((devctl_hdl_t)dcp); errno = ENOMEM; return (NULL); } if ((chop = strrchr(iocpath_dup, '/')) == NULL) { devctl_release((devctl_hdl_t)dcp); errno = EINVAL; return (NULL); } *chop = '\0'; nodename = chop + 1; /* * remove the "@0,0" string */ tok = strtok(nodename, "@"); if ((minorname = malloc(strlen(tok) +1)) == NULL) { if (_libdevice_debug) (void) printf("DEVCTL_PM_DEV: failed malloc for" " minorname\n"); devctl_release((devctl_hdl_t)dcp); errno = ENOMEM; return (NULL); } (void) strcpy(minorname, tok); if (_libdevice_debug) { (void) printf("DEVCTL_PM_DEV: minorname %s\n", minorname); } /* * construct the name of the ioctl device * by concatenating either ":a,raw" or ":"minorname */ (void) strlcat(iocpath, ":", MAXPATHLEN); if (strcmp(minorname, "disk_chan") == 0 || strcmp(minorname, "disk_wwn") == 0 || strcmp(minorname, "disk_cdrom") == 0) { strlcpy_size = strlcat(iocpath, devctl_target_raw, MAXPATHLEN); } else { strlcpy_size = strlcat(iocpath, minorname, MAXPATHLEN); } if (strlcpy_size >= MAXPATHLEN) { devctl_release((devctl_hdl_t)dcp); errno = EINVAL; return (NULL); } else if (_libdevice_debug) { (void) printf("DEVCTL_PM_DEV: iocpath %s\n", iocpath); } break; case DEVCTL_AP: /* * take the pathname as provided. */ break; case DEVCTL_BUS: /* * chop off any minor name and concatenate the * ":devctl" minor node name string. */ if ((chop = strrchr(iocpath, ':')) != NULL) *chop = '\0'; if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >= MAXPATHLEN) { devctl_release((devctl_hdl_t)dcp); errno = EINVAL; return (NULL); } break; case DEVCTL_CLONE: /* * create a device handle for a new device created * from a call to devctl_bus_dev_create() */ dcp->hdltype = DEVCTL_DEVICE; /* FALLTHRU */ case DEVCTL_DEVICE: /* * Chop up the last device component in the pathname. * The componets are passed as nodename and unitaddr * in the IOCTL data for DEVCTL ops on devices. */ if ((chop = strrchr(iocpath, '/')) == NULL) { devctl_release((devctl_hdl_t)dcp); errno = EINVAL; return (NULL); } *chop = '\0'; nodename = chop + 1; unitsep = strchr(nodename, '@'); minorsep = strchr(nodename, ':'); if (unitsep == NULL) { devctl_release((devctl_hdl_t)dcp); errno = EINVAL; return (NULL); } /* * copy the nodename and unit address */ if (((dcp->nodename = malloc(MAXNAMELEN)) == NULL) || ((dcp->unitaddr = malloc(MAXNAMELEN)) == NULL)) { devctl_release((devctl_hdl_t)dcp); errno = ENOMEM; return (NULL); } *unitsep = '\0'; if (minorsep != NULL) *minorsep = '\0'; (void) snprintf(dcp->nodename, MAXNAMELEN, "%s", nodename); (void) snprintf(dcp->unitaddr, MAXNAMELEN, "%s", unitsep+1); /* * construct the name of the ioctl device */ if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >= MAXPATHLEN) { devctl_release((devctl_hdl_t)dcp); errno = EINVAL; return (NULL); } break; default: devctl_release((devctl_hdl_t)dcp); errno = EINVAL; return (NULL); } if (_libdevice_debug) (void) printf("dc_mkhndl: iocpath %s ", iocpath); /* * verify the devctl or ap device exists and is a * character device interface. */ if (stat(iocpath, &sb) == 0) { if ((sb.st_mode & S_IFMT) != S_IFCHR) { if (_libdevice_debug) (void) printf(" - not character device\n"); errno = ENODEV; devctl_release((devctl_hdl_t)dcp); return (NULL); } } else { /* * return failure with errno value set by stat */ if (_libdevice_debug) (void) printf(" - stat failed\n"); devctl_release((devctl_hdl_t)dcp); return (NULL); } /* * if this was a new device, dup the parents handle, otherwise * just open the device. */ if (type == DEVCTL_CLONE) dcp->fd = dup(DCP(pc)->fd); else dcp->fd = open(iocpath, oflags); if (dcp->fd == -1) { if (_libdevice_debug) (void) printf(" - open/dup failed %d\n", errno); /* * leave errno as set by open/dup */ devctl_release((devctl_hdl_t)dcp); return (NULL); } if (_libdevice_debug) (void) printf(" - open success\n"); return ((devctl_hdl_t)dcp); }
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); }
/* * 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); }