Example #1
0
int
_npf_ruleset_list(int fd, const char *rname, nl_config_t *ncf)
{
	prop_dictionary_t rldict, ret;
	int error;

	rldict = prop_dictionary_create();
	if (rldict == NULL) {
		return ENOMEM;
	}
	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_LIST);
	error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
	if (!error) {
		prop_array_t rules;

		rules = prop_dictionary_get(ret, "rules");
		if (rules == NULL) {
			return EINVAL;
		}
		prop_object_release(ncf->ncf_rules_list);
		ncf->ncf_rules_list = rules;
	}
	return error;
}
Example #2
0
int
npf_config_submit(nl_config_t *ncf, int fd)
{
	const char *plist = ncf->ncf_plist;
	prop_dictionary_t npf_dict;
	prop_array_t rlset;
	int error = 0;

	npf_dict = prop_dictionary_create();
	if (npf_dict == NULL) {
		return ENOMEM;
	}
	prop_dictionary_set_uint32(npf_dict, "version", NPF_VERSION);

	rlset = _npf_ruleset_transform(ncf->ncf_rules_list);
	if (rlset == NULL) {
		prop_object_release(npf_dict);
		return ENOMEM;
	}
	prop_object_release(ncf->ncf_rules_list);
	ncf->ncf_rules_list = rlset;

	prop_dictionary_set(npf_dict, "rules", ncf->ncf_rules_list);
	prop_dictionary_set(npf_dict, "algs", ncf->ncf_alg_list);
	prop_dictionary_set(npf_dict, "rprocs", ncf->ncf_rproc_list);
	prop_dictionary_set(npf_dict, "tables", ncf->ncf_table_list);
	prop_dictionary_set(npf_dict, "translation", ncf->ncf_nat_list);
	prop_dictionary_set_bool(npf_dict, "flush", ncf->ncf_flush);
	if (ncf->ncf_debug) {
		prop_dictionary_set(npf_dict, "debug", ncf->ncf_debug);
	}

	if (plist) {
		if (!prop_dictionary_externalize_to_file(npf_dict, plist)) {
			error = errno;
		}
		prop_object_release(npf_dict);
		return error;
	}
	if (fd) {
		error = prop_dictionary_sendrecv_ioctl(npf_dict, fd,
		    IOC_NPF_RELOAD, &ncf->ncf_err);
		if (error) {
			prop_object_release(npf_dict);
			assert(ncf->ncf_err == NULL);
			return error;
		}
		prop_dictionary_get_int32(ncf->ncf_err, "errno", &error);
	}
	prop_object_release(npf_dict);
	return error;
}
Example #3
0
static int
hdaudioctl_list(int fd)
{
	prop_dictionary_t request, response;
	prop_dictionary_t dict;
	prop_object_iterator_t iter;
	prop_object_t obj;
	prop_array_t array;
	uint16_t nid, codecid;
	uint16_t vendor, product;
	uint32_t subsystem;
	const char *device = NULL;
	int error;

	request = prop_dictionary_create();
	if (request == NULL) {
		fprintf(stderr, "out of memory\n");
		return ENOMEM;
	}

	error = prop_dictionary_sendrecv_ioctl(request, fd,
	    HDAUDIO_FGRP_INFO, &response);
	if (error != 0) {
		perror("HDAUDIO_FGRP_INFO failed");
		return error;
	}

	array = prop_dictionary_get(response, "function-group-info");
	iter = prop_array_iterator(array);
	prop_object_iterator_reset(iter);
	while ((obj = prop_object_iterator_next(iter)) != NULL) {
		dict = (prop_dictionary_t)obj;
		prop_dictionary_get_uint16(dict, "codecid", &codecid);
		prop_dictionary_get_uint16(dict, "nid", &nid);
		prop_dictionary_get_uint16(dict, "vendor-id", &vendor);
		prop_dictionary_get_uint16(dict, "product-id", &product);
		prop_dictionary_get_uint32(dict, "subsystem-id", &subsystem);
		prop_dictionary_get_cstring_nocopy(dict, "device", &device);

		printf("codecid 0x%02X nid 0x%02X vendor 0x%04X "
		    "product 0x%04X subsystem 0x%08X device %s\n",
		    codecid, nid, vendor, product, subsystem,
		    device ? device : "<none>");
	}

	prop_object_release(array);
	prop_object_release(response);
	prop_object_release(request);

	return 0;
}
Example #4
0
int
npf_ruleset_add(int fd, const char *rname, nl_rule_t *rl, uint64_t *id)
{
	prop_dictionary_t rldict = rl->nrl_dict;
	prop_dictionary_t ret;
	int error;

	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_ADD);
	error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
	if (!error) {
		prop_dictionary_get_uint64(ret, "id", id);
	}
	return error;
}
Example #5
0
static int
hdaudioctl_set(int fd, int argc, char *argv[])
{
	prop_dictionary_t request, response;
	prop_array_t config = NULL;
	uint16_t nid, codecid;
	int error;

	if (argc < 2 || argc > 3)
		usage();

	codecid = strtol(argv[0], NULL, 0);
	nid = strtol(argv[1], NULL, 0);
	if (argc == 3) {
		config = prop_array_internalize_from_file(argv[2]);
		if (config == NULL) {
			fprintf(stderr,
			    "couldn't load configuration from %s\n", argv[2]);
			return EIO;
		}
	}

	request = prop_dictionary_create();
	if (request == NULL) {
		fprintf(stderr, "out of memory\n");
		return ENOMEM;
	}

	prop_dictionary_set_uint16(request, "codecid", codecid);
	prop_dictionary_set_uint16(request, "nid", nid);
	if (config)
		prop_dictionary_set(request, "pin-config", config);

	error = prop_dictionary_sendrecv_ioctl(request, fd,
	    HDAUDIO_FGRP_SETCONFIG, &response);
	if (error != 0) {
		perror("HDAUDIO_FGRP_SETCONFIG failed");
		return error;
	}

	prop_object_release(response);
	prop_object_release(request);

	return 0;
}
static void _dm_rename_kern(struct dm_task *dmt)
{
	prop_dictionary_t dm_dict_in, dm_dict_out;

	dm_dict_in = prop_dictionary_create(); /* Dictionary send to kernel */

	/* Set command name to dictionary */
	prop_dictionary_set_cstring(dm_dict_in, DM_IOCTL_COMMAND,
	    "nrename");
	prop_dictionary_set_cstring(dm_dict_in, "dev_name", dmt->dev_name);
	prop_dictionary_set_cstring(dm_dict_in, "new_name", dmt->newname);

	/* Set flags to dictionary. */
	prop_dictionary_set_uint32(dm_dict_in,DM_IOCTL_FLAGS,0);

	if (prop_dictionary_sendrecv_ioctl(dm_dict_in,_control_fd,
		NETBSD_DM_IOCTL,&dm_dict_out) != 0) {
		log_error("rename failed");
	}
}
Example #7
0
static int
hdaudioctl_get(int fd, int argc, char *argv[])
{
	prop_dictionary_t request, response;
	prop_array_t config;
	uint16_t nid, codecid;
	const char *xml;
	int error;

	if (argc != 2)
		usage();

	codecid = strtol(argv[0], NULL, 0);
	nid = strtol(argv[1], NULL, 0);

	request = prop_dictionary_create();
	if (request == NULL) {
		fprintf(stderr, "out of memory\n");
		return ENOMEM;
	}

	prop_dictionary_set_uint16(request, "codecid", codecid);
	prop_dictionary_set_uint16(request, "nid", nid);

	error = prop_dictionary_sendrecv_ioctl(request, fd,
	    HDAUDIO_FGRP_GETCONFIG, &response);
	if (error != 0) {
		perror("HDAUDIO_FGRP_GETCONFIG failed");
		return error;
	}

	config = prop_dictionary_get(response, "pin-config");
	xml = prop_array_externalize(config);

	printf("%s\n", xml);

	prop_object_release(response);
	prop_object_release(request);

	return 0;
}
Example #8
0
prop_array_t
udev_getdevs(int devfd)
{
	prop_dictionary_t	pd, rpd;
	prop_string_t		ps;
	prop_array_t		pa;

	pd = prop_dictionary_create();
	if (pd == NULL) {
		err(1, "prop_dictionary_create()");
	}

	ps = prop_string_create_cstring("getdevs");
	if (ps == NULL) {
		prop_object_release(pd);
		err(1, "prop_string_create_cstring()");
	}

	if (prop_dictionary_set(pd, "command", ps) == false) {
		prop_object_release(ps);
		prop_object_release(pd);
		err(1, "prop_dictionary_set()");
	}

	prop_object_release(ps);

	/* Send dictionary to kernel space */
	if (prop_dictionary_sendrecv_ioctl(pd, devfd, UDEVPROP, &rpd) != 0)
		err(1, "prop_array_recv_ioctl()");

	prop_object_release(pd);

	pa = prop_dictionary_get(rpd, "array");
	if (pa == NULL)
		goto out;
	prop_object_retain(pa);

out:
	prop_object_release(rpd);
	return pa;
}
Example #9
0
gboolean
drvctl_find_device(const gchar *devnode, prop_dictionary_t *properties)
{
	prop_dictionary_t command_dict;
	prop_dictionary_t args_dict;
	prop_dictionary_t results_dict;
	int err;
	   
	command_dict = prop_dictionary_create ();
	args_dict = prop_dictionary_create ();
		
	prop_dictionary_set_cstring_nocopy (command_dict, "drvctl-command", "get-properties");
	prop_dictionary_set_cstring_nocopy (args_dict, "device-name", devnode);  
	prop_dictionary_set (command_dict, "drvctl-arguments", args_dict);
	prop_object_release (args_dict);

	err = prop_dictionary_sendrecv_ioctl (command_dict, drvctl_fd,
					      DRVCTLCOMMAND, &results_dict);
	prop_object_release (command_dict);
	if (err)
		return FALSE;

	if (prop_dictionary_get_int8 (results_dict, "drvctl-error", &err) == false || err != 0) {
		prop_object_release (results_dict);
		return FALSE;
	}

	if (properties) {
		prop_dictionary_t result_data;
		result_data = prop_dictionary_get (results_dict, "drvctl-result-data");
		if (result_data)
			*properties = prop_dictionary_copy (result_data);
	}

	prop_object_release (results_dict);

	return TRUE;
}
/*
 * This function is heart of NetBSD libdevmapper-> device-mapper kernel protocol
 * It creates proplib_dictionary from dm task structure and sends it to NetBSD
 * kernel driver. After succesfull ioctl it create dmi structure from returned
 * proplib dictionary. This way I keep number of changes in NetBSD version of
 * libdevmapper as small as posible.
 */
