Exemplo n.º 1
0
/*
 * Add the environment variable specified by the format string [fmt].
 */
static void
_zed_event_add_var(uint64_t eid, zed_strings_t *zsp, const char *fmt, ...)
{
	char buf[4096];
	va_list vargs;
	int n;
	const char *p;
	size_t namelen;

	assert(zsp != NULL);
	assert(fmt != NULL);

	va_start(vargs, fmt);
	n = vsnprintf(buf, sizeof (buf), fmt, vargs);
	va_end(vargs);
	p = strchr(buf, '=');
	namelen = (p) ? p - buf : strlen(buf);

	if ((n < 0) || (n >= sizeof (buf))) {
		zed_log_msg(LOG_WARNING, "Failed to add %.*s for eid=%llu: %s",
		    namelen, buf, eid, "Exceeded buffer size");
	} else if (!p) {
		zed_log_msg(LOG_WARNING, "Failed to add %.*s for eid=%llu: %s",
		    namelen, buf, eid, "Missing assignment");
	} else if (zed_strings_add(zsp, buf) < 0) {
		zed_log_msg(LOG_WARNING, "Failed to add %.*s for eid=%llu: %s",
		    namelen, buf, eid, strerror(ENOMEM));
	}
}
Exemplo n.º 2
0
Arquivo: zfs_mod.c Projeto: pyavdr/zfs
static void
zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
{
    dev_data_t *dp = data;
    char *path;
    uint_t c, children;
    nvlist_t **child;

    /*
     * First iterate over any children.
     */
    if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
                                   &child, &children) == 0) {
        for (c = 0; c < children; c++)
            zfs_iter_vdev(zhp, child[c], data);
        return;
    }

    /* once a vdev was matched and processed there is nothing left to do */
    if (dp->dd_found)
        return;

    /*
     * Match by GUID if available otherwise fallback to devid or physical
     */
    if (dp->dd_vdev_guid != 0) {
        uint64_t guid;

        if (nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID,
                                 &guid) != 0 || guid != dp->dd_vdev_guid) {
            return;
        }
        zed_log_msg(LOG_INFO, "  zfs_iter_vdev: matched on %llu", guid);
        dp->dd_found = B_TRUE;

    } else if (dp->dd_compare != NULL) {
        /*
         * NOTE: On Linux there is an event for partition, so unlike
         * illumos, substring matching is not required to accomodate
         * the partition suffix. An exact match will be present in
         * the dp->dd_compare value.
         */
        if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 ||
                strcmp(dp->dd_compare, path) != 0) {
            return;
        }
        zed_log_msg(LOG_INFO, "  zfs_iter_vdev: matched %s on %s",
                    dp->dd_prop, path);
        dp->dd_found = B_TRUE;

        /* pass the new devid for use by replacing code */
        if (dp->dd_islabeled && dp->dd_new_devid != NULL) {
            (void) nvlist_add_string(nvl, "new_devid",
                                     dp->dd_new_devid);
        }
    }

    (dp->dd_func)(zhp, nvl, dp->dd_islabeled);
}
Exemplo n.º 3
0
static int
zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
{
    char *devname = data;
    boolean_t avail_spare, l2cache;
    vdev_state_t newstate;
    nvlist_t *tgt;

    zed_log_msg(LOG_INFO, "zfsdle_vdev_online: searching for '%s' in '%s'",
                devname, zpool_get_name(zhp));

    if ((tgt = zpool_find_vdev_by_physpath(zhp, devname,
                                           &avail_spare, &l2cache, NULL)) != NULL) {
        char *path, fullpath[MAXPATHLEN];
        uint64_t wholedisk = 0ULL;

        verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH,
                                    &path) == 0);
        verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
                                    &wholedisk) == 0);

        (void) strlcpy(fullpath, path, sizeof (fullpath));
        if (wholedisk) {
            char *spath = zfs_strip_partition(fullpath);
            if (!spath) {
                zed_log_msg(LOG_INFO, "%s: Can't alloc",
                            __func__);
                return (0);
            }

            (void) strlcpy(fullpath, spath, sizeof (fullpath));
            free(spath);

            /*
             * We need to reopen the pool associated with this
             * device so that the kernel can update the size
             * of the expanded device.
             */
            (void) zpool_reopen(zhp);
        }

        if (zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) {
            zed_log_msg(LOG_INFO, "zfsdle_vdev_online: setting "
                        "device '%s' to ONLINE state in pool '%s'",
                        fullpath, zpool_get_name(zhp));
            if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL)
                (void) zpool_vdev_online(zhp, fullpath, 0,
                                         &newstate);
        }
        zpool_close(zhp);
        return (1);
    }
    zpool_close(zhp);
    return (0);
}
Exemplo n.º 4
0
/*
 * Write the [eid] & [etime] of the last processed event to the opened
 * [zcp] state_file.  Note that etime[] is an array of size 2.
 * Return 0 on success, -1 on error.
 */
int
zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[])
{
	ssize_t len;
	struct iovec iov[3];
	ssize_t n;

	if (!zcp) {
		errno = EINVAL;
		zed_log_msg(LOG_ERR,
		    "Failed to write state file: %s", strerror(errno));
		return (-1);
	}
	if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t) -1) {
		zed_log_msg(LOG_WARNING,
		    "Failed to reposition state file offset: %s",
		    strerror(errno));
		return (-1);
	}
	len = 0;
	iov[0].iov_base = &eid;
	len += iov[0].iov_len = sizeof (eid);
	iov[1].iov_base = &etime[0];
	len += iov[1].iov_len = sizeof (etime[0]);
	iov[2].iov_base = &etime[1];
	len += iov[2].iov_len = sizeof (etime[1]);

	n = writev(zcp->state_fd, iov, 3);
	if (n < 0) {
		zed_log_msg(LOG_WARNING,
		    "Failed to write state file \"%s\": %s",
		    zcp->state_file, strerror(errno));
		return (-1);
	}
	if (n != len) {
		errno = EIO;
		zed_log_msg(LOG_WARNING,
		    "Failed to write state file \"%s\": Wrote %d of %d bytes",
		    zcp->state_file, n, len);
		return (-1);
	}
	if (fdatasync(zcp->state_fd) < 0) {
		zed_log_msg(LOG_WARNING,
		    "Failed to sync state file \"%s\": %s",
		    zcp->state_file, strerror(errno));
		return (-1);
	}
	return (0);
}
Exemplo n.º 5
0
/*
 * Destroy the configuration [zcp].
 *
 * Note: zfs_hdl & zevent_fd are destroyed via zed_event_fini().
 */
void
zed_conf_destroy(struct zed_conf *zcp)
{
	if (!zcp)
		return;

	if (zcp->state_fd >= 0) {
		if (close(zcp->state_fd) < 0)
			zed_log_msg(LOG_WARNING,
			    "Failed to close state file \"%s\": %s",
			    zcp->state_file, strerror(errno));
		zcp->state_fd = -1;
	}
	if (zcp->pid_file) {
		if ((unlink(zcp->pid_file) < 0) && (errno != ENOENT))
			zed_log_msg(LOG_WARNING,
			    "Failed to remove PID file \"%s\": %s",
			    zcp->pid_file, strerror(errno));
	}
	if (zcp->pid_fd >= 0) {
		if (close(zcp->pid_fd) < 0)
			zed_log_msg(LOG_WARNING,
			    "Failed to close PID file \"%s\": %s",
			    zcp->pid_file, strerror(errno));
		zcp->pid_fd = -1;
	}
	if (zcp->conf_file) {
		free(zcp->conf_file);
		zcp->conf_file = NULL;
	}
	if (zcp->pid_file) {
		free(zcp->pid_file);
		zcp->pid_file = NULL;
	}
	if (zcp->zedlet_dir) {
		free(zcp->zedlet_dir);
		zcp->zedlet_dir = NULL;
	}
	if (zcp->state_file) {
		free(zcp->state_file);
		zcp->state_file = NULL;
	}
	if (zcp->zedlets) {
		zed_strings_destroy(zcp->zedlets);
		zcp->zedlets = NULL;
	}
	free(zcp);
}
Exemplo n.º 6
0
/*
 * Handle a EC_DEV_ADD.ESC_DISK event.
 *
 * illumos
 *	Expects: DEV_PHYS_PATH string in schema
 *	Matches: vdev's ZPOOL_CONFIG_PHYS_PATH or ZPOOL_CONFIG_DEVID
 *
 *      path: '/dev/dsk/c0t1d0s0' (persistent)
 *     devid: 'id1,sd@SATA_____Hitachi_HDS72101______JP2940HZ3H74MC/a'
 * phys_path: '/pci@0,0/pci103c,1609@11/disk@1,0:a'
 *
 * linux
 *	provides: DEV_PHYS_PATH and DEV_IDENTIFIER strings in schema
 *	Matches: vdev's ZPOOL_CONFIG_PHYS_PATH or ZPOOL_CONFIG_DEVID
 *
 *      path: '/dev/sdc1' (not persistent)
 *     devid: 'ata-SAMSUNG_HD204UI_S2HGJD2Z805891-part1'
 * phys_path: 'pci-0000:04:00.0-sas-0x4433221106000000-lun-0'
 */
