Example #1
0
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);
}
Example #2
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);
	}
}
Example #3
0
/*
 * 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);
}
Example #4
0
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);
}
Example #5
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);
}
Example #6
0
/*
 * 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);
}
Example #7
0
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);
}
Example #8
0
/*
 * 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);
}