static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command)
{
	struct dm_ioctl *dmi;
	prop_dictionary_t dm_dict_in, dm_dict_out;

	uint32_t flags;

	dm_dict_in = NULL;

	dm_dict_in = prop_dictionary_create(); /* Dictionary send to kernel */
	dm_dict_out = prop_dictionary_create(); /* Dictionary received from kernel */

	/* Set command name to dictionary */
	prop_dictionary_set_cstring(dm_dict_in, DM_IOCTL_COMMAND,
	    _cmd_data_v4[dmt->type].name);

	/* Parse dmi from libdevmapper to dictionary */
	if (_flatten(dmt, dm_dict_in) < 0)
		goto bad;

	prop_dictionary_get_uint32(dm_dict_in, DM_IOCTL_FLAGS, &flags);

	if (dmt->type == DM_DEVICE_TABLE)
		flags |= DM_STATUS_TABLE_FLAG;

	if (dmt->no_open_count)
		flags |= DM_SKIP_BDGET_FLAG;

	flags |= DM_EXISTS_FLAG;

	/* Set flags to dictionary. */
	prop_dictionary_set_uint32(dm_dict_in,DM_IOCTL_FLAGS,flags);
	log_very_verbose("Ioctl type  %s --- flags %d",_cmd_data_v4[dmt->type].name,flags);
	//printf("name %s, major %d minor %d\n uuid %s\n", 
        //dm_task_get_name(dmt), dmt->minor, dmt->major, dm_task_get_uuid(dmt));
	/* Send dictionary to kernel and wait for reply. */

	if (prop_dictionary_sendrecv_ioctl(dm_dict_in,_control_fd,
		NETBSD_DM_IOCTL,&dm_dict_out) != 0) {

		if (errno == ENOENT &&
		    ((dmt->type == DM_DEVICE_INFO) ||
			(dmt->type == DM_DEVICE_MKNODES) ||
			(dmt->type == DM_DEVICE_STATUS))) {

			/*
			 * Linux version doesn't fail when ENOENT is returned
			 * for nonexisting device after info, deps, mknodes call.
			 * It returns dmi sent to kernel with DM_EXISTS_FLAG = 0;
			 */

			dmi = nbsd_dm_dict_to_dmi(dm_dict_in,_cmd_data_v4[dmt->type].cmd);

			dmi->flags &= ~DM_EXISTS_FLAG;

			prop_object_release(dm_dict_in);
			prop_object_release(dm_dict_out);

			goto out;
		} else {
			log_error("ioctl %s call failed: %s\n",
			    _cmd_data_v4[dmt->type].name, strerror(errno));

			prop_object_release(dm_dict_in);
			prop_object_release(dm_dict_out);

			goto bad;
		}
	}

	/* Parse kernel dictionary to dmi structure and return it to libdevmapper. */
	dmi = nbsd_dm_dict_to_dmi(dm_dict_out,_cmd_data_v4[dmt->type].cmd);

	prop_object_release(dm_dict_in);
	prop_object_release(dm_dict_out);
out:
	return dmi;
bad:
	return NULL;
}
Example #11
0
int
main(int argc, char **argv)
{
	int c, mode;
	char *attr = 0;
	extern char *optarg;
	extern int optind;
	int fd, res;
	size_t children;
	struct devpmargs paa = {.devname = "", .flags = 0};
	struct devlistargs laa = {.l_devname = "", .l_childname = NULL,
				  .l_children = 0};
	struct devdetachargs daa;
	struct devrescanargs raa;
	int *locs, i;
	prop_dictionary_t command_dict, args_dict, results_dict,
			  data_dict;
	prop_string_t string;
	prop_number_t number;
	char *xml;

	mode = 0;
	while ((c = getopt(argc, argv, OPTS)) != -1) {
		switch (c) {
		case 'Q':
		case 'R':
		case 'S':
		case 'd':
		case 'l':
		case 'p':
		case 'r':
			mode = c;
			break;
		case 'a':
			attr = optarg;
			break;
		case '?':
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if (argc < 1 || mode == 0)
		usage();

	fd = open(DRVCTLDEV, OPEN_MODE(mode), 0);
	if (fd < 0)
		err(2, "open %s", DRVCTLDEV);

	switch (mode) {
	case 'Q':
		paa.flags = DEVPM_F_SUBTREE;
		/*FALLTHROUGH*/
	case 'R':
		strlcpy(paa.devname, argv[0], sizeof(paa.devname));

		if (ioctl(fd, DRVRESUMEDEV, &paa) == -1)
			err(3, "DRVRESUMEDEV");
		break;
	case 'S':
		strlcpy(paa.devname, argv[0], sizeof(paa.devname));

		if (ioctl(fd, DRVSUSPENDDEV, &paa) == -1)
			err(3, "DRVSUSPENDDEV");
		break;
	case 'd':
		strlcpy(daa.devname, argv[0], sizeof(daa.devname));

		if (ioctl(fd, DRVDETACHDEV, &daa) == -1)
			err(3, "DRVDETACHDEV");
		break;
	case 'l':
		strlcpy(laa.l_devname, argv[0], sizeof(laa.l_devname));

		if (ioctl(fd, DRVLISTDEV, &laa) == -1)
			err(3, "DRVLISTDEV");

		children = laa.l_children;

		laa.l_childname = malloc(children * sizeof(laa.l_childname[0]));
		if (laa.l_childname == NULL)
			err(5, "DRVLISTDEV");
		if (ioctl(fd, DRVLISTDEV, &laa) == -1)
			err(3, "DRVLISTDEV");
		if (laa.l_children > children)
			err(6, "DRVLISTDEV: number of children grew");

		for (i = 0; i < laa.l_children; i++)
			printf("%s %s\n", laa.l_devname, laa.l_childname[i]);
		break;
	case 'r':
		memset(&raa, 0, sizeof(raa));
		strlcpy(raa.busname, argv[0], sizeof(raa.busname));
		if (attr)
			strlcpy(raa.ifattr, attr, sizeof(raa.ifattr));
		if (argc > 1) {
			locs = malloc((argc - 1) * sizeof(int));
			if (!locs)
				err(5, "malloc int[%d]", argc - 1);
			for (i = 0; i < argc - 1; i++)
				locs[i] = atoi(argv[i + 1]);
			raa.numlocators = argc - 1;
			raa.locators = locs;
		}

		if (ioctl(fd, DRVRESCANBUS, &raa) == -1)
			err(3, "DRVRESCANBUS");
		break;
	case 'p':

		command_dict = prop_dictionary_create();
		args_dict = prop_dictionary_create();

		string = prop_string_create_cstring_nocopy("get-properties");
		prop_dictionary_set(command_dict, "drvctl-command", string);
		prop_object_release(string);

		string = prop_string_create_cstring(argv[0]);
		prop_dictionary_set(args_dict, "device-name", string);
		prop_object_release(string);

		prop_dictionary_set(command_dict, "drvctl-arguments",
				    args_dict);
		prop_object_release(args_dict);

		res = prop_dictionary_sendrecv_ioctl(command_dict, fd,
						     DRVCTLCOMMAND,
						     &results_dict);
		prop_object_release(command_dict);
		if (res)
			errx(3, "DRVCTLCOMMAND: %s", strerror(res));

		number = prop_dictionary_get(results_dict, "drvctl-error");
		if (prop_number_integer_value(number) != 0) {
			errx(3, "get-properties: %s",
			    strerror((int)prop_number_integer_value(number)));
		}

		data_dict = prop_dictionary_get(results_dict,
						"drvctl-result-data");
		if (data_dict == NULL) {
			errx(3, "get-properties: failed to return result data");
		}

		xml = prop_dictionary_externalize(data_dict);
		prop_object_release(results_dict);

		printf("Properties for device `%s':\n%s",
		       argv[0], xml);
		free(xml);
		break;
	default:
		errx(4, "unknown command");
	}

	return (0);
}
Example #12
0
/*
 * This function is heart of NetBSD libdevmapper-> device-mapper kernel protocol
 * It creates proplib_dictionary from dm task structure and sends it to NetBSD
 * kernel driver. After succesfull ioctl it create dmi structure from returned
 * proplib dictionary. This way I keep number of changes in NetBSD version of
 * libdevmapper as small as posible.
 */
static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command)
{
	struct dm_ioctl *dmi;
	prop_dictionary_t dm_dict_in, dm_dict_out;
	
	uint32_t flags;

	dm_dict_in = NULL;
	
	dm_dict_in = prop_dictionary_create(); /* Dictionary send to kernel */
	dm_dict_out = prop_dictionary_create(); /* Dictionary received from kernel */

	/* Set command name to dictionary */
	prop_dictionary_set_cstring(dm_dict_in, DM_IOCTL_COMMAND,
	    _cmd_data_v4[dmt->type].name);

	/* Parse dmi from libdevmapper to dictionary */
	if (_flatten(dmt, dm_dict_in) < 0)
		goto bad;

	prop_dictionary_get_uint32(dm_dict_in, DM_IOCTL_FLAGS, &flags);
		
	if (dmt->type == DM_DEVICE_TABLE)
		flags |= DM_STATUS_TABLE_FLAG;

	if (dmt->no_open_count)
		flags |= DM_SKIP_BDGET_FLAG;

	flags |= DM_EXISTS_FLAG;
	
	/* Set flags to dictionary. */
	prop_dictionary_set_uint32(dm_dict_in,DM_IOCTL_FLAGS,flags);
	
	prop_dictionary_externalize_to_file(dm_dict_in,"/tmp/test_in");
	
	log_very_verbose("Ioctl type  %s --- flags %d",_cmd_data_v4[dmt->type].name,flags);
	//printf("name %s, major %d minor %d\n uuid %s\n", 
        //dm_task_get_name(dmt), dmt->minor, dmt->major, dm_task_get_uuid(dmt));
	/* Send dictionary to kernel and wait for reply. */
#ifdef RUMP_ACTION
	struct plistref prefp;
	int err;
	prop_dictionary_externalize_to_pref(dm_dict_in, &prefp);

	if (rump_sys_ioctl(_control_fd, NETBSD_DM_IOCTL, &prefp) != 0) {

		dm_dict_out = prop_dictionary_internalize(prefp.pref_plist);
#else	
	if (prop_dictionary_sendrecv_ioctl(dm_dict_in,_control_fd,
		NETBSD_DM_IOCTL,&dm_dict_out) != 0) {
#endif
		if (errno == ENOENT &&
		    ((dmt->type == DM_DEVICE_INFO) ||
			(dmt->type == DM_DEVICE_MKNODES) ||
			(dmt->type == DM_DEVICE_STATUS))) {

			/*
			 * Linux version doesn't fail when ENOENT is returned
			 * for nonexisting device after info, deps, mknodes call.
			 * It returns dmi sent to kernel with DM_EXISTS_FLAG = 0;
			 */
			
			dmi = nbsd_dm_dict_to_dmi(dm_dict_in,_cmd_data_v4[dmt->type].cmd);

			dmi->flags &= ~DM_EXISTS_FLAG; 

			prop_object_release(dm_dict_in);
			prop_object_release(dm_dict_out);

			goto out;
		} else {
			log_error("ioctl %s call failed with errno %d\n", 
					  _cmd_data_v4[dmt->type].name, errno);

			prop_object_release(dm_dict_in);
			prop_object_release(dm_dict_out);

			goto bad;
		}
	}

#ifdef RUMP_ACTION
	dm_dict_out = prop_dictionary_internalize(prefp.pref_plist);
#endif	
	prop_dictionary_externalize_to_file(dm_dict_out,"/tmp/test_out");

	/* Parse kernel dictionary to dmi structure and return it to libdevmapper. */
	dmi = nbsd_dm_dict_to_dmi(dm_dict_out,_cmd_data_v4[dmt->type].cmd);

	prop_object_release(dm_dict_in);
	prop_object_release(dm_dict_out);
out:	
	return dmi;
bad:
	return NULL;
}

/* Create new edvice nodes in mapper/ dir. */
void dm_task_update_nodes(void)
{
	update_devs();
}

/* Run dm command which is descirbed in dm_task structure. */
int dm_task_run(struct dm_task *dmt)
{
	struct dm_ioctl *dmi;
	unsigned command;

	if ((unsigned) dmt->type >=
	    (sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) {
		log_error("Internal error: unknown device-mapper task %d",
			  dmt->type);
		return 0;
	}

	command = _cmd_data_v4[dmt->type].cmd;

	/* Old-style creation had a table supplied */
	if (dmt->type == DM_DEVICE_CREATE && dmt->head)
		return _create_and_load_v4(dmt);

	if (dmt->type == DM_DEVICE_MKNODES && !dmt->dev_name &&
	    !dmt->uuid && dmt->major <= 0)
		return _mknodes_v4(dmt);

	if ((dmt->type == DM_DEVICE_RELOAD) && dmt->suppress_identical_reload)
		return _reload_with_suppression_v4(dmt);
	
	if (!_open_control())
		return 0;

	if (!(dmi = _do_dm_ioctl(dmt, command)))
		return 0;

	switch (dmt->type) {
	case DM_DEVICE_CREATE:
		add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev),
		    dmt->uid, dmt->gid, dmt->mode, 0);
		break;

	case DM_DEVICE_REMOVE:
		/* FIXME Kernel needs to fill in dmi->name */
		if (dmt->dev_name)
			rm_dev_node(dmt->dev_name, 0);
		break;

	case DM_DEVICE_RENAME:
		/* FIXME Kernel needs to fill in dmi->name */
		if (dmt->dev_name)
			rename_dev_node(dmt->dev_name, dmt->newname, 0);
		break;

	case DM_DEVICE_RESUME:
		/* FIXME Kernel needs to fill in dmi->name */
		set_dev_node_read_ahead(dmt->dev_name, dmt->read_ahead,
					dmt->read_ahead_flags);
		break;
	
	case DM_DEVICE_MKNODES:
		if (dmi->flags & DM_EXISTS_FLAG)
			add_dev_node(dmi->name, MAJOR(dmi->dev),
				     MINOR(dmi->dev),
			    dmt->uid, dmt->gid, dmt->mode, 0);
		else if (dmt->dev_name)
			rm_dev_node(dmt->dev_name, 0);
		break;

	case DM_DEVICE_STATUS:
	case DM_DEVICE_TABLE:
	case DM_DEVICE_WAITEVENT:
		if (!_unmarshal_status(dmt, dmi))
			goto bad;
		break;
	}

	/* Was structure reused? */
	if (dmt->dmi.v4)
		dm_free(dmt->dmi.v4);

	dmt->dmi.v4 = dmi;
	return 1;

      bad:
	dm_free(dmi);
	return 0;
}

void dm_lib_release(void)
{
	if (_control_fd != -1) {
		close(_control_fd);
		_control_fd = -1;
	}
	update_devs();
}

void dm_lib_exit(void)
{
	dm_lib_release();
	dm_dump_memory();
	_version_ok = 1;
	_version_checked = 0;
}