static int
zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi)
{
	char *devpath = NULL, *devid;
	boolean_t is_slice;

	/*
	 * Expecting a devid string and an optional physical location
	 */
	if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0)
		return (-1);

	(void) nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devpath);

	is_slice = (nvlist_lookup_boolean(nvl, DEV_IS_PART) == 0);

	zed_log_msg(LOG_INFO, "zfs_deliver_add: adding %s (%s) (is_slice %d)",
	    devid, devpath ? devpath : "NULL", is_slice);

	/*
	 * Iterate over all vdevs looking for a match in the folllowing order:
	 * 1. ZPOOL_CONFIG_DEVID (identifies the unique disk)
	 * 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location).
	 *
	 * For disks, we only want to pay attention to vdevs marked as whole
	 * disks or are a multipath device.
	 */
	if (!devid_iter(devid, zfs_process_add, is_slice) && devpath != NULL)
		(void) devphys_iter(devpath, devid, zfs_process_add, is_slice);

	return (0);
}
Exemplo n.º 7
0
Arquivo: zfs_mod.c Projeto: pyavdr/zfs
/*
 * This function handles the ESC_DEV_DLE event.
 */
static int
zfs_deliver_dle(nvlist_t *nvl)
{
    char *devname;

    if (nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devname) != 0) {
        zed_log_msg(LOG_INFO, "zfs_deliver_event: no physpath");
        return (-1);
    }

    if (zpool_iter(g_zfshdl, zfsdle_vdev_online, devname) != 1) {
        zed_log_msg(LOG_INFO, "zfs_deliver_event: device '%s' not "
                    "found", devname);
        return (1);
    }
    return (0);
}
Exemplo n.º 8
0
static int
_zed_event_add_array_err(uint64_t eid, const char *name)
{
	errno = EMSGSIZE;
	zed_log_msg(LOG_WARNING,
	    "Failed to convert nvpair \"%s\" for eid=%llu: "
	    "Exceeded buffer size", name, eid);
	return (-1);
}
Exemplo n.º 9
0
/*
 * Read the opened [zcp] state_file to obtain the eid & etime of the last event
 * processed.  Write the state from the last event to the [eidp] & [etime] args
 * passed by reference.  Note that etime[] is an array of size 2.
 * Return 0 on success, -1 on error.
 */
int
zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[])
{
	ssize_t len;
	struct iovec iov[3];
	ssize_t n;

	if (!zcp || !eidp || !etime) {
		errno = EINVAL;
		zed_log_msg(LOG_ERR,
		    "Failed to read state file: %s", strerror(errno));
		return (-1);
	}
	if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t) -1) {
		zed_log_msg(LOG_WARNING,
		    "Failed to reposition state file offset: %s",
		    strerror(errno));
		return (-1);
	}
	len = 0;
	iov[0].iov_base = eidp;
	len += iov[0].iov_len = sizeof (*eidp);
	iov[1].iov_base = &etime[0];
	len += iov[1].iov_len = sizeof (etime[0]);
	iov[2].iov_base = &etime[1];
	len += iov[2].iov_len = sizeof (etime[1]);

	n = readv(zcp->state_fd, iov, 3);
	if (n == 0) {
		*eidp = 0;
	} else if (n < 0) {
		zed_log_msg(LOG_WARNING,
		    "Failed to read state file \"%s\": %s",
		    zcp->state_file, strerror(errno));
		return (-1);
	} else if (n != len) {
		errno = EIO;
		zed_log_msg(LOG_WARNING,
		    "Failed to read state file \"%s\": Read %d of %d bytes",
		    zcp->state_file, n, len);
		return (-1);
	}
	return (0);
}
Exemplo n.º 10
0
/*
 * This function handles the ESC_DEV_DLE device change event.  Use the
 * provided vdev guid when looking up a disk or partition, when the guid
 * is not present assume the entire disk is owned by ZFS and append the
 * expected -part1 partition information then lookup by physical path.
 */
static int
zfs_deliver_dle(nvlist_t *nvl)
{
	char *devname, name[MAXPATHLEN];
	uint64_t guid;

	if (nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &guid) == 0) {
		sprintf(name, "%llu", (u_longlong_t)guid);
	} else if (nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devname) == 0) {
		strlcpy(name, devname, MAXPATHLEN);
		zfs_append_partition(name, MAXPATHLEN);
	} else {
		zed_log_msg(LOG_INFO, "zfs_deliver_dle: no guid or physpath");
	}

	if (zpool_iter(g_zfshdl, zfsdle_vdev_online, name) != 1) {
		zed_log_msg(LOG_INFO, "zfs_deliver_dle: device '%s' not "
		    "found", name);
		return (1);
	}

	return (0);
}
Exemplo n.º 11
0
Arquivo: zfs_mod.c Projeto: pyavdr/zfs
static int
zfs_iter_pool(zpool_handle_t *zhp, void *data)
{
    nvlist_t *config, *nvl;
    dev_data_t *dp = data;
    uint64_t pool_guid;
    unavailpool_t *pool;

    zed_log_msg(LOG_INFO, "zfs_iter_pool: evaluating vdevs on %s (by %s)",
                zpool_get_name(zhp), dp->dd_vdev_guid ? "GUID" : dp->dd_prop);

    /*
     * For each vdev in this pool, look for a match to apply dd_func
     */
    if ((config = zpool_get_config(zhp, NULL)) != NULL) {
        if (dp->dd_pool_guid == 0 ||
                (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
                                      &pool_guid) == 0 && pool_guid == dp->dd_pool_guid)) {
            (void) nvlist_lookup_nvlist(config,
                                        ZPOOL_CONFIG_VDEV_TREE, &nvl);
            zfs_iter_vdev(zhp, nvl, data);
        }
    }

    /*
     * if this pool was originally unavailable,
     * then enable its datasets asynchronously
     */
    if (g_enumeration_done)  {
        for (pool = list_head(&g_pool_list); pool != NULL;
                pool = list_next(&g_pool_list, pool)) {

            if (pool->uap_enable_tid != 0)
                continue;	/* entry already processed */
            if (strcmp(zpool_get_name(zhp),
                       zpool_get_name(pool->uap_zhp)))
                continue;
            if (zfs_toplevel_state(zhp) >= VDEV_STATE_DEGRADED) {
                /* send to a background thread; keep on list */
                (void) pthread_create(&pool->uap_enable_tid,
                                      NULL, zfs_enable_ds, pool);
                break;
            }
        }
    }

    zpool_close(zhp);
    return (dp->dd_found);	/* cease iteration after a match */
}
Exemplo n.º 12
0
static int
zfs_unavail_pool(zpool_handle_t *zhp, void *data)
{
	zed_log_msg(LOG_INFO, "zfs_unavail_pool: examining '%s' (state %d)",
	    zpool_get_name(zhp), (int)zfs_toplevel_state(zhp));

	if (zfs_toplevel_state(zhp) < VDEV_STATE_DEGRADED) {
		unavailpool_t *uap;
		uap = malloc(sizeof (unavailpool_t));
		uap->uap_zhp = zhp;
		list_insert_tail((list_t *)data, uap);
	} else {
		zpool_close(zhp);
	}
	return (0);
}
Exemplo n.º 13
0
/*
 * Close the libzfs interface.
 */
void
zed_event_fini(struct zed_conf *zcp)
{
	if (!zcp)
		zed_log_die("Failed zed_event_fini: %s", strerror(EINVAL));

	if (zcp->zevent_fd >= 0) {
		if (close(zcp->zevent_fd) < 0)
			zed_log_msg(LOG_WARNING, "Failed to close \"%s\": %s",
			    ZFS_DEV, strerror(errno));

		zcp->zevent_fd = -1;
	}
	if (zcp->zfs_hdl) {
		libzfs_fini(zcp->zfs_hdl);
		zcp->zfs_hdl = NULL;
	}
}
Exemplo n.º 14
0
/*
 * Called when we receive a VDEV_CHECK event, which indicates a device could not
 * be opened during initial pool open, but the autoreplace property was set on
 * the pool.  In this case, we treat it as if it were an add event.
 */
static int
zfs_deliver_check(nvlist_t *nvl)
{
	dev_data_t data = { 0 };

	if (nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID,
	    &data.dd_pool_guid) != 0 ||
	    nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID,
	    &data.dd_vdev_guid) != 0 ||
	    data.dd_vdev_guid == 0)
		return (0);

	zed_log_msg(LOG_INFO, "zfs_deliver_check: pool '%llu', vdev %llu",
	    data.dd_pool_guid, data.dd_vdev_guid);

	data.dd_func = zfs_process_add;

	(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);

	return (0);
}
Exemplo n.º 15
0
Arquivo: zed.c Projeto: Spencerx/zfs-1
/*
 * Lock all current and future pages in the virtual memory address space.
 *   Access to locked pages will never be delayed by a page fault.
 * EAGAIN is tested up to max_tries in case this is a transient error.
 */
static void
_lock_memory(void)
{
#if HAVE_MLOCKALL
	int i = 0;
	const int max_tries = 10;

	for (i = 0; i < max_tries; i++) {
		if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
			zed_log_msg(LOG_INFO, "Locked all pages in memory");
			return;
		}
		if (errno != EAGAIN)
			break;
	}
	zed_log_die("Failed to lock memory pages: %s", strerror(errno));

#else /* HAVE_MLOCKALL */
	zed_log_die("Failed to lock memory pages: mlockall() not supported");
#endif /* HAVE_MLOCKALL */
}
Exemplo n.º 16
0
/*
 * The device associated with the given vdev (either by devid or physical path)
 * has been added to the system.  If 'isdisk' is set, then we only attempt a
 * replacement if it's a whole disk.  This also implies that we should label the
 * disk first.
 *
 * First, we attempt to online the device (making sure to undo any spare
 * operation when finished).  If this succeeds, then we're done.  If it fails,
 * and the new state is VDEV_CANT_OPEN, it indicates that the device was opened,
 * but that the label was not what we expected.  If the 'autoreplace' property
 * is enabled, then we relabel the disk (if specified), and attempt a 'zpool
 * replace'.  If the online is successful, but the new state is something else
 * (REMOVED or FAULTED), it indicates that we're out of sync or in some sort of
 * race, and we should avoid attempting to relabel the disk.
 *
 * Also can arrive here from a ESC_ZFS_VDEV_CHECK event
 */
static void
zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
{
	char *path;
	vdev_state_t newstate;
	nvlist_t *nvroot, *newvd;
	pendingdev_t *device;
	uint64_t wholedisk = 0ULL;
	uint64_t offline = 0ULL;
	uint64_t guid = 0ULL;
	char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL;
	char rawpath[PATH_MAX], fullpath[PATH_MAX];
	char devpath[PATH_MAX];
	int ret;
	int is_dm = 0;
	int is_sd = 0;
	uint_t c;
	vdev_stat_t *vs;

	if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0)
		return;

	/* Skip healthy disks */
	verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
	    (uint64_t **)&vs, &c) == 0);
	if (vs->vs_state == VDEV_STATE_HEALTHY) {
		zed_log_msg(LOG_INFO, "%s: %s is already healthy, skip it.",
		    __func__, path);
		return;
	}

	(void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_PHYS_PATH, &physpath);
	(void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
	    &enc_sysfs_path);
	(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
	(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline);
	(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid);

	if (offline)
		return;  /* don't intervene if it was taken offline */

	is_dm = zfs_dev_is_dm(path);
	zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s', phys '%s'"
	    " wholedisk %d, dm %d (%llu)", zpool_get_name(zhp), path,
	    physpath ? physpath : "NULL", wholedisk, is_dm,
	    (long long unsigned int)guid);

	/*
	 * The VDEV guid is preferred for identification (gets passed in path)
	 */
	if (guid != 0) {
		(void) snprintf(fullpath, sizeof (fullpath), "%llu",
		    (long long unsigned int)guid);
	} else {
		/*
		 * otherwise use path sans partition suffix for whole disks
		 */
		(void) strlcpy(fullpath, path, sizeof (fullpath));
		if (wholedisk) {
			char *spath = zfs_strip_partition(fullpath);
			if (!spath) {
				zed_log_msg(LOG_INFO, "%s: Can't alloc",
				    __func__);
				return;
			}

			(void) strlcpy(fullpath, spath, sizeof (fullpath));
			free(spath);
		}
	}

	/*
	 * Attempt to online the device.
	 */
	if (zpool_vdev_online(zhp, fullpath,
	    ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, &newstate) == 0 &&
	    (newstate == VDEV_STATE_HEALTHY ||
	    newstate == VDEV_STATE_DEGRADED)) {
		zed_log_msg(LOG_INFO, "  zpool_vdev_online: vdev %s is %s",
		    fullpath, (newstate == VDEV_STATE_HEALTHY) ?
		    "HEALTHY" : "DEGRADED");
		return;
	}

	/*
	 * vdev_id alias rule for using scsi_debug devices (FMA automated
	 * testing)
	 */
	if (physpath != NULL && strcmp("scsidebug", physpath) == 0)
		is_sd = 1;

	/*
	 * If the pool doesn't have the autoreplace property set, then use
	 * vdev online to trigger a FMA fault by posting an ereport.
	 */
	if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) ||
	    !(wholedisk || is_dm) || (physpath == NULL)) {
		(void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
		    &newstate);
		zed_log_msg(LOG_INFO, "Pool's autoreplace is not enabled or "
		    "not a whole disk for '%s'", fullpath);
		return;
	}

	/*
	 * Convert physical path into its current device node.  Rawpath
	 * needs to be /dev/disk/by-vdev for a scsi_debug device since
	 * /dev/disk/by-path will not be present.
	 */
	(void) snprintf(rawpath, sizeof (rawpath), "%s%s",
	    is_sd ? DEV_BYVDEV_PATH : DEV_BYPATH_PATH, physpath);

	if (realpath(rawpath, devpath) == NULL && !is_dm) {
		zed_log_msg(LOG_INFO, "  realpath: %s failed (%s)",
		    rawpath, strerror(errno));

		(void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
		    &newstate);

		zed_log_msg(LOG_INFO, "  zpool_vdev_online: %s FORCEFAULT (%s)",
		    fullpath, libzfs_error_description(g_zfshdl));
		return;
	}

	/* Only autoreplace bad disks */
	if ((vs->vs_state != VDEV_STATE_DEGRADED) &&
	    (vs->vs_state != VDEV_STATE_FAULTED) &&
	    (vs->vs_state != VDEV_STATE_CANT_OPEN)) {
		return;
	}

	nvlist_lookup_string(vdev, "new_devid", &new_devid);

	if (is_dm) {
		/* Don't label device mapper or multipath disks. */
	} else if (!labeled) {
		/*
		 * we're auto-replacing a raw disk, so label it first
		 */
		char *leafname;

		/*
		 * If this is a request to label a whole disk, then attempt to
		 * write out the label.  Before we can label the disk, we need
		 * to map the physical string that was matched on to the under
		 * lying device node.
		 *
		 * If any part of this process fails, then do a force online
		 * to trigger a ZFS fault for the device (and any hot spare
		 * replacement).
		 */
		leafname = strrchr(devpath, '/') + 1;

		/*
		 * If this is a request to label a whole disk, then attempt to
		 * write out the label.
		 */
		if (zpool_label_disk(g_zfshdl, zhp, leafname) != 0) {
			zed_log_msg(LOG_INFO, "  zpool_label_disk: could not "
			    "label '%s' (%s)", leafname,
			    libzfs_error_description(g_zfshdl));

			(void) zpool_vdev_online(zhp, fullpath,
			    ZFS_ONLINE_FORCEFAULT, &newstate);
			return;
		}

		/*
		 * The disk labeling is asynchronous on Linux. Just record
		 * this label request and return as there will be another
		 * disk add event for the partition after the labeling is
		 * completed.
		 */
		device = malloc(sizeof (pendingdev_t));
		(void) strlcpy(device->pd_physpath, physpath,
		    sizeof (device->pd_physpath));
		list_insert_tail(&g_device_list, device);

		zed_log_msg(LOG_INFO, "  zpool_label_disk: async '%s' (%llu)",
		    leafname, (u_longlong_t)guid);

		return;	/* resumes at EC_DEV_ADD.ESC_DISK for partition */

	} else /* labeled */ {
		boolean_t found = B_FALSE;
		/*
		 * match up with request above to label the disk
		 */
		for (device = list_head(&g_device_list); device != NULL;
		    device = list_next(&g_device_list, device)) {
			if (strcmp(physpath, device->pd_physpath) == 0) {
				list_remove(&g_device_list, device);
				free(device);
				found = B_TRUE;
				break;
			}
			zed_log_msg(LOG_INFO, "zpool_label_disk: %s != %s",
			    physpath, device->pd_physpath);
		}
		if (!found) {
			/* unexpected partition slice encountered */
			zed_log_msg(LOG_INFO, "labeled disk %s unexpected here",
			    fullpath);
			(void) zpool_vdev_online(zhp, fullpath,
			    ZFS_ONLINE_FORCEFAULT, &newstate);
			return;
		}

		zed_log_msg(LOG_INFO, "  zpool_label_disk: resume '%s' (%llu)",
		    physpath, (u_longlong_t)guid);

		(void) snprintf(devpath, sizeof (devpath), "%s%s",
		    DEV_BYID_PATH, new_devid);
	}

	/*
	 * Construct the root vdev to pass to zpool_vdev_attach().  While adding
	 * the entire vdev structure is harmless, we construct a reduced set of
	 * path/physpath/wholedisk to keep it simple.
	 */
	if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0) {
		zed_log_msg(LOG_WARNING, "zfs_mod: nvlist_alloc out of memory");
		return;
	}
	if (nvlist_alloc(&newvd, NV_UNIQUE_NAME, 0) != 0) {
		zed_log_msg(LOG_WARNING, "zfs_mod: nvlist_alloc out of memory");
		nvlist_free(nvroot);
		return;
	}

	if (nvlist_add_string(newvd, ZPOOL_CONFIG_TYPE, VDEV_TYPE_DISK) != 0 ||
	    nvlist_add_string(newvd, ZPOOL_CONFIG_PATH, path) != 0 ||
	    nvlist_add_string(newvd, ZPOOL_CONFIG_DEVID, new_devid) != 0 ||
	    (physpath != NULL && nvlist_add_string(newvd,
	    ZPOOL_CONFIG_PHYS_PATH, physpath) != 0) ||
	    (enc_sysfs_path != NULL && nvlist_add_string(newvd,
	    ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH, enc_sysfs_path) != 0) ||
	    nvlist_add_uint64(newvd, ZPOOL_CONFIG_WHOLE_DISK, wholedisk) != 0 ||
	    nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) != 0 ||
	    nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, &newvd,
	    1) != 0) {
		zed_log_msg(LOG_WARNING, "zfs_mod: unable to add nvlist pairs");
		nvlist_free(newvd);
		nvlist_free(nvroot);
		return;
	}

	nvlist_free(newvd);

	/*
	 * Wait for udev to verify the links exist, then auto-replace
	 * the leaf disk at same physical location.
	 */
	if (zpool_label_disk_wait(path, 3000) != 0) {
		zed_log_msg(LOG_WARNING, "zfs_mod: expected replacement "
		    "disk %s is missing", path);
		nvlist_free(nvroot);
		return;
	}

	ret = zpool_vdev_attach(zhp, fullpath, path, nvroot, B_TRUE);

	zed_log_msg(LOG_INFO, "  zpool_vdev_replace: %s with %s (%s)",
	    fullpath, path, (ret == 0) ? "no errors" :
	    libzfs_error_description(g_zfshdl));

	nvlist_free(nvroot);
}
Exemplo n.º 17
0
Arquivo: zed.c Projeto: Spencerx/zfs-1
/*
 * ZFS Event Daemon (ZED).
 */
int
main(int argc, char *argv[])
{
	struct zed_conf *zcp;
	uint64_t saved_eid;
	int64_t saved_etime[2];

	zed_log_init(argv[0]);
	zed_log_stderr_open(LOG_NOTICE);
	zcp = zed_conf_create();
	zed_conf_parse_opts(zcp, argc, argv);
	if (zcp->do_verbose)
		zed_log_stderr_open(LOG_INFO);

	if (geteuid() != 0)
		zed_log_die("Must be run as root");

	(void) umask(0);

	_setup_sig_handlers();

	zed_conf_parse_file(zcp);

	zed_file_close_from(STDERR_FILENO + 1);

	if (chdir("/") < 0)
		zed_log_die("Failed to change to root directory");

	if (zed_conf_scan_dir(zcp) < 0)
		exit(EXIT_FAILURE);

	if (zcp->do_memlock)
		_lock_memory();

	if (!zcp->do_foreground) {
		_become_daemon();
		zed_log_syslog_open(LOG_DAEMON);
		zed_log_stderr_close();
	}
	zed_log_msg(LOG_NOTICE,
	    "ZFS Event Daemon %s-%s", ZFS_META_VERSION, ZFS_META_RELEASE);

	(void) zed_conf_write_pid(zcp);

	if (zed_conf_open_state(zcp) < 0)
		exit(EXIT_FAILURE);

	if (zed_conf_read_state(zcp, &saved_eid, saved_etime) < 0)
		exit(EXIT_FAILURE);

 retry:
	if (zed_event_init(zcp)) {
		/*
		 * If we failed to open /dev/zfs, but force was requested, we
		 * sleep waiting for it to come alive. This lets zed sit around
		 * waiting for the kernel module to load.
		 */
		if (zcp->do_force) {
			sleep(30);
			if (!_got_exit)	goto retry;
		}
		zed_log_die("Failed to initialize libzfs");
    }

	zed_event_seek(zcp, saved_eid, saved_etime);

	while (!_got_exit) {
		if (_got_hup) {
			_got_hup = 0;
			(void) zed_conf_scan_dir(zcp);
		}
		if (zed_event_service(zcp)) break;
	}
	zed_log_msg(LOG_NOTICE, "Exiting");
	zed_event_fini(zcp);
	if (zcp->do_force && !_got_exit) {
		goto retry;
	}
	zed_conf_destroy(zcp);
	zed_log_fini();
	exit(EXIT_SUCCESS);
}
Exemplo n.º 18
0
/*
 * ZFS Event Daemon (ZED).
 */
int
main(int argc, char *argv[])
{
	struct zed_conf *zcp;
	uint64_t saved_eid;
	int64_t saved_etime[2];

	zed_log_init(argv[0]);
	zed_log_stderr_open(LOG_NOTICE);
	zcp = zed_conf_create();
	zed_conf_parse_opts(zcp, argc, argv);
	if (zcp->do_verbose)
		zed_log_stderr_open(LOG_INFO);

	if (geteuid() != 0)
		zed_log_die("Must be run as root");

	(void) umask(0);

	_setup_sig_handlers();

	zed_conf_parse_file(zcp);

	zed_file_close_from(STDERR_FILENO + 1);

	if (chdir("/") < 0)
		zed_log_die("Failed to change to root directory");

	if (zed_conf_scan_dir(zcp) < 0)
		exit(EXIT_FAILURE);

	if (zcp->do_memlock)
		_lock_memory();

	if (!zcp->do_foreground) {
		_become_daemon();
		zed_log_syslog_open(LOG_DAEMON);
		zed_log_stderr_close();
	}
	zed_log_msg(LOG_NOTICE,
	    "ZFS Event Daemon %s-%s", ZFS_META_VERSION, ZFS_META_RELEASE);

	(void) zed_conf_write_pid(zcp);

	if (zed_conf_open_state(zcp) < 0)
		exit(EXIT_FAILURE);

	if (zed_conf_read_state(zcp, &saved_eid, saved_etime) < 0)
		exit(EXIT_FAILURE);

	zed_event_init(zcp);
	zed_event_seek(zcp, saved_eid, saved_etime);

	while (!_got_exit) {
		if (_got_hup) {
			_got_hup = 0;
			(void) zed_conf_scan_dir(zcp);
		}
		zed_event_service(zcp);
	}
	zed_log_msg(LOG_NOTICE, "Exiting");
	zed_event_fini(zcp);
	zed_conf_destroy(zcp);
	zed_log_fini();
	exit(EXIT_SUCCESS);
}
Exemplo n.º 19
0
/*
 * Add an environment variable for [eid] to the container [zsp].
 *
 * The variable name is the concatenation of [prefix] and [name] converted to
 * uppercase with non-alphanumeric characters converted to underscores;
 * [prefix] is optional, and [name] must begin with an alphabetic character.
 * If the converted variable name already exists within the container [zsp],
 * its existing value will be replaced with the new value.
 *
 * The variable value is specified by the format string [fmt].
 *
 * Returns 0 on success, and -1 on error (with errno set).
 *
 * All environment variables in [zsp] should be added through this function.
 */
static int
_zed_event_add_var(uint64_t eid, zed_strings_t *zsp,
    const char *prefix, const char *name, const char *fmt, ...)
{
	char keybuf[MAXBUF];
	char valbuf[MAXBUF];
	char *dstp;
	const char *srcp;
	const char *lastp;
	int n;
	int buflen;
	va_list vargs;

	assert(zsp != NULL);
	assert(fmt != NULL);

	if (!name) {
		errno = EINVAL;
		zed_log_msg(LOG_WARNING,
		    "Failed to add variable for eid=%llu: Name is empty", eid);
		return (-1);
	} else if (!isalpha(name[0])) {
		errno = EINVAL;
		zed_log_msg(LOG_WARNING,
		    "Failed to add variable for eid=%llu: "
		    "Name \"%s\" is invalid", eid, name);
		return (-1);
	}
	/*
	 * Construct the string key by converting PREFIX (if present) and NAME.
	 */
	dstp = keybuf;
	lastp = keybuf + sizeof (keybuf);
	if (prefix) {
		for (srcp = prefix; *srcp && (dstp < lastp); srcp++)
			*dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_';
	}
	for (srcp = name; *srcp && (dstp < lastp); srcp++)
		*dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_';

	if (dstp == lastp) {
		errno = ENAMETOOLONG;
		zed_log_msg(LOG_WARNING,
		    "Failed to add variable for eid=%llu: Name too long", eid);
		return (-1);
	}
	*dstp = '\0';
	/*
	 * Construct the string specified by "[PREFIX][NAME]=[FMT]".
	 */
	dstp = valbuf;
	buflen = sizeof (valbuf);
	n = strlcpy(dstp, keybuf, buflen);
	if (n >= sizeof (valbuf)) {
		errno = EMSGSIZE;
		zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
		    keybuf, eid, "Exceeded buffer size");
		return (-1);
	}
	dstp += n;
	buflen -= n;

	*dstp++ = '=';
	buflen--;

	va_start(vargs, fmt);
	n = vsnprintf(dstp, buflen, fmt, vargs);
	va_end(vargs);

	if ((n < 0) || (n >= buflen)) {
		errno = EMSGSIZE;
		zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
		    keybuf, eid, "Exceeded buffer size");
		return (-1);
	} else if (zed_strings_add(zsp, keybuf, valbuf) < 0) {
		zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
		    keybuf, eid, strerror(errno));
		return (-1);
	}
	return (0);
}
Exemplo n.º 20
0
/*
 * Convert the nvpair [nvp] to a string which is added to the environment
 * of the child process.
 * Return 0 on success, -1 on error.
 *
 * FIXME: Refactor with cmd/zpool/zpool_main.c:zpool_do_events_nvprint()?
 */
