⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libdm-iface.c

📁 Linux Device Mapper Source Code
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "lib.h"#include "libdm-targets.h"#include "libdm-common.h"#ifdef DM_COMPAT#  include "libdm-compat.h"#endif#include <fcntl.h>#include <dirent.h>#include <sys/ioctl.h>#include <limits.h>#ifdef linux#  include "kdev_t.h"#  include <linux/limits.h>#else#  define MAJOR(x) major((x))#  define MINOR(x) minor((x))#  define MKDEV(x,y) makedev((x),(y))#endif#include <linux/dm-ioctl.h>/* * Ensure build compatibility.   * The hard-coded versions here are the highest present  * in the _cmd_data arrays. */#if !((DM_VERSION_MAJOR == 1 && DM_VERSION_MINOR >= 0) || \      (DM_VERSION_MAJOR == 4 && DM_VERSION_MINOR >= 0))#error The version of dm-ioctl.h included is incompatible.#endif/* FIXME This should be exported in device-mapper.h */#define DM_NAME "device-mapper"#define PROC_MISC "/proc/misc"#define PROC_DEVICES "/proc/devices"#define MISC_NAME "misc"#define NUMBER_OF_MAJORS 4096/* dm major version no for running kernel */static unsigned _dm_version = DM_VERSION_MAJOR;static unsigned _dm_version_minor = 0;static unsigned _dm_version_patchlevel = 0;static int _log_suppress = 0;static dm_bitset_t _dm_bitset = NULL;static int _control_fd = -1;static int _version_checked = 0;static int _version_ok = 1;static unsigned _ioctl_buffer_double_factor = 0;/* * Support both old and new major numbers to ease the transition. * Clumsy, but only temporary. */#if DM_VERSION_MAJOR == 4 && defined(DM_COMPAT)const int _dm_compat = 1;#elseconst int _dm_compat = 0;#endif/* *INDENT-OFF* */static struct cmd_data _cmd_data_v4[] = {	{"create",	DM_DEV_CREATE,		{4, 0, 0}},	{"reload",	DM_TABLE_LOAD,		{4, 0, 0}},	{"remove",	DM_DEV_REMOVE,		{4, 0, 0}},	{"remove_all",	DM_REMOVE_ALL,		{4, 0, 0}},	{"suspend",	DM_DEV_SUSPEND,		{4, 0, 0}},	{"resume",	DM_DEV_SUSPEND,		{4, 0, 0}},	{"info",	DM_DEV_STATUS,		{4, 0, 0}},	{"deps",	DM_TABLE_DEPS,		{4, 0, 0}},	{"rename",	DM_DEV_RENAME,		{4, 0, 0}},	{"version",	DM_VERSION,		{4, 0, 0}},	{"status",	DM_TABLE_STATUS,	{4, 0, 0}},	{"table",	DM_TABLE_STATUS,	{4, 0, 0}},	{"waitevent",	DM_DEV_WAIT,		{4, 0, 0}},	{"names",	DM_LIST_DEVICES,	{4, 0, 0}},	{"clear",	DM_TABLE_CLEAR,		{4, 0, 0}},	{"mknodes",	DM_DEV_STATUS,		{4, 0, 0}},#ifdef DM_LIST_VERSIONS	{"versions",	DM_LIST_VERSIONS,	{4, 1, 0}},#endif#ifdef DM_TARGET_MSG	{"message",	DM_TARGET_MSG,		{4, 2, 0}},#endif#ifdef DM_DEV_SET_GEOMETRY	{"setgeometry",	DM_DEV_SET_GEOMETRY,	{4, 6, 0}},#endif};/* *INDENT-ON* */#define ALIGNMENT_V1 sizeof(int)#define ALIGNMENT 8/* FIXME Rejig library to record & use errno instead */#ifndef DM_EXISTS_FLAG#  define DM_EXISTS_FLAG 0x00000004#endifstatic void *_align(void *ptr, unsigned int a){	register unsigned long agn = --a;	return (void *) (((unsigned long) ptr + agn) & ~agn);}#ifdef DM_IOCTLS/* * Set number to NULL to populate _dm_bitset - otherwise first * match is returned. */static int _get_proc_number(const char *file, const char *name,			    uint32_t *number){	FILE *fl;	char nm[256];	int c;	uint32_t num;	if (!(fl = fopen(file, "r"))) {		log_sys_error("fopen", file);		return 0;	}	while (!feof(fl)) {		if (fscanf(fl, "%d %255s\n", &num, &nm[0]) == 2) {			if (!strcmp(name, nm)) {				if (number) {					*number = num;					if (fclose(fl))						log_sys_error("fclose", file);					return 1;				}				dm_bit_set(_dm_bitset, num);			}		} else do {			c = fgetc(fl);		} while (c != EOF && c != '\n');	}	if (fclose(fl))		log_sys_error("fclose", file);	if (number) {		log_error("%s: No entry for %s found", file, name);		return 0;	}	return 1;}static int _control_device_number(uint32_t *major, uint32_t *minor){	if (!_get_proc_number(PROC_DEVICES, MISC_NAME, major) ||	    !_get_proc_number(PROC_MISC, DM_NAME, minor)) {		*major = 0;		return 0;	}	return 1;}/* * Returns 1 if exists; 0 if it doesn't; -1 if it's wrong */static int _control_exists(const char *control, uint32_t major, uint32_t minor){	struct stat buf;	if (stat(control, &buf) < 0) {		if (errno != ENOENT)			log_sys_error("stat", control);		return 0;	}	if (!S_ISCHR(buf.st_mode)) {		log_verbose("%s: Wrong inode type", control);		if (!unlink(control))			return 0;		log_sys_error("unlink", control);		return -1;	}	if (major && buf.st_rdev != MKDEV(major, minor)) {		log_verbose("%s: Wrong device number: (%u, %u) instead of "			    "(%u, %u)", control,			    MAJOR(buf.st_mode), MINOR(buf.st_mode),			    major, minor);		if (!unlink(control))			return 0;		log_sys_error("unlink", control);		return -1;	}	return 1;}static int _create_control(const char *control, uint32_t major, uint32_t minor){	int ret;	mode_t old_umask;	if (!major)		return 0;	old_umask = umask(0022);	ret = dm_create_dir(dm_dir());	umask(old_umask);	if (!ret)		return 0;	log_verbose("Creating device %s (%u, %u)", control, major, minor);	if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR,		  MKDEV(major, minor)) < 0)  {		log_sys_error("mknod", control);		return 0;	}#ifdef HAVE_SELINUX	if (!dm_set_selinux_context(control, S_IFCHR)) {		stack;		return 0;	}#endif	return 1;}#endifstatic int _create_dm_bitset(void){#ifdef DM_IOCTLS	if (_dm_bitset)		return 1;	if (!(_dm_bitset = dm_bitset_create(NULL, NUMBER_OF_MAJORS)))		return 0;	if (!_get_proc_number(PROC_DEVICES, DM_NAME, NULL)) {		dm_bitset_destroy(_dm_bitset);		_dm_bitset = NULL;		return 0;	}	return 1;#else	return 0;#endif}int dm_is_dm_major(uint32_t major){	if (!_create_dm_bitset())		return 0;	return dm_bit(_dm_bitset, major) ? 1 : 0;}static int _open_control(void){#ifdef DM_IOCTLS	char control[PATH_MAX];	uint32_t major = 0, minor;	if (_control_fd != -1)		return 1;	snprintf(control, sizeof(control), "%s/control", dm_dir());	if (!_control_device_number(&major, &minor))		log_error("Is device-mapper driver missing from kernel?");	if (!_control_exists(control, major, minor) &&	    !_create_control(control, major, minor))		goto error;	if ((_control_fd = open(control, O_RDWR)) < 0) {		log_sys_error("open", control);		goto error;	}	if (!_create_dm_bitset()) {		log_error("Failed to set up list of device-mapper major numbers");		return 0;	}	return 1;error:	log_error("Failure to communicate with kernel device-mapper driver.");	return 0;#else	return 1;#endif}void dm_task_destroy(struct dm_task *dmt){	struct target *t, *n;	for (t = dmt->head; t; t = n) {		n = t->next;		dm_free(t->params);		dm_free(t->type);		dm_free(t);	}	if (dmt->dev_name)		dm_free(dmt->dev_name);	if (dmt->newname)		dm_free(dmt->newname);	if (dmt->message)		dm_free(dmt->message);	if (dmt->dmi.v4)		dm_free(dmt->dmi.v4);	if (dmt->uuid)		dm_free(dmt->uuid);	dm_free(dmt);}/* * Protocol Version 1 compatibility functions. */#ifdef DM_COMPATstatic int _dm_task_get_driver_version_v1(struct dm_task *dmt, char *version,					  size_t size){	unsigned int *v;	if (!dmt->dmi.v1) {		version[0] = '\0';		return 0;	}	v = dmt->dmi.v1->version;	snprintf(version, size, "%u.%u.%u", v[0], v[1], v[2]);	return 1;}/* Unmarshall the target info returned from a status call */static int _unmarshal_status_v1(struct dm_task *dmt, struct dm_ioctl_v1 *dmi){	char *outbuf = (char *) dmi + dmi->data_start;	char *outptr = outbuf;	int32_t i;	struct dm_target_spec_v1 *spec;	for (i = 0; i < dmi->target_count; i++) {		spec = (struct dm_target_spec_v1 *) outptr;		if (!dm_task_add_target(dmt, spec->sector_start,					(uint64_t) spec->length,					spec->target_type,					outptr + sizeof(*spec))) {			return 0;		}		outptr = outbuf + spec->next;	}	return 1;}static int _dm_format_dev_v1(char *buf, int bufsize, uint32_t dev_major,			     uint32_t dev_minor){	int r;	if (bufsize < 8)		return 0;	r = snprintf(buf, bufsize, "%03x:%03x", dev_major, dev_minor);	if (r < 0 || r > bufsize - 1)		return 0;	return 1;}static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info){	if (!dmt->dmi.v1)		return 0;	memset(info, 0, sizeof(*info));	info->exists = dmt->dmi.v1->flags & DM_EXISTS_FLAG ? 1 : 0;	if (!info->exists)		return 1;	info->suspended = dmt->dmi.v1->flags & DM_SUSPEND_FLAG ? 1 : 0;	info->read_only = dmt->dmi.v1->flags & DM_READONLY_FLAG ? 1 : 0;	info->target_count = dmt->dmi.v1->target_count;	info->open_count = dmt->dmi.v1->open_count;	info->event_nr = 0;	info->major = MAJOR(dmt->dmi.v1->dev);	info->minor = MINOR(dmt->dmi.v1->dev);	info->live_table = 1;	info->inactive_table = 0;	return 1;}static const char *_dm_task_get_name_v1(const struct dm_task *dmt){	return (dmt->dmi.v1->name);}static const char *_dm_task_get_uuid_v1(const struct dm_task *dmt){	return (dmt->dmi.v1->uuid);}static struct dm_deps *_dm_task_get_deps_v1(struct dm_task *dmt){	log_error("deps version 1 no longer supported by libdevmapper");	return NULL;}static struct dm_names *_dm_task_get_names_v1(struct dm_task *dmt){	return (struct dm_names *) (((void *) dmt->dmi.v1) +				    dmt->dmi.v1->data_start);}static void *_add_target_v1(struct target *t, void *out, void *end){	void *out_sp = out;	struct dm_target_spec_v1 sp;	size_t sp_size = sizeof(struct dm_target_spec_v1);	int len;	const char no_space[] = "Ran out of memory building ioctl parameter";	out += sp_size;	if (out >= end) {		log_error(no_space);		return NULL;	}	sp.status = 0;	sp.sector_start = t->start;	sp.length = t->length;	strncpy(sp.target_type, t->type, sizeof(sp.target_type));	len = strlen(t->params);	if ((out + len + 1) >= end) {		log_error(no_space);		log_error("t->params= '%s'", t->params);		return NULL;	}	strcpy((char *) out, t->params);	out += len + 1;	/* align next block */	out = _align(out, ALIGNMENT_V1);	sp.next = out - out_sp;	memcpy(out_sp, &sp, sp_size);	return out;}static struct dm_ioctl_v1 *_flatten_v1(struct dm_task *dmt){	const size_t min_size = 16 * 1024;	const int (*version)[3];	struct dm_ioctl_v1 *dmi;	struct target *t;	size_t len = sizeof(struct dm_ioctl_v1);	void *b, *e;	int count = 0;	for (t = dmt->head; t; t = t->next) {		len += sizeof(struct dm_target_spec_v1);		len += strlen(t->params) + 1 + ALIGNMENT_V1;		count++;	}	if (count && dmt->newname) {		log_error("targets and newname are incompatible");		return NULL;	}	if (dmt->newname)		len += strlen(dmt->newname) + 1;	/*	 * Give len a minimum size so that we have space to store	 * dependencies or status information.	 */	if (len < min_size)		len = min_size;	if (!(dmi = dm_malloc(len)))		return NULL;	memset(dmi, 0, len);	version = &_cmd_data_v1[dmt->type].version;	dmi->version[0] = (*version)[0];	dmi->version[1] = (*version)[1];	dmi->version[2] = (*version)[2];	dmi->data_size = len;	dmi->data_start = sizeof(struct dm_ioctl_v1);	if (dmt->dev_name)		strncpy(dmi->name, dmt->dev_name, sizeof(dmi->name));	if (dmt->type == DM_DEVICE_SUSPEND)		dmi->flags |= DM_SUSPEND_FLAG;	if (dmt->read_only)		dmi->flags |= DM_READONLY_FLAG;	if (dmt->minor >= 0) {		if (dmt->major <= 0) {			log_error("Missing major number for persistent device");			return NULL;		}		dmi->flags |= DM_PERSISTENT_DEV_FLAG;		dmi->dev = MKDEV(dmt->major, dmt->minor);	}	if (dmt->uuid)		strncpy(dmi->uuid, dmt->uuid, sizeof(dmi->uuid));	dmi->target_count = count;	b = (void *) (dmi + 1);	e = (void *) ((char *) dmi + len);	for (t = dmt->head; t; t = t->next)		if (!(b = _add_target_v1(t, b, e)))			goto bad;	if (dmt->newname)		strcpy(b, dmt->newname);	return dmi;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -