From: Alasdair Kergon Date: Thu, 6 Jan 2005 18:22:43 +0000 (+0000) Subject: Attempt to fix /dev/mapper/control transparently if it's wrong. X-Git-Tag: v1_00_20~1 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=0f3c161c1154ed81db7a4b6893c02c1ab78919ff;p=dm.git Attempt to fix /dev/mapper/control transparently if it's wrong. --- diff --git a/WHATS_NEW b/WHATS_NEW index 0580853..722e948 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 1.00.20 - ============================= + Attempt to fix /dev/mapper/control transparently if it's wrong. Configuration-time option for setting uid/gid/mode for /dev/mapper nodes. Update kernel patches for 2.4.27/2.4.28-pre-4 (includes minor fixes). Add --noheadings columns option for colon-separated dmsetup output. diff --git a/include/.symlinks b/include/.symlinks index d6da3b4..01c6fdc 100644 --- a/include/.symlinks +++ b/include/.symlinks @@ -1,2 +1,3 @@ ../lib/libdevmapper.h +../lib/libdm-file.h ../po/pogen.h diff --git a/include/intl.h b/include/intl.h new file mode 100644 index 0000000..ed6335d --- /dev/null +++ b/include/intl.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004-2005 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 General Public License v.2. + * + * You should have received a copy of the GNU 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 + */ + +#ifndef _LVM_INTL_H +#define _LVM_INTL_H + +#ifdef INTL_PACKAGE +# include +# define _(String) dgettext(INTL_PACKAGE, (String)) +#else +# define _(String) (String) +#endif + +#endif diff --git a/include/lib.h b/include/lib.h new file mode 100644 index 0000000..9b779dc --- /dev/null +++ b/include/lib.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004-2005 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 General Public License v.2. + * + * You should have received a copy of the GNU 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 + */ + +/* + * This file must be included first by every library source file. + */ +#ifndef _LVM_LIB_H +#define _LVM_LIB_H + +#define _REENTRANT +#define _GNU_SOURCE +#define _FILE_OFFSET_BITS 64 + +#include "log.h" +#include "intl.h" + +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/lib/Makefile.in b/lib/Makefile.in index 5f5309e..2d7c23a 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -1,6 +1,6 @@ # # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. -# Copyright (C) 2004 Red Hat, Inc. All rights reserved. +# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. # # This file is part of the device-mapper userspace tools. # @@ -17,7 +17,7 @@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ interface = @interface@ -SOURCES = libdm-common.c $(interface)/libdm-iface.c +SOURCES = libdm-common.c libdm-file.c $(interface)/libdm-iface.c INCLUDES = -I$(interface) diff --git a/lib/ioctl/libdm-iface.c b/lib/ioctl/libdm-iface.c index 555cdf6..460a7d2 100644 --- a/lib/ioctl/libdm-iface.c +++ b/lib/ioctl/libdm-iface.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * @@ -13,22 +13,17 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "lib.h" #include "libdm-targets.h" #include "libdm-common.h" -#include "log.h" +#include "libdm-file.h" #ifdef DM_COMPAT # include "libdm-compat.h" #endif -#include -#include -#include -#include #include #include -#include -#include #include #include @@ -53,6 +48,13 @@ #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" + /* dm major version no for running kernel */ static int _dm_version = DM_VERSION_MAJOR; static int _log_suppress = 0; @@ -114,22 +116,144 @@ static void *_align(void *ptr, unsigned int a) return (void *) (((unsigned long) ptr + agn) & ~agn); } +static int _get_proc_number(const char *file, const char *name, + uint32_t *number) +{ + FILE *fl; + char nm[256]; + int c; + + if (!(fl = fopen(file, "r"))) { + log_error("%s: fopen failed: %s", file, strerror(errno)); + return 0; + } + + while (!feof(fl)) { + if (fscanf(fl, "%d %255s\n", number, &nm[0]) == 2) { + if (!strcmp(name, nm)) { + fclose(fl); + return 1; + } + } + do { + c = fgetc(fl); + } while (c != EOF && c != '\n'); + } + fclose(fl); + + log_error("%s: No entry for %s found", file, name); + return 0; +} + +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_error("%s: stat failed: %s", control, + strerror(errno)); + return 0; + } + + if (!S_ISCHR(buf.st_mode)) { + log_verbose("%s: Wrong inode type", control); + if (!unlink(control)) + return 0; + log_error("%s: unlink failed: %s", control, + strerror(errno)); + 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_error("%s: unlink failed: %s", control, + strerror(errno)); + 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 = 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_error("%s: mknod failed: %s", control, strerror(errno)); + return 0; + } + +#ifdef HAVE_SELINUX + if (!set_selinux_context(control)) { + stack; + return 0; + } +#endif + + return 1; +} + static int _open_control(void) { 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_error("%s: open failed: %s", control, strerror(errno)); - log_error("Is device-mapper driver missing from kernel?"); - return 0; + goto error; } return 1; + +error: + log_error("Failure to communicate with kernel device-mapper driver."); + return 0; } void dm_task_destroy(struct dm_task *dmt) diff --git a/lib/libdm-common.c b/lib/libdm-common.c index 2e9b05f..44f4dfe 100644 --- a/lib/libdm-common.c +++ b/lib/libdm-common.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * @@ -13,20 +13,14 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "lib.h" #include "libdm-targets.h" #include "libdm-common.h" #include "list.h" -#include "log.h" #include "kdev_t.h" -#include -#include #include -#include #include -#include -#include -#include #include #ifdef HAVE_SELINUX @@ -100,14 +94,14 @@ struct dm_task *dm_task_create(int type) { struct dm_task *dmt = malloc(sizeof(*dmt)); - if (!dm_check_version()) - return NULL; - if (!dmt) { log_error("dm_task_create: malloc(%d) failed", sizeof(*dmt)); return NULL; } + if (!dm_check_version()) + return NULL; + memset(dmt, 0, sizeof(*dmt)); dmt->type = type; @@ -205,7 +199,7 @@ int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size, } #ifdef HAVE_SELINUX -static int _set_selinux_context(const char *path) +int set_selinux_context(const char *path) { security_context_t scontext; @@ -270,7 +264,7 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor, } #ifdef HAVE_SELINUX - if (!_set_selinux_context(path)) + if (!set_selinux_context(path)) return 0; #endif diff --git a/lib/libdm-common.h.in b/lib/libdm-common.h.in index c2a97e9..5129e45 100644 --- a/lib/libdm-common.h.in +++ b/lib/libdm-common.h.in @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * @@ -28,6 +28,8 @@ int rm_dev_node(const char *dev_name); int rename_dev_node(const char *old_name, const char *new_name); void update_devs(void); +int set_selinux_context(const char *path); + #define DM_LIB_VERSION @DM_LIB_VERSION@ #endif diff --git a/lib/libdm-file.c b/lib/libdm-file.c new file mode 100644 index 0000000..5295b9e --- /dev/null +++ b/lib/libdm-file.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004-2005 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 General Public License v.2. + * + * You should have received a copy of the GNU 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-file.h" + +#include +#include +#include +#include + +static int _create_dir_recursive(const char *dir) +{ + char *orig, *s; + int rc; + + log_verbose("Creating directory \"%s\"", dir); + /* Create parent directories */ + orig = s = strdup(dir); + while ((s = strchr(s, '/')) != NULL) { + *s = '\0'; + if (*orig) { + rc = mkdir(orig, 0777); + if (rc < 0 && errno != EEXIST) { + log_error("%s: mkdir failed: %s", orig, + strerror(errno)); + free(orig); + return 0; + } + } + *s++ = '/'; + } + free(orig); + + /* Create final directory */ + rc = mkdir(dir, 0777); + if (rc < 0 && errno != EEXIST) { + log_error("%s: mkdir failed: %s", orig, + strerror(errno)); + return 0; + } + return 1; +} + +int create_dir(const char *dir) +{ + struct stat info; + + if (!*dir) + return 1; + + if (stat(dir, &info) < 0) + return _create_dir_recursive(dir); + + if (S_ISDIR(info.st_mode)) + return 1; + + log_error("Directory \"%s\" not found", dir); + return 0; +} + diff --git a/lib/libdm-file.h b/lib/libdm-file.h new file mode 100644 index 0000000..b2d48e2 --- /dev/null +++ b/lib/libdm-file.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004-2005 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 General Public License v.2. + * + * You should have received a copy of the GNU 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 + */ + +#ifndef LIB_DMFILE_H +#define LIB_DMFILE_H + +/* + * Create directory (recursively) if necessary. Return 1 + * if directory was successfully created (or already exists), else 0. + */ +int create_dir(const char *dir); + +#endif