static void
_zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
{
	const char *name;
	data_type_t type;
	const char *prefix = ZEVENT_VAR_PREFIX;
	boolean_t b;
	double d;
	uint8_t i8;
	uint16_t i16;
	uint32_t i32;
	uint64_t i64;
	char *str;

	assert(zsp != NULL);
	assert(nvp != NULL);

	name = nvpair_name(nvp);
	type = nvpair_type(nvp);

	switch (type) {
	case DATA_TYPE_BOOLEAN:
		_zed_event_add_var(eid, zsp, prefix, name, "%s", "1");
		break;
	case DATA_TYPE_BOOLEAN_VALUE:
		(void) nvpair_value_boolean_value(nvp, &b);
		_zed_event_add_var(eid, zsp, prefix, name, "%s", b ? "1" : "0");
		break;
	case DATA_TYPE_BYTE:
		(void) nvpair_value_byte(nvp, &i8);
		_zed_event_add_var(eid, zsp, prefix, name, "%d", i8);
		break;
	case DATA_TYPE_INT8:
		(void) nvpair_value_int8(nvp, (int8_t *) &i8);
		_zed_event_add_var(eid, zsp, prefix, name, "%d", i8);
		break;
	case DATA_TYPE_UINT8:
		(void) nvpair_value_uint8(nvp, &i8);
		_zed_event_add_var(eid, zsp, prefix, name, "%u", i8);
		break;
	case DATA_TYPE_INT16:
		(void) nvpair_value_int16(nvp, (int16_t *) &i16);
		_zed_event_add_var(eid, zsp, prefix, name, "%d", i16);
		break;
	case DATA_TYPE_UINT16:
		(void) nvpair_value_uint16(nvp, &i16);
		_zed_event_add_var(eid, zsp, prefix, name, "%u", i16);
		break;
	case DATA_TYPE_INT32:
		(void) nvpair_value_int32(nvp, (int32_t *) &i32);
		_zed_event_add_var(eid, zsp, prefix, name, "%d", i32);
		break;
	case DATA_TYPE_UINT32:
		(void) nvpair_value_uint32(nvp, &i32);
		_zed_event_add_var(eid, zsp, prefix, name, "%u", i32);
		break;
	case DATA_TYPE_INT64:
		(void) nvpair_value_int64(nvp, (int64_t *) &i64);
		_zed_event_add_var(eid, zsp, prefix, name,
		    "%lld", (longlong_t) i64);
		break;
	case DATA_TYPE_UINT64:
		(void) nvpair_value_uint64(nvp, &i64);
		_zed_event_add_var(eid, zsp, prefix, name,
		    (_zed_event_value_is_hex(name) ? "0x%.16llX" : "%llu"),
		    (u_longlong_t) i64);
		/*
		 * shadow readable strings for vdev state pairs
		 */
		if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE) == 0 ||
		    strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE) == 0) {
			char alt[32];

			(void) snprintf(alt, sizeof (alt), "%s_str", name);
			_zed_event_add_var(eid, zsp, prefix, alt, "%s",
			    zpool_state_to_name(i64, VDEV_AUX_NONE));
		}
		break;
	case DATA_TYPE_DOUBLE:
		(void) nvpair_value_double(nvp, &d);
		_zed_event_add_var(eid, zsp, prefix, name, "%g", d);
		break;
	case DATA_TYPE_HRTIME:
		(void) nvpair_value_hrtime(nvp, (hrtime_t *) &i64);
		_zed_event_add_var(eid, zsp, prefix, name,
		    "%llu", (u_longlong_t) i64);
		break;
	case DATA_TYPE_NVLIST:
		_zed_event_add_var(eid, zsp, prefix, name,
		    "%s", "_NOT_IMPLEMENTED_");			/* FIXME */
		break;
	case DATA_TYPE_STRING:
		(void) nvpair_value_string(nvp, &str);
		_zed_event_add_var(eid, zsp, prefix, name,
		    "%s", (str ? str : "<NULL>"));
		break;
	case DATA_TYPE_BOOLEAN_ARRAY:
		_zed_event_add_var(eid, zsp, prefix, name,
		    "%s", "_NOT_IMPLEMENTED_");			/* FIXME */
		break;
	case DATA_TYPE_BYTE_ARRAY:
		_zed_event_add_var(eid, zsp, prefix, name,
		    "%s", "_NOT_IMPLEMENTED_");			/* FIXME */
		break;
	case DATA_TYPE_INT8_ARRAY:
		_zed_event_add_int8_array(eid, zsp, prefix, nvp);
		break;
	case DATA_TYPE_UINT8_ARRAY:
		_zed_event_add_uint8_array(eid, zsp, prefix, nvp);
		break;
	case DATA_TYPE_INT16_ARRAY:
		_zed_event_add_int16_array(eid, zsp, prefix, nvp);
		break;
	case DATA_TYPE_UINT16_ARRAY:
		_zed_event_add_uint16_array(eid, zsp, prefix, nvp);
		break;
	case DATA_TYPE_INT32_ARRAY:
		_zed_event_add_int32_array(eid, zsp, prefix, nvp);
		break;
	case DATA_TYPE_UINT32_ARRAY:
		_zed_event_add_uint32_array(eid, zsp, prefix, nvp);
		break;
	case DATA_TYPE_INT64_ARRAY:
		_zed_event_add_int64_array(eid, zsp, prefix, nvp);
		break;
	case DATA_TYPE_UINT64_ARRAY:
		_zed_event_add_uint64_array(eid, zsp, prefix, nvp);
		break;
	case DATA_TYPE_STRING_ARRAY:
		_zed_event_add_string_array(eid, zsp, prefix, nvp);
		break;
	case DATA_TYPE_NVLIST_ARRAY:
		_zed_event_add_var(eid, zsp, prefix, name,
		    "%s", "_NOT_IMPLEMENTED_");			/* FIXME */
		break;
	default:
		errno = EINVAL;
		zed_log_msg(LOG_WARNING,
		    "Failed to convert nvpair \"%s\" for eid=%llu: "
		    "Unrecognized type=%u", name, eid, (unsigned int) type);
		break;
	}
}
Exemplo n.º 21
0
/*
 * Open and lock the [zcp] state_file.
 * Return 0 on success, -1 on error.
 *
 * FIXME: Move state information into kernel.
 */
int
zed_conf_open_state(struct zed_conf *zcp)
{
	char dirbuf[PATH_MAX];
	mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
	int n;
	char *p;
	int rv;

	if (!zcp || !zcp->state_file) {
		errno = EINVAL;
		zed_log_msg(LOG_ERR, "Failed to open state file: %s",
		    strerror(errno));
		return (-1);
	}
	n = strlcpy(dirbuf, zcp->state_file, sizeof (dirbuf));
	if (n >= sizeof (dirbuf)) {
		errno = ENAMETOOLONG;
		zed_log_msg(LOG_WARNING, "Failed to open state file: %s",
		    strerror(errno));
		return (-1);
	}
	p = strrchr(dirbuf, '/');
	if (p)
		*p = '\0';

	if ((mkdirp(dirbuf, dirmode) < 0) && (errno != EEXIST)) {
		zed_log_msg(LOG_WARNING,
		    "Failed to create directory \"%s\": %s",
		    dirbuf, strerror(errno));
		return (-1);
	}
	if (zcp->state_fd >= 0) {
		if (close(zcp->state_fd) < 0) {
			zed_log_msg(LOG_WARNING,
			    "Failed to close state file \"%s\": %s",
			    zcp->state_file, strerror(errno));
			return (-1);
		}
	}
	if (zcp->do_zero)
		(void) unlink(zcp->state_file);

	zcp->state_fd = open(zcp->state_file,
	    (O_RDWR | O_CREAT), (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
	if (zcp->state_fd < 0) {
		zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s",
		    zcp->state_file, strerror(errno));
		return (-1);
	}
	rv = zed_file_lock(zcp->state_fd);
	if (rv < 0) {
		zed_log_msg(LOG_WARNING, "Failed to lock state file \"%s\": %s",
		    zcp->state_file, strerror(errno));
		return (-1);
	}
	if (rv > 0) {
		pid_t pid = zed_file_is_locked(zcp->state_fd);
		if (pid < 0) {
			zed_log_msg(LOG_WARNING,
			    "Failed to test lock on state file \"%s\"",
			    zcp->state_file);
		} else if (pid > 0) {
			zed_log_msg(LOG_WARNING,
			    "Found PID %d bound to state file \"%s\"",
			    pid, zcp->state_file);
		} else {
			zed_log_msg(LOG_WARNING,
			    "Inconsistent lock state on state file \"%s\"",
			    zcp->state_file);
		}
		return (-1);
	}
	return (0);
}
Exemplo n.º 22
0
/*
 * Write the PID file specified in [zcp].
 * Return 0 on success, -1 on error.
 *
 * This must be called after fork()ing to become a daemon (so the correct PID
 * is recorded), but before daemonization is complete and the parent process
 * exits (for synchronization with systemd).
 */
int
zed_conf_write_pid(struct zed_conf *zcp)
{
	const mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
	const mode_t filemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
	char buf[PATH_MAX];
	int n;
	char *p;
	mode_t mask;
	int rv;

	if (!zcp || !zcp->pid_file) {
		errno = EINVAL;
		zed_log_msg(LOG_ERR, "Failed to create PID file: %s",
		    strerror(errno));
		return (-1);
	}
	assert(zcp->pid_fd == -1);
	/*
	 * Create PID file directory if needed.
	 */
	n = strlcpy(buf, zcp->pid_file, sizeof (buf));
	if (n >= sizeof (buf)) {
		errno = ENAMETOOLONG;
		zed_log_msg(LOG_ERR, "Failed to create PID file: %s",
		    strerror(errno));
		goto err;
	}
	p = strrchr(buf, '/');
	if (p)
		*p = '\0';

	if ((mkdirp(buf, dirmode) < 0) && (errno != EEXIST)) {
		zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s",
		    buf, strerror(errno));
		goto err;
	}
	/*
	 * Obtain PID file lock.
	 */
	mask = umask(0);
	umask(mask | 022);
	zcp->pid_fd = open(zcp->pid_file, (O_RDWR | O_CREAT), filemode);
	umask(mask);
	if (zcp->pid_fd < 0) {
		zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s",
		    zcp->pid_file, strerror(errno));
		goto err;
	}
	rv = zed_file_lock(zcp->pid_fd);
	if (rv < 0) {
		zed_log_msg(LOG_ERR, "Failed to lock PID file \"%s\": %s",
		    zcp->pid_file, strerror(errno));
		goto err;
	} else if (rv > 0) {
		pid_t pid = zed_file_is_locked(zcp->pid_fd);
		if (pid < 0) {
			zed_log_msg(LOG_ERR,
			    "Failed to test lock on PID file \"%s\"",
			    zcp->pid_file);
		} else if (pid > 0) {
			zed_log_msg(LOG_ERR,
			    "Found PID %d bound to PID file \"%s\"",
			    pid, zcp->pid_file);
		} else {
			zed_log_msg(LOG_ERR,
			    "Inconsistent lock state on PID file \"%s\"",
			    zcp->pid_file);
		}
		goto err;
	}
	/*
	 * Write PID file.
	 */
	n = snprintf(buf, sizeof (buf), "%d\n", (int) getpid());
	if ((n < 0) || (n >= sizeof (buf))) {
		errno = ERANGE;
		zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
		    zcp->pid_file, strerror(errno));
	} else if (zed_file_write_n(zcp->pid_fd, buf, n) != n) {
		zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
		    zcp->pid_file, strerror(errno));
	} else if (fdatasync(zcp->pid_fd) < 0) {
		zed_log_msg(LOG_ERR, "Failed to sync PID file \"%s\": %s",
		    zcp->pid_file, strerror(errno));
	} else {
		return (0);
	}

err:
	if (zcp->pid_fd >= 0) {
		(void) close(zcp->pid_fd);
		zcp->pid_fd = -1;
	}
	return (-1);
}
Exemplo n.º 23
0
/*
 * Convert the nvpair [nvp] to a string which is added to the environment
 * of the child process.
 * Return 0 on success, -1 on error.
 *
 * FIXME: Refactor with cmd/zpool/zpool_main.c:zpool_do_events_nvprint()?
 */
static void
_zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
{
	const char *name;
	data_type_t type;
	char buf[4096];
	int buflen;
	int n;
	char *p;
	const char *q;
	const char *fmt;

	boolean_t b;
	double d;
	uint8_t i8;
	uint16_t i16;
	uint32_t i32;
	uint64_t i64;
	char *str;

	assert(zsp != NULL);
	assert(nvp != NULL);

	name = nvpair_name(nvp);
	type = nvpair_type(nvp);
	buflen = sizeof (buf);

	/* Copy NAME prefix for ZED zevent namespace. */
	n = strlcpy(buf, ZEVENT_VAR_PREFIX, sizeof (buf));
	if (n >= sizeof (buf)) {
		zed_log_msg(LOG_WARNING,
		    "Failed to convert nvpair \"%s\" for eid=%llu: %s",
		    name, eid, "Exceeded buffer size");
		return;
	}
	buflen -= n;
	p = buf + n;

	/* Convert NAME to alphanumeric uppercase. */
	for (q = name; *q && (buflen > 0); q++) {
		*p++ = isalnum(*q) ? toupper(*q) : '_';
		buflen--;
	}

	/* Separate NAME from VALUE. */
	if (buflen > 0) {
		*p++ = '=';
		buflen--;
	}
	*p = '\0';

	/* Convert VALUE. */
	switch (type) {
	case DATA_TYPE_BOOLEAN:
		n = snprintf(p, buflen, "%s", "1");
		break;
	case DATA_TYPE_BOOLEAN_VALUE:
		(void) nvpair_value_boolean_value(nvp, &b);
		n = snprintf(p, buflen, "%s", b ? "1" : "0");
		break;
	case DATA_TYPE_BYTE:
		(void) nvpair_value_byte(nvp, &i8);
		n = snprintf(p, buflen, "%d", i8);
		break;
	case DATA_TYPE_INT8:
		(void) nvpair_value_int8(nvp, (int8_t *) &i8);
		n = snprintf(p, buflen, "%d", i8);
		break;
	case DATA_TYPE_UINT8:
		(void) nvpair_value_uint8(nvp, &i8);
		n = snprintf(p, buflen, "%u", i8);
		break;
	case DATA_TYPE_INT16:
		(void) nvpair_value_int16(nvp, (int16_t *) &i16);
		n = snprintf(p, buflen, "%d", i16);
		break;
	case DATA_TYPE_UINT16:
		(void) nvpair_value_uint16(nvp, &i16);
		n = snprintf(p, buflen, "%u", i16);
		break;
	case DATA_TYPE_INT32:
		(void) nvpair_value_int32(nvp, (int32_t *) &i32);
		n = snprintf(p, buflen, "%d", i32);
		break;
	case DATA_TYPE_UINT32:
		(void) nvpair_value_uint32(nvp, &i32);
		n = snprintf(p, buflen, "%u", i32);
		break;
	case DATA_TYPE_INT64:
		(void) nvpair_value_int64(nvp, (int64_t *) &i64);
		n = snprintf(p, buflen, "%lld", (longlong_t) i64);
		break;
	case DATA_TYPE_UINT64:
		(void) nvpair_value_uint64(nvp, &i64);
		fmt = _zed_event_value_is_hex(name) ? "0x%.16llX" : "%llu";
		n = snprintf(p, buflen, fmt, (u_longlong_t) i64);
		break;
	case DATA_TYPE_DOUBLE:
		(void) nvpair_value_double(nvp, &d);
		n = snprintf(p, buflen, "%g", d);
		break;
	case DATA_TYPE_HRTIME:
		(void) nvpair_value_hrtime(nvp, (hrtime_t *) &i64);
		n = snprintf(p, buflen, "%llu", (u_longlong_t) i64);
		break;
	case DATA_TYPE_NVLIST:
		/* FIXME */
		n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
		break;
	case DATA_TYPE_STRING:
		(void) nvpair_value_string(nvp, &str);
		n = snprintf(p, buflen, "%s", (str ? str : "<NULL>"));
		break;
	case DATA_TYPE_BOOLEAN_ARRAY:
		/* FIXME */
		n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
		break;
	case DATA_TYPE_BYTE_ARRAY:
		/* FIXME */
		n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
		break;
	case DATA_TYPE_INT8_ARRAY:
		n = _zed_event_convert_int8_array(p, buflen, nvp);
		break;
	case DATA_TYPE_UINT8_ARRAY:
		n = _zed_event_convert_uint8_array(p, buflen, nvp);
		break;
	case DATA_TYPE_INT16_ARRAY:
		n = _zed_event_convert_int16_array(p, buflen, nvp);
		break;
	case DATA_TYPE_UINT16_ARRAY:
		n = _zed_event_convert_uint16_array(p, buflen, nvp);
		break;
	case DATA_TYPE_INT32_ARRAY:
		n = _zed_event_convert_int32_array(p, buflen, nvp);
		break;
	case DATA_TYPE_UINT32_ARRAY:
		n = _zed_event_convert_uint32_array(p, buflen, nvp);
		break;
	case DATA_TYPE_INT64_ARRAY:
		n = _zed_event_convert_int64_array(p, buflen, nvp);
		break;
	case DATA_TYPE_UINT64_ARRAY:
		fmt = _zed_event_value_is_hex(name) ? "0x%.16llX " : "%llu ";
		n = _zed_event_convert_uint64_array(p, buflen, nvp, fmt);
		break;
	case DATA_TYPE_STRING_ARRAY:
		n = _zed_event_convert_string_array(p, buflen, nvp);
		break;
	case DATA_TYPE_NVLIST_ARRAY:
		/* FIXME */
		n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
		break;
	default:
		zed_log_msg(LOG_WARNING,
		    "Failed to convert nvpair \"%s\" for eid=%llu: "
		    "Unrecognized type=%u", name, eid, (unsigned int) type);
		return;
	}
	if ((n < 0) || (n >= sizeof (buf))) {
		zed_log_msg(LOG_WARNING,
		    "Failed to convert nvpair \"%s\" for eid=%llu: %s",
		    name, eid, "Exceeded buffer size");
		return;
	}
	if (zed_strings_add(zsp, buf) < 0) {
		zed_log_msg(LOG_WARNING,
		    "Failed to convert nvpair \"%s\" for eid=%llu: %s",
		    name, eid, strerror(ENOMEM));
		return;
	}
}
Exemplo n.º 24
0
static int
zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
{
	char *devname = data;
	boolean_t avail_spare, l2cache;
	nvlist_t *tgt;
	int error;

	zed_log_msg(LOG_INFO, "zfsdle_vdev_online: searching for '%s' in '%s'",
	    devname, zpool_get_name(zhp));

	if ((tgt = zpool_find_vdev_by_physpath(zhp, devname,
	    &avail_spare, &l2cache, NULL)) != NULL) {
		char *path, fullpath[MAXPATHLEN];
		uint64_t wholedisk;

		error = nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &path);
		if (error) {
			zpool_close(zhp);
			return (0);
		}

		error = nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
		    &wholedisk);
		if (error)
			wholedisk = 0;

		if (wholedisk) {
			path = strrchr(path, '/');
			if (path != NULL) {
				path = zfs_strip_partition(path + 1);
				if (path == NULL) {
					zpool_close(zhp);
					return (0);
				}
			} else {
				zpool_close(zhp);
				return (0);
			}

			(void) strlcpy(fullpath, path, sizeof (fullpath));
			free(path);

			/*
			 * We need to reopen the pool associated with this
			 * device so that the kernel can update the size of
			 * the expanded device.  When expanding there is no
			 * need to restart the scrub from the beginning.
			 */
			boolean_t scrub_restart = B_FALSE;
			(void) zpool_reopen_one(zhp, &scrub_restart);
		} else {
			(void) strlcpy(fullpath, path, sizeof (fullpath));
		}

		if (zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) {
			vdev_state_t newstate;

			if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL) {
				error = zpool_vdev_online(zhp, fullpath, 0,
				    &newstate);
				zed_log_msg(LOG_INFO, "zfsdle_vdev_online: "
				    "setting device '%s' to ONLINE state "
				    "in pool '%s': %d", fullpath,
				    zpool_get_name(zhp), error);
			}
		}
		zpool_close(zhp);
		return (1);
	}
	zpool_close(zhp);
	return (0);
}
Exemplo n.º 25
0
/*
 * Seek to the event specified by [saved_eid] and [saved_etime].
 * This protects against processing a given event more than once.
 * Return 0 upon a successful seek to the specified event, or -1 otherwise.
 *
 * A zevent is considered to be uniquely specified by its (eid,time) tuple.
 * The unsigned 64b eid is set to 1 when the kernel module is loaded, and
 * incremented by 1 for each new event.  Since the state file can persist
 * across a kernel module reload, the time must be checked to ensure a match.
 */
int
zed_event_seek(struct zed_conf *zcp, uint64_t saved_eid, int64_t saved_etime[])
{
	uint64_t eid;
	int found;
	nvlist_t *nvl;
	int n_dropped;
	int64_t *etime;
	uint_t nelem;
	int rv;

	if (!zcp) {
		errno = EINVAL;
		zed_log_msg(LOG_ERR, "Failed to seek zevent: %s",
		    strerror(errno));
		return (-1);
	}
	eid = 0;
	found = 0;
	while ((eid < saved_eid) && !found) {
		rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped,
		    ZEVENT_NONBLOCK, zcp->zevent_fd);

		if ((rv != 0) || !nvl)
			break;

		if (n_dropped > 0) {
			zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
			/*
			 * FIXME: Increase max size of event nvlist in
			 *   /sys/module/zfs/parameters/zfs_zevent_len_max ?
			 */
		}
		if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
			zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
		} else if (nvlist_lookup_int64_array(nvl, "time",
		    &etime, &nelem) != 0) {
			zed_log_msg(LOG_WARNING,
			    "Failed to lookup zevent time (eid=%llu)", eid);
		} else if (nelem != 2) {
			zed_log_msg(LOG_WARNING,
			    "Failed to lookup zevent time (eid=%llu, nelem=%u)",
			    eid, nelem);
		} else if ((eid != saved_eid) ||
		    (etime[0] != saved_etime[0]) ||
		    (etime[1] != saved_etime[1])) {
			/* no-op */
		} else {
			found = 1;
		}
		free(nvl);
	}
	if (!found && (saved_eid > 0)) {
		if (zpool_events_seek(zcp->zfs_hdl, ZEVENT_SEEK_START,
		    zcp->zevent_fd) < 0)
			zed_log_msg(LOG_WARNING, "Failed to seek to eid=0");
		else
			eid = 0;
	}
	zed_log_msg(LOG_NOTICE, "Processing events since eid=%llu", eid);
	return (found ? 0 : -1);
}
Exemplo n.º 26
0
Arquivo: zfs_mod.c Projeto: pyavdr/zfs
/*
 * The device associated with the given vdev (either by devid or physical path)
 * has been added to the system.  If 'isdisk' is set, then we only attempt a
 * replacement if it's a whole disk.  This also implies that we should label the
 * disk first.
 *
 * First, we attempt to online the device (making sure to undo any spare
 * operation when finished).  If this succeeds, then we're done.  If it fails,
 * and the new state is VDEV_CANT_OPEN, it indicates that the device was opened,
 * but that the label was not what we expected.  If the 'autoreplace' property
 * is not set, then we relabel the disk (if specified), and attempt a 'zpool
 * replace'.  If the online is successful, but the new state is something else
 * (REMOVED or FAULTED), it indicates that we're out of sync or in some sort of
 * race, and we should avoid attempting to relabel the disk.
 *
 * Also can arrive here from a ESC_ZFS_VDEV_CHECK event
 */
static void
zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
{
    char *path;
    vdev_state_t newstate;
    nvlist_t *nvroot, *newvd;
    pendingdev_t *device;
    uint64_t wholedisk = 0ULL;
    uint64_t offline = 0ULL;
    uint64_t guid = 0ULL;
    char *physpath = NULL, *new_devid = NULL;
    char rawpath[PATH_MAX], fullpath[PATH_MAX];
    char devpath[PATH_MAX];
    int ret;

    if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0)
        return;

    (void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_PHYS_PATH, &physpath);
    (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
    (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline);
    (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid);

    if (offline)
        return;  /* don't intervene if it was taken offline */

    zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s' (%llu)",
                zpool_get_name(zhp), path, (long long unsigned int)guid);

    /*
     * The VDEV guid is preferred for identification (gets passed in path)
     */
    if (guid != 0) {
        (void) snprintf(fullpath, sizeof (fullpath), "%llu",
                        (long long unsigned int)guid);
    } else {
        /*
         * otherwise use path sans partition suffix for whole disks
         */
        (void) strlcpy(fullpath, path, sizeof (fullpath));
        if (wholedisk) {
            char *spath = zfs_strip_partition(g_zfshdl, fullpath);

            (void) strlcpy(fullpath, spath, sizeof (fullpath));
            free(spath);
        }
    }

    /*
     * Attempt to online the device.
     */
    if (zpool_vdev_online(zhp, fullpath,
                          ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, &newstate) == 0 &&
            (newstate == VDEV_STATE_HEALTHY ||
             newstate == VDEV_STATE_DEGRADED)) {
        zed_log_msg(LOG_INFO, "  zpool_vdev_online: vdev %s is %s",
                    fullpath, (newstate == VDEV_STATE_HEALTHY) ?
                    "HEALTHY" : "DEGRADED");
        return;
    }

    /*
     * If the pool doesn't have the autoreplace property set, then attempt
     * a true online (without the unspare flag), which will trigger a FMA
     * fault.
     */
    if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) ||
            !wholedisk || physpath == NULL) {
        (void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
                                 &newstate);
        zed_log_msg(LOG_INFO, "  zpool_vdev_online: %s FORCEFAULT (%s)",
                    fullpath, libzfs_error_description(g_zfshdl));
        return;
    }

    /*
     * convert physical path into its current device node
     */
    (void) snprintf(rawpath, sizeof (rawpath), "%s%s", DEV_BYPATH_PATH,
                    physpath);
    if (realpath(rawpath, devpath) == NULL) {
        zed_log_msg(LOG_INFO, "  realpath: %s failed (%s)",
                    rawpath, strerror(errno));

        (void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
                                 &newstate);

        zed_log_msg(LOG_INFO, "  zpool_vdev_online: %s FORCEFAULT (%s)",
                    fullpath, libzfs_error_description(g_zfshdl));
        return;
    }

    /*
     * we're auto-replacing a raw disk, so label it first
     */
    if (!labeled) {
        char *leafname;

        /*
         * If this is a request to label a whole disk, then attempt to
         * write out the label.  Before we can label the disk, we need
         * to map the physical string that was matched on to the under
         * lying device node.
         *
         * If any part of this process fails, then do a force online
         * to trigger a ZFS fault for the device (and any hot spare
         * replacement).
         */
        leafname = strrchr(devpath, '/') + 1;

        /*
         * If this is a request to label a whole disk, then attempt to
         * write out the label.
         */
        if (zpool_label_disk(g_zfshdl, zhp, leafname) != 0) {
            zed_log_msg(LOG_INFO, "  zpool_label_disk: could not "
                        "label '%s' (%s)", leafname,
                        libzfs_error_description(g_zfshdl));

            (void) zpool_vdev_online(zhp, fullpath,
                                     ZFS_ONLINE_FORCEFAULT, &newstate);
            return;
        }

        /*
         * The disk labeling is asynchronous on Linux. Just record
         * this label request and return as there will be another
         * disk add event for the partition after the labeling is
         * completed.
         */
        device = malloc(sizeof (pendingdev_t));
        (void) strlcpy(device->pd_physpath, physpath,
                       sizeof (device->pd_physpath));
        list_insert_tail(&g_device_list, device);

        zed_log_msg(LOG_INFO, "  zpool_label_disk: async '%s' (%llu)",
                    leafname, (long long unsigned int)guid);

        return;	/* resumes at EC_DEV_ADD.ESC_DISK for partition */

    } else { /* labeled */
        boolean_t found = B_FALSE;
        /*
         * match up with request above to label the disk
         */
        for (device = list_head(&g_device_list); device != NULL;
                device = list_next(&g_device_list, device)) {
            if (strcmp(physpath, device->pd_physpath) == 0) {
                list_remove(&g_device_list, device);
                free(device);
                found = B_TRUE;
                break;
            }
        }
        if (!found) {
            /* unexpected partition slice encountered */
            (void) zpool_vdev_online(zhp, fullpath,
                                     ZFS_ONLINE_FORCEFAULT, &newstate);
            return;
        }

        zed_log_msg(LOG_INFO, "  zpool_label_disk: resume '%s' (%llu)",
                    physpath, (long long unsigned int)guid);

        if (nvlist_lookup_string(vdev, "new_devid", &new_devid) != 0) {
            zed_log_msg(LOG_INFO, "  auto replace: missing devid!");
            return;
        }

        (void) snprintf(devpath, sizeof (devpath), "%s%s",
                        DEV_BYID_PATH, new_devid);
        path = devpath;
    }

    /*
     * Construct the root vdev to pass to zpool_vdev_attach().  While adding
     * the entire vdev structure is harmless, we construct a reduced set of
     * path/physpath/wholedisk to keep it simple.
     */
    if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0) {
        zed_log_msg(LOG_WARNING, "zfs_mod: nvlist_alloc out of memory");
        return;
    }
    if (nvlist_alloc(&newvd, NV_UNIQUE_NAME, 0) != 0) {
        zed_log_msg(LOG_WARNING, "zfs_mod: nvlist_alloc out of memory");
        nvlist_free(nvroot);
        return;
    }

    if (nvlist_add_string(newvd, ZPOOL_CONFIG_TYPE, VDEV_TYPE_DISK) != 0 ||
            nvlist_add_string(newvd, ZPOOL_CONFIG_PATH, path) != 0 ||
            nvlist_add_string(newvd, ZPOOL_CONFIG_DEVID, new_devid) != 0 ||
            (physpath != NULL && nvlist_add_string(newvd,
                    ZPOOL_CONFIG_PHYS_PATH, physpath) != 0) ||
            nvlist_add_uint64(newvd, ZPOOL_CONFIG_WHOLE_DISK, wholedisk) != 0 ||
            nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) != 0 ||
            nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, &newvd,
                                    1) != 0) {
        zed_log_msg(LOG_WARNING, "zfs_mod: unable to add nvlist pairs");
        nvlist_free(newvd);
        nvlist_free(nvroot);
        return;
    }

    nvlist_free(newvd);

    /*
     * auto replace a leaf disk at same physical location
     */
    ret = zpool_vdev_attach(zhp, fullpath, path, nvroot, B_TRUE);

    zed_log_msg(LOG_INFO, "  zpool_vdev_replace: %s with %s (%s)",
                fullpath, path, (ret == 0) ? "no errors" :
                libzfs_error_description(g_zfshdl));

    nvlist_free(nvroot);
}
Exemplo n.º 27
0
/*
 * Scan the [zcp] zedlet_dir for files to exec based on the event class.
 * Files must be executable by user, but not writable by group or other.
 * Dotfiles are ignored.
 *
 * Return 0 on success with an updated set of zedlets,
 * or -1 on error with errno set.
 *
 * FIXME: Check if zedlet_dir and all parent dirs are secure.
 */
int
zed_conf_scan_dir(struct zed_conf *zcp)
{
	zed_strings_t *zedlets;
	DIR *dirp;
	struct dirent *direntp;
	char pathname[PATH_MAX];
	struct stat st;
	int n;

	if (!zcp) {
		errno = EINVAL;
		zed_log_msg(LOG_ERR, "Failed to scan zedlet dir: %s",
		    strerror(errno));
		return (-1);
	}
	zedlets = zed_strings_create();
	if (!zedlets) {
		errno = ENOMEM;
		zed_log_msg(LOG_WARNING, "Failed to scan dir \"%s\": %s",
		    zcp->zedlet_dir, strerror(errno));
		return (-1);
	}
	dirp = opendir(zcp->zedlet_dir);
	if (!dirp) {
		int errno_bak = errno;
		zed_log_msg(LOG_WARNING, "Failed to open dir \"%s\": %s",
		    zcp->zedlet_dir, strerror(errno));
		zed_strings_destroy(zedlets);
		errno = errno_bak;
		return (-1);
	}
	while ((direntp = readdir(dirp))) {
		if (direntp->d_name[0] == '.')
			continue;

		n = snprintf(pathname, sizeof (pathname),
		    "%s/%s", zcp->zedlet_dir, direntp->d_name);
		if ((n < 0) || (n >= sizeof (pathname))) {
			zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s",
			    direntp->d_name, strerror(ENAMETOOLONG));
			continue;
		}
		if (stat(pathname, &st) < 0) {
			zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s",
			    pathname, strerror(errno));
			continue;
		}
		if (!S_ISREG(st.st_mode)) {
			zed_log_msg(LOG_INFO,
			    "Ignoring \"%s\": not a regular file",
			    direntp->d_name);
			continue;
		}
		if ((st.st_uid != 0) && !zcp->do_force) {
			zed_log_msg(LOG_NOTICE,
			    "Ignoring \"%s\": not owned by root",
			    direntp->d_name);
			continue;
		}
		if (!(st.st_mode & S_IXUSR)) {
			zed_log_msg(LOG_INFO,
			    "Ignoring \"%s\": not executable by user",
			    direntp->d_name);
			continue;
		}
		if ((st.st_mode & S_IWGRP) & !zcp->do_force) {
			zed_log_msg(LOG_NOTICE,
			    "Ignoring \"%s\": writable by group",
			    direntp->d_name);
			continue;
		}
		if ((st.st_mode & S_IWOTH) & !zcp->do_force) {
			zed_log_msg(LOG_NOTICE,
			    "Ignoring \"%s\": writable by other",
			    direntp->d_name);
			continue;
		}
		if (zed_strings_add(zedlets, direntp->d_name) < 0) {
			zed_log_msg(LOG_WARNING,
			    "Failed to register \"%s\": %s",
			    direntp->d_name, strerror(errno));
			continue;
		}
		if (zcp->do_verbose)
			zed_log_msg(LOG_INFO,
			    "Registered zedlet \"%s\"", direntp->d_name);
	}
	if (closedir(dirp) < 0) {
		int errno_bak = errno;
		zed_log_msg(LOG_WARNING, "Failed to close dir \"%s\": %s",
		    zcp->zedlet_dir, strerror(errno));
		zed_strings_destroy(zedlets);
		errno = errno_bak;
		return (-1);
	}
	if (zcp->zedlets)
		zed_strings_destroy(zcp->zedlets);

	zcp->zedlets = zedlets;
	return (0);
}
Exemplo n.º 28
0
/*
 * Fork a child process to handle event [eid].  The program [prog]
 * in directory [dir] is executed with the envionment [env].
 *
 * The file descriptor [zfd] is the zevent_fd used to track the
 * current cursor location within the zevent nvlist.
 */
static void
_zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
    char *env[], int zfd)
{
	char path[PATH_MAX];
	int n;
	pid_t pid;
	int fd;
	pid_t wpid;
	int status;

	assert(dir != NULL);
	assert(prog != NULL);
	assert(env != NULL);
	assert(zfd >= 0);

	n = snprintf(path, sizeof (path), "%s/%s", dir, prog);
	if ((n < 0) || (n >= sizeof (path))) {
		zed_log_msg(LOG_WARNING,
		    "Failed to fork \"%s\" for eid=%llu: %s",
		    prog, eid, strerror(ENAMETOOLONG));
		return;
	}
	pid = fork();
	if (pid < 0) {
		zed_log_msg(LOG_WARNING,
		    "Failed to fork \"%s\" for eid=%llu: %s",
		    prog, eid, strerror(errno));
		return;
	} else if (pid == 0) {
		(void) umask(022);
		if ((fd = open("/dev/null", O_RDWR)) != -1) {
			(void) dup2(fd, STDIN_FILENO);
			(void) dup2(fd, STDOUT_FILENO);
			(void) dup2(fd, STDERR_FILENO);
		}
		(void) dup2(zfd, ZEVENT_FILENO);
		zed_file_close_from(ZEVENT_FILENO + 1);
		execle(path, prog, NULL, env);
		_exit(127);
	} else {
		zed_log_msg(LOG_INFO, "Invoking \"%s\" eid=%llu pid=%d",
		    prog, eid, pid);
		/* FIXME: Timeout rogue child processes with sigalarm? */
restart:
		wpid = waitpid(pid, &status, 0);
		if (wpid == (pid_t) -1) {
			if (errno == EINTR)
				goto restart;
			zed_log_msg(LOG_WARNING,
			    "Failed to wait for \"%s\" eid=%llu pid=%d",
			    prog, eid, pid);
		} else if (WIFEXITED(status)) {
			zed_log_msg(LOG_INFO,
			    "Finished \"%s\" eid=%llu pid=%d exit=%d",
			    prog, eid, pid, WEXITSTATUS(status));
		} else if (WIFSIGNALED(status)) {
			zed_log_msg(LOG_INFO,
			    "Finished \"%s\" eid=%llu pid=%d sig=%d/%s",
			    prog, eid, pid, WTERMSIG(status),
			    strsignal(WTERMSIG(status)));
		} else {
			zed_log_msg(LOG_INFO,
			    "Finished \"%s\" eid=%llu pid=%d status=0x%X",
			    prog, eid, (unsigned int) status);
		}
	}
}