mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
device-mapper: Fork libdm internally.
The device-mapper directory now holds a copy of libdm source. At the moment this code is identical to libdm. Over time code will migrate out to appropriate places (see doc/refactoring.txt). The libdm directory still exists, and contains the source for the libdevmapper shared library, which we will continue to ship (though not neccessarily update). All code using libdm should now use the version in device-mapper.
This commit is contained in:
parent
7f97c7ea9a
commit
ccc35e2647
@ -211,8 +211,7 @@ endif
|
||||
endif
|
||||
|
||||
include test/unit/Makefile
|
||||
|
||||
include device-mapper/Makefile
|
||||
include device_mapper/Makefile
|
||||
|
||||
ifneq ($(shell which ctags),)
|
||||
.PHONY: tags
|
||||
|
3
configure
vendored
3
configure
vendored
@ -15559,7 +15559,7 @@ _ACEOF
|
||||
|
||||
|
||||
################################################################################
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/Makefile lib/Makefile lib/locking/Makefile include/lvm-version.h libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile"
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl libdm/make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/Makefile lib/Makefile lib/locking/Makefile include/lvm-version.h libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
@ -16256,6 +16256,7 @@ do
|
||||
"include/configure.h") CONFIG_HEADERS="$CONFIG_HEADERS include/configure.h" ;;
|
||||
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
|
||||
"make.tmpl") CONFIG_FILES="$CONFIG_FILES make.tmpl" ;;
|
||||
"libdm/make.tmpl") CONFIG_FILES="$CONFIG_FILES libdm/make.tmpl" ;;
|
||||
"daemons/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/Makefile" ;;
|
||||
"daemons/clvmd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/clvmd/Makefile" ;;
|
||||
"daemons/cmirrord/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/cmirrord/Makefile" ;;
|
||||
|
@ -2088,6 +2088,7 @@ dnl -- keep utility scripts running properly
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
make.tmpl
|
||||
libdm/make.tmpl
|
||||
daemons/Makefile
|
||||
daemons/clvmd/Makefile
|
||||
daemons/cmirrord/Makefile
|
||||
|
@ -74,7 +74,7 @@ TARGETS = \
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS) -laio
|
||||
LIBS += $(LVMINTERNAL_LIBS) $(PTHREAD_LIBS) -laio
|
||||
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
INSTALL_TARGETS = \
|
||||
|
@ -26,7 +26,6 @@ TARGETS = cmirrord
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper
|
||||
LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
|
||||
CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
|
@ -12,8 +12,8 @@
|
||||
#ifndef _LVM_CLOG_CLUSTER_H
|
||||
#define _LVM_CLOG_CLUSTER_H
|
||||
|
||||
#include "libdm/misc/dm-log-userspace.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/misc/dm-log-userspace.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
|
||||
#define DM_ULOG_CHECKPOINT_READY 21
|
||||
|
@ -12,7 +12,7 @@
|
||||
#ifndef _LVM_CLOG_FUNCTIONS_H
|
||||
#define _LVM_CLOG_FUNCTIONS_H
|
||||
|
||||
#include "libdm/misc/dm-log-userspace.h"
|
||||
#include "device_mapper/misc/dm-log-userspace.h"
|
||||
#include "cluster.h"
|
||||
|
||||
#define LOG_RESUMED 1
|
||||
|
@ -57,13 +57,13 @@ all: device-mapper
|
||||
device-mapper: $(TARGETS)
|
||||
|
||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
||||
LIBS += -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += $(PTHREAD_LIBS)
|
||||
|
||||
dmeventd: $(LIB_SHARED) dmeventd.o
|
||||
$(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(top_builddir)/device_mapper/libdevice-mapper.a $(LIBS) -lm
|
||||
|
||||
dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
|
||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
|
||||
|
||||
@ -73,7 +73,6 @@ endif
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
-include $(top_builddir)/libdm/libdevmapper.cflow
|
||||
-include $(top_builddir)/lib/liblvm-internal.cflow
|
||||
-include $(top_builddir)/lib/liblvm2cmd.cflow
|
||||
-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
|
||||
|
@ -16,7 +16,7 @@
|
||||
* dmeventd - dm event daemon to monitor active mapped devices
|
||||
*/
|
||||
|
||||
#include "libdm/misc/dm-logging.h"
|
||||
#include "device_mapper/misc/dm-logging.h"
|
||||
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "dmeventd.h"
|
||||
|
@ -12,10 +12,11 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libdm/misc/dm-logging.h"
|
||||
#include "libdm/misc/dmlib.h"
|
||||
#include "device_mapper/misc/dm-logging.h"
|
||||
#include "device_mapper/misc/dmlib.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "dmeventd.h"
|
||||
#include "lib/misc/intl.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
@ -25,6 +26,7 @@
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
#include <pthread.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int _debug_level = 0;
|
||||
static int _use_syslog = 0;
|
||||
|
@ -8,4 +8,3 @@ Description: device-mapper event library
|
||||
Version: @DM_LIB_PATCHLEVEL@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -ldevmapper-event
|
||||
Requires.private: devmapper
|
||||
|
@ -24,7 +24,7 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += @LVM2CMD_LIB@ $(PTHREAD_LIBS)
|
||||
|
||||
install_lvm2: install_lib_shared
|
||||
|
||||
|
@ -30,7 +30,7 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
LIBS += -ldevmapper-event-lvm2
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
|
@ -29,7 +29,7 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
LIBS += -ldevmapper-event-lvm2
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
|
@ -26,7 +26,7 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
LIBS += -ldevmapper-event-lvm2
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
|
@ -29,7 +29,7 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
LIBS += -ldevmapper-event-lvm2
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
|
@ -35,13 +35,12 @@ all: device-mapper
|
||||
device-mapper: $(TARGETS)
|
||||
|
||||
CFLAGS_dmfilemapd.o += $(EXTRA_EXEC_CFLAGS)
|
||||
LIBS += -ldevmapper
|
||||
|
||||
dmfilemapd: $(LIB_SHARED) dmfilemapd.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
|
||||
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS)
|
||||
|
||||
dmfilemapd.static: $(LIB_STATIC) dmfilemapd.o $(interfacebuilddir)/libdevmapper.a
|
||||
dmfilemapd.static: $(LIB_STATIC) dmfilemapd.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L$(interfacebuilddir) \
|
||||
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS) $(STATIC_LIBS)
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "libdm/misc/dm-logging.h"
|
||||
#include "device_mapper/misc/dm-logging.h"
|
||||
|
||||
#include "lib/config/defaults.h"
|
||||
|
||||
|
@ -32,15 +32,17 @@ CFLAGS_lvmetactl.o += $(EXTRA_EXEC_CFLAGS)
|
||||
CFLAGS_lvmetad-core.o += $(EXTRA_EXEC_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) $(PTHREAD_LIBS) -lm
|
||||
|
||||
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) -ldaemonserver $(LIBS)
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a \
|
||||
$(top_builddir)/device_mapper/libdevice-mapper.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(top_builddir)/device_mapper/libdevice-mapper.a -ldaemonserver $(LIBS)
|
||||
|
||||
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LIBS)
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a \
|
||||
$(top_builddir)/device_mapper/libdevice-mapper.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(top_builddir)/device_mapper/libdevice-mapper.a $(LIBS)
|
||||
|
||||
CLEAN_TARGETS += lvmetactl.o
|
||||
|
||||
|
@ -36,7 +36,7 @@ include $(top_builddir)/make.tmpl
|
||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
||||
|
||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "lvm-version.h"
|
||||
#include "daemons/lvmetad/lvmetad-client.h"
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
#include "libdm/misc/dm-ioctl.h"
|
||||
#include "device_mapper/misc/dm-ioctl.h"
|
||||
|
||||
/* #include <assert.h> */
|
||||
#include <errno.h>
|
||||
|
@ -30,7 +30,7 @@ include $(top_builddir)/make.tmpl
|
||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(DAEMON_LIBS) -ldaemonserver -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += $(DAEMON_LIBS) -ldaemonserver $(PTHREAD_LIBS)
|
||||
|
||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
|
@ -1,20 +0,0 @@
|
||||
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
DM_SOURCE=\
|
||||
device-mapper/vdo/status.c
|
||||
|
||||
DM_DEPENDS=$(subst .c,.d,$(DM_SOURCE))
|
||||
DM_OBJECTS=$(DM_SOURCE:%.c=%.o)
|
||||
CLEAN_TARGETS+=$(DM_DEPENDS) $(DM_OBJECTS)
|
||||
|
||||
-include $(DM_DEPENDS)
|
46
device_mapper/Makefile
Normal file
46
device_mapper/Makefile
Normal file
@ -0,0 +1,46 @@
|
||||
# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
DEVICE_MAPPER_SOURCE=\
|
||||
device_mapper/datastruct/bitset.c \
|
||||
device_mapper/datastruct/hash.c \
|
||||
device_mapper/datastruct/list.c \
|
||||
device_mapper/libdm-common.c \
|
||||
device_mapper/libdm-config.c \
|
||||
device_mapper/libdm-deptree.c \
|
||||
device_mapper/libdm-file.c \
|
||||
device_mapper/libdm-report.c \
|
||||
device_mapper/libdm-stats.c \
|
||||
device_mapper/libdm-string.c \
|
||||
device_mapper/libdm-targets.c \
|
||||
device_mapper/libdm-timestamp.c \
|
||||
device_mapper/mm/dbg_malloc.c \
|
||||
device_mapper/mm/pool.c \
|
||||
device_mapper/regex/matcher.c \
|
||||
device_mapper/regex/parse_rx.c \
|
||||
device_mapper/regex/ttree.c \
|
||||
device_mapper/ioctl/libdm-iface.c
|
||||
|
||||
DEVICE_MAPPER_DEPENDS=$(subst .c,.d,$(DEVICE_MAPPER_SOURCE))
|
||||
DEVICE_MAPPER_OBJECTS=$(subst .c,.o,$(DEVICE_MAPPER_SOURCE))
|
||||
CLEAN_TARGETS+=$(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS)
|
||||
|
||||
-include $(DEVICE_MAPPER_DEPENDS)
|
||||
|
||||
$(DEVICE_MAPPER_OBJECTS): INCLUDES+=-Idevice_mapper/
|
||||
|
||||
device_mapper/libdevice-mapper.a: $(DEVICE_MAPPER_OBJECTS)
|
||||
@echo " [AR] $@"
|
||||
$(Q) $(RM) $@
|
||||
$(Q) $(AR) rsv $@ $(DEVICE_MAPPER_OBJECTS) > /dev/null
|
||||
|
||||
CLEAN_TARGETS+=device_mapper/libdevice-mapper.a
|
258
device_mapper/datastruct/bitset.c
Normal file
258
device_mapper/datastruct/bitset.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/* FIXME: calculate this. */
|
||||
#define INT_SHIFT 5
|
||||
|
||||
dm_bitset_t dm_bitset_create(struct dm_pool *mem, unsigned num_bits)
|
||||
{
|
||||
unsigned n = (num_bits / DM_BITS_PER_INT) + 2;
|
||||
size_t size = sizeof(int) * n;
|
||||
dm_bitset_t bs;
|
||||
|
||||
if (mem)
|
||||
bs = dm_pool_zalloc(mem, size);
|
||||
else
|
||||
bs = dm_zalloc(size);
|
||||
|
||||
if (!bs)
|
||||
return NULL;
|
||||
|
||||
*bs = num_bits;
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
void dm_bitset_destroy(dm_bitset_t bs)
|
||||
{
|
||||
dm_free(bs);
|
||||
}
|
||||
|
||||
int dm_bitset_equal(dm_bitset_t in1, dm_bitset_t in2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = (in1[0] / DM_BITS_PER_INT) + 1; i; i--)
|
||||
if (in1[i] != in2[i])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_bit_and(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = (in1[0] / DM_BITS_PER_INT) + 1; i; i--)
|
||||
out[i] = in1[i] & in2[i];
|
||||
}
|
||||
void dm_bit_union(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2)
|
||||
{
|
||||
int i;
|
||||
for (i = (in1[0] / DM_BITS_PER_INT) + 1; i; i--)
|
||||
out[i] = in1[i] | in2[i];
|
||||
}
|
||||
|
||||
static int _test_word(uint32_t test, int bit)
|
||||
{
|
||||
uint32_t tb = test >> bit;
|
||||
|
||||
return (tb ? ffs(tb) + bit - 1 : -1);
|
||||
}
|
||||
|
||||
static int _test_word_rev(uint32_t test, int bit)
|
||||
{
|
||||
uint32_t tb = test << (DM_BITS_PER_INT - 1 - bit);
|
||||
|
||||
return (tb ? bit - clz(tb) : -1);
|
||||
}
|
||||
|
||||
int dm_bit_get_next(dm_bitset_t bs, int last_bit)
|
||||
{
|
||||
int bit, word;
|
||||
uint32_t test;
|
||||
|
||||
last_bit++; /* otherwise we'll return the same bit again */
|
||||
|
||||
/*
|
||||
* bs[0] holds number of bits
|
||||
*/
|
||||
while (last_bit < (int) bs[0]) {
|
||||
word = last_bit >> INT_SHIFT;
|
||||
test = bs[word + 1];
|
||||
bit = last_bit & (DM_BITS_PER_INT - 1);
|
||||
|
||||
if ((bit = _test_word(test, bit)) >= 0)
|
||||
return (word * DM_BITS_PER_INT) + bit;
|
||||
|
||||
last_bit = last_bit - (last_bit & (DM_BITS_PER_INT - 1)) +
|
||||
DM_BITS_PER_INT;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dm_bit_get_prev(dm_bitset_t bs, int last_bit)
|
||||
{
|
||||
int bit, word;
|
||||
uint32_t test;
|
||||
|
||||
last_bit--; /* otherwise we'll return the same bit again */
|
||||
|
||||
/*
|
||||
* bs[0] holds number of bits
|
||||
*/
|
||||
while (last_bit >= 0) {
|
||||
word = last_bit >> INT_SHIFT;
|
||||
test = bs[word + 1];
|
||||
bit = last_bit & (DM_BITS_PER_INT - 1);
|
||||
|
||||
if ((bit = _test_word_rev(test, bit)) >= 0)
|
||||
return (word * DM_BITS_PER_INT) + bit;
|
||||
|
||||
last_bit = (last_bit & ~(DM_BITS_PER_INT - 1)) - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dm_bit_get_first(dm_bitset_t bs)
|
||||
{
|
||||
return dm_bit_get_next(bs, -1);
|
||||
}
|
||||
|
||||
int dm_bit_get_last(dm_bitset_t bs)
|
||||
{
|
||||
return dm_bit_get_prev(bs, bs[0] + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Based on the Linux kernel __bitmap_parselist from lib/bitmap.c
|
||||
*/
|
||||
dm_bitset_t dm_bitset_parse_list(const char *str, struct dm_pool *mem,
|
||||
size_t min_num_bits)
|
||||
{
|
||||
unsigned a, b;
|
||||
int c, old_c, totaldigits, ndigits, nmaskbits;
|
||||
int at_start, in_range;
|
||||
dm_bitset_t mask = NULL;
|
||||
const char *start = str;
|
||||
size_t len;
|
||||
|
||||
scan:
|
||||
len = strlen(str);
|
||||
totaldigits = c = 0;
|
||||
nmaskbits = 0;
|
||||
do {
|
||||
at_start = 1;
|
||||
in_range = 0;
|
||||
a = b = 0;
|
||||
ndigits = totaldigits;
|
||||
|
||||
/* Get the next value or range of values */
|
||||
while (len) {
|
||||
old_c = c;
|
||||
c = *str++;
|
||||
len--;
|
||||
if (isspace(c))
|
||||
continue;
|
||||
|
||||
/* A '\0' or a ',' signal the end of a value or range */
|
||||
if (c == '\0' || c == ',')
|
||||
break;
|
||||
/*
|
||||
* whitespaces between digits are not allowed,
|
||||
* but it's ok if whitespaces are on head or tail.
|
||||
* when old_c is whilespace,
|
||||
* if totaldigits == ndigits, whitespace is on head.
|
||||
* if whitespace is on tail, it should not run here.
|
||||
* as c was ',' or '\0',
|
||||
* the last code line has broken the current loop.
|
||||
*/
|
||||
if ((totaldigits != ndigits) && isspace(old_c))
|
||||
goto_bad;
|
||||
|
||||
if (c == '-') {
|
||||
if (at_start || in_range)
|
||||
goto_bad;
|
||||
b = 0;
|
||||
in_range = 1;
|
||||
at_start = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isdigit(c))
|
||||
goto_bad;
|
||||
|
||||
b = b * 10 + (c - '0');
|
||||
if (!in_range)
|
||||
a = b;
|
||||
at_start = 0;
|
||||
totaldigits++;
|
||||
}
|
||||
if (ndigits == totaldigits)
|
||||
continue;
|
||||
/* if no digit is after '-', it's wrong */
|
||||
if (at_start && in_range)
|
||||
goto_bad;
|
||||
if (!(a <= b))
|
||||
goto_bad;
|
||||
if (b >= nmaskbits)
|
||||
nmaskbits = b + 1;
|
||||
while ((a <= b) && mask) {
|
||||
dm_bit_set(mask, a);
|
||||
a++;
|
||||
}
|
||||
} while (len && c == ',');
|
||||
|
||||
if (!mask) {
|
||||
if (min_num_bits && (nmaskbits < min_num_bits))
|
||||
nmaskbits = min_num_bits;
|
||||
|
||||
if (!(mask = dm_bitset_create(mem, nmaskbits)))
|
||||
goto_bad;
|
||||
str = start;
|
||||
goto scan;
|
||||
}
|
||||
|
||||
return mask;
|
||||
bad:
|
||||
if (mask) {
|
||||
if (mem)
|
||||
dm_pool_free(mem, mask);
|
||||
else
|
||||
dm_bitset_destroy(mask);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/*
|
||||
* Maintain backward compatibility with older versions that did not
|
||||
* accept a 'min_num_bits' argument to dm_bitset_parse_list().
|
||||
*/
|
||||
dm_bitset_t dm_bitset_parse_list_v1_02_129(const char *str, struct dm_pool *mem);
|
||||
dm_bitset_t dm_bitset_parse_list_v1_02_129(const char *str, struct dm_pool *mem)
|
||||
{
|
||||
return dm_bitset_parse_list(str, mem, 0);
|
||||
}
|
||||
|
||||
#else /* if defined(__GNUC__) */
|
||||
|
||||
#endif
|
392
device_mapper/datastruct/hash.c
Normal file
392
device_mapper/datastruct/hash.c
Normal file
@ -0,0 +1,392 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
|
||||
struct dm_hash_node {
|
||||
struct dm_hash_node *next;
|
||||
void *data;
|
||||
unsigned data_len;
|
||||
unsigned keylen;
|
||||
char key[0];
|
||||
};
|
||||
|
||||
struct dm_hash_table {
|
||||
unsigned num_nodes;
|
||||
unsigned num_slots;
|
||||
struct dm_hash_node **slots;
|
||||
};
|
||||
|
||||
/* Permutation of the Integers 0 through 255 */
|
||||
static unsigned char _nums[] = {
|
||||
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
|
||||
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
|
||||
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
|
||||
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
|
||||
144,
|
||||
176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
|
||||
178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
|
||||
221,
|
||||
102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
|
||||
166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
|
||||
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
|
||||
194,
|
||||
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
|
||||
139,
|
||||
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
|
||||
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
|
||||
43,
|
||||
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
|
||||
71,
|
||||
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
|
||||
109,
|
||||
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
|
||||
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
|
||||
209
|
||||
};
|
||||
|
||||
static struct dm_hash_node *_create_node(const char *str, unsigned len)
|
||||
{
|
||||
struct dm_hash_node *n = dm_malloc(sizeof(*n) + len);
|
||||
|
||||
if (n) {
|
||||
memcpy(n->key, str, len);
|
||||
n->keylen = len;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned long _hash(const char *str, unsigned len)
|
||||
{
|
||||
unsigned long h = 0, g;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
h <<= 4;
|
||||
h += _nums[(unsigned char) *str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
if (g) {
|
||||
h ^= g >> 16u;
|
||||
h ^= g >> 5u;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
struct dm_hash_table *dm_hash_create(unsigned size_hint)
|
||||
{
|
||||
size_t len;
|
||||
unsigned new_size = 16u;
|
||||
struct dm_hash_table *hc = dm_zalloc(sizeof(*hc));
|
||||
|
||||
if (!hc)
|
||||
return_0;
|
||||
|
||||
/* round size hint up to a power of two */
|
||||
while (new_size < size_hint)
|
||||
new_size = new_size << 1;
|
||||
|
||||
hc->num_slots = new_size;
|
||||
len = sizeof(*(hc->slots)) * new_size;
|
||||
if (!(hc->slots = dm_zalloc(len)))
|
||||
goto_bad;
|
||||
|
||||
return hc;
|
||||
|
||||
bad:
|
||||
dm_free(hc->slots);
|
||||
dm_free(hc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _free_nodes(struct dm_hash_table *t)
|
||||
{
|
||||
struct dm_hash_node *c, *n;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
for (c = t->slots[i]; c; c = n) {
|
||||
n = c->next;
|
||||
dm_free(c);
|
||||
}
|
||||
}
|
||||
|
||||
void dm_hash_destroy(struct dm_hash_table *t)
|
||||
{
|
||||
_free_nodes(t);
|
||||
dm_free(t->slots);
|
||||
dm_free(t);
|
||||
}
|
||||
|
||||
static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len)
|
||||
{
|
||||
unsigned h = _hash(key, len) & (t->num_slots - 1);
|
||||
struct dm_hash_node **c;
|
||||
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||
if ((*c)->keylen != len)
|
||||
continue;
|
||||
|
||||
if (!memcmp(key, (*c)->key, len))
|
||||
break;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len)
|
||||
{
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
return *c ? (*c)->data : 0;
|
||||
}
|
||||
|
||||
int dm_hash_insert_binary(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len, void *data)
|
||||
{
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
if (*c)
|
||||
(*c)->data = data;
|
||||
else {
|
||||
struct dm_hash_node *n = _create_node(key, len);
|
||||
|
||||
if (!n)
|
||||
return 0;
|
||||
|
||||
n->data = data;
|
||||
n->next = 0;
|
||||
*c = n;
|
||||
t->num_nodes++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_hash_remove_binary(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len)
|
||||
{
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
if (*c) {
|
||||
struct dm_hash_node *old = *c;
|
||||
*c = (*c)->next;
|
||||
dm_free(old);
|
||||
t->num_nodes--;
|
||||
}
|
||||
}
|
||||
|
||||
void *dm_hash_lookup(struct dm_hash_table *t, const char *key)
|
||||
{
|
||||
return dm_hash_lookup_binary(t, key, strlen(key) + 1);
|
||||
}
|
||||
|
||||
int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data)
|
||||
{
|
||||
return dm_hash_insert_binary(t, key, strlen(key) + 1, data);
|
||||
}
|
||||
|
||||
void dm_hash_remove(struct dm_hash_table *t, const char *key)
|
||||
{
|
||||
dm_hash_remove_binary(t, key, strlen(key) + 1);
|
||||
}
|
||||
|
||||
static struct dm_hash_node **_find_str_with_val(struct dm_hash_table *t,
|
||||
const void *key, const void *val,
|
||||
uint32_t len, uint32_t val_len)
|
||||
{
|
||||
struct dm_hash_node **c;
|
||||
unsigned h;
|
||||
|
||||
h = _hash(key, len) & (t->num_slots - 1);
|
||||
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||
if ((*c)->keylen != len)
|
||||
continue;
|
||||
|
||||
if (!memcmp(key, (*c)->key, len) && (*c)->data) {
|
||||
if (((*c)->data_len == val_len) &&
|
||||
!memcmp(val, (*c)->data, val_len))
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
|
||||
const void *val, uint32_t val_len)
|
||||
{
|
||||
struct dm_hash_node *n;
|
||||
struct dm_hash_node *first;
|
||||
int len = strlen(key) + 1;
|
||||
unsigned h;
|
||||
|
||||
n = _create_node(key, len);
|
||||
if (!n)
|
||||
return 0;
|
||||
|
||||
n->data = (void *)val;
|
||||
n->data_len = val_len;
|
||||
|
||||
h = _hash(key, len) & (t->num_slots - 1);
|
||||
|
||||
first = t->slots[h];
|
||||
|
||||
if (first)
|
||||
n->next = first;
|
||||
else
|
||||
n->next = 0;
|
||||
t->slots[h] = n;
|
||||
|
||||
t->num_nodes++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look through multiple entries with the same key for one that has a
|
||||
* matching val and return that. If none have maching val, return NULL.
|
||||
*/
|
||||
void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key,
|
||||
const void *val, uint32_t val_len)
|
||||
{
|
||||
struct dm_hash_node **c;
|
||||
|
||||
c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len);
|
||||
|
||||
return (c && *c) ? (*c)->data : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look through multiple entries with the same key for one that has a
|
||||
* matching val and remove that.
|
||||
*/
|
||||
void dm_hash_remove_with_val(struct dm_hash_table *t, const char *key,
|
||||
const void *val, uint32_t val_len)
|
||||
{
|
||||
struct dm_hash_node **c;
|
||||
|
||||
c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len);
|
||||
|
||||
if (c && *c) {
|
||||
struct dm_hash_node *old = *c;
|
||||
*c = (*c)->next;
|
||||
dm_free(old);
|
||||
t->num_nodes--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the value for a key and count how many
|
||||
* entries have the same key.
|
||||
*
|
||||
* If no entries have key, return NULL and set count to 0.
|
||||
*
|
||||
* If one entry has the key, the function returns the val,
|
||||
* and sets count to 1.
|
||||
*
|
||||
* If N entries have the key, the function returns the val
|
||||
* from the first entry, and sets count to N.
|
||||
*/
|
||||
void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *count)
|
||||
{
|
||||
struct dm_hash_node **c;
|
||||
struct dm_hash_node **c1 = NULL;
|
||||
uint32_t len = strlen(key) + 1;
|
||||
unsigned h;
|
||||
|
||||
*count = 0;
|
||||
|
||||
h = _hash(key, len) & (t->num_slots - 1);
|
||||
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||
if ((*c)->keylen != len)
|
||||
continue;
|
||||
|
||||
if (!memcmp(key, (*c)->key, len)) {
|
||||
(*count)++;
|
||||
if (!c1)
|
||||
c1 = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c1)
|
||||
return NULL;
|
||||
else
|
||||
return *c1 ? (*c1)->data : 0;
|
||||
}
|
||||
|
||||
unsigned dm_hash_get_num_entries(struct dm_hash_table *t)
|
||||
{
|
||||
return t->num_nodes;
|
||||
}
|
||||
|
||||
void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
|
||||
{
|
||||
struct dm_hash_node *c, *n;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
for (c = t->slots[i]; c; c = n) {
|
||||
n = c->next;
|
||||
f(c->data);
|
||||
}
|
||||
}
|
||||
|
||||
void dm_hash_wipe(struct dm_hash_table *t)
|
||||
{
|
||||
_free_nodes(t);
|
||||
memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots);
|
||||
t->num_nodes = 0u;
|
||||
}
|
||||
|
||||
char *dm_hash_get_key(struct dm_hash_table *t __attribute__((unused)),
|
||||
struct dm_hash_node *n)
|
||||
{
|
||||
return n->key;
|
||||
}
|
||||
|
||||
void *dm_hash_get_data(struct dm_hash_table *t __attribute__((unused)),
|
||||
struct dm_hash_node *n)
|
||||
{
|
||||
return n->data;
|
||||
}
|
||||
|
||||
static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s)
|
||||
{
|
||||
struct dm_hash_node *c = NULL;
|
||||
unsigned i;
|
||||
|
||||
for (i = s; i < t->num_slots && !c; i++)
|
||||
c = t->slots[i];
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t)
|
||||
{
|
||||
return _next_slot(t, 0);
|
||||
}
|
||||
|
||||
struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||
{
|
||||
unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
|
||||
|
||||
return n->next ? n->next : _next_slot(t, h + 1);
|
||||
}
|
168
device_mapper/datastruct/list.c
Normal file
168
device_mapper/datastruct/list.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* Initialise a list before use.
|
||||
* The list head's next and previous pointers point back to itself.
|
||||
*/
|
||||
void dm_list_init(struct dm_list *head)
|
||||
{
|
||||
head->n = head->p = head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element before 'head'.
|
||||
* If 'head' is the list head, this adds an element to the end of the list.
|
||||
*/
|
||||
void dm_list_add(struct dm_list *head, struct dm_list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head;
|
||||
elem->p = head->p;
|
||||
|
||||
head->p->n = elem;
|
||||
head->p = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element after 'head'.
|
||||
* If 'head' is the list head, this adds an element to the front of the list.
|
||||
*/
|
||||
void dm_list_add_h(struct dm_list *head, struct dm_list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head->n;
|
||||
elem->p = head;
|
||||
|
||||
head->n->p = elem;
|
||||
head->n = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete an element from its list.
|
||||
* Note that this doesn't change the element itself - it may still be safe
|
||||
* to follow its pointers.
|
||||
*/
|
||||
void dm_list_del(struct dm_list *elem)
|
||||
{
|
||||
elem->n->p = elem->p;
|
||||
elem->p->n = elem->n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an element from existing list and insert before 'head'.
|
||||
*/
|
||||
void dm_list_move(struct dm_list *head, struct dm_list *elem)
|
||||
{
|
||||
dm_list_del(elem);
|
||||
dm_list_add(head, elem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the list empty?
|
||||
*/
|
||||
int dm_list_empty(const struct dm_list *head)
|
||||
{
|
||||
return head->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the first element of the list?
|
||||
*/
|
||||
int dm_list_start(const struct dm_list *head, const struct dm_list *elem)
|
||||
{
|
||||
return elem->p == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the last element of the list?
|
||||
*/
|
||||
int dm_list_end(const struct dm_list *head, const struct dm_list *elem)
|
||||
{
|
||||
return elem->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return first element of the list or NULL if empty
|
||||
*/
|
||||
struct dm_list *dm_list_first(const struct dm_list *head)
|
||||
{
|
||||
return (dm_list_empty(head) ? NULL : head->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return last element of the list or NULL if empty
|
||||
*/
|
||||
struct dm_list *dm_list_last(const struct dm_list *head)
|
||||
{
|
||||
return (dm_list_empty(head) ? NULL : head->p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the previous element of the list, or NULL if we've reached the start.
|
||||
*/
|
||||
struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem)
|
||||
{
|
||||
return (dm_list_start(head, elem) ? NULL : elem->p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next element of the list, or NULL if we've reached the end.
|
||||
*/
|
||||
struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem)
|
||||
{
|
||||
return (dm_list_end(head, elem) ? NULL : elem->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of elements in a list by walking it.
|
||||
*/
|
||||
unsigned int dm_list_size(const struct dm_list *head)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
const struct dm_list *v;
|
||||
|
||||
dm_list_iterate(v, head)
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Join two lists together.
|
||||
* This moves all the elements of the list 'head1' to the end of the list
|
||||
* 'head', leaving 'head1' empty.
|
||||
*/
|
||||
void dm_list_splice(struct dm_list *head, struct dm_list *head1)
|
||||
{
|
||||
assert(head->n);
|
||||
assert(head1->n);
|
||||
|
||||
if (dm_list_empty(head1))
|
||||
return;
|
||||
|
||||
head1->p->n = head;
|
||||
head1->n->p = head->p;
|
||||
|
||||
head->p->n = head1->n;
|
||||
head->p = head1->p;
|
||||
|
||||
dm_list_init(head1);
|
||||
}
|
2196
device_mapper/ioctl/libdm-iface.c
Normal file
2196
device_mapper/ioctl/libdm-iface.c
Normal file
File diff suppressed because it is too large
Load Diff
88
device_mapper/ioctl/libdm-targets.h
Normal file
88
device_mapper/ioctl/libdm-targets.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef LIB_DMTARGETS_H
|
||||
#define LIB_DMTARGETS_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
struct dm_ioctl;
|
||||
|
||||
struct target {
|
||||
uint64_t start;
|
||||
uint64_t length;
|
||||
char *type;
|
||||
char *params;
|
||||
|
||||
struct target *next;
|
||||
};
|
||||
|
||||
struct dm_task {
|
||||
int type;
|
||||
char *dev_name;
|
||||
char *mangled_dev_name;
|
||||
|
||||
struct target *head, *tail;
|
||||
|
||||
int read_only;
|
||||
uint32_t event_nr;
|
||||
int major;
|
||||
int minor;
|
||||
int allow_default_major_fallback;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
mode_t mode;
|
||||
uint32_t read_ahead;
|
||||
uint32_t read_ahead_flags;
|
||||
union {
|
||||
struct dm_ioctl *v4;
|
||||
} dmi;
|
||||
char *newname;
|
||||
char *message;
|
||||
char *geometry;
|
||||
uint64_t sector;
|
||||
int no_flush;
|
||||
int no_open_count;
|
||||
int skip_lockfs;
|
||||
int query_inactive_table;
|
||||
int suppress_identical_reload;
|
||||
dm_add_node_t add_node;
|
||||
uint64_t existing_table_size;
|
||||
int cookie_set;
|
||||
int new_uuid;
|
||||
int secure_data;
|
||||
int retry_remove;
|
||||
int deferred_remove;
|
||||
int enable_checks;
|
||||
int expected_errno;
|
||||
int ioctl_errno;
|
||||
|
||||
int record_timestamp;
|
||||
|
||||
char *uuid;
|
||||
char *mangled_uuid;
|
||||
};
|
||||
|
||||
struct cmd_data {
|
||||
const char *name;
|
||||
const unsigned cmd;
|
||||
const int version[3];
|
||||
};
|
||||
|
||||
int dm_check_version(void);
|
||||
uint64_t dm_task_get_existing_table_size(struct dm_task *dmt);
|
||||
|
||||
#endif
|
3755
device_mapper/libdevmapper.h
Normal file
3755
device_mapper/libdevmapper.h
Normal file
File diff suppressed because it is too large
Load Diff
2691
device_mapper/libdm-common.c
Normal file
2691
device_mapper/libdm-common.c
Normal file
File diff suppressed because it is too large
Load Diff
58
device_mapper/libdm-common.h
Normal file
58
device_mapper/libdm-common.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef LIB_DMCOMMON_H
|
||||
#define LIB_DMCOMMON_H
|
||||
|
||||
#include "libdevmapper.h"
|
||||
|
||||
#define DM_DEFAULT_NAME_MANGLING_MODE_ENV_VAR_NAME "DM_DEFAULT_NAME_MANGLING_MODE"
|
||||
|
||||
#define DEV_NAME(dmt) (dmt->mangled_dev_name ? : dmt->dev_name)
|
||||
#define DEV_UUID(DMT) (dmt->mangled_uuid ? : dmt->uuid)
|
||||
|
||||
int mangle_string(const char *str, const char *str_name, size_t len,
|
||||
char *buf, size_t buf_len, dm_string_mangling_t mode);
|
||||
|
||||
int unmangle_string(const char *str, const char *str_name, size_t len,
|
||||
char *buf, size_t buf_len, dm_string_mangling_t mode);
|
||||
|
||||
int check_multiple_mangled_string_allowed(const char *str, const char *str_name,
|
||||
dm_string_mangling_t mode);
|
||||
|
||||
struct target *create_target(uint64_t start,
|
||||
uint64_t len,
|
||||
const char *type, const char *params);
|
||||
|
||||
int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major,
|
||||
uid_t uid, gid_t gid, mode_t mode, int check_udev, unsigned rely_on_udev);
|
||||
int rm_dev_node(const char *dev_name, int check_udev, unsigned rely_on_udev);
|
||||
int rename_dev_node(const char *old_name, const char *new_name,
|
||||
int check_udev, unsigned rely_on_udev);
|
||||
int get_dev_node_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,
|
||||
uint32_t *read_ahead);
|
||||
int set_dev_node_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,
|
||||
uint32_t read_ahead, uint32_t read_ahead_flags);
|
||||
void update_devs(void);
|
||||
void selinux_release(void);
|
||||
|
||||
void inc_suspended(void);
|
||||
void dec_suspended(void);
|
||||
|
||||
int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s);
|
||||
|
||||
int get_uname_version(unsigned *major, unsigned *minor, unsigned *release);
|
||||
|
||||
#endif
|
1486
device_mapper/libdm-config.c
Normal file
1486
device_mapper/libdm-config.c
Normal file
File diff suppressed because it is too large
Load Diff
3853
device_mapper/libdm-deptree.c
Normal file
3853
device_mapper/libdm-deptree.c
Normal file
File diff suppressed because it is too large
Load Diff
261
device_mapper/libdm-file.c
Normal file
261
device_mapper/libdm-file.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int _is_dir(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st) < 0) {
|
||||
log_sys_error("stat", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
log_error("Existing path %s is not "
|
||||
"a directory.", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _create_dir_recursive(const char *dir)
|
||||
{
|
||||
char *orig, *s;
|
||||
int rc, r = 0;
|
||||
|
||||
log_verbose("Creating directory \"%s\"", dir);
|
||||
/* Create parent directories */
|
||||
orig = s = dm_strdup(dir);
|
||||
if (!s) {
|
||||
log_error("Failed to duplicate directory name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((s = strchr(s, '/')) != NULL) {
|
||||
*s = '\0';
|
||||
if (*orig) {
|
||||
rc = mkdir(orig, 0777);
|
||||
if (rc < 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (!_is_dir(orig))
|
||||
goto_out;
|
||||
} else {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", orig);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
*s++ = '/';
|
||||
}
|
||||
|
||||
/* Create final directory */
|
||||
rc = mkdir(dir, 0777);
|
||||
if (rc < 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (!_is_dir(dir))
|
||||
goto_out;
|
||||
} else {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", orig);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
dm_free(orig);
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_create_dir(const char *dir)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
if (!*dir)
|
||||
return 1;
|
||||
|
||||
if (stat(dir, &info) == 0 && S_ISDIR(info.st_mode))
|
||||
return 1;
|
||||
|
||||
if (!_create_dir_recursive(dir))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_is_empty_dir(const char *dir)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
DIR *d;
|
||||
|
||||
if (!(d = opendir(dir))) {
|
||||
log_sys_error("opendir", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((dirent = readdir(d)))
|
||||
if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, ".."))
|
||||
break;
|
||||
|
||||
if (closedir(d))
|
||||
log_sys_error("closedir", dir);
|
||||
|
||||
return dirent ? 0 : 1;
|
||||
}
|
||||
|
||||
int dm_fclose(FILE *stream)
|
||||
{
|
||||
int prev_fail = ferror(stream);
|
||||
int fclose_fail = fclose(stream);
|
||||
|
||||
/* If there was a previous failure, but fclose succeeded,
|
||||
clear errno, since ferror does not set it, and its value
|
||||
may be unrelated to the ferror-reported failure. */
|
||||
if (prev_fail && !fclose_fail)
|
||||
errno = 0;
|
||||
|
||||
return prev_fail || fclose_fail ? EOF : 0;
|
||||
}
|
||||
|
||||
int dm_create_lockfile(const char *lockfile)
|
||||
{
|
||||
int fd, value;
|
||||
size_t bufferlen;
|
||||
ssize_t write_out;
|
||||
struct flock lock;
|
||||
char buffer[50];
|
||||
int retries = 0;
|
||||
|
||||
if ((fd = open(lockfile, O_CREAT | O_WRONLY,
|
||||
(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) {
|
||||
log_error("Cannot open lockfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_start = 0;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_len = 0;
|
||||
retry_fcntl:
|
||||
if (fcntl(fd, F_SETLK, &lock) < 0) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
goto retry_fcntl;
|
||||
case EACCES:
|
||||
case EAGAIN:
|
||||
if (retries == 20) {
|
||||
log_error("Cannot lock lockfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
break;
|
||||
} else {
|
||||
++ retries;
|
||||
usleep(1000);
|
||||
goto retry_fcntl;
|
||||
}
|
||||
default:
|
||||
log_error("process is already running");
|
||||
}
|
||||
|
||||
goto fail_close;
|
||||
}
|
||||
|
||||
if (ftruncate(fd, 0) < 0) {
|
||||
log_error("Cannot truncate pidfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%u\n", getpid());
|
||||
|
||||
bufferlen = strlen(buffer);
|
||||
write_out = write(fd, buffer, bufferlen);
|
||||
|
||||
if ((write_out < 0) || (write_out == 0 && errno)) {
|
||||
log_error("Cannot write pid to pidfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
|
||||
if ((write_out == 0) || ((size_t)write_out < bufferlen)) {
|
||||
log_error("Cannot write pid to pidfile [%s], shortwrite of"
|
||||
"[%" PRIsize_t "] bytes, expected [%" PRIsize_t "]\n",
|
||||
lockfile, write_out, bufferlen);
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
|
||||
if ((value = fcntl(fd, F_GETFD, 0)) < 0) {
|
||||
log_error("Cannot get close-on-exec flag from pidfile [%s], "
|
||||
"error was [%s]", lockfile, strerror(errno));
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
value |= FD_CLOEXEC;
|
||||
if (fcntl(fd, F_SETFD, value) < 0) {
|
||||
log_error("Cannot set close-on-exec flag from pidfile [%s], "
|
||||
"error was [%s]", lockfile, strerror(errno));
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
fail_close_unlink:
|
||||
if (unlink(lockfile))
|
||||
log_sys_debug("unlink", lockfile);
|
||||
fail_close:
|
||||
if (close(fd))
|
||||
log_sys_debug("close", lockfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_daemon_is_running(const char* lockfile)
|
||||
{
|
||||
int fd;
|
||||
struct flock lock;
|
||||
|
||||
if((fd = open(lockfile, O_RDONLY)) < 0)
|
||||
return 0;
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_start = 0;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_len = 0;
|
||||
if (fcntl(fd, F_GETLK, &lock) < 0) {
|
||||
log_error("Cannot check lock status of lockfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
if (close(fd))
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (close(fd))
|
||||
stack;
|
||||
|
||||
return (lock.l_type == F_UNLCK) ? 0 : 1;
|
||||
}
|
5104
device_mapper/libdm-report.c
Normal file
5104
device_mapper/libdm-report.c
Normal file
File diff suppressed because it is too large
Load Diff
5095
device_mapper/libdm-stats.c
Normal file
5095
device_mapper/libdm-stats.c
Normal file
File diff suppressed because it is too large
Load Diff
718
device_mapper/libdm-string.c
Normal file
718
device_mapper/libdm-string.c
Normal file
@ -0,0 +1,718 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <math.h> /* fabs() */
|
||||
#include <float.h> /* DBL_EPSILON */
|
||||
|
||||
/*
|
||||
* consume characters while they match the predicate function.
|
||||
*/
|
||||
static char *_consume(char *buffer, int (*fn) (int))
|
||||
{
|
||||
while (*buffer && fn(*buffer))
|
||||
buffer++;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int _isword(int c)
|
||||
{
|
||||
return !isspace(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Split buffer into NULL-separated words in argv.
|
||||
* Returns number of words.
|
||||
*/
|
||||
int dm_split_words(char *buffer, unsigned max,
|
||||
unsigned ignore_comments __attribute__((unused)),
|
||||
char **argv)
|
||||
{
|
||||
unsigned arg;
|
||||
|
||||
for (arg = 0; arg < max; arg++) {
|
||||
buffer = _consume(buffer, isspace);
|
||||
if (!*buffer)
|
||||
break;
|
||||
|
||||
argv[arg] = buffer;
|
||||
buffer = _consume(buffer, _isword);
|
||||
|
||||
if (*buffer) {
|
||||
*buffer = '\0';
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove hyphen quoting from a component of a name.
|
||||
* NULL-terminates the component and returns start of next component.
|
||||
*/
|
||||
static char *_unquote(char *component)
|
||||
{
|
||||
char *c = component;
|
||||
char *o = c;
|
||||
char *r;
|
||||
|
||||
while (*c) {
|
||||
if (*(c + 1)) {
|
||||
if (*c == '-') {
|
||||
if (*(c + 1) == '-')
|
||||
c++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
*o = *c;
|
||||
o++;
|
||||
c++;
|
||||
}
|
||||
|
||||
r = (*c) ? c + 1 : c;
|
||||
*o = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_split_lvm_name(struct dm_pool *mem, const char *dmname,
|
||||
char **vgname, char **lvname, char **layer)
|
||||
{
|
||||
if (!vgname || !lvname || !layer) {
|
||||
log_error(INTERNAL_ERROR "dm_split_lvm_name: Forbidden NULL parameter detected.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mem && (!dmname || !(*vgname = dm_pool_strdup(mem, dmname)))) {
|
||||
log_error("Failed to duplicate lvm name.");
|
||||
return 0;
|
||||
} else if (!*vgname) {
|
||||
log_error("Missing lvm name for split.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_unquote(*layer = _unquote(*lvname = _unquote(*vgname)));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* On error, up to glibc 2.0.6, snprintf returned -1 if buffer was too small;
|
||||
* From glibc 2.1 it returns number of chars (excl. trailing null) that would
|
||||
* have been written had there been room.
|
||||
*
|
||||
* dm_snprintf reverts to the old behaviour.
|
||||
*/
|
||||
int dm_snprintf(char *buf, size_t bufsize, const char *format, ...)
|
||||
{
|
||||
int n;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
n = vsnprintf(buf, bufsize, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (n < 0 || ((unsigned) n >= bufsize))
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
const char *dm_basename(const char *path)
|
||||
{
|
||||
const char *p = strrchr(path, '/');
|
||||
|
||||
return p ? p + 1 : path;
|
||||
}
|
||||
|
||||
int dm_vasprintf(char **result, const char *format, va_list aq)
|
||||
{
|
||||
int i, n, size = 16;
|
||||
va_list ap;
|
||||
char *buf = dm_malloc(size);
|
||||
|
||||
*result = 0;
|
||||
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
for (i = 0;; i++) {
|
||||
va_copy(ap, aq);
|
||||
n = vsnprintf(buf, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (0 <= n && n < size)
|
||||
break;
|
||||
|
||||
dm_free(buf);
|
||||
/* Up to glibc 2.0.6 returns -1 */
|
||||
size = (n < 0) ? size * 2 : n + 1;
|
||||
if (!(buf = dm_malloc(size)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i > 1) {
|
||||
/* Reallocating more then once? */
|
||||
if (!(*result = dm_strdup(buf))) {
|
||||
dm_free(buf);
|
||||
return -1;
|
||||
}
|
||||
dm_free(buf);
|
||||
} else
|
||||
*result = buf;
|
||||
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
int dm_asprintf(char **result, const char *format, ...)
|
||||
{
|
||||
int r;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
r = dm_vasprintf(result, format, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count occurences of 'c' in 'str' until we reach a null char.
|
||||
*
|
||||
* Returns:
|
||||
* len - incremented for each char we encounter.
|
||||
* count - number of occurrences of 'c' and 'c2'.
|
||||
*/
|
||||
static void _count_chars(const char *str, size_t *len, int *count,
|
||||
const int c1, const int c2)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == c1 || *ptr == c2)
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count occurrences of 'c' in 'str' of length 'size'.
|
||||
*
|
||||
* Returns:
|
||||
* Number of occurrences of 'c'
|
||||
*/
|
||||
unsigned dm_count_chars(const char *str, size_t len, const int c)
|
||||
{
|
||||
size_t i;
|
||||
unsigned count = 0;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (str[i] == c)
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Length of string after escaping double quotes and backslashes.
|
||||
*/
|
||||
size_t dm_escaped_len(const char *str)
|
||||
{
|
||||
size_t len = 1;
|
||||
int count = 0;
|
||||
|
||||
_count_chars(str, &len, &count, '\"', '\\');
|
||||
|
||||
return count + len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting orig_char with quote_char.
|
||||
* Optionally also quote quote_char.
|
||||
*/
|
||||
static void _quote_characters(char **out, const char *src,
|
||||
const int orig_char, const int quote_char,
|
||||
int quote_quote_char)
|
||||
{
|
||||
while (*src) {
|
||||
if (*src == orig_char ||
|
||||
(*src == quote_char && quote_quote_char))
|
||||
*(*out)++ = quote_char;
|
||||
|
||||
*(*out)++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _unquote_one_character(char *src, const char orig_char,
|
||||
const char quote_char)
|
||||
{
|
||||
char *out;
|
||||
char s, n;
|
||||
|
||||
/* Optimise for the common case where no changes are needed. */
|
||||
while ((s = *src++)) {
|
||||
if (s == quote_char &&
|
||||
((n = *src) == orig_char || n == quote_char)) {
|
||||
out = src++;
|
||||
*(out - 1) = n;
|
||||
|
||||
while ((s = *src++)) {
|
||||
if (s == quote_char &&
|
||||
((n = *src) == orig_char || n == quote_char)) {
|
||||
s = n;
|
||||
src++;
|
||||
}
|
||||
*out = s;
|
||||
out++;
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unquote each character given in orig_char array and unquote quote_char
|
||||
* as well. Also save the first occurrence of each character from orig_char
|
||||
* that was found unquoted in arr_substr_first_unquoted array. This way we can
|
||||
* process several characters in one go.
|
||||
*/
|
||||
static void _unquote_characters(char *src, const char *orig_chars,
|
||||
size_t num_orig_chars,
|
||||
const char quote_char,
|
||||
char *arr_substr_first_unquoted[])
|
||||
{
|
||||
char *out = src;
|
||||
char c, s, n;
|
||||
unsigned i;
|
||||
|
||||
while ((s = *src++)) {
|
||||
for (i = 0; i < num_orig_chars; i++) {
|
||||
c = orig_chars[i];
|
||||
if (s == quote_char &&
|
||||
((n = *src) == c || n == quote_char)) {
|
||||
s = n;
|
||||
src++;
|
||||
break;
|
||||
}
|
||||
if (arr_substr_first_unquoted && (s == c) &&
|
||||
!arr_substr_first_unquoted[i])
|
||||
arr_substr_first_unquoted[i] = out;
|
||||
};
|
||||
*out++ = s;
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting hyphens with hyphens.
|
||||
*/
|
||||
static void _quote_hyphens(char **out, const char *src)
|
||||
{
|
||||
_quote_characters(out, src, '-', '-', 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
|
||||
*/
|
||||
char *dm_build_dm_name(struct dm_pool *mem, const char *vgname,
|
||||
const char *lvname, const char *layer)
|
||||
{
|
||||
size_t len = 1;
|
||||
int hyphens = 1;
|
||||
char *r, *out;
|
||||
|
||||
_count_chars(vgname, &len, &hyphens, '-', 0);
|
||||
_count_chars(lvname, &len, &hyphens, '-', 0);
|
||||
|
||||
if (layer && *layer) {
|
||||
_count_chars(layer, &len, &hyphens, '-', 0);
|
||||
hyphens++;
|
||||
}
|
||||
|
||||
len += hyphens;
|
||||
|
||||
if (!(r = dm_pool_alloc(mem, len))) {
|
||||
log_error("build_dm_name: Allocation failed for %" PRIsize_t
|
||||
" for %s %s %s.", len, vgname, lvname, layer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = r;
|
||||
_quote_hyphens(&out, vgname);
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, lvname);
|
||||
|
||||
if (layer && *layer) {
|
||||
/* No hyphen if the layer begins with _ e.g. _mlog */
|
||||
if (*layer != '_')
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, layer);
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *dm_build_dm_uuid(struct dm_pool *mem, const char *uuid_prefix, const char *lvid, const char *layer)
|
||||
{
|
||||
char *dmuuid;
|
||||
size_t len;
|
||||
|
||||
if (!layer)
|
||||
layer = "";
|
||||
|
||||
len = strlen(uuid_prefix) + strlen(lvid) + strlen(layer) + 2;
|
||||
|
||||
if (!(dmuuid = dm_pool_alloc(mem, len))) {
|
||||
log_error("build_dm_name: Allocation failed for %" PRIsize_t
|
||||
" %s %s.", len, lvid, layer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sprintf(dmuuid, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer);
|
||||
|
||||
return dmuuid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting double quotes with backslashes.
|
||||
*/
|
||||
char *dm_escape_double_quotes(char *out, const char *src)
|
||||
{
|
||||
char *buf = out;
|
||||
|
||||
_quote_characters(&buf, src, '\"', '\\', 1);
|
||||
*buf = '\0';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Undo quoting in situ.
|
||||
*/
|
||||
void dm_unescape_double_quotes(char *src)
|
||||
{
|
||||
_unquote_one_character(src, '\"', '\\');
|
||||
}
|
||||
|
||||
/*
|
||||
* Unescape colons and "at" signs in situ and save the substrings
|
||||
* starting at the position of the first unescaped colon and the
|
||||
* first unescaped "at" sign. This is normally used to unescape
|
||||
* device names used as PVs.
|
||||
*/
|
||||
void dm_unescape_colons_and_at_signs(char *src,
|
||||
char **substr_first_unquoted_colon,
|
||||
char **substr_first_unquoted_at_sign)
|
||||
{
|
||||
const char *orig_chars = ":@";
|
||||
char *arr_substr_first_unquoted[] = {NULL, NULL, NULL};
|
||||
|
||||
_unquote_characters(src, orig_chars, 2, '\\', arr_substr_first_unquoted);
|
||||
|
||||
if (substr_first_unquoted_colon)
|
||||
*substr_first_unquoted_colon = arr_substr_first_unquoted[0];
|
||||
|
||||
if (substr_first_unquoted_at_sign)
|
||||
*substr_first_unquoted_at_sign = arr_substr_first_unquoted[1];
|
||||
}
|
||||
|
||||
int dm_strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
if (memccpy(dest, src, 0, n))
|
||||
return 1;
|
||||
|
||||
if (n > 0)
|
||||
dest[n - 1] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test if the doubles are close enough to be considered equal */
|
||||
static int _close_enough(double d1, double d2)
|
||||
{
|
||||
return fabs(d1 - d2) < DBL_EPSILON;
|
||||
}
|
||||
|
||||
#define BASE_UNKNOWN 0
|
||||
#define BASE_SHARED 1
|
||||
#define BASE_1024 8
|
||||
#define BASE_1000 15
|
||||
#define BASE_SPECIAL 21
|
||||
#define NUM_UNIT_PREFIXES 6
|
||||
#define NUM_SPECIAL 3
|
||||
|
||||
#define SIZE_BUF 128
|
||||
|
||||
const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
|
||||
char unit_type, int use_si_units,
|
||||
uint64_t unit_factor, int include_suffix,
|
||||
dm_size_suffix_t suffix_type)
|
||||
{
|
||||
unsigned base = BASE_UNKNOWN;
|
||||
unsigned s;
|
||||
int precision;
|
||||
double d;
|
||||
uint64_t byte = UINT64_C(0);
|
||||
uint64_t units = UINT64_C(1024);
|
||||
char *size_buf = NULL;
|
||||
char new_unit_type = '\0', unit_type_buf[2];
|
||||
const char *prefix = "";
|
||||
const char * const size_str[][3] = {
|
||||
/* BASE_UNKNOWN */
|
||||
{" ", " ", " "}, /* [0] */
|
||||
|
||||
/* BASE_SHARED - Used if use_si_units = 0 */
|
||||
{" Exabyte", " EB", "E"}, /* [1] */
|
||||
{" Petabyte", " PB", "P"}, /* [2] */
|
||||
{" Terabyte", " TB", "T"}, /* [3] */
|
||||
{" Gigabyte", " GB", "G"}, /* [4] */
|
||||
{" Megabyte", " MB", "M"}, /* [5] */
|
||||
{" Kilobyte", " KB", "K"}, /* [6] */
|
||||
{" Byte ", " B", "B"}, /* [7] */
|
||||
|
||||
/* BASE_1024 - Used if use_si_units = 1 */
|
||||
{" Exbibyte", " EiB", "e"}, /* [8] */
|
||||
{" Pebibyte", " PiB", "p"}, /* [9] */
|
||||
{" Tebibyte", " TiB", "t"}, /* [10] */
|
||||
{" Gibibyte", " GiB", "g"}, /* [11] */
|
||||
{" Mebibyte", " MiB", "m"}, /* [12] */
|
||||
{" Kibibyte", " KiB", "k"}, /* [13] */
|
||||
{" Byte ", " B", "b"}, /* [14] */
|
||||
|
||||
/* BASE_1000 - Used if use_si_units = 1 */
|
||||
{" Exabyte", " EB", "E"}, /* [15] */
|
||||
{" Petabyte", " PB", "P"}, /* [16] */
|
||||
{" Terabyte", " TB", "T"}, /* [17] */
|
||||
{" Gigabyte", " GB", "G"}, /* [18] */
|
||||
{" Megabyte", " MB", "M"}, /* [19] */
|
||||
{" Kilobyte", " kB", "K"}, /* [20] */
|
||||
|
||||
/* BASE_SPECIAL */
|
||||
{" Byte ", " B ", "B"}, /* [21] (shared with BASE_1000) */
|
||||
{" Units ", " Un", "U"}, /* [22] */
|
||||
{" Sectors ", " Se", "S"}, /* [23] */
|
||||
};
|
||||
|
||||
if (!(size_buf = dm_pool_alloc(mem, SIZE_BUF))) {
|
||||
log_error("no memory for size display buffer");
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!use_si_units) {
|
||||
/* Case-independent match */
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (toupper((int) unit_type) ==
|
||||
*size_str[BASE_SHARED + s][2]) {
|
||||
base = BASE_SHARED;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Case-dependent match for powers of 1000 */
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (unit_type == *size_str[BASE_1000 + s][2]) {
|
||||
base = BASE_1000;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Case-dependent match for powers of 1024 */
|
||||
if (base == BASE_UNKNOWN)
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (unit_type == *size_str[BASE_1024 + s][2]) {
|
||||
base = BASE_1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (base == BASE_UNKNOWN)
|
||||
/* Check for special units - s, b or u */
|
||||
for (s = 0; s < NUM_SPECIAL; s++)
|
||||
if (toupper((int) unit_type) ==
|
||||
*size_str[BASE_SPECIAL + s][2]) {
|
||||
base = BASE_SPECIAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (size == UINT64_C(0)) {
|
||||
if (base == BASE_UNKNOWN)
|
||||
s = 0;
|
||||
sprintf(size_buf, "0%s", include_suffix ? size_str[base + s][suffix_type] : "");
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
size *= UINT64_C(512);
|
||||
|
||||
if (base != BASE_UNKNOWN) {
|
||||
if (!unit_factor) {
|
||||
unit_type_buf[0] = unit_type;
|
||||
unit_type_buf[1] = '\0';
|
||||
if (!(unit_factor = dm_units_to_factor(&unit_type_buf[0], &new_unit_type, 1, NULL)) ||
|
||||
unit_type != new_unit_type) {
|
||||
/* The two functions should match (and unrecognised units get treated like 'h'). */
|
||||
log_error(INTERNAL_ERROR "Inconsistent units: %c and %c.", unit_type, new_unit_type);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
byte = unit_factor;
|
||||
} else {
|
||||
/* Human-readable style */
|
||||
if (unit_type == 'H' || unit_type == 'R') {
|
||||
units = UINT64_C(1000);
|
||||
base = BASE_1000;
|
||||
} else {
|
||||
units = UINT64_C(1024);
|
||||
base = BASE_1024;
|
||||
}
|
||||
|
||||
if (!use_si_units)
|
||||
base = BASE_SHARED;
|
||||
|
||||
byte = units * units * units * units * units * units;
|
||||
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++)
|
||||
byte /= units;
|
||||
|
||||
if ((s < NUM_UNIT_PREFIXES) &&
|
||||
((unit_type == 'R') || (unit_type == 'r'))) {
|
||||
/* When the rounding would cause difference, add '<' prefix
|
||||
* i.e. 2043M is more then 1.9949G prints <2.00G
|
||||
* This version is for 2 digits fixed precision */
|
||||
d = 100. * (double) size / byte;
|
||||
if (!_close_enough(floorl(d), nearbyintl(d)))
|
||||
prefix = "<";
|
||||
}
|
||||
|
||||
include_suffix = 1;
|
||||
}
|
||||
|
||||
/* FIXME Make precision configurable */
|
||||
switch (toupper(*size_str[base + s][DM_SIZE_UNIT])) {
|
||||
case 'B':
|
||||
case 'S':
|
||||
precision = 0;
|
||||
break;
|
||||
default:
|
||||
precision = 2;
|
||||
}
|
||||
|
||||
snprintf(size_buf, SIZE_BUF, "%s%.*f%s", prefix, precision,
|
||||
(double) size / byte, include_suffix ? size_str[base + s][suffix_type] : "");
|
||||
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
uint64_t dm_units_to_factor(const char *units, char *unit_type,
|
||||
int strict, const char **endptr)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
uint64_t v;
|
||||
double custom_value = 0;
|
||||
uint64_t multiplier;
|
||||
|
||||
if (endptr)
|
||||
*endptr = units;
|
||||
|
||||
if (isdigit(*units)) {
|
||||
custom_value = strtod(units, &ptr);
|
||||
if (ptr == units)
|
||||
return 0;
|
||||
v = (uint64_t) strtoull(units, NULL, 10);
|
||||
if (_close_enough((double) v, custom_value))
|
||||
custom_value = 0; /* Use integer arithmetic */
|
||||
units = ptr;
|
||||
} else
|
||||
v = 1;
|
||||
|
||||
/* Only one units char permitted in strict mode. */
|
||||
if (strict && units[0] && units[1])
|
||||
return 0;
|
||||
|
||||
if (v == 1)
|
||||
*unit_type = *units;
|
||||
else
|
||||
*unit_type = 'U';
|
||||
|
||||
switch (*units) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
case 'r':
|
||||
case 'R':
|
||||
multiplier = v = UINT64_C(1);
|
||||
*unit_type = *units;
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
multiplier = UINT64_C(1);
|
||||
break;
|
||||
#define KILO UINT64_C(1024)
|
||||
case 's':
|
||||
case 'S':
|
||||
multiplier = (KILO/2);
|
||||
break;
|
||||
case 'k':
|
||||
multiplier = KILO;
|
||||
break;
|
||||
case 'm':
|
||||
multiplier = KILO * KILO;
|
||||
break;
|
||||
case 'g':
|
||||
multiplier = KILO * KILO * KILO;
|
||||
break;
|
||||
case 't':
|
||||
multiplier = KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'p':
|
||||
multiplier = KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'e':
|
||||
multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
#undef KILO
|
||||
#define KILO UINT64_C(1000)
|
||||
case 'K':
|
||||
multiplier = KILO;
|
||||
break;
|
||||
case 'M':
|
||||
multiplier = KILO * KILO;
|
||||
break;
|
||||
case 'G':
|
||||
multiplier = KILO * KILO * KILO;
|
||||
break;
|
||||
case 'T':
|
||||
multiplier = KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'P':
|
||||
multiplier = KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'E':
|
||||
multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
#undef KILO
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (endptr)
|
||||
*endptr = units + 1;
|
||||
|
||||
if (_close_enough(custom_value, 0.))
|
||||
return v * multiplier; /* Use integer arithmetic */
|
||||
else
|
||||
return (uint64_t) (custom_value * multiplier);
|
||||
}
|
565
device_mapper/libdm-targets.c
Normal file
565
device_mapper/libdm-targets.c
Normal file
@ -0,0 +1,565 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
#include "libdm-common.h"
|
||||
|
||||
int dm_get_status_snapshot(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_snapshot **status)
|
||||
{
|
||||
struct dm_status_snapshot *s;
|
||||
int r;
|
||||
|
||||
if (!params) {
|
||||
log_error("Failed to parse invalid snapshot params.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) {
|
||||
log_error("Failed to allocate snapshot status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sscanf(params, FMTu64 "/" FMTu64 " " FMTu64,
|
||||
&s->used_sectors, &s->total_sectors,
|
||||
&s->metadata_sectors);
|
||||
|
||||
if (r == 3 || r == 2)
|
||||
s->has_metadata_sectors = (r == 3);
|
||||
else if (!strcmp(params, "Invalid"))
|
||||
s->invalid = 1;
|
||||
else if (!strcmp(params, "Merge failed"))
|
||||
s->merge_failed = 1;
|
||||
else if (!strcmp(params, "Overflow"))
|
||||
s->overflow = 1;
|
||||
else {
|
||||
dm_pool_free(mem, s);
|
||||
log_error("Failed to parse snapshot params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip nr fields each delimited by a single space.
|
||||
* FIXME Don't assume single space.
|
||||
*/
|
||||
static const char *_skip_fields(const char *p, unsigned nr)
|
||||
{
|
||||
while (p && nr-- && (p = strchr(p, ' ')))
|
||||
p++;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count number of single-space delimited fields.
|
||||
* Number of fields is number of spaces plus one.
|
||||
*/
|
||||
static unsigned _count_fields(const char *p)
|
||||
{
|
||||
unsigned nr = 1;
|
||||
|
||||
if (!p || !*p)
|
||||
return 0;
|
||||
|
||||
while ((p = _skip_fields(p, 1)))
|
||||
nr++;
|
||||
|
||||
return nr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Various RAID status versions include:
|
||||
* Versions < 1.5.0 (4 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio>
|
||||
* Versions 1.5.0+ (6 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio> <sync_action> <mismatch_cnt>
|
||||
* Versions 1.9.0+ (7 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio> <sync_action> <mismatch_cnt> <data_offset>
|
||||
*/
|
||||
int dm_get_status_raid(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_raid **status)
|
||||
{
|
||||
int i;
|
||||
unsigned num_fields;
|
||||
const char *p, *pp, *msg_fields = "";
|
||||
struct dm_status_raid *s = NULL;
|
||||
unsigned a = 0;
|
||||
|
||||
if ((num_fields = _count_fields(params)) < 4)
|
||||
goto_bad;
|
||||
|
||||
/* Second field holds the device count */
|
||||
msg_fields = "<#devs> ";
|
||||
if (!(p = _skip_fields(params, 1)) || (sscanf(p, "%d", &i) != 1))
|
||||
goto_bad;
|
||||
|
||||
msg_fields = "";
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
|
||||
goto_bad;
|
||||
|
||||
if (!(s->raid_type = dm_pool_zalloc(mem, p - params)))
|
||||
goto_bad; /* memory is freed when pool is destroyed */
|
||||
|
||||
if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) /* Space for health chars */
|
||||
goto_bad;
|
||||
|
||||
msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
|
||||
if (sscanf(params, "%s %u %s " FMTu64 "/" FMTu64,
|
||||
s->raid_type,
|
||||
&s->dev_count,
|
||||
s->dev_health,
|
||||
&s->insync_regions,
|
||||
&s->total_regions) != 5)
|
||||
goto_bad;
|
||||
|
||||
/*
|
||||
* All pre-1.5.0 version parameters are read. Now we check
|
||||
* for additional 1.5.0+ parameters (i.e. num_fields at least 6).
|
||||
*
|
||||
* Note that 'sync_action' will be NULL (and mismatch_count
|
||||
* will be 0) if the kernel returns a pre-1.5.0 status.
|
||||
*/
|
||||
if (num_fields < 6)
|
||||
goto out;
|
||||
|
||||
msg_fields = "<sync_action> and <mismatch_cnt> ";
|
||||
|
||||
/* Skip pre-1.5.0 params */
|
||||
if (!(p = _skip_fields(params, 4)) || !(pp = _skip_fields(p, 1)))
|
||||
goto_bad;
|
||||
|
||||
if (!(s->sync_action = dm_pool_zalloc(mem, pp - p)))
|
||||
goto_bad;
|
||||
|
||||
if (sscanf(p, "%s " FMTu64, s->sync_action, &s->mismatch_count) != 2)
|
||||
goto_bad;
|
||||
|
||||
if (num_fields < 7)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* All pre-1.9.0 version parameters are read. Now we check
|
||||
* for additional 1.9.0+ parameters (i.e. nr_fields at least 7).
|
||||
*
|
||||
* Note that data_offset will be 0 if the
|
||||
* kernel returns a pre-1.9.0 status.
|
||||
*/
|
||||
msg_fields = "<data_offset>";
|
||||
if (!(p = _skip_fields(params, 6))) /* skip pre-1.9.0 params */
|
||||
goto bad;
|
||||
if (sscanf(p, FMTu64, &s->data_offset) != 1)
|
||||
goto bad;
|
||||
|
||||
out:
|
||||
*status = s;
|
||||
|
||||
if (s->insync_regions == s->total_regions) {
|
||||
/* FIXME: kernel gives misleading info here
|
||||
* Trying to recognize a true state */
|
||||
while (i-- > 0)
|
||||
if (s->dev_health[i] == 'a')
|
||||
a++; /* Count number of 'a' */
|
||||
|
||||
if (a && a < s->dev_count) {
|
||||
/* SOME legs are in 'a' */
|
||||
if (!strcasecmp(s->sync_action, "recover")
|
||||
|| !strcasecmp(s->sync_action, "idle"))
|
||||
/* Kernel may possibly start some action
|
||||
* in near-by future, do not report 100% */
|
||||
s->insync_regions--;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Failed to parse %sraid params: %s", msg_fields, params);
|
||||
|
||||
if (s)
|
||||
dm_pool_free(mem, s);
|
||||
|
||||
*status = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* <metadata block size> <#used metadata blocks>/<#total metadata blocks>
|
||||
* <cache block size> <#used cache blocks>/<#total cache blocks>
|
||||
* <#read hits> <#read misses> <#write hits> <#write misses>
|
||||
* <#demotions> <#promotions> <#dirty> <#features> <features>*
|
||||
* <#core args> <core args>* <policy name> <#policy args> <policy args>*
|
||||
*
|
||||
* metadata block size : Fixed block size for each metadata block in
|
||||
* sectors
|
||||
* #used metadata blocks : Number of metadata blocks used
|
||||
* #total metadata blocks : Total number of metadata blocks
|
||||
* cache block size : Configurable block size for the cache device
|
||||
* in sectors
|
||||
* #used cache blocks : Number of blocks resident in the cache
|
||||
* #total cache blocks : Total number of cache blocks
|
||||
* #read hits : Number of times a READ bio has been mapped
|
||||
* to the cache
|
||||
* #read misses : Number of times a READ bio has been mapped
|
||||
* to the origin
|
||||
* #write hits : Number of times a WRITE bio has been mapped
|
||||
* to the cache
|
||||
* #write misses : Number of times a WRITE bio has been
|
||||
* mapped to the origin
|
||||
* #demotions : Number of times a block has been removed
|
||||
* from the cache
|
||||
* #promotions : Number of times a block has been moved to
|
||||
* the cache
|
||||
* #dirty : Number of blocks in the cache that differ
|
||||
* from the origin
|
||||
* #feature args : Number of feature args to follow
|
||||
* feature args : 'writethrough' (optional)
|
||||
* #core args : Number of core arguments (must be even)
|
||||
* core args : Key/value pairs for tuning the core
|
||||
* e.g. migration_threshold
|
||||
* *policy name : Name of the policy
|
||||
* #policy args : Number of policy arguments to follow (must be even)
|
||||
* policy args : Key/value pairs
|
||||
* e.g. sequential_threshold
|
||||
*/
|
||||
int dm_get_status_cache(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_cache **status)
|
||||
{
|
||||
int i, feature_argc;
|
||||
char *str;
|
||||
const char *p, *pp;
|
||||
struct dm_status_cache *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_cache))))
|
||||
return_0;
|
||||
|
||||
if (strstr(params, "Error")) {
|
||||
s->error = 1;
|
||||
s->fail = 1; /* This is also I/O fail state */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strstr(params, "Fail")) {
|
||||
s->fail = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read in args that have definitive placement */
|
||||
if (sscanf(params,
|
||||
" " FMTu32
|
||||
" " FMTu64 "/" FMTu64
|
||||
" " FMTu32
|
||||
" " FMTu64 "/" FMTu64
|
||||
" " FMTu64 " " FMTu64
|
||||
" " FMTu64 " " FMTu64
|
||||
" " FMTu64 " " FMTu64
|
||||
" " FMTu64
|
||||
" %d",
|
||||
&s->metadata_block_size,
|
||||
&s->metadata_used_blocks, &s->metadata_total_blocks,
|
||||
&s->block_size, /* AKA, chunk_size */
|
||||
&s->used_blocks, &s->total_blocks,
|
||||
&s->read_hits, &s->read_misses,
|
||||
&s->write_hits, &s->write_misses,
|
||||
&s->demotions, &s->promotions,
|
||||
&s->dirty_blocks,
|
||||
&feature_argc) != 14)
|
||||
goto bad;
|
||||
|
||||
/* Now jump to "features" section */
|
||||
if (!(p = _skip_fields(params, 12)))
|
||||
goto bad;
|
||||
|
||||
/* Read in features */
|
||||
for (i = 0; i < feature_argc; i++) {
|
||||
if (!strncmp(p, "writethrough ", 13))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strncmp(p, "writeback ", 10))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
|
||||
else if (!strncmp(p, "passthrough ", 12))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
else if (!strncmp(p, "metadata2 ", 10))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_METADATA2;
|
||||
else
|
||||
log_error("Unknown feature in status: %s", params);
|
||||
|
||||
if (!(p = _skip_fields(p, 1)))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Read in core_args. */
|
||||
if (sscanf(p, "%d ", &s->core_argc) != 1)
|
||||
goto bad;
|
||||
if ((s->core_argc > 0) &&
|
||||
(!(s->core_argv = dm_pool_zalloc(mem, sizeof(char *) * s->core_argc)) ||
|
||||
!(p = _skip_fields(p, 1)) ||
|
||||
!(str = dm_pool_strdup(mem, p)) ||
|
||||
!(p = _skip_fields(p, (unsigned) s->core_argc)) ||
|
||||
(dm_split_words(str, s->core_argc, 0, s->core_argv) != s->core_argc)))
|
||||
goto bad;
|
||||
|
||||
/* Read in policy args */
|
||||
pp = p;
|
||||
if (!(p = _skip_fields(p, 1)) ||
|
||||
!(s->policy_name = dm_pool_zalloc(mem, (p - pp))))
|
||||
goto bad;
|
||||
if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2)
|
||||
goto bad;
|
||||
if (s->policy_argc &&
|
||||
(!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) ||
|
||||
!(p = _skip_fields(p, 1)) ||
|
||||
!(str = dm_pool_strdup(mem, p)) ||
|
||||
(dm_split_words(str, s->policy_argc, 0, s->policy_argv) != s->policy_argc)))
|
||||
goto bad;
|
||||
|
||||
/* TODO: improve this parser */
|
||||
if (strstr(p, " ro"))
|
||||
s->read_only = 1;
|
||||
|
||||
if (strstr(p, " needs_check"))
|
||||
s->needs_check = 1;
|
||||
out:
|
||||
*status = s;
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Failed to parse cache params: %s", params);
|
||||
dm_pool_free(mem, s);
|
||||
*status = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s)
|
||||
{
|
||||
int pos;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
if (!params) {
|
||||
log_error("Failed to parse invalid thin params.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strstr(params, "Error")) {
|
||||
s->error = 1;
|
||||
s->fail = 1; /* This is also I/O fail state */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strstr(params, "Fail")) {
|
||||
s->fail = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: add support for held metadata root */
|
||||
if (sscanf(params, FMTu64 " " FMTu64 "/" FMTu64 " " FMTu64 "/" FMTu64 "%n",
|
||||
&s->transaction_id,
|
||||
&s->used_metadata_blocks,
|
||||
&s->total_metadata_blocks,
|
||||
&s->used_data_blocks,
|
||||
&s->total_data_blocks, &pos) < 5) {
|
||||
log_error("Failed to parse thin pool params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* New status flags */
|
||||
if (strstr(params + pos, "no_discard_passdown"))
|
||||
s->discards = DM_THIN_DISCARDS_NO_PASSDOWN;
|
||||
else if (strstr(params + pos, "ignore_discard"))
|
||||
s->discards = DM_THIN_DISCARDS_IGNORE;
|
||||
else /* default discard_passdown */
|
||||
s->discards = DM_THIN_DISCARDS_PASSDOWN;
|
||||
|
||||
/* Default is 'writable' (rw) data */
|
||||
if (strstr(params + pos, "out_of_data_space"))
|
||||
s->out_of_data_space = 1;
|
||||
else if (strstr(params + pos, "ro "))
|
||||
s->read_only = 1;
|
||||
|
||||
/* Default is 'queue_if_no_space' */
|
||||
if (strstr(params + pos, "error_if_no_space"))
|
||||
s->error_if_no_space = 1;
|
||||
|
||||
if (strstr(params + pos, "needs_check"))
|
||||
s->needs_check = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_get_status_thin_pool(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_thin_pool **status)
|
||||
{
|
||||
struct dm_status_thin_pool *s;
|
||||
|
||||
if (!(s = dm_pool_alloc(mem, sizeof(struct dm_status_thin_pool)))) {
|
||||
log_error("Failed to allocate thin_pool status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!parse_thin_pool_status(params, s)) {
|
||||
dm_pool_free(mem, s);
|
||||
return_0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_get_status_thin(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_thin **status)
|
||||
{
|
||||
struct dm_status_thin *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin)))) {
|
||||
log_error("Failed to allocate thin status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(params, '-')) {
|
||||
/* nothing to parse */
|
||||
} else if (strstr(params, "Fail")) {
|
||||
s->fail = 1;
|
||||
} else if (sscanf(params, FMTu64 " " FMTu64,
|
||||
&s->mapped_sectors,
|
||||
&s->highest_mapped_sector) != 2) {
|
||||
dm_pool_free(mem, s);
|
||||
log_error("Failed to parse thin params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* dm core parms: 0 409600 mirror
|
||||
* Mirror core parms: 2 253:4 253:5 400/400
|
||||
* New-style failure params: 1 AA
|
||||
* New-style log params: 3 cluster 253:3 A
|
||||
* or 3 disk 253:3 A
|
||||
* or 1 core
|
||||
*/
|
||||
#define DM_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
|
||||
|
||||
int dm_get_status_mirror(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_mirror **status)
|
||||
{
|
||||
struct dm_status_mirror *s;
|
||||
const char *p, *pos = params;
|
||||
unsigned num_devs, argc, i;
|
||||
int used;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) {
|
||||
log_error("Failed to alloc mem pool to parse mirror status.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sscanf(pos, "%u %n", &num_devs, &used) != 1)
|
||||
goto_out;
|
||||
pos += used;
|
||||
|
||||
if (num_devs > DM_MIRROR_MAX_IMAGES) {
|
||||
log_error(INTERNAL_ERROR "More then " DM_TO_STRING(DM_MIRROR_MAX_IMAGES)
|
||||
" reported in mirror status.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(s->devs = dm_pool_alloc(mem, num_devs * sizeof(*(s->devs))))) {
|
||||
log_error("Allocation of devs failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_devs; ++i, pos += used)
|
||||
if (sscanf(pos, "%u:%u %n",
|
||||
&(s->devs[i].major), &(s->devs[i].minor), &used) != 2)
|
||||
goto_out;
|
||||
|
||||
if (sscanf(pos, FMTu64 "/" FMTu64 "%n",
|
||||
&s->insync_regions, &s->total_regions, &used) != 2)
|
||||
goto_out;
|
||||
pos += used;
|
||||
|
||||
if (sscanf(pos, "%u %n", &argc, &used) != 1)
|
||||
goto_out;
|
||||
pos += used;
|
||||
|
||||
for (i = 0; i < num_devs ; ++i)
|
||||
s->devs[i].health = pos[i];
|
||||
|
||||
if (!(pos = _skip_fields(pos, argc)))
|
||||
goto_out;
|
||||
|
||||
if (strncmp(pos, "userspace", 9) == 0) {
|
||||
pos += 9;
|
||||
/* FIXME: support status of userspace mirror implementation */
|
||||
}
|
||||
|
||||
if (sscanf(pos, "%u %n", &argc, &used) != 1)
|
||||
goto_out;
|
||||
pos += used;
|
||||
|
||||
if (argc == 1) {
|
||||
/* core, cluster-core */
|
||||
if (!(s->log_type = dm_pool_strdup(mem, pos))) {
|
||||
log_error("Allocation of log type string failed.");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (!(p = _skip_fields(pos, 1)))
|
||||
goto_out;
|
||||
|
||||
/* disk, cluster-disk */
|
||||
if (!(s->log_type = dm_pool_strndup(mem, pos, p - pos - 1))) {
|
||||
log_error("Allocation of log type string failed.");
|
||||
goto out;
|
||||
}
|
||||
pos = p;
|
||||
|
||||
if ((argc > 2) && !strcmp(s->log_type, "disk")) {
|
||||
s->log_count = argc - 2;
|
||||
|
||||
if (!(s->logs = dm_pool_alloc(mem, s->log_count * sizeof(*(s->logs))))) {
|
||||
log_error("Allocation of logs failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < s->log_count; ++i, pos += used)
|
||||
if (sscanf(pos, "%u:%u %n",
|
||||
&s->logs[i].major, &s->logs[i].minor, &used) != 2)
|
||||
goto_out;
|
||||
|
||||
for (i = 0; i < s->log_count; ++i)
|
||||
s->logs[i].health = pos[i];
|
||||
}
|
||||
}
|
||||
|
||||
s->dev_count = num_devs;
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
out:
|
||||
log_error("Failed to parse mirror status %s.", params);
|
||||
dm_pool_free(mem, s);
|
||||
*status = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
178
device_mapper/libdm-timestamp.c
Normal file
178
device_mapper/libdm-timestamp.c
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Rackable Systems All rights reserved.
|
||||
* Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstract out the time methods used so they can be adjusted later -
|
||||
* the results of these routines should stay in-core.
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NSEC_PER_USEC UINT64_C(1000)
|
||||
#define NSEC_PER_MSEC UINT64_C(1000000)
|
||||
#define NSEC_PER_SEC UINT64_C(1000000000)
|
||||
|
||||
/*
|
||||
* The realtime section uses clock_gettime with the CLOCK_MONOTONIC
|
||||
* parameter to prevent issues with time warps
|
||||
* This implementation requires librt.
|
||||
*/
|
||||
#ifdef HAVE_REALTIME
|
||||
|
||||
#include <time.h>
|
||||
|
||||
struct dm_timestamp {
|
||||
struct timespec t;
|
||||
};
|
||||
|
||||
static uint64_t _timestamp_to_uint64(struct dm_timestamp *ts)
|
||||
{
|
||||
uint64_t stamp = 0;
|
||||
|
||||
stamp += (uint64_t) ts->t.tv_sec * NSEC_PER_SEC;
|
||||
stamp += (uint64_t) ts->t.tv_nsec;
|
||||
|
||||
return stamp;
|
||||
}
|
||||
|
||||
struct dm_timestamp *dm_timestamp_alloc(void)
|
||||
{
|
||||
struct dm_timestamp *ts = NULL;
|
||||
|
||||
if (!(ts = dm_zalloc(sizeof(*ts))))
|
||||
stack;
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
int dm_timestamp_get(struct dm_timestamp *ts)
|
||||
{
|
||||
if (!ts)
|
||||
return 0;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) {
|
||||
log_sys_error("clock_gettime", "get_timestamp");
|
||||
ts->t.tv_sec = 0;
|
||||
ts->t.tv_nsec = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else /* ! HAVE_REALTIME */
|
||||
|
||||
/*
|
||||
* The !realtime section just uses gettimeofday and is therefore subject
|
||||
* to ntp-type time warps - not sure if should allow that.
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
struct dm_timestamp {
|
||||
struct timeval t;
|
||||
};
|
||||
|
||||
static uint64_t _timestamp_to_uint64(struct dm_timestamp *ts)
|
||||
{
|
||||
uint64_t stamp = 0;
|
||||
|
||||
stamp += ts->t.tv_sec * NSEC_PER_SEC;
|
||||
stamp += ts->t.tv_usec * NSEC_PER_USEC;
|
||||
|
||||
return stamp;
|
||||
}
|
||||
|
||||
struct dm_timestamp *dm_timestamp_alloc(void)
|
||||
{
|
||||
struct dm_timestamp *ts;
|
||||
|
||||
if (!(ts = dm_malloc(sizeof(*ts))))
|
||||
stack;
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
int dm_timestamp_get(struct dm_timestamp *ts)
|
||||
{
|
||||
if (!ts)
|
||||
return 0;
|
||||
|
||||
if (gettimeofday(&ts->t, NULL)) {
|
||||
log_sys_error("gettimeofday", "get_timestamp");
|
||||
ts->t.tv_sec = 0;
|
||||
ts->t.tv_usec = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* HAVE_REALTIME */
|
||||
|
||||
/*
|
||||
* Compare two timestamps.
|
||||
*
|
||||
* Return: -1 if ts1 is less than ts2
|
||||
* 0 if ts1 is equal to ts2
|
||||
* 1 if ts1 is greater than ts2
|
||||
*/
|
||||
int dm_timestamp_compare(struct dm_timestamp *ts1, struct dm_timestamp *ts2)
|
||||
{
|
||||
uint64_t t1, t2;
|
||||
|
||||
t1 = _timestamp_to_uint64(ts1);
|
||||
t2 = _timestamp_to_uint64(ts2);
|
||||
|
||||
if (t2 < t1)
|
||||
return 1;
|
||||
|
||||
if (t1 < t2)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the absolute difference in nanoseconds between
|
||||
* the dm_timestamp objects ts1 and ts2.
|
||||
*
|
||||
* Callers that need to know whether ts1 is before, equal to, or after ts2
|
||||
* in addition to the magnitude should use dm_timestamp_compare.
|
||||
*/
|
||||
uint64_t dm_timestamp_delta(struct dm_timestamp *ts1, struct dm_timestamp *ts2)
|
||||
{
|
||||
uint64_t t1, t2;
|
||||
|
||||
t1 = _timestamp_to_uint64(ts1);
|
||||
t2 = _timestamp_to_uint64(ts2);
|
||||
|
||||
if (t1 > t2)
|
||||
return t1 - t2;
|
||||
|
||||
return t2 - t1;
|
||||
}
|
||||
|
||||
void dm_timestamp_copy(struct dm_timestamp *ts_new, struct dm_timestamp *ts_old)
|
||||
{
|
||||
*ts_new = *ts_old;
|
||||
}
|
||||
|
||||
void dm_timestamp_destroy(struct dm_timestamp *ts)
|
||||
{
|
||||
dm_free(ts);
|
||||
}
|
364
device_mapper/misc/dm-ioctl.h
Normal file
364
device_mapper/misc/dm-ioctl.h
Normal file
@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
|
||||
* Copyright (C) 2004 - 2017 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_DM_IOCTL_V4_H
|
||||
#define _LINUX_DM_IOCTL_V4_H
|
||||
|
||||
#ifdef __linux__
|
||||
# include <linux/types.h>
|
||||
#endif
|
||||
|
||||
#define DM_DIR "mapper" /* Slashes not supported */
|
||||
#define DM_CONTROL_NODE "control"
|
||||
#define DM_MAX_TYPE_NAME 16
|
||||
#define DM_NAME_LEN 128
|
||||
#define DM_UUID_LEN 129
|
||||
|
||||
/*
|
||||
* A traditional ioctl interface for the device mapper.
|
||||
*
|
||||
* Each device can have two tables associated with it, an
|
||||
* 'active' table which is the one currently used by io passing
|
||||
* through the device, and an 'inactive' one which is a table
|
||||
* that is being prepared as a replacement for the 'active' one.
|
||||
*
|
||||
* DM_VERSION:
|
||||
* Just get the version information for the ioctl interface.
|
||||
*
|
||||
* DM_REMOVE_ALL:
|
||||
* Remove all dm devices, destroy all tables. Only really used
|
||||
* for debug.
|
||||
*
|
||||
* DM_LIST_DEVICES:
|
||||
* Get a list of all the dm device names.
|
||||
*
|
||||
* DM_DEV_CREATE:
|
||||
* Create a new device, neither the 'active' or 'inactive' table
|
||||
* slots will be filled. The device will be in suspended state
|
||||
* after creation, however any io to the device will get errored
|
||||
* since it will be out-of-bounds.
|
||||
*
|
||||
* DM_DEV_REMOVE:
|
||||
* Remove a device, destroy any tables.
|
||||
*
|
||||
* DM_DEV_RENAME:
|
||||
* Rename a device or set its uuid if none was previously supplied.
|
||||
*
|
||||
* DM_SUSPEND:
|
||||
* This performs both suspend and resume, depending which flag is
|
||||
* passed in.
|
||||
* Suspend: This command will not return until all pending io to
|
||||
* the device has completed. Further io will be deferred until
|
||||
* the device is resumed.
|
||||
* Resume: It is no longer an error to issue this command on an
|
||||
* unsuspended device. If a table is present in the 'inactive'
|
||||
* slot, it will be moved to the active slot, then the old table
|
||||
* from the active slot will be _destroyed_. Finally the device
|
||||
* is resumed.
|
||||
*
|
||||
* DM_DEV_STATUS:
|
||||
* Retrieves the status for the table in the 'active' slot.
|
||||
*
|
||||
* DM_DEV_WAIT:
|
||||
* Wait for a significant event to occur to the device. This
|
||||
* could either be caused by an event triggered by one of the
|
||||
* targets of the table in the 'active' slot, or a table change.
|
||||
*
|
||||
* DM_TABLE_LOAD:
|
||||
* Load a table into the 'inactive' slot for the device. The
|
||||
* device does _not_ need to be suspended prior to this command.
|
||||
*
|
||||
* DM_TABLE_CLEAR:
|
||||
* Destroy any table in the 'inactive' slot (ie. abort).
|
||||
*
|
||||
* DM_TABLE_DEPS:
|
||||
* Return a set of device dependencies for the 'active' table.
|
||||
*
|
||||
* DM_TABLE_STATUS:
|
||||
* Return the targets status for the 'active' table.
|
||||
*
|
||||
* DM_TARGET_MSG:
|
||||
* Pass a message string to the target at a specific offset of a device.
|
||||
*
|
||||
* DM_DEV_SET_GEOMETRY:
|
||||
* Set the geometry of a device by passing in a string in this format:
|
||||
*
|
||||
* "cylinders heads sectors_per_track start_sector"
|
||||
*
|
||||
* Beware that CHS geometry is nearly obsolete and only provided
|
||||
* for compatibility with dm devices that can be booted by a PC
|
||||
* BIOS. See struct hd_geometry for range limits. Also note that
|
||||
* the geometry is erased if the device size changes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* All ioctl arguments consist of a single chunk of memory, with
|
||||
* this structure at the start. If a uuid is specified any
|
||||
* lookup (eg. for a DM_INFO) will be done on that, *not* the
|
||||
* name.
|
||||
*/
|
||||
struct dm_ioctl {
|
||||
/*
|
||||
* The version number is made up of three parts:
|
||||
* major - no backward or forward compatibility,
|
||||
* minor - only backwards compatible,
|
||||
* patch - both backwards and forwards compatible.
|
||||
*
|
||||
* All clients of the ioctl interface should fill in the
|
||||
* version number of the interface that they were
|
||||
* compiled with.
|
||||
*
|
||||
* All recognised ioctl commands (ie. those that don't
|
||||
* return -ENOTTY) fill out this field, even if the
|
||||
* command failed.
|
||||
*/
|
||||
uint32_t version[3]; /* in/out */
|
||||
uint32_t data_size; /* total size of data passed in
|
||||
* including this struct */
|
||||
|
||||
uint32_t data_start; /* offset to start of data
|
||||
* relative to start of this struct */
|
||||
|
||||
uint32_t target_count; /* in/out */
|
||||
int32_t open_count; /* out */
|
||||
uint32_t flags; /* in/out */
|
||||
|
||||
/*
|
||||
* event_nr holds either the event number (input and output) or the
|
||||
* udev cookie value (input only).
|
||||
* The DM_DEV_WAIT ioctl takes an event number as input.
|
||||
* The DM_SUSPEND, DM_DEV_REMOVE and DM_DEV_RENAME ioctls
|
||||
* use the field as a cookie to return in the DM_COOKIE
|
||||
* variable with the uevents they issue.
|
||||
* For output, the ioctls return the event number, not the cookie.
|
||||
*/
|
||||
uint32_t event_nr; /* in/out */
|
||||
uint32_t padding;
|
||||
|
||||
uint64_t dev; /* in/out */
|
||||
|
||||
char name[DM_NAME_LEN]; /* device name */
|
||||
char uuid[DM_UUID_LEN]; /* unique identifier for
|
||||
* the block device */
|
||||
char data[7]; /* padding or data */
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to specify tables. These structures appear after the
|
||||
* dm_ioctl.
|
||||
*/
|
||||
struct dm_target_spec {
|
||||
uint64_t sector_start;
|
||||
uint64_t length;
|
||||
int32_t status; /* used when reading from kernel only */
|
||||
|
||||
/*
|
||||
* Location of the next dm_target_spec.
|
||||
* - When specifying targets on a DM_TABLE_LOAD command, this value is
|
||||
* the number of bytes from the start of the "current" dm_target_spec
|
||||
* to the start of the "next" dm_target_spec.
|
||||
* - When retrieving targets on a DM_TABLE_STATUS command, this value
|
||||
* is the number of bytes from the start of the first dm_target_spec
|
||||
* (that follows the dm_ioctl struct) to the start of the "next"
|
||||
* dm_target_spec.
|
||||
*/
|
||||
uint32_t next;
|
||||
|
||||
char target_type[DM_MAX_TYPE_NAME];
|
||||
|
||||
/*
|
||||
* Parameter string starts immediately after this object.
|
||||
* Be careful to add padding after string to ensure correct
|
||||
* alignment of subsequent dm_target_spec.
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to retrieve the target dependencies.
|
||||
*/
|
||||
struct dm_target_deps {
|
||||
uint32_t count; /* Array size */
|
||||
uint32_t padding; /* unused */
|
||||
uint64_t dev[0]; /* out */
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to get a list of all dm devices.
|
||||
*/
|
||||
struct dm_name_list {
|
||||
uint64_t dev;
|
||||
uint32_t next; /* offset to the next record from
|
||||
the _start_ of this */
|
||||
char name[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to retrieve the target versions
|
||||
*/
|
||||
struct dm_target_versions {
|
||||
uint32_t next;
|
||||
uint32_t version[3];
|
||||
|
||||
char name[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to pass message to a target
|
||||
*/
|
||||
struct dm_target_msg {
|
||||
uint64_t sector; /* Device sector */
|
||||
|
||||
char message[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* If you change this make sure you make the corresponding change
|
||||
* to dm-ioctl.c:lookup_ioctl()
|
||||
*/
|
||||
enum {
|
||||
/* Top level cmds */
|
||||
DM_VERSION_CMD = 0,
|
||||
DM_REMOVE_ALL_CMD,
|
||||
DM_LIST_DEVICES_CMD,
|
||||
|
||||
/* device level cmds */
|
||||
DM_DEV_CREATE_CMD,
|
||||
DM_DEV_REMOVE_CMD,
|
||||
DM_DEV_RENAME_CMD,
|
||||
DM_DEV_SUSPEND_CMD,
|
||||
DM_DEV_STATUS_CMD,
|
||||
DM_DEV_WAIT_CMD,
|
||||
|
||||
/* Table level cmds */
|
||||
DM_TABLE_LOAD_CMD,
|
||||
DM_TABLE_CLEAR_CMD,
|
||||
DM_TABLE_DEPS_CMD,
|
||||
DM_TABLE_STATUS_CMD,
|
||||
|
||||
/* Added later */
|
||||
DM_LIST_VERSIONS_CMD,
|
||||
DM_TARGET_MSG_CMD,
|
||||
DM_DEV_SET_GEOMETRY_CMD,
|
||||
DM_DEV_ARM_POLL_CMD,
|
||||
};
|
||||
|
||||
#define DM_IOCTL 0xfd
|
||||
|
||||
#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
|
||||
#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
|
||||
#define DM_LIST_DEVICES _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_WAIT _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, DM_DEV_ARM_POLL_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_TABLE_LOAD _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
|
||||
#define DM_TABLE_CLEAR _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
|
||||
#define DM_TABLE_DEPS _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl)
|
||||
#define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_VERSION_MAJOR 4
|
||||
#define DM_VERSION_MINOR 36
|
||||
#define DM_VERSION_PATCHLEVEL 0
|
||||
#define DM_VERSION_EXTRA "-ioctl (2017-06-09)"
|
||||
|
||||
/* Status bits */
|
||||
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
|
||||
#define DM_SUSPEND_FLAG (1 << 1) /* In/Out */
|
||||
#define DM_PERSISTENT_DEV_FLAG (1 << 3) /* In */
|
||||
|
||||
/*
|
||||
* Flag passed into ioctl STATUS command to get table information
|
||||
* rather than current status.
|
||||
*/
|
||||
#define DM_STATUS_TABLE_FLAG (1 << 4) /* In */
|
||||
|
||||
/*
|
||||
* Flags that indicate whether a table is present in either of
|
||||
* the two table slots that a device has.
|
||||
*/
|
||||
#define DM_ACTIVE_PRESENT_FLAG (1 << 5) /* Out */
|
||||
#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */
|
||||
|
||||
/*
|
||||
* Indicates that the buffer passed in wasn't big enough for the
|
||||
* results.
|
||||
*/
|
||||
#define DM_BUFFER_FULL_FLAG (1 << 8) /* Out */
|
||||
|
||||
/*
|
||||
* This flag is now ignored.
|
||||
*/
|
||||
#define DM_SKIP_BDGET_FLAG (1 << 9) /* In */
|
||||
|
||||
/*
|
||||
* Set this to avoid attempting to freeze any filesystem when suspending.
|
||||
*/
|
||||
#define DM_SKIP_LOCKFS_FLAG (1 << 10) /* In */
|
||||
|
||||
/*
|
||||
* Set this to suspend without flushing queued ios.
|
||||
* Also disables flushing uncommitted changes in the thin target before
|
||||
* generating statistics for DM_TABLE_STATUS and DM_DEV_WAIT.
|
||||
*/
|
||||
#define DM_NOFLUSH_FLAG (1 << 11) /* In */
|
||||
|
||||
/*
|
||||
* If set, any table information returned will relate to the inactive
|
||||
* table instead of the live one. Always check DM_INACTIVE_PRESENT_FLAG
|
||||
* is set before using the data returned.
|
||||
*/
|
||||
#define DM_QUERY_INACTIVE_TABLE_FLAG (1 << 12) /* In */
|
||||
|
||||
/*
|
||||
* If set, a uevent was generated for which the caller may need to wait.
|
||||
*/
|
||||
#define DM_UEVENT_GENERATED_FLAG (1 << 13) /* Out */
|
||||
|
||||
/*
|
||||
* If set, rename changes the uuid not the name. Only permitted
|
||||
* if no uuid was previously supplied: an existing uuid cannot be changed.
|
||||
*/
|
||||
#define DM_UUID_FLAG (1 << 14) /* In */
|
||||
|
||||
/*
|
||||
* If set, all buffers are wiped after use. Use when sending
|
||||
* or requesting sensitive data such as an encryption key.
|
||||
*/
|
||||
#define DM_SECURE_DATA_FLAG (1 << 15) /* In */
|
||||
|
||||
/*
|
||||
* If set, a message generated output data.
|
||||
*/
|
||||
#define DM_DATA_OUT_FLAG (1 << 16) /* Out */
|
||||
|
||||
/*
|
||||
* If set with DM_DEV_REMOVE or DM_REMOVE_ALL this indicates that if
|
||||
* the device cannot be removed immediately because it is still in use
|
||||
* it should instead be scheduled for removal when it gets closed.
|
||||
*
|
||||
* On return from DM_DEV_REMOVE, DM_DEV_STATUS or other ioctls, this
|
||||
* flag indicates that the device is scheduled to be removed when it
|
||||
* gets closed.
|
||||
*/
|
||||
#define DM_DEFERRED_REMOVE (1 << 17) /* In/Out */
|
||||
|
||||
/*
|
||||
* If set, the device is suspended internally.
|
||||
*/
|
||||
#define DM_INTERNAL_SUSPEND_FLAG (1 << 18) /* Out */
|
||||
|
||||
#endif /* _LINUX_DM_IOCTL_H */
|
418
device_mapper/misc/dm-log-userspace.h
Normal file
418
device_mapper/misc/dm-log-userspace.h
Normal file
@ -0,0 +1,418 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2009 Red Hat, Inc.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef __DM_LOG_USERSPACE_H__
|
||||
#define __DM_LOG_USERSPACE_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "dm-ioctl.h" /* For DM_UUID_LEN */
|
||||
|
||||
/*
|
||||
* The device-mapper userspace log module consists of a kernel component and
|
||||
* a user-space component. The kernel component implements the API defined
|
||||
* in dm-dirty-log.h. Its purpose is simply to pass the parameters and
|
||||
* return values of those API functions between kernel and user-space.
|
||||
*
|
||||
* Below are defined the 'request_types' - DM_ULOG_CTR, DM_ULOG_DTR, etc.
|
||||
* These request types represent the different functions in the device-mapper
|
||||
* dirty log API. Each of these is described in more detail below.
|
||||
*
|
||||
* The user-space program must listen for requests from the kernel (representing
|
||||
* the various API functions) and process them.
|
||||
*
|
||||
* User-space begins by setting up the communication link (error checking
|
||||
* removed for clarity):
|
||||
* fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
|
||||
* addr.nl_family = AF_NETLINK;
|
||||
* addr.nl_groups = CN_IDX_DM;
|
||||
* addr.nl_pid = 0;
|
||||
* r = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
|
||||
* opt = addr.nl_groups;
|
||||
* setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &opt, sizeof(opt));
|
||||
*
|
||||
* User-space will then wait to receive requests from the kernel, which it
|
||||
* will process as described below. The requests are received in the form,
|
||||
* ((struct dm_ulog_request) + (additional data)). Depending on the request
|
||||
* type, there may or may not be 'additional data'. In the descriptions below,
|
||||
* you will see 'Payload-to-userspace' and 'Payload-to-kernel'. The
|
||||
* 'Payload-to-userspace' is what the kernel sends in 'additional data' as
|
||||
* necessary parameters to complete the request. The 'Payload-to-kernel' is
|
||||
* the 'additional data' returned to the kernel that contains the necessary
|
||||
* results of the request. The 'data_size' field in the dm_ulog_request
|
||||
* structure denotes the availability and amount of payload data.
|
||||
*/
|
||||
|
||||
/*
|
||||
* DM_ULOG_CTR corresponds to (found in dm-dirty-log.h):
|
||||
* int (*ctr)(struct dm_dirty_log *log, struct dm_target *ti,
|
||||
* unsigned argc, char **argv);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* A single string containing all the argv arguments separated by ' 's
|
||||
* Payload-to-kernel:
|
||||
* The name of the device that is used as the backing store for the log
|
||||
* data. 'dm_get_device' will be called on this device. ('dm_put_device'
|
||||
* will be called on this device automatically after calling DM_ULOG_DTR.)
|
||||
* If there is no device needed for log data, 'data_size' in the
|
||||
* dm_ulog_request struct should be 0.
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is the reference that
|
||||
* will be used by all request types to a specific log. The constructor must
|
||||
* record this assotiation with the instance created.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field, filling the
|
||||
* data field with the log device if necessary, and setting 'data_size'
|
||||
* appropriately.
|
||||
*/
|
||||
#define DM_ULOG_CTR 1
|
||||
|
||||
/*
|
||||
* DM_ULOG_DTR corresponds to (found in dm-dirty-log.h):
|
||||
* void (*dtr)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* A single string containing all the argv arguments separated by ' 's
|
||||
* Payload-to-kernel:
|
||||
* None. ('data_size' in the dm_ulog_request struct should be 0.)
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is all that is
|
||||
* necessary to identify the log instance being destroyed. There is no
|
||||
* payload data.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_DTR 2
|
||||
|
||||
/*
|
||||
* DM_ULOG_PRESUSPEND corresponds to (found in dm-dirty-log.h):
|
||||
* int (*presuspend)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is all that is
|
||||
* necessary to identify the log instance being presuspended. There is no
|
||||
* payload data.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_PRESUSPEND 3
|
||||
|
||||
/*
|
||||
* DM_ULOG_POSTSUSPEND corresponds to (found in dm-dirty-log.h):
|
||||
* int (*postsuspend)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is all that is
|
||||
* necessary to identify the log instance being postsuspended. There is no
|
||||
* payload data.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_POSTSUSPEND 4
|
||||
|
||||
/*
|
||||
* DM_ULOG_RESUME corresponds to (found in dm-dirty-log.h):
|
||||
* int (*resume)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is all that is
|
||||
* necessary to identify the log instance being resumed. There is no
|
||||
* payload data.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_RESUME 5
|
||||
|
||||
/*
|
||||
* DM_ULOG_GET_REGION_SIZE corresponds to (found in dm-dirty-log.h):
|
||||
* uint32_t (*get_region_size)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* uint64_t - contains the region size
|
||||
*
|
||||
* The region size is something that was determined at constructor time.
|
||||
* It is returned in the payload area and 'data_size' is set to
|
||||
* reflect this.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field appropriately.
|
||||
*/
|
||||
#define DM_ULOG_GET_REGION_SIZE 6
|
||||
|
||||
/*
|
||||
* DM_ULOG_IS_CLEAN corresponds to (found in dm-dirty-log.h):
|
||||
* int (*is_clean)(struct dm_dirty_log *log, region_t region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t - the region to get clean status on
|
||||
* Payload-to-kernel:
|
||||
* int64_t - 1 if clean, 0 otherwise
|
||||
*
|
||||
* Payload is sizeof(uint64_t) and contains the region for which the clean
|
||||
* status is being made.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - filling the payload with 0 (not clean) or
|
||||
* 1 (clean), setting 'data_size' and 'error' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_IS_CLEAN 7
|
||||
|
||||
/*
|
||||
* DM_ULOG_IN_SYNC corresponds to (found in dm-dirty-log.h):
|
||||
* int (*in_sync)(struct dm_dirty_log *log, region_t region,
|
||||
* int can_block);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t - the region to get sync status on
|
||||
* Payload-to-kernel:
|
||||
* int64_t - 1 if in-sync, 0 otherwise
|
||||
*
|
||||
* Exactly the same as 'is_clean' above, except this time asking "has the
|
||||
* region been recovered?" vs. "is the region not being modified?"
|
||||
*/
|
||||
#define DM_ULOG_IN_SYNC 8
|
||||
|
||||
/*
|
||||
* DM_ULOG_FLUSH corresponds to (found in dm-dirty-log.h):
|
||||
* int (*flush)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* No incoming or outgoing payload. Simply flush log state to disk.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_FLUSH 9
|
||||
|
||||
/*
|
||||
* DM_ULOG_MARK_REGION corresponds to (found in dm-dirty-log.h):
|
||||
* void (*mark_region)(struct dm_dirty_log *log, region_t region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t [] - region(s) to mark
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* Incoming payload contains the one or more regions to mark dirty.
|
||||
* The number of regions contained in the payload can be determined from
|
||||
* 'data_size/sizeof(uint64_t)'.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_MARK_REGION 10
|
||||
|
||||
/*
|
||||
* DM_ULOG_CLEAR_REGION corresponds to (found in dm-dirty-log.h):
|
||||
* void (*clear_region)(struct dm_dirty_log *log, region_t region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t [] - region(s) to clear
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* Incoming payload contains the one or more regions to mark clean.
|
||||
* The number of regions contained in the payload can be determined from
|
||||
* 'data_size/sizeof(uint64_t)'.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_CLEAR_REGION 11
|
||||
|
||||
/*
|
||||
* DM_ULOG_GET_RESYNC_WORK corresponds to (found in dm-dirty-log.h):
|
||||
* int (*get_resync_work)(struct dm_dirty_log *log, region_t *region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* {
|
||||
* int64_t i; -- 1 if recovery necessary, 0 otherwise
|
||||
* uint64_t r; -- The region to recover if i=1
|
||||
* }
|
||||
* 'data_size' should be set appropriately.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field appropriately.
|
||||
*/
|
||||
#define DM_ULOG_GET_RESYNC_WORK 12
|
||||
|
||||
/*
|
||||
* DM_ULOG_SET_REGION_SYNC corresponds to (found in dm-dirty-log.h):
|
||||
* void (*set_region_sync)(struct dm_dirty_log *log,
|
||||
* region_t region, int in_sync);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* {
|
||||
* uint64_t - region to set sync state on
|
||||
* int64_t - 0 if not-in-sync, 1 if in-sync
|
||||
* }
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_SET_REGION_SYNC 13
|
||||
|
||||
/*
|
||||
* DM_ULOG_GET_SYNC_COUNT corresponds to (found in dm-dirty-log.h):
|
||||
* region_t (*get_sync_count)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* uint64_t - the number of in-sync regions
|
||||
*
|
||||
* No incoming payload. Kernel-bound payload contains the number of
|
||||
* regions that are in-sync (in a size_t).
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_GET_SYNC_COUNT 14
|
||||
|
||||
/*
|
||||
* DM_ULOG_STATUS_INFO corresponds to (found in dm-dirty-log.h):
|
||||
* int (*status)(struct dm_dirty_log *log, STATUSTYPE_INFO,
|
||||
* char *result, unsigned maxlen);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* Character string containing STATUSTYPE_INFO
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_STATUS_INFO 15
|
||||
|
||||
/*
|
||||
* DM_ULOG_STATUS_TABLE corresponds to (found in dm-dirty-log.h):
|
||||
* int (*status)(struct dm_dirty_log *log, STATUSTYPE_TABLE,
|
||||
* char *result, unsigned maxlen);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* Character string containing STATUSTYPE_TABLE
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_STATUS_TABLE 16
|
||||
|
||||
/*
|
||||
* DM_ULOG_IS_REMOTE_RECOVERING corresponds to (found in dm-dirty-log.h):
|
||||
* int (*is_remote_recovering)(struct dm_dirty_log *log, region_t region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t - region to determine recovery status on
|
||||
* Payload-to-kernel:
|
||||
* {
|
||||
* int64_t is_recovering; -- 0 if no, 1 if yes
|
||||
* uint64_t in_sync_hint; -- lowest region still needing resync
|
||||
* }
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_IS_REMOTE_RECOVERING 17
|
||||
|
||||
/*
|
||||
* (DM_ULOG_REQUEST_MASK & request_type) to get the request type
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* A single string containing all the argv arguments separated by ' 's
|
||||
* Payload-to-kernel:
|
||||
* None. ('data_size' in the dm_ulog_request struct should be 0.)
|
||||
*
|
||||
* We are reserving 8 bits of the 32-bit 'request_type' field for the
|
||||
* various request types above. The remaining 24-bits are currently
|
||||
* set to zero and are reserved for future use and compatibility concerns.
|
||||
*
|
||||
* User-space should always use DM_ULOG_REQUEST_TYPE to acquire the
|
||||
* request type from the 'request_type' field to maintain forward compatibility.
|
||||
*/
|
||||
#define DM_ULOG_REQUEST_MASK 0xFF
|
||||
#define DM_ULOG_REQUEST_TYPE(request_type) \
|
||||
(DM_ULOG_REQUEST_MASK & (request_type))
|
||||
|
||||
/*
|
||||
* DM_ULOG_REQUEST_VERSION is incremented when there is a
|
||||
* change to the way information is passed between kernel
|
||||
* and userspace. This could be a structure change of
|
||||
* dm_ulog_request or a change in the way requests are
|
||||
* issued/handled. Changes are outlined here:
|
||||
* version 1: Initial implementation
|
||||
* version 2: DM_ULOG_CTR allowed to return a string containing a
|
||||
* device name that is to be registered with DM via
|
||||
* 'dm_get_device'.
|
||||
*/
|
||||
#define DM_ULOG_REQUEST_VERSION 2
|
||||
|
||||
struct dm_ulog_request {
|
||||
/*
|
||||
* The local unique identifier (luid) and the universally unique
|
||||
* identifier (uuid) are used to tie a request to a specific
|
||||
* mirror log. A single machine log could probably make due with
|
||||
* just the 'luid', but a cluster-aware log must use the 'uuid' and
|
||||
* the 'luid'. The uuid is what is required for node to node
|
||||
* communication concerning a particular log, but the 'luid' helps
|
||||
* differentiate between logs that are being swapped and have the
|
||||
* same 'uuid'. (Think "live" and "inactive" device-mapper tables.)
|
||||
*/
|
||||
uint64_t luid;
|
||||
char uuid[DM_UUID_LEN];
|
||||
char padding[3]; /* Padding because DM_UUID_LEN = 129 */
|
||||
|
||||
uint32_t version; /* See DM_ULOG_REQUEST_VERSION */
|
||||
int32_t error; /* Used to report back processing errors */
|
||||
|
||||
uint32_t seq; /* Sequence number for request */
|
||||
uint32_t request_type; /* DM_ULOG_* defined above */
|
||||
uint32_t data_size; /* How much data (not including this struct) */
|
||||
|
||||
char data[];
|
||||
};
|
||||
|
||||
#endif /* __DM_LOG_USERSPACE_H__ */
|
34
device_mapper/misc/dm-logging.h
Normal file
34
device_mapper/misc/dm-logging.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _DM_LOGGING_H
|
||||
#define _DM_LOGGING_H
|
||||
|
||||
#include "libdevmapper.h"
|
||||
|
||||
extern dm_log_with_errno_fn dm_log_with_errno;
|
||||
|
||||
#define LOG_MESG(l, f, ln, e, x...) \
|
||||
dm_log_with_errno(l, f, ln, e, ## x)
|
||||
|
||||
#define LOG_LINE(l, x...) LOG_MESG(l, __FILE__, __LINE__, 0, ## x)
|
||||
#define LOG_LINE_WITH_ERRNO(l, e, x...) LOG_MESG(l, __FILE__, __LINE__, e, ## x)
|
||||
|
||||
/* Debug messages may have a type instead of an errno */
|
||||
#define LOG_LINE_WITH_CLASS(l, c, x...) LOG_MESG(l, __FILE__, __LINE__, c, ## x)
|
||||
|
||||
#include "lib/log/log.h"
|
||||
|
||||
#endif
|
33
device_mapper/misc/dmlib.h
Normal file
33
device_mapper/misc/dmlib.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 LVM2.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file must be included first by every device-mapper library source file.
|
||||
*/
|
||||
#ifndef _DM_LIB_H
|
||||
#define _DM_LIB_H
|
||||
|
||||
// FIXME: get rid of this whole file
|
||||
|
||||
#include "configure.h"
|
||||
|
||||
#define _REENTRANT
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "lib/misc/util.h"
|
||||
#include "dm-logging.h"
|
||||
|
||||
#endif
|
22
device_mapper/misc/kdev_t.h
Normal file
22
device_mapper/misc/kdev_t.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _LIBDM_KDEV_H
|
||||
#define _LIBDM_KDEV_H
|
||||
|
||||
#define MAJOR(dev) ((dev & 0xfff00) >> 8)
|
||||
#define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
|
||||
#define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
|
||||
|
||||
#endif
|
413
device_mapper/mm/dbg_malloc.c
Normal file
413
device_mapper/mm/dbg_malloc.c
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
|
||||
#ifdef VALGRIND_POOL
|
||||
#include "memcheck.h"
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void *dm_malloc_aux(size_t s, const char *file, int line)
|
||||
__attribute__((__malloc__)) __attribute__((__warn_unused_result__));
|
||||
void *dm_malloc_aux_debug(size_t s, const char *file, int line)
|
||||
__attribute__((__malloc__)) __attribute__((__warn_unused_result__));
|
||||
static void *_dm_malloc_aligned_aux(size_t s, size_t a, const char *file, int line)
|
||||
__attribute__((__malloc__)) __attribute__((__warn_unused_result__));
|
||||
void *dm_zalloc_aux(size_t s, const char *file, int line)
|
||||
__attribute__((__malloc__)) __attribute__((__warn_unused_result__));
|
||||
void *dm_zalloc_aux_debug(size_t s, const char *file, int line)
|
||||
__attribute__((__malloc__)) __attribute__((__warn_unused_result__));
|
||||
void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
|
||||
__attribute__((__warn_unused_result__));
|
||||
void dm_free_aux(void *p);
|
||||
char *dm_strdup_aux(const char *str, const char *file, int line)
|
||||
__attribute__((__warn_unused_result__));
|
||||
int dm_dump_memory_debug(void);
|
||||
void dm_bounds_check_debug(void);
|
||||
|
||||
char *dm_strdup_aux(const char *str, const char *file, int line)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (!str) {
|
||||
log_error(INTERNAL_ERROR "dm_strdup called with NULL pointer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ret = dm_malloc_aux_debug(strlen(str) + 1, file, line)))
|
||||
strcpy(ret, str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct memblock {
|
||||
struct memblock *prev, *next; /* All allocated blocks are linked */
|
||||
size_t length; /* Size of the requested block */
|
||||
int id; /* Index of the block */
|
||||
const char *file; /* File that allocated */
|
||||
int line; /* Line that allocated */
|
||||
void *magic; /* Address of this block */
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
static struct {
|
||||
unsigned block_serialno;/* Non-decreasing serialno of block */
|
||||
unsigned blocks_allocated; /* Current number of blocks allocated */
|
||||
unsigned blocks_max; /* Max no of concurrently-allocated blocks */
|
||||
unsigned int bytes, mbytes;
|
||||
|
||||
} _mem_stats = {
|
||||
0, 0, 0, 0, 0};
|
||||
|
||||
static struct memblock *_head = 0;
|
||||
static struct memblock *_tail = 0;
|
||||
|
||||
void *dm_malloc_aux_debug(size_t s, const char *file, int line)
|
||||
{
|
||||
struct memblock *nb;
|
||||
size_t tsize = s + sizeof(*nb) + sizeof(unsigned long);
|
||||
|
||||
if (s > 50000000) {
|
||||
log_error("Huge memory allocation (size %" PRIsize_t
|
||||
") rejected - metadata corruption?", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(nb = malloc(tsize))) {
|
||||
log_error("couldn't allocate any memory, size = %" PRIsize_t,
|
||||
s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set up the file and line info */
|
||||
nb->file = file;
|
||||
nb->line = line;
|
||||
|
||||
dm_bounds_check();
|
||||
|
||||
/* setup fields */
|
||||
nb->magic = nb + 1;
|
||||
nb->length = s;
|
||||
nb->id = ++_mem_stats.block_serialno;
|
||||
nb->next = 0;
|
||||
|
||||
/* stomp a pretty pattern across the new memory
|
||||
and fill in the boundary bytes */
|
||||
{
|
||||
char *ptr = (char *) (nb + 1);
|
||||
size_t i;
|
||||
for (i = 0; i < s; i++)
|
||||
*ptr++ = i & 0x1 ? (char) 0xba : (char) 0xbe;
|
||||
|
||||
for (i = 0; i < sizeof(unsigned long); i++)
|
||||
*ptr++ = (char) nb->id;
|
||||
}
|
||||
|
||||
nb->prev = _tail;
|
||||
|
||||
/* link to tail of the list */
|
||||
if (!_head)
|
||||
_head = _tail = nb;
|
||||
else {
|
||||
_tail->next = nb;
|
||||
_tail = nb;
|
||||
}
|
||||
|
||||
_mem_stats.blocks_allocated++;
|
||||
if (_mem_stats.blocks_allocated > _mem_stats.blocks_max)
|
||||
_mem_stats.blocks_max = _mem_stats.blocks_allocated;
|
||||
|
||||
_mem_stats.bytes += s;
|
||||
if (_mem_stats.bytes > _mem_stats.mbytes)
|
||||
_mem_stats.mbytes = _mem_stats.bytes;
|
||||
|
||||
/* log_debug_mem("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated,
|
||||
_mem_stats.bytes); */
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(nb + 1, s);
|
||||
#endif
|
||||
return nb + 1;
|
||||
}
|
||||
|
||||
void *dm_zalloc_aux_debug(size_t s, const char *file, int line)
|
||||
{
|
||||
void *ptr = dm_malloc_aux_debug(s, file, line);
|
||||
|
||||
if (ptr)
|
||||
memset(ptr, 0, s);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void dm_free_aux(void *p)
|
||||
{
|
||||
char *ptr;
|
||||
size_t i;
|
||||
struct memblock *mb = ((struct memblock *) p) - 1;
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
dm_bounds_check();
|
||||
|
||||
/* sanity check */
|
||||
assert(mb->magic == p);
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_DEFINED(p, mb->length);
|
||||
#endif
|
||||
/* check data at the far boundary */
|
||||
ptr = (char *) p + mb->length;
|
||||
for (i = 0; i < sizeof(unsigned long); i++)
|
||||
if (ptr[i] != (char) mb->id)
|
||||
assert(!"Damage at far end of block");
|
||||
|
||||
/* have we freed this before ? */
|
||||
assert(mb->id != 0);
|
||||
|
||||
/* unlink */
|
||||
if (mb->prev)
|
||||
mb->prev->next = mb->next;
|
||||
else
|
||||
_head = mb->next;
|
||||
|
||||
if (mb->next)
|
||||
mb->next->prev = mb->prev;
|
||||
else
|
||||
_tail = mb->prev;
|
||||
|
||||
mb->id = 0;
|
||||
|
||||
/* stomp a different pattern across the memory */
|
||||
ptr = p;
|
||||
for (i = 0; i < mb->length; i++)
|
||||
ptr[i] = i & 1 ? (char) 0xde : (char) 0xad;
|
||||
|
||||
assert(_mem_stats.blocks_allocated);
|
||||
_mem_stats.blocks_allocated--;
|
||||
_mem_stats.bytes -= mb->length;
|
||||
|
||||
/* free the memory */
|
||||
free(mb);
|
||||
}
|
||||
|
||||
void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
|
||||
{
|
||||
void *r;
|
||||
struct memblock *mb = ((struct memblock *) p) - 1;
|
||||
|
||||
r = dm_malloc_aux_debug(s, file, line);
|
||||
|
||||
if (r && p) {
|
||||
memcpy(r, p, mb->length);
|
||||
dm_free_aux(p);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_dump_memory_debug(void)
|
||||
{
|
||||
unsigned long tot = 0;
|
||||
struct memblock *mb;
|
||||
char str[32];
|
||||
|
||||
if (_head)
|
||||
log_very_verbose("You have a memory leak:");
|
||||
|
||||
for (mb = _head; mb; mb = mb->next) {
|
||||
#ifdef VALGRIND_POOL
|
||||
/*
|
||||
* We can't look at the memory in case it has had
|
||||
* VALGRIND_MAKE_MEM_NOACCESS called on it.
|
||||
*/
|
||||
str[0] = '\0';
|
||||
#else
|
||||
size_t c;
|
||||
|
||||
for (c = 0; c < sizeof(str) - 1; c++) {
|
||||
if (c >= mb->length)
|
||||
str[c] = ' ';
|
||||
else if (((char *)mb->magic)[c] == '\0')
|
||||
str[c] = '\0';
|
||||
else if (((char *)mb->magic)[c] < ' ')
|
||||
str[c] = '?';
|
||||
else
|
||||
str[c] = ((char *)mb->magic)[c];
|
||||
}
|
||||
str[sizeof(str) - 1] = '\0';
|
||||
#endif
|
||||
|
||||
LOG_MESG(_LOG_INFO, mb->file, mb->line, 0,
|
||||
"block %d at %p, size %" PRIsize_t "\t [%s]",
|
||||
mb->id, mb->magic, mb->length, str);
|
||||
tot += mb->length;
|
||||
}
|
||||
|
||||
if (_head)
|
||||
log_very_verbose("%ld bytes leaked in total", tot);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_bounds_check_debug(void)
|
||||
{
|
||||
struct memblock *mb = _head;
|
||||
while (mb) {
|
||||
size_t i;
|
||||
char *ptr = ((char *) (mb + 1)) + mb->length;
|
||||
for (i = 0; i < sizeof(unsigned long); i++)
|
||||
if (*ptr++ != (char) mb->id)
|
||||
assert(!"Memory smash");
|
||||
|
||||
mb = mb->next;
|
||||
}
|
||||
}
|
||||
|
||||
void *dm_malloc_aux(size_t s, const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)))
|
||||
{
|
||||
if (s > 50000000) {
|
||||
log_error("Huge memory allocation (size %" PRIsize_t
|
||||
") rejected - metadata corruption?", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return malloc(s);
|
||||
}
|
||||
|
||||
/* Allocate size s with alignment a (or page size if 0) */
|
||||
static void *_dm_malloc_aligned_aux(size_t s, size_t a, const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)))
|
||||
{
|
||||
void *memptr;
|
||||
int r;
|
||||
|
||||
if (!a)
|
||||
a = getpagesize();
|
||||
|
||||
if (s > 50000000) {
|
||||
log_error("Huge memory allocation (size %" PRIsize_t
|
||||
") rejected - metadata corruption?", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r = posix_memalign(&memptr, a, s))) {
|
||||
log_error("Failed to allocate %" PRIsize_t " bytes aligned to %" PRIsize_t ": %s", s, a, strerror(r));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return memptr;
|
||||
}
|
||||
|
||||
void *dm_zalloc_aux(size_t s, const char *file, int line)
|
||||
{
|
||||
void *ptr = dm_malloc_aux(s, file, line);
|
||||
|
||||
if (ptr)
|
||||
memset(ptr, 0, s);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEM
|
||||
|
||||
void *dm_malloc_wrapper(size_t s, const char *file, int line)
|
||||
{
|
||||
return dm_malloc_aux_debug(s, file, line);
|
||||
}
|
||||
|
||||
void *dm_malloc_aligned_wrapper(size_t s, size_t a, const char *file, int line)
|
||||
{
|
||||
/* FIXME Implement alignment when debugging - currently just ignored */
|
||||
return _dm_malloc_aux_debug(s, file, line);
|
||||
}
|
||||
|
||||
void *dm_zalloc_wrapper(size_t s, const char *file, int line)
|
||||
{
|
||||
return dm_zalloc_aux_debug(s, file, line);
|
||||
}
|
||||
|
||||
char *dm_strdup_wrapper(const char *str, const char *file, int line)
|
||||
{
|
||||
return dm_strdup_aux(str, file, line);
|
||||
}
|
||||
|
||||
void dm_free_wrapper(void *ptr)
|
||||
{
|
||||
dm_free_aux(ptr);
|
||||
}
|
||||
|
||||
void *dm_realloc_wrapper(void *p, unsigned int s, const char *file, int line)
|
||||
{
|
||||
return dm_realloc_aux(p, s, file, line);
|
||||
}
|
||||
|
||||
int dm_dump_memory_wrapper(void)
|
||||
{
|
||||
return dm_dump_memory_debug();
|
||||
}
|
||||
|
||||
void dm_bounds_check_wrapper(void)
|
||||
{
|
||||
dm_bounds_check_debug();
|
||||
}
|
||||
|
||||
#else /* !DEBUG_MEM */
|
||||
|
||||
void *dm_malloc_wrapper(size_t s, const char *file, int line)
|
||||
{
|
||||
return dm_malloc_aux(s, file, line);
|
||||
}
|
||||
|
||||
void *dm_malloc_aligned_wrapper(size_t s, size_t a, const char *file, int line)
|
||||
{
|
||||
return _dm_malloc_aligned_aux(s, a, file, line);
|
||||
}
|
||||
|
||||
void *dm_zalloc_wrapper(size_t s, const char *file, int line)
|
||||
{
|
||||
return dm_zalloc_aux(s, file, line);
|
||||
}
|
||||
|
||||
char *dm_strdup_wrapper(const char *str,
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)))
|
||||
{
|
||||
return strdup(str);
|
||||
}
|
||||
|
||||
void dm_free_wrapper(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void *dm_realloc_wrapper(void *p, unsigned int s,
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)))
|
||||
{
|
||||
return realloc(p, s);
|
||||
}
|
||||
|
||||
int dm_dump_memory_wrapper(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_bounds_check_wrapper(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* DEBUG_MEM */
|
292
device_mapper/mm/pool-debug.c
Normal file
292
device_mapper/mm/pool-debug.c
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "dmlib.h"
|
||||
#include <assert.h>
|
||||
|
||||
struct block {
|
||||
struct block *next;
|
||||
size_t size;
|
||||
void *data;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned block_serialno; /* Non-decreasing serialno of block */
|
||||
unsigned blocks_allocated; /* Current number of blocks allocated */
|
||||
unsigned blocks_max; /* Max no of concurrently-allocated blocks */
|
||||
unsigned int bytes, maxbytes;
|
||||
} pool_stats;
|
||||
|
||||
struct dm_pool {
|
||||
struct dm_list list;
|
||||
const char *name;
|
||||
void *orig_pool; /* to pair it with first allocation call */
|
||||
unsigned locked;
|
||||
long crc;
|
||||
|
||||
int begun;
|
||||
struct block *object;
|
||||
|
||||
struct block *blocks;
|
||||
struct block *tail;
|
||||
|
||||
pool_stats stats;
|
||||
};
|
||||
|
||||
/* by default things come out aligned for doubles */
|
||||
#define DEFAULT_ALIGNMENT __alignof__ (double)
|
||||
|
||||
struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
|
||||
{
|
||||
struct dm_pool *mem = dm_zalloc(sizeof(*mem));
|
||||
|
||||
if (!mem) {
|
||||
log_error("Couldn't create memory pool %s (size %"
|
||||
PRIsize_t ")", name, sizeof(*mem));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mem->name = name;
|
||||
mem->orig_pool = mem;
|
||||
|
||||
#ifdef DEBUG_POOL
|
||||
log_debug_mem("Created mempool %s at %p", name, mem);
|
||||
#endif
|
||||
|
||||
dm_list_add(&_dm_pools, &mem->list);
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void _free_blocks(struct dm_pool *p, struct block *b)
|
||||
{
|
||||
struct block *n;
|
||||
|
||||
if (p->locked)
|
||||
log_error(INTERNAL_ERROR "_free_blocks from locked pool %s",
|
||||
p->name);
|
||||
|
||||
while (b) {
|
||||
p->stats.bytes -= b->size;
|
||||
p->stats.blocks_allocated--;
|
||||
|
||||
n = b->next;
|
||||
dm_free(b->data);
|
||||
dm_free(b);
|
||||
b = n;
|
||||
}
|
||||
}
|
||||
|
||||
static void _pool_stats(struct dm_pool *p, const char *action)
|
||||
{
|
||||
#ifdef DEBUG_POOL
|
||||
log_debug_mem("%s mempool %s at %p: %u/%u bytes, %u/%u blocks, "
|
||||
"%u allocations)", action, p->name, p, p->stats.bytes,
|
||||
p->stats.maxbytes, p->stats.blocks_allocated,
|
||||
p->stats.blocks_max, p->stats.block_serialno);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
}
|
||||
|
||||
void dm_pool_destroy(struct dm_pool *p)
|
||||
{
|
||||
_pool_stats(p, "Destroying");
|
||||
_free_blocks(p, p->blocks);
|
||||
dm_list_del(&p->list);
|
||||
dm_free(p);
|
||||
}
|
||||
|
||||
void *dm_pool_alloc(struct dm_pool *p, size_t s)
|
||||
{
|
||||
return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
static void _append_block(struct dm_pool *p, struct block *b)
|
||||
{
|
||||
if (p->locked)
|
||||
log_error(INTERNAL_ERROR "_append_blocks to locked pool %s",
|
||||
p->name);
|
||||
|
||||
if (p->tail) {
|
||||
p->tail->next = b;
|
||||
p->tail = b;
|
||||
} else
|
||||
p->blocks = p->tail = b;
|
||||
|
||||
p->stats.block_serialno++;
|
||||
p->stats.blocks_allocated++;
|
||||
if (p->stats.blocks_allocated > p->stats.blocks_max)
|
||||
p->stats.blocks_max = p->stats.blocks_allocated;
|
||||
|
||||
p->stats.bytes += b->size;
|
||||
if (p->stats.bytes > p->stats.maxbytes)
|
||||
p->stats.maxbytes = p->stats.bytes;
|
||||
}
|
||||
|
||||
static struct block *_new_block(size_t s, unsigned alignment)
|
||||
{
|
||||
/* FIXME: I'm currently ignoring the alignment arg. */
|
||||
size_t len = sizeof(struct block) + s;
|
||||
struct block *b = dm_malloc(len);
|
||||
|
||||
/*
|
||||
* Too lazy to implement alignment for debug version, and
|
||||
* I don't think LVM will use anything but default
|
||||
* align.
|
||||
*/
|
||||
assert(alignment <= DEFAULT_ALIGNMENT);
|
||||
|
||||
if (!b) {
|
||||
log_error("Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(b->data = dm_malloc(s))) {
|
||||
log_error("Out of memory");
|
||||
dm_free(b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b->next = NULL;
|
||||
b->size = s;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
|
||||
{
|
||||
struct block *b = _new_block(s, alignment);
|
||||
|
||||
if (!b)
|
||||
return_NULL;
|
||||
|
||||
_append_block(p, b);
|
||||
|
||||
return b->data;
|
||||
}
|
||||
|
||||
void dm_pool_empty(struct dm_pool *p)
|
||||
{
|
||||
_pool_stats(p, "Emptying");
|
||||
_free_blocks(p, p->blocks);
|
||||
p->blocks = p->tail = NULL;
|
||||
}
|
||||
|
||||
void dm_pool_free(struct dm_pool *p, void *ptr)
|
||||
{
|
||||
struct block *b, *prev = NULL;
|
||||
|
||||
_pool_stats(p, "Freeing (before)");
|
||||
|
||||
for (b = p->blocks; b; b = b->next) {
|
||||
if (b->data == ptr)
|
||||
break;
|
||||
prev = b;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this fires then you tried to free a
|
||||
* pointer that either wasn't from this
|
||||
* pool, or isn't the start of a block.
|
||||
*/
|
||||
assert(b);
|
||||
|
||||
_free_blocks(p, b);
|
||||
|
||||
if (prev) {
|
||||
p->tail = prev;
|
||||
prev->next = NULL;
|
||||
} else
|
||||
p->blocks = p->tail = NULL;
|
||||
|
||||
_pool_stats(p, "Freeing (after)");
|
||||
}
|
||||
|
||||
int dm_pool_begin_object(struct dm_pool *p, size_t init_size)
|
||||
{
|
||||
assert(!p->begun);
|
||||
p->begun = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
|
||||
{
|
||||
struct block *new;
|
||||
size_t new_size;
|
||||
|
||||
if (p->locked)
|
||||
log_error(INTERNAL_ERROR "Grow objects in locked pool %s",
|
||||
p->name);
|
||||
|
||||
if (!delta)
|
||||
delta = strlen(extra);
|
||||
|
||||
assert(p->begun);
|
||||
|
||||
if (p->object)
|
||||
new_size = delta + p->object->size;
|
||||
else
|
||||
new_size = delta;
|
||||
|
||||
if (!(new = _new_block(new_size, DEFAULT_ALIGNMENT))) {
|
||||
log_error("Couldn't extend object.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p->object) {
|
||||
memcpy(new->data, p->object->data, p->object->size);
|
||||
dm_free(p->object->data);
|
||||
dm_free(p->object);
|
||||
}
|
||||
p->object = new;
|
||||
|
||||
memcpy((char*)new->data + new_size - delta, extra, delta);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *dm_pool_end_object(struct dm_pool *p)
|
||||
{
|
||||
assert(p->begun);
|
||||
_append_block(p, p->object);
|
||||
|
||||
p->begun = 0;
|
||||
p->object = NULL;
|
||||
return p->tail->data;
|
||||
}
|
||||
|
||||
void dm_pool_abandon_object(struct dm_pool *p)
|
||||
{
|
||||
assert(p->begun);
|
||||
dm_free(p->object);
|
||||
p->begun = 0;
|
||||
p->object = NULL;
|
||||
}
|
||||
|
||||
static long _pool_crc(const struct dm_pool *p)
|
||||
{
|
||||
#ifndef DEBUG_ENFORCE_POOL_LOCKING
|
||||
#warning pool crc not implemented with pool debug
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _pool_protect(struct dm_pool *p, int prot)
|
||||
{
|
||||
#ifdef DEBUG_ENFORCE_POOL_LOCKING
|
||||
#warning pool mprotect not implemented with pool debug
|
||||
#endif
|
||||
return 1;
|
||||
}
|
363
device_mapper/mm/pool-fast.c
Normal file
363
device_mapper/mm/pool-fast.c
Normal file
@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef VALGRIND_POOL
|
||||
#include "memcheck.h"
|
||||
#endif
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
#include <stddef.h> /* For musl libc */
|
||||
#include <malloc.h>
|
||||
|
||||
struct chunk {
|
||||
char *begin, *end;
|
||||
struct chunk *prev;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct dm_pool {
|
||||
struct dm_list list;
|
||||
struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
|
||||
list to stop 'bobbling' */
|
||||
const char *name;
|
||||
size_t chunk_size;
|
||||
size_t object_len;
|
||||
unsigned object_alignment;
|
||||
int locked;
|
||||
long crc;
|
||||
};
|
||||
|
||||
static void _align_chunk(struct chunk *c, unsigned alignment);
|
||||
static struct chunk *_new_chunk(struct dm_pool *p, size_t s);
|
||||
static void _free_chunk(struct chunk *c);
|
||||
|
||||
/* by default things come out aligned for doubles */
|
||||
#define DEFAULT_ALIGNMENT __alignof__ (double)
|
||||
|
||||
struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
|
||||
{
|
||||
size_t new_size = 1024;
|
||||
struct dm_pool *p = dm_zalloc(sizeof(*p));
|
||||
|
||||
if (!p) {
|
||||
log_error("Couldn't create memory pool %s (size %"
|
||||
PRIsize_t ")", name, sizeof(*p));
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->name = name;
|
||||
/* round chunk_hint up to the next power of 2 */
|
||||
p->chunk_size = chunk_hint + sizeof(struct chunk);
|
||||
while (new_size < p->chunk_size)
|
||||
new_size <<= 1;
|
||||
p->chunk_size = new_size;
|
||||
pthread_mutex_lock(&_dm_pools_mutex);
|
||||
dm_list_add(&_dm_pools, &p->list);
|
||||
pthread_mutex_unlock(&_dm_pools_mutex);
|
||||
return p;
|
||||
}
|
||||
|
||||
void dm_pool_destroy(struct dm_pool *p)
|
||||
{
|
||||
struct chunk *c, *pr;
|
||||
_free_chunk(p->spare_chunk);
|
||||
c = p->chunk;
|
||||
while (c) {
|
||||
pr = c->prev;
|
||||
_free_chunk(c);
|
||||
c = pr;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_dm_pools_mutex);
|
||||
dm_list_del(&p->list);
|
||||
pthread_mutex_unlock(&_dm_pools_mutex);
|
||||
dm_free(p);
|
||||
}
|
||||
|
||||
void *dm_pool_alloc(struct dm_pool *p, size_t s)
|
||||
{
|
||||
return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
|
||||
{
|
||||
struct chunk *c = p->chunk;
|
||||
void *r;
|
||||
|
||||
/* realign begin */
|
||||
if (c)
|
||||
_align_chunk(c, alignment);
|
||||
|
||||
/* have we got room ? */
|
||||
if (!c || (c->begin > c->end) || ((c->end - c->begin) < (int) s)) {
|
||||
/* allocate new chunk */
|
||||
size_t needed = s + alignment + sizeof(struct chunk);
|
||||
c = _new_chunk(p, (needed > p->chunk_size) ?
|
||||
needed : p->chunk_size);
|
||||
|
||||
if (!c)
|
||||
return_NULL;
|
||||
|
||||
_align_chunk(c, alignment);
|
||||
}
|
||||
|
||||
r = c->begin;
|
||||
c->begin += s;
|
||||
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(r, s);
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void dm_pool_empty(struct dm_pool *p)
|
||||
{
|
||||
struct chunk *c;
|
||||
|
||||
for (c = p->chunk; c && c->prev; c = c->prev)
|
||||
;
|
||||
|
||||
if (c)
|
||||
dm_pool_free(p, (char *) (c + 1));
|
||||
}
|
||||
|
||||
void dm_pool_free(struct dm_pool *p, void *ptr)
|
||||
{
|
||||
struct chunk *c = p->chunk;
|
||||
|
||||
while (c) {
|
||||
if (((char *) c < (char *) ptr) &&
|
||||
((char *) c->end > (char *) ptr)) {
|
||||
c->begin = ptr;
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_NOACCESS(c->begin, c->end - c->begin);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (p->spare_chunk)
|
||||
_free_chunk(p->spare_chunk);
|
||||
|
||||
c->begin = (char *) (c + 1);
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_NOACCESS(c->begin, c->end - c->begin);
|
||||
#endif
|
||||
|
||||
p->spare_chunk = c;
|
||||
c = c->prev;
|
||||
}
|
||||
|
||||
if (!c)
|
||||
log_error(INTERNAL_ERROR "pool_free asked to free pointer "
|
||||
"not in pool");
|
||||
else
|
||||
p->chunk = c;
|
||||
}
|
||||
|
||||
int dm_pool_begin_object(struct dm_pool *p, size_t hint)
|
||||
{
|
||||
struct chunk *c = p->chunk;
|
||||
const size_t align = DEFAULT_ALIGNMENT;
|
||||
|
||||
p->object_len = 0;
|
||||
p->object_alignment = align;
|
||||
|
||||
if (c)
|
||||
_align_chunk(c, align);
|
||||
|
||||
if (!c || (c->begin > c->end) || ((c->end - c->begin) < (int) hint)) {
|
||||
/* allocate a new chunk */
|
||||
c = _new_chunk(p,
|
||||
hint > (p->chunk_size - sizeof(struct chunk)) ?
|
||||
hint + sizeof(struct chunk) + align :
|
||||
p->chunk_size);
|
||||
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
_align_chunk(c, align);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
|
||||
{
|
||||
struct chunk *c = p->chunk, *nc;
|
||||
|
||||
if (!delta)
|
||||
delta = strlen(extra);
|
||||
|
||||
if ((c->end - (c->begin + p->object_len)) < (int) delta) {
|
||||
/* move into a new chunk */
|
||||
if (p->object_len + delta > (p->chunk_size / 2))
|
||||
nc = _new_chunk(p, (p->object_len + delta) * 2);
|
||||
else
|
||||
nc = _new_chunk(p, p->chunk_size);
|
||||
|
||||
if (!nc)
|
||||
return 0;
|
||||
|
||||
_align_chunk(p->chunk, p->object_alignment);
|
||||
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(p->chunk->begin, p->object_len);
|
||||
#endif
|
||||
|
||||
memcpy(p->chunk->begin, c->begin, p->object_len);
|
||||
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_NOACCESS(c->begin, p->object_len);
|
||||
#endif
|
||||
|
||||
c = p->chunk;
|
||||
}
|
||||
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(p->chunk->begin + p->object_len, delta);
|
||||
#endif
|
||||
|
||||
memcpy(c->begin + p->object_len, extra, delta);
|
||||
p->object_len += delta;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *dm_pool_end_object(struct dm_pool *p)
|
||||
{
|
||||
struct chunk *c = p->chunk;
|
||||
void *r = c->begin;
|
||||
c->begin += p->object_len;
|
||||
p->object_len = 0u;
|
||||
p->object_alignment = DEFAULT_ALIGNMENT;
|
||||
return r;
|
||||
}
|
||||
|
||||
void dm_pool_abandon_object(struct dm_pool *p)
|
||||
{
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_NOACCESS(p->chunk, p->object_len);
|
||||
#endif
|
||||
p->object_len = 0;
|
||||
p->object_alignment = DEFAULT_ALIGNMENT;
|
||||
}
|
||||
|
||||
static void _align_chunk(struct chunk *c, unsigned alignment)
|
||||
{
|
||||
c->begin += alignment - ((unsigned long) c->begin & (alignment - 1));
|
||||
}
|
||||
|
||||
static struct chunk *_new_chunk(struct dm_pool *p, size_t s)
|
||||
{
|
||||
struct chunk *c;
|
||||
|
||||
if (p->spare_chunk &&
|
||||
((p->spare_chunk->end - p->spare_chunk->begin) >= (ptrdiff_t)s)) {
|
||||
/* reuse old chunk */
|
||||
c = p->spare_chunk;
|
||||
p->spare_chunk = 0;
|
||||
} else {
|
||||
#ifdef DEBUG_ENFORCE_POOL_LOCKING
|
||||
if (!_pagesize) {
|
||||
_pagesize = getpagesize(); /* lvm_pagesize(); */
|
||||
_pagesize_mask = _pagesize - 1;
|
||||
}
|
||||
/*
|
||||
* Allocate page aligned size so malloc could work.
|
||||
* Otherwise page fault would happen from pool unrelated
|
||||
* memory writes of internal malloc pointers.
|
||||
*/
|
||||
# define aligned_malloc(s) (posix_memalign((void**)&c, _pagesize, \
|
||||
ALIGN_ON_PAGE(s)) == 0)
|
||||
#else
|
||||
# define aligned_malloc(s) (c = dm_malloc(s))
|
||||
#endif /* DEBUG_ENFORCE_POOL_LOCKING */
|
||||
if (!aligned_malloc(s)) {
|
||||
#undef aligned_malloc
|
||||
log_error("Out of memory. Requested %" PRIsize_t
|
||||
" bytes.", s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c->begin = (char *) (c + 1);
|
||||
c->end = (char *) c + s;
|
||||
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_NOACCESS(c->begin, c->end - c->begin);
|
||||
#endif
|
||||
}
|
||||
|
||||
c->prev = p->chunk;
|
||||
p->chunk = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void _free_chunk(struct chunk *c)
|
||||
{
|
||||
#ifdef VALGRIND_POOL
|
||||
# ifdef DEBUG_MEM
|
||||
if (c)
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(c + 1, c->end - (char *) (c + 1));
|
||||
# endif
|
||||
#endif
|
||||
#ifdef DEBUG_ENFORCE_POOL_LOCKING
|
||||
/* since DEBUG_MEM is using own memory list */
|
||||
free(c); /* for posix_memalign() */
|
||||
#else
|
||||
dm_free(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calc crc/hash from pool's memory chunks with internal pointers
|
||||
*/
|
||||
static long _pool_crc(const struct dm_pool *p)
|
||||
{
|
||||
long crc_hash = 0;
|
||||
#ifndef DEBUG_ENFORCE_POOL_LOCKING
|
||||
const struct chunk *c;
|
||||
const long *ptr, *end;
|
||||
|
||||
for (c = p->chunk; c; c = c->prev) {
|
||||
end = (const long *) (c->begin < c->end ? (long) c->begin & ~7: (long) c->end);
|
||||
ptr = (const long *) c;
|
||||
#ifdef VALGRIND_POOL
|
||||
VALGRIND_MAKE_MEM_DEFINED(ptr, (end - ptr) * sizeof(*end));
|
||||
#endif
|
||||
while (ptr < end) {
|
||||
crc_hash += *ptr++;
|
||||
crc_hash += (crc_hash << 10);
|
||||
crc_hash ^= (crc_hash >> 6);
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG_ENFORCE_POOL_LOCKING */
|
||||
|
||||
return crc_hash;
|
||||
}
|
||||
|
||||
static int _pool_protect(struct dm_pool *p, int prot)
|
||||
{
|
||||
#ifdef DEBUG_ENFORCE_POOL_LOCKING
|
||||
struct chunk *c;
|
||||
|
||||
for (c = p->chunk; c; c = c->prev) {
|
||||
if (mprotect(c, (size_t) ((c->end - (char *) c) - 1), prot) != 0) {
|
||||
log_sys_error("mprotect", "");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
189
device_mapper/mm/pool.c
Normal file
189
device_mapper/mm/pool.c
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static DM_LIST_INIT(_dm_pools);
|
||||
static pthread_mutex_t _dm_pools_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
void dm_pools_check_leaks(void);
|
||||
|
||||
#ifdef DEBUG_ENFORCE_POOL_LOCKING
|
||||
#ifdef DEBUG_POOL
|
||||
#error Do not use DEBUG_POOL with DEBUG_ENFORCE_POOL_LOCKING
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use mprotect system call to ensure all locked pages are not writable.
|
||||
* Generates segmentation fault with write access to the locked pool.
|
||||
*
|
||||
* - Implementation is using posix_memalign() to get page aligned
|
||||
* memory blocks (could be implemented also through malloc).
|
||||
* - Only pool-fast is properly handled for now.
|
||||
* - Checksum is slower compared to mprotect.
|
||||
*/
|
||||
static size_t _pagesize = 0;
|
||||
static size_t _pagesize_mask = 0;
|
||||
#define ALIGN_ON_PAGE(size) (((size) + (_pagesize_mask)) & ~(_pagesize_mask))
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_POOL
|
||||
#include "pool-debug.c"
|
||||
#else
|
||||
#include "pool-fast.c"
|
||||
#endif
|
||||
|
||||
char *dm_pool_strdup(struct dm_pool *p, const char *str)
|
||||
{
|
||||
size_t len = strlen(str) + 1;
|
||||
char *ret = dm_pool_alloc(p, len);
|
||||
|
||||
if (ret)
|
||||
memcpy(ret, str, len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *dm_pool_strndup(struct dm_pool *p, const char *str, size_t n)
|
||||
{
|
||||
char *ret = dm_pool_alloc(p, n + 1);
|
||||
|
||||
if (ret) {
|
||||
strncpy(ret, str, n);
|
||||
ret[n] = '\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *dm_pool_zalloc(struct dm_pool *p, size_t s)
|
||||
{
|
||||
void *ptr = dm_pool_alloc(p, s);
|
||||
|
||||
if (ptr)
|
||||
memset(ptr, 0, s);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void dm_pools_check_leaks(void)
|
||||
{
|
||||
struct dm_pool *p;
|
||||
|
||||
pthread_mutex_lock(&_dm_pools_mutex);
|
||||
if (dm_list_empty(&_dm_pools)) {
|
||||
pthread_mutex_unlock(&_dm_pools_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
log_error("You have a memory leak (not released memory pool):");
|
||||
dm_list_iterate_items(p, &_dm_pools) {
|
||||
#ifdef DEBUG_POOL
|
||||
log_error(" [%p] %s (%u bytes)",
|
||||
p->orig_pool,
|
||||
p->name, p->stats.bytes);
|
||||
#else
|
||||
log_error(" [%p] %s", p, p->name);
|
||||
#endif
|
||||
}
|
||||
pthread_mutex_unlock(&_dm_pools_mutex);
|
||||
log_error(INTERNAL_ERROR "Unreleased memory pool(s) found.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of locked pool.
|
||||
*
|
||||
* \param p
|
||||
* Pool to be tested for lock status.
|
||||
*
|
||||
* \return
|
||||
* 1 when the pool is locked, 0 otherwise.
|
||||
*/
|
||||
int dm_pool_locked(struct dm_pool *p)
|
||||
{
|
||||
return p->locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock memory pool.
|
||||
*
|
||||
* \param p
|
||||
* Pool to be locked.
|
||||
*
|
||||
* \param crc
|
||||
* Bool specifies whether to store the pool crc/hash checksum.
|
||||
*
|
||||
* \return
|
||||
* 1 (success) when the pool was preperly locked, 0 otherwise.
|
||||
*/
|
||||
int dm_pool_lock(struct dm_pool *p, int crc)
|
||||
{
|
||||
if (p->locked) {
|
||||
log_error(INTERNAL_ERROR "Pool %s is already locked.",
|
||||
p->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (crc)
|
||||
p->crc = _pool_crc(p); /* Get crc for pool */
|
||||
|
||||
if (!_pool_protect(p, PROT_READ)) {
|
||||
_pool_protect(p, PROT_READ | PROT_WRITE);
|
||||
return_0;
|
||||
}
|
||||
|
||||
p->locked = 1;
|
||||
|
||||
log_debug_mem("Pool %s is locked.", p->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock memory pool.
|
||||
*
|
||||
* \param p
|
||||
* Pool to be unlocked.
|
||||
*
|
||||
* \param crc
|
||||
* Bool enables compare of the pool crc/hash with the stored value
|
||||
* at pool lock. The pool is not properly unlocked if there is a mismatch.
|
||||
*
|
||||
* \return
|
||||
* 1 (success) when the pool was properly unlocked, 0 otherwise.
|
||||
*/
|
||||
int dm_pool_unlock(struct dm_pool *p, int crc)
|
||||
{
|
||||
if (!p->locked) {
|
||||
log_error(INTERNAL_ERROR "Pool %s is already unlocked.",
|
||||
p->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->locked = 0;
|
||||
|
||||
if (!_pool_protect(p, PROT_READ | PROT_WRITE))
|
||||
return_0;
|
||||
|
||||
log_debug_mem("Pool %s is unlocked.", p->name);
|
||||
|
||||
if (crc && (p->crc != _pool_crc(p))) {
|
||||
log_error(INTERNAL_ERROR "Pool %s crc mismatch.", p->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
575
device_mapper/regex/matcher.c
Normal file
575
device_mapper/regex/matcher.c
Normal file
@ -0,0 +1,575 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
#include "parse_rx.h"
|
||||
#include "ttree.h"
|
||||
#include "assert.h"
|
||||
|
||||
struct dfa_state {
|
||||
struct dfa_state *next;
|
||||
int final;
|
||||
dm_bitset_t bits;
|
||||
struct dfa_state *lookup[256];
|
||||
};
|
||||
|
||||
struct dm_regex { /* Instance variables for the lexer */
|
||||
struct dfa_state *start;
|
||||
unsigned num_nodes;
|
||||
unsigned num_charsets;
|
||||
int nodes_entered;
|
||||
struct rx_node **nodes;
|
||||
int charsets_entered;
|
||||
struct rx_node **charsets;
|
||||
struct dm_pool *scratch, *mem;
|
||||
|
||||
/* stuff for on the fly dfa calculation */
|
||||
dm_bitset_t charmap[256];
|
||||
dm_bitset_t dfa_copy;
|
||||
struct ttree *tt;
|
||||
dm_bitset_t bs;
|
||||
struct dfa_state *h, *t;
|
||||
};
|
||||
|
||||
static int _count_nodes(struct rx_node *rx)
|
||||
{
|
||||
int r = 1;
|
||||
|
||||
if (rx->left)
|
||||
r += _count_nodes(rx->left);
|
||||
|
||||
if (rx->right)
|
||||
r += _count_nodes(rx->right);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static unsigned _count_charsets(struct rx_node *rx)
|
||||
{
|
||||
if (rx->type == CHARSET)
|
||||
return 1;
|
||||
|
||||
return (rx->left ? _count_charsets(rx->left) : 0) +
|
||||
(rx->right ? _count_charsets(rx->right) : 0);
|
||||
}
|
||||
|
||||
static void _enumerate_charsets_internal(struct rx_node *rx, unsigned *i)
|
||||
{
|
||||
if (rx->type == CHARSET)
|
||||
rx->charset_index = (*i)++;
|
||||
else {
|
||||
if (rx->left)
|
||||
_enumerate_charsets_internal(rx->left, i);
|
||||
if (rx->right)
|
||||
_enumerate_charsets_internal(rx->right, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void _enumerate_charsets(struct rx_node *rx)
|
||||
{
|
||||
unsigned i = 0;
|
||||
_enumerate_charsets_internal(rx, &i);
|
||||
}
|
||||
|
||||
static void _fill_table(struct dm_regex *m, struct rx_node *rx)
|
||||
{
|
||||
assert((rx->type != OR) || (rx->left && rx->right));
|
||||
|
||||
if (rx->left)
|
||||
_fill_table(m, rx->left);
|
||||
|
||||
if (rx->right)
|
||||
_fill_table(m, rx->right);
|
||||
|
||||
m->nodes[m->nodes_entered++] = rx;
|
||||
if (rx->type == CHARSET)
|
||||
m->charsets[m->charsets_entered++] = rx;
|
||||
}
|
||||
|
||||
static int _create_bitsets(struct dm_regex *m)
|
||||
{
|
||||
unsigned i;
|
||||
struct rx_node *n;
|
||||
|
||||
for (i = 0; i < m->num_nodes; i++) {
|
||||
n = m->nodes[i];
|
||||
if (!(n->firstpos = dm_bitset_create(m->scratch, m->num_charsets)))
|
||||
return_0;
|
||||
if (!(n->lastpos = dm_bitset_create(m->scratch, m->num_charsets)))
|
||||
return_0;
|
||||
if (!(n->followpos = dm_bitset_create(m->scratch, m->num_charsets)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _calc_functions(struct dm_regex *m)
|
||||
{
|
||||
unsigned i, j, final = 1;
|
||||
struct rx_node *rx, *c1, *c2;
|
||||
|
||||
for (i = 0; i < m->num_nodes; i++) {
|
||||
rx = m->nodes[i];
|
||||
c1 = rx->left;
|
||||
c2 = rx->right;
|
||||
|
||||
if (rx->type == CHARSET && dm_bit(rx->charset, TARGET_TRANS))
|
||||
rx->final = final++;
|
||||
|
||||
switch (rx->type) {
|
||||
case CAT:
|
||||
if (c1->nullable)
|
||||
dm_bit_union(rx->firstpos,
|
||||
c1->firstpos, c2->firstpos);
|
||||
else
|
||||
dm_bit_copy(rx->firstpos, c1->firstpos);
|
||||
|
||||
if (c2->nullable)
|
||||
dm_bit_union(rx->lastpos,
|
||||
c1->lastpos, c2->lastpos);
|
||||
else
|
||||
dm_bit_copy(rx->lastpos, c2->lastpos);
|
||||
|
||||
rx->nullable = c1->nullable && c2->nullable;
|
||||
break;
|
||||
|
||||
case PLUS:
|
||||
dm_bit_copy(rx->firstpos, c1->firstpos);
|
||||
dm_bit_copy(rx->lastpos, c1->lastpos);
|
||||
rx->nullable = c1->nullable;
|
||||
break;
|
||||
|
||||
case OR:
|
||||
dm_bit_union(rx->firstpos, c1->firstpos, c2->firstpos);
|
||||
dm_bit_union(rx->lastpos, c1->lastpos, c2->lastpos);
|
||||
rx->nullable = c1->nullable || c2->nullable;
|
||||
break;
|
||||
|
||||
case QUEST:
|
||||
case STAR:
|
||||
dm_bit_copy(rx->firstpos, c1->firstpos);
|
||||
dm_bit_copy(rx->lastpos, c1->lastpos);
|
||||
rx->nullable = 1;
|
||||
break;
|
||||
|
||||
case CHARSET:
|
||||
dm_bit_set(rx->firstpos, rx->charset_index);
|
||||
dm_bit_set(rx->lastpos, rx->charset_index);
|
||||
rx->nullable = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "Unknown calc node type");
|
||||
}
|
||||
|
||||
/*
|
||||
* followpos has it's own switch
|
||||
* because PLUS and STAR do the
|
||||
* same thing.
|
||||
*/
|
||||
switch (rx->type) {
|
||||
case CAT:
|
||||
for (j = 0; j < m->num_charsets; j++) {
|
||||
struct rx_node *n = m->charsets[j];
|
||||
if (dm_bit(c1->lastpos, j))
|
||||
dm_bit_union(n->followpos,
|
||||
n->followpos, c2->firstpos);
|
||||
}
|
||||
break;
|
||||
|
||||
case PLUS:
|
||||
case STAR:
|
||||
for (j = 0; j < m->num_charsets; j++) {
|
||||
struct rx_node *n = m->charsets[j];
|
||||
if (dm_bit(rx->lastpos, j))
|
||||
dm_bit_union(n->followpos,
|
||||
n->followpos, rx->firstpos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct dfa_state *_create_dfa_state(struct dm_pool *mem)
|
||||
{
|
||||
return dm_pool_zalloc(mem, sizeof(struct dfa_state));
|
||||
}
|
||||
|
||||
static struct dfa_state *_create_state_queue(struct dm_pool *mem,
|
||||
struct dfa_state *dfa,
|
||||
dm_bitset_t bits)
|
||||
{
|
||||
if (!(dfa->bits = dm_bitset_create(mem, bits[0]))) /* first element is the size */
|
||||
return_NULL;
|
||||
|
||||
dm_bit_copy(dfa->bits, bits);
|
||||
dfa->next = 0;
|
||||
dfa->final = -1;
|
||||
|
||||
return dfa;
|
||||
}
|
||||
|
||||
static int _calc_state(struct dm_regex *m, struct dfa_state *dfa, int a)
|
||||
{
|
||||
int set_bits = 0, i;
|
||||
dm_bitset_t dfa_bits = dfa->bits;
|
||||
dm_bit_and(m->dfa_copy, m->charmap[a], dfa_bits);
|
||||
|
||||
/* iterate through all the states in firstpos */
|
||||
for (i = dm_bit_get_first(m->dfa_copy); i >= 0; i = dm_bit_get_next(m->dfa_copy, i)) {
|
||||
if (a == TARGET_TRANS)
|
||||
dfa->final = m->charsets[i]->final;
|
||||
|
||||
dm_bit_union(m->bs, m->bs, m->charsets[i]->followpos);
|
||||
set_bits = 1;
|
||||
}
|
||||
|
||||
if (set_bits) {
|
||||
struct dfa_state *tmp;
|
||||
struct dfa_state *ldfa = ttree_lookup(m->tt, m->bs + 1);
|
||||
if (!ldfa) {
|
||||
/* push */
|
||||
if (!(ldfa = _create_dfa_state(m->mem)))
|
||||
return_0;
|
||||
|
||||
ttree_insert(m->tt, m->bs + 1, ldfa);
|
||||
if (!(tmp = _create_state_queue(m->scratch, ldfa, m->bs)))
|
||||
return_0;
|
||||
if (!m->h)
|
||||
m->h = m->t = tmp;
|
||||
else {
|
||||
m->t->next = tmp;
|
||||
m->t = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
dfa->lookup[a] = ldfa;
|
||||
dm_bit_clear_all(m->bs);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _calc_states(struct dm_regex *m, struct rx_node *rx)
|
||||
{
|
||||
unsigned iwidth = (m->num_charsets / DM_BITS_PER_INT) + 1;
|
||||
struct dfa_state *dfa;
|
||||
struct rx_node *n;
|
||||
unsigned i;
|
||||
int a;
|
||||
|
||||
if (!(m->tt = ttree_create(m->scratch, iwidth)))
|
||||
return_0;
|
||||
|
||||
if (!(m->bs = dm_bitset_create(m->scratch, m->num_charsets)))
|
||||
return_0;
|
||||
|
||||
/* build some char maps */
|
||||
for (a = 0; a < 256; a++)
|
||||
if (!(m->charmap[a] = dm_bitset_create(m->scratch, m->num_charsets)))
|
||||
return_0;
|
||||
|
||||
for (i = 0; i < m->num_nodes; i++) {
|
||||
n = m->nodes[i];
|
||||
if (n->type == CHARSET) {
|
||||
for (a = dm_bit_get_first(n->charset);
|
||||
a >= 0; a = dm_bit_get_next(n->charset, a))
|
||||
dm_bit_set(m->charmap[a], n->charset_index);
|
||||
}
|
||||
}
|
||||
|
||||
/* create first state */
|
||||
if (!(dfa = _create_dfa_state(m->mem)))
|
||||
return_0;
|
||||
|
||||
m->start = dfa;
|
||||
ttree_insert(m->tt, rx->firstpos + 1, dfa);
|
||||
|
||||
/* prime the queue */
|
||||
if (!(m->h = m->t = _create_state_queue(m->scratch, dfa, rx->firstpos)))
|
||||
return_0;
|
||||
|
||||
if (!(m->dfa_copy = dm_bitset_create(m->scratch, m->num_charsets)))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forces all the dfa states to be calculated up front, ie. what
|
||||
* _calc_states() used to do before we switched to calculating on demand.
|
||||
*/
|
||||
static int _force_states(struct dm_regex *m)
|
||||
{
|
||||
int a;
|
||||
|
||||
/* keep processing until there's nothing in the queue */
|
||||
struct dfa_state *s;
|
||||
while ((s = m->h)) {
|
||||
/* pop state off front of the queue */
|
||||
m->h = m->h->next;
|
||||
|
||||
/* iterate through all the inputs for this state */
|
||||
dm_bit_clear_all(m->bs);
|
||||
for (a = 0; a < 256; a++)
|
||||
if (!_calc_state(m, s, a))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dm_regex *dm_regex_create(struct dm_pool *mem, const char * const *patterns,
|
||||
unsigned num_patterns)
|
||||
{
|
||||
char *all, *ptr;
|
||||
unsigned i;
|
||||
size_t len = 0;
|
||||
struct rx_node *rx;
|
||||
struct dm_regex *m;
|
||||
struct dm_pool *scratch = mem;
|
||||
|
||||
if (!(m = dm_pool_zalloc(mem, sizeof(*m))))
|
||||
return_NULL;
|
||||
|
||||
/* join the regexps together, delimiting with zero */
|
||||
for (i = 0; i < num_patterns; i++)
|
||||
len += strlen(patterns[i]) + 8;
|
||||
|
||||
ptr = all = dm_pool_alloc(scratch, len + 1);
|
||||
|
||||
if (!all)
|
||||
goto_bad;
|
||||
|
||||
for (i = 0; i < num_patterns; i++) {
|
||||
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
|
||||
if (i < (num_patterns - 1))
|
||||
*ptr++ = '|';
|
||||
}
|
||||
|
||||
/* parse this expression */
|
||||
if (!(rx = rx_parse_tok(scratch, all, ptr))) {
|
||||
log_error("Couldn't parse regex");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
m->mem = mem;
|
||||
m->scratch = scratch;
|
||||
m->num_nodes = _count_nodes(rx);
|
||||
m->num_charsets = _count_charsets(rx);
|
||||
_enumerate_charsets(rx);
|
||||
if (!(m->nodes = dm_pool_alloc(scratch, sizeof(*m->nodes) * m->num_nodes)))
|
||||
goto_bad;
|
||||
|
||||
if (!(m->charsets = dm_pool_alloc(scratch, sizeof(*m->charsets) * m->num_charsets)))
|
||||
goto_bad;
|
||||
|
||||
_fill_table(m, rx);
|
||||
|
||||
if (!_create_bitsets(m))
|
||||
goto_bad;
|
||||
|
||||
_calc_functions(m);
|
||||
|
||||
if (!_calc_states(m, rx))
|
||||
goto_bad;
|
||||
|
||||
return m;
|
||||
|
||||
bad:
|
||||
dm_pool_free(mem, m);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dfa_state *_step_matcher(struct dm_regex *m, int c, struct dfa_state *cs, int *r)
|
||||
{
|
||||
struct dfa_state *ns;
|
||||
|
||||
if (!(ns = cs->lookup[(unsigned char) c])) {
|
||||
if (!_calc_state(m, cs, (unsigned char) c))
|
||||
return_NULL;
|
||||
|
||||
if (!(ns = cs->lookup[(unsigned char) c]))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// yuck, we have to special case the target trans
|
||||
if ((ns->final == -1) &&
|
||||
!_calc_state(m, ns, TARGET_TRANS))
|
||||
return_NULL;
|
||||
|
||||
if (ns->final && (ns->final > *r))
|
||||
*r = ns->final;
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
int dm_regex_match(struct dm_regex *regex, const char *s)
|
||||
{
|
||||
struct dfa_state *cs = regex->start;
|
||||
int r = 0;
|
||||
|
||||
dm_bit_clear_all(regex->bs);
|
||||
if (!(cs = _step_matcher(regex, HAT_CHAR, cs, &r)))
|
||||
goto out;
|
||||
|
||||
for (; *s; s++)
|
||||
if (!(cs = _step_matcher(regex, *s, cs, &r)))
|
||||
goto out;
|
||||
|
||||
_step_matcher(regex, DOLLAR_CHAR, cs, &r);
|
||||
|
||||
out:
|
||||
/* subtract 1 to get back to zero index */
|
||||
return r - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The next block of code concerns calculating a fingerprint for the dfa.
|
||||
*
|
||||
* We're not calculating a minimal dfa in _calculate_state (maybe a future
|
||||
* improvement). As such it's possible that two non-isomorphic dfas
|
||||
* recognise the same language. This can only really happen if you start
|
||||
* with equivalent, but different regexes (for example the simplifier in
|
||||
* parse_rx.c may have changed).
|
||||
*
|
||||
* The code is inefficient; repeatedly searching a singly linked list for
|
||||
* previously seen nodes. Not worried since this is test code.
|
||||
*/
|
||||
struct node_list {
|
||||
unsigned node_id;
|
||||
struct dfa_state *node;
|
||||
struct node_list *next;
|
||||
};
|
||||
|
||||
struct printer {
|
||||
struct dm_pool *mem;
|
||||
struct node_list *pending;
|
||||
struct node_list *processed;
|
||||
unsigned next_index;
|
||||
};
|
||||
|
||||
static uint32_t _randomise(uint32_t n)
|
||||
{
|
||||
/* 2^32 - 5 */
|
||||
uint32_t const prime = (~0) - 4;
|
||||
return n * prime;
|
||||
}
|
||||
|
||||
static int _seen(struct node_list *n, struct dfa_state *node, uint32_t *i)
|
||||
{
|
||||
while (n) {
|
||||
if (n->node == node) {
|
||||
*i = n->node_id;
|
||||
return 1;
|
||||
}
|
||||
n = n->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Push node if it's not been seen before, returning a unique index.
|
||||
*/
|
||||
static uint32_t _push_node(struct printer *p, struct dfa_state *node)
|
||||
{
|
||||
uint32_t i;
|
||||
struct node_list *n;
|
||||
|
||||
if (_seen(p->pending, node, &i) ||
|
||||
_seen(p->processed, node, &i))
|
||||
return i;
|
||||
|
||||
if (!(n = dm_pool_alloc(p->mem, sizeof(*n))))
|
||||
return_0;
|
||||
|
||||
n->node_id = ++p->next_index; /* start from 1, keep 0 as error code */
|
||||
n->node = node;
|
||||
n->next = p->pending;
|
||||
p->pending = n;
|
||||
|
||||
return n->node_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pop the front node, and fill out it's previously assigned index.
|
||||
*/
|
||||
static struct dfa_state *_pop_node(struct printer *p)
|
||||
{
|
||||
struct dfa_state *node = NULL;
|
||||
struct node_list *n;
|
||||
|
||||
if (p->pending) {
|
||||
n = p->pending;
|
||||
p->pending = n->next;
|
||||
n->next = p->processed;
|
||||
p->processed = n;
|
||||
|
||||
node = n->node;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static uint32_t _combine(uint32_t n1, uint32_t n2)
|
||||
{
|
||||
return ((n1 << 8) | (n1 >> 24)) ^ _randomise(n2);
|
||||
}
|
||||
|
||||
static uint32_t _fingerprint(struct printer *p)
|
||||
{
|
||||
int c;
|
||||
uint32_t result = 0;
|
||||
struct dfa_state *node;
|
||||
|
||||
while ((node = _pop_node(p))) {
|
||||
result = _combine(result, (node->final < 0) ? 0 : node->final);
|
||||
for (c = 0; c < 256; c++)
|
||||
result = _combine(result,
|
||||
_push_node(p, node->lookup[c]));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t dm_regex_fingerprint(struct dm_regex *regex)
|
||||
{
|
||||
struct printer p;
|
||||
uint32_t result = 0;
|
||||
struct dm_pool *mem = dm_pool_create("regex fingerprint", 1024);
|
||||
|
||||
if (!mem)
|
||||
return_0;
|
||||
|
||||
if (!_force_states(regex))
|
||||
goto_out;
|
||||
|
||||
p.mem = mem;
|
||||
p.pending = NULL;
|
||||
p.processed = NULL;
|
||||
p.next_index = 0;
|
||||
|
||||
if (!_push_node(&p, regex->start))
|
||||
goto_out;
|
||||
|
||||
result = _fingerprint(&p);
|
||||
out:
|
||||
dm_pool_destroy(mem);
|
||||
|
||||
return result;
|
||||
}
|
667
device_mapper/regex/parse_rx.c
Normal file
667
device_mapper/regex/parse_rx.c
Normal file
@ -0,0 +1,667 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
#include "parse_rx.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <ctype.h>
|
||||
|
||||
__attribute__ ((__unused__))
|
||||
static void _regex_print(struct rx_node *rx, int depth, unsigned show_nodes)
|
||||
{
|
||||
int i, numchars;
|
||||
|
||||
if (rx->left) {
|
||||
if (rx->left->type != CHARSET && (show_nodes || (!((rx->type == CAT || rx->type == OR) && rx->left->type == CAT))))
|
||||
printf("(");
|
||||
|
||||
_regex_print(rx->left, depth + 1, show_nodes);
|
||||
|
||||
if (rx->left->type != CHARSET && (show_nodes || (!((rx->type == CAT || rx->type == OR) && rx->left->type == CAT))))
|
||||
printf(")");
|
||||
}
|
||||
|
||||
/* display info about the node */
|
||||
switch (rx->type) {
|
||||
case CAT:
|
||||
break;
|
||||
|
||||
case OR:
|
||||
printf("|");
|
||||
break;
|
||||
|
||||
case STAR:
|
||||
printf("*");
|
||||
break;
|
||||
|
||||
case PLUS:
|
||||
printf("+");
|
||||
break;
|
||||
|
||||
case QUEST:
|
||||
printf("?");
|
||||
break;
|
||||
|
||||
case CHARSET:
|
||||
numchars = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (dm_bit(rx->charset, i) && (isprint(i) || i == HAT_CHAR || i == DOLLAR_CHAR))
|
||||
numchars++;
|
||||
if (numchars == 97) {
|
||||
printf(".");
|
||||
break;
|
||||
}
|
||||
if (numchars > 1)
|
||||
printf("[");
|
||||
for (i = 0; i < 256; i++)
|
||||
if (dm_bit(rx->charset, i)) {
|
||||
if (isprint(i))
|
||||
printf("%c", (char) i);
|
||||
else if (i == HAT_CHAR)
|
||||
printf("^");
|
||||
else if (i == DOLLAR_CHAR)
|
||||
printf("$");
|
||||
}
|
||||
if (numchars > 1)
|
||||
printf("]");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unknown type");
|
||||
}
|
||||
|
||||
if (rx->right) {
|
||||
if (rx->right->type != CHARSET && (show_nodes || (!(rx->type == CAT && rx->right->type == CAT) && rx->right->right)))
|
||||
printf("(");
|
||||
_regex_print(rx->right, depth + 1, show_nodes);
|
||||
if (rx->right->type != CHARSET && (show_nodes || (!(rx->type == CAT && rx->right->type == CAT) && rx->right->right)))
|
||||
printf(")");
|
||||
}
|
||||
|
||||
if (!depth)
|
||||
printf("\n");
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
struct parse_sp { /* scratch pad for the parsing process */
|
||||
struct dm_pool *mem;
|
||||
int type; /* token type, 0 indicates a charset */
|
||||
dm_bitset_t charset; /* The current charset */
|
||||
const char *cursor; /* where we are in the regex */
|
||||
const char *rx_end; /* 1pte for the expression being parsed */
|
||||
};
|
||||
|
||||
static struct rx_node *_or_term(struct parse_sp *ps);
|
||||
|
||||
static void _single_char(struct parse_sp *ps, unsigned int c, const char *ptr)
|
||||
{
|
||||
ps->type = 0;
|
||||
ps->cursor = ptr + 1;
|
||||
dm_bit_clear_all(ps->charset);
|
||||
dm_bit_set(ps->charset, c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next token from the regular expression.
|
||||
* Returns: 1 success, 0 end of input, -1 error.
|
||||
*/
|
||||
static int _rx_get_token(struct parse_sp *ps)
|
||||
{
|
||||
int neg = 0, range = 0;
|
||||
char c, lc = 0;
|
||||
const char *ptr = ps->cursor;
|
||||
if (ptr == ps->rx_end) { /* end of input ? */
|
||||
ps->type = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (*ptr) {
|
||||
/* charsets and ncharsets */
|
||||
case '[':
|
||||
ptr++;
|
||||
if (*ptr == '^') {
|
||||
dm_bit_set_all(ps->charset);
|
||||
|
||||
/* never transition on zero */
|
||||
dm_bit_clear(ps->charset, 0);
|
||||
neg = 1;
|
||||
ptr++;
|
||||
|
||||
} else
|
||||
dm_bit_clear_all(ps->charset);
|
||||
|
||||
while ((ptr < ps->rx_end) && (*ptr != ']')) {
|
||||
if (*ptr == '\\') {
|
||||
/* an escaped character */
|
||||
ptr++;
|
||||
switch (*ptr) {
|
||||
case 'n':
|
||||
c = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
c = '\r';
|
||||
break;
|
||||
case 't':
|
||||
c = '\t';
|
||||
break;
|
||||
default:
|
||||
c = *ptr;
|
||||
}
|
||||
} else if (*ptr == '-' && lc) {
|
||||
/* we've got a range on our hands */
|
||||
range = 1;
|
||||
ptr++;
|
||||
if (ptr == ps->rx_end) {
|
||||
log_error("Incomplete range"
|
||||
"specification");
|
||||
return -1;
|
||||
}
|
||||
c = *ptr;
|
||||
} else
|
||||
c = *ptr;
|
||||
|
||||
if (range) {
|
||||
/* add lc - c into the bitset */
|
||||
if (lc > c) {
|
||||
char tmp = c;
|
||||
c = lc;
|
||||
lc = tmp;
|
||||
}
|
||||
|
||||
for (; lc <= c; lc++) {
|
||||
if (neg)
|
||||
dm_bit_clear(ps->charset, lc);
|
||||
else
|
||||
dm_bit_set(ps->charset, lc);
|
||||
}
|
||||
range = 0;
|
||||
} else {
|
||||
/* add c into the bitset */
|
||||
if (neg)
|
||||
dm_bit_clear(ps->charset, c);
|
||||
else
|
||||
dm_bit_set(ps->charset, c);
|
||||
}
|
||||
ptr++;
|
||||
lc = c;
|
||||
}
|
||||
|
||||
if (ptr >= ps->rx_end) {
|
||||
ps->type = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ps->type = 0;
|
||||
ps->cursor = ptr + 1;
|
||||
break;
|
||||
|
||||
/* These characters are special, we just return their ASCII
|
||||
codes as the type. Sorted into ascending order to help the
|
||||
compiler */
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case '+':
|
||||
case '?':
|
||||
case '|':
|
||||
ps->type = (int) *ptr;
|
||||
ps->cursor = ptr + 1;
|
||||
break;
|
||||
|
||||
case '^':
|
||||
_single_char(ps, HAT_CHAR, ptr);
|
||||
break;
|
||||
|
||||
case '$':
|
||||
_single_char(ps, DOLLAR_CHAR, ptr);
|
||||
break;
|
||||
|
||||
case '.':
|
||||
/* The 'all but newline' character set */
|
||||
ps->type = 0;
|
||||
ps->cursor = ptr + 1;
|
||||
dm_bit_set_all(ps->charset);
|
||||
dm_bit_clear(ps->charset, (int) '\n');
|
||||
dm_bit_clear(ps->charset, (int) '\r');
|
||||
dm_bit_clear(ps->charset, 0);
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
/* escaped character */
|
||||
ptr++;
|
||||
if (ptr >= ps->rx_end) {
|
||||
log_error("Badly quoted character at end "
|
||||
"of expression");
|
||||
ps->type = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ps->type = 0;
|
||||
ps->cursor = ptr + 1;
|
||||
dm_bit_clear_all(ps->charset);
|
||||
switch (*ptr) {
|
||||
case 'n':
|
||||
dm_bit_set(ps->charset, (int) '\n');
|
||||
break;
|
||||
case 'r':
|
||||
dm_bit_set(ps->charset, (int) '\r');
|
||||
break;
|
||||
case 't':
|
||||
dm_bit_set(ps->charset, (int) '\t');
|
||||
break;
|
||||
default:
|
||||
dm_bit_set(ps->charset, (int) *ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* add a single character to the bitset */
|
||||
ps->type = 0;
|
||||
ps->cursor = ptr + 1;
|
||||
dm_bit_clear_all(ps->charset);
|
||||
dm_bit_set(ps->charset, (int) (unsigned char) *ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct rx_node *_node(struct dm_pool *mem, int type,
|
||||
struct rx_node *l, struct rx_node *r)
|
||||
{
|
||||
struct rx_node *n = dm_pool_zalloc(mem, sizeof(*n));
|
||||
|
||||
if (n) {
|
||||
if (type == CHARSET && !(n->charset = dm_bitset_create(mem, 256))) {
|
||||
dm_pool_free(mem, n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n->type = type;
|
||||
n->left = l;
|
||||
n->right = r;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static struct rx_node *_term(struct parse_sp *ps)
|
||||
{
|
||||
struct rx_node *n;
|
||||
|
||||
switch (ps->type) {
|
||||
case 0:
|
||||
if (!(n = _node(ps->mem, CHARSET, NULL, NULL)))
|
||||
return_NULL;
|
||||
|
||||
dm_bit_copy(n->charset, ps->charset);
|
||||
_rx_get_token(ps); /* match charset */
|
||||
break;
|
||||
|
||||
case '(':
|
||||
_rx_get_token(ps); /* match '(' */
|
||||
n = _or_term(ps);
|
||||
if (ps->type != ')') {
|
||||
log_error("missing ')' in regular expression");
|
||||
return 0;
|
||||
}
|
||||
_rx_get_token(ps); /* match ')' */
|
||||
break;
|
||||
|
||||
default:
|
||||
n = 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static struct rx_node *_closure_term(struct parse_sp *ps)
|
||||
{
|
||||
struct rx_node *l, *n;
|
||||
|
||||
if (!(l = _term(ps)))
|
||||
return NULL;
|
||||
|
||||
for (;;) {
|
||||
switch (ps->type) {
|
||||
case '*':
|
||||
n = _node(ps->mem, STAR, l, NULL);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
n = _node(ps->mem, PLUS, l, NULL);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
n = _node(ps->mem, QUEST, l, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
return l;
|
||||
}
|
||||
|
||||
if (!n)
|
||||
return_NULL;
|
||||
|
||||
_rx_get_token(ps);
|
||||
l = n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static struct rx_node *_cat_term(struct parse_sp *ps)
|
||||
{
|
||||
struct rx_node *l, *r, *n;
|
||||
|
||||
if (!(l = _closure_term(ps)))
|
||||
return NULL;
|
||||
|
||||
if (ps->type == '|')
|
||||
return l;
|
||||
|
||||
if (!(r = _cat_term(ps)))
|
||||
return l;
|
||||
|
||||
if (!(n = _node(ps->mem, CAT, l, r)))
|
||||
stack;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static struct rx_node *_or_term(struct parse_sp *ps)
|
||||
{
|
||||
struct rx_node *l, *r, *n;
|
||||
|
||||
if (!(l = _cat_term(ps)))
|
||||
return NULL;
|
||||
|
||||
if (ps->type != '|')
|
||||
return l;
|
||||
|
||||
_rx_get_token(ps); /* match '|' */
|
||||
|
||||
if (!(r = _or_term(ps))) {
|
||||
log_error("Badly formed 'or' expression");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(n = _node(ps->mem, OR, l, r)))
|
||||
stack;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/* Macros for left and right nodes. Inverted if 'leftmost' is set. */
|
||||
#define LEFT(a) (leftmost ? (a)->left : (a)->right)
|
||||
#define RIGHT(a) (leftmost ? (a)->right : (a)->left)
|
||||
|
||||
/*
|
||||
* The optimiser spots common prefixes on either side of an 'or' node, and
|
||||
* lifts them outside the 'or' with a 'cat'.
|
||||
*/
|
||||
static unsigned _depth(struct rx_node *r, unsigned leftmost)
|
||||
{
|
||||
int count = 1;
|
||||
|
||||
while (r->type != CHARSET && LEFT(r) && (leftmost || r->type != OR)) {
|
||||
count++;
|
||||
r = LEFT(r);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: a unique key could be built up as part of the parse, to make the
|
||||
* comparison quick. Alternatively we could use cons-hashing, and then
|
||||
* this would simply be a pointer comparison.
|
||||
*/
|
||||
static int _nodes_equal(struct rx_node *l, struct rx_node *r)
|
||||
{
|
||||
if (l->type != r->type)
|
||||
return 0;
|
||||
|
||||
switch (l->type) {
|
||||
case CAT:
|
||||
case OR:
|
||||
return _nodes_equal(l->left, r->left) &&
|
||||
_nodes_equal(l->right, r->right);
|
||||
|
||||
case STAR:
|
||||
case PLUS:
|
||||
case QUEST:
|
||||
return _nodes_equal(l->left, r->left);
|
||||
|
||||
case CHARSET:
|
||||
/*
|
||||
* Never change anything containing TARGET_TRANS
|
||||
* used by matcher as boundary marker between concatenated
|
||||
* expressions.
|
||||
*/
|
||||
return (!dm_bit(l->charset, TARGET_TRANS) && dm_bitset_equal(l->charset, r->charset));
|
||||
}
|
||||
|
||||
/* NOTREACHED */
|
||||
return_0;
|
||||
}
|
||||
|
||||
static int _find_leftmost_common(struct rx_node *or,
|
||||
struct rx_node **l,
|
||||
struct rx_node **r,
|
||||
unsigned leftmost)
|
||||
{
|
||||
struct rx_node *left = or->left, *right = or->right;
|
||||
unsigned left_depth = _depth(left, leftmost);
|
||||
unsigned right_depth = _depth(right, leftmost);
|
||||
|
||||
while (left_depth > right_depth && left->type != OR) {
|
||||
left = LEFT(left);
|
||||
left_depth--;
|
||||
}
|
||||
|
||||
while (right_depth > left_depth && right->type != OR) {
|
||||
right = LEFT(right);
|
||||
right_depth--;
|
||||
}
|
||||
|
||||
if (left_depth != right_depth)
|
||||
return 0;
|
||||
|
||||
while (left_depth) {
|
||||
if (left->type == CAT && right->type == CAT) {
|
||||
if (_nodes_equal(LEFT(left), LEFT(right))) {
|
||||
*l = left;
|
||||
*r = right;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (left->type == OR || right->type == OR)
|
||||
break;
|
||||
left = LEFT(left);
|
||||
right = LEFT(right);
|
||||
left_depth--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If top node is OR, rotate (leftmost example) from ((ab)|((ac)|d)) to (((ab)|(ac))|d) */
|
||||
static int _rotate_ors(struct rx_node *r, unsigned leftmost)
|
||||
{
|
||||
struct rx_node *old_node;
|
||||
|
||||
if (r->type != OR || RIGHT(r)->type != OR)
|
||||
return 0;
|
||||
|
||||
old_node = RIGHT(r);
|
||||
|
||||
if (leftmost) {
|
||||
r->right = RIGHT(old_node);
|
||||
old_node->right = LEFT(old_node);
|
||||
old_node->left = LEFT(r);
|
||||
r->left = old_node;
|
||||
} else {
|
||||
r->left = RIGHT(old_node);
|
||||
old_node->left = LEFT(old_node);
|
||||
old_node->right = LEFT(r);
|
||||
r->right = old_node;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct rx_node *_exchange_nodes(struct dm_pool *mem, struct rx_node *r,
|
||||
struct rx_node *left_cat, struct rx_node *right_cat,
|
||||
unsigned leftmost)
|
||||
{
|
||||
struct rx_node *new_r;
|
||||
|
||||
if (leftmost)
|
||||
new_r = _node(mem, CAT, LEFT(left_cat), r);
|
||||
else
|
||||
new_r = _node(mem, CAT, r, LEFT(right_cat));
|
||||
|
||||
if (!new_r)
|
||||
return_NULL;
|
||||
|
||||
memcpy(left_cat, RIGHT(left_cat), sizeof(*left_cat));
|
||||
memcpy(right_cat, RIGHT(right_cat), sizeof(*right_cat));
|
||||
|
||||
return new_r;
|
||||
}
|
||||
|
||||
static struct rx_node *_pass(struct dm_pool *mem,
|
||||
struct rx_node *r,
|
||||
int *changed)
|
||||
{
|
||||
struct rx_node *left, *right;
|
||||
|
||||
/*
|
||||
* walk the tree, optimising every 'or' node.
|
||||
*/
|
||||
switch (r->type) {
|
||||
case CAT:
|
||||
if (!(r->left = _pass(mem, r->left, changed)))
|
||||
return_NULL;
|
||||
|
||||
if (!(r->right = _pass(mem, r->right, changed)))
|
||||
return_NULL;
|
||||
|
||||
break;
|
||||
|
||||
case STAR:
|
||||
case PLUS:
|
||||
case QUEST:
|
||||
if (!(r->left = _pass(mem, r->left, changed)))
|
||||
return_NULL;
|
||||
|
||||
break;
|
||||
case OR:
|
||||
/* It's important we optimise sub nodes first */
|
||||
if (!(r->left = _pass(mem, r->left, changed)))
|
||||
return_NULL;
|
||||
|
||||
if (!(r->right = _pass(mem, r->right, changed)))
|
||||
return_NULL;
|
||||
/*
|
||||
* If rotate_ors changes the tree, left and right are stale,
|
||||
* so just set 'changed' to repeat the search.
|
||||
*
|
||||
* FIXME Check we can't 'bounce' between left and right rotations here.
|
||||
*/
|
||||
if (_find_leftmost_common(r, &left, &right, 1)) {
|
||||
if (!_rotate_ors(r, 1))
|
||||
r = _exchange_nodes(mem, r, left, right, 1);
|
||||
*changed = 1;
|
||||
} else if (_find_leftmost_common(r, &left, &right, 0)) {
|
||||
if (!_rotate_ors(r, 0))
|
||||
r = _exchange_nodes(mem, r, left, right, 0);
|
||||
*changed = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case CHARSET:
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct rx_node *_optimise(struct dm_pool *mem, struct rx_node *r)
|
||||
{
|
||||
/*
|
||||
* We're looking for (or (... (cat <foo> a)) (... (cat <foo> b)))
|
||||
* and want to turn it into (cat <foo> (or (... a) (... b)))
|
||||
*
|
||||
* (fa)|(fb) becomes f(a|b)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initially done as an inefficient multipass algorithm.
|
||||
*/
|
||||
int changed;
|
||||
|
||||
do {
|
||||
changed = 0;
|
||||
r = _pass(mem, r, &changed);
|
||||
} while (r && changed);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
struct rx_node *rx_parse_tok(struct dm_pool *mem,
|
||||
const char *begin, const char *end)
|
||||
{
|
||||
struct rx_node *r;
|
||||
struct parse_sp *ps = dm_pool_zalloc(mem, sizeof(*ps));
|
||||
|
||||
if (!ps)
|
||||
return_NULL;
|
||||
|
||||
ps->mem = mem;
|
||||
if (!(ps->charset = dm_bitset_create(mem, 256))) {
|
||||
log_error("Regex charset allocation failed");
|
||||
dm_pool_free(mem, ps);
|
||||
return NULL;
|
||||
}
|
||||
ps->cursor = begin;
|
||||
ps->rx_end = end;
|
||||
_rx_get_token(ps); /* load the first token */
|
||||
|
||||
if (!(r = _or_term(ps))) {
|
||||
log_error("Parse error in regex");
|
||||
dm_pool_free(mem, ps);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(r = _optimise(mem, r))) {
|
||||
log_error("Regex optimisation error");
|
||||
dm_pool_free(mem, ps);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
struct rx_node *rx_parse_str(struct dm_pool *mem, const char *str)
|
||||
{
|
||||
return rx_parse_tok(mem, str, str + strlen(str));
|
||||
}
|
55
device_mapper/regex/parse_rx.h
Normal file
55
device_mapper/regex/parse_rx.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _DM_PARSE_REGEX_H
|
||||
#define _DM_PARSE_REGEX_H
|
||||
|
||||
enum {
|
||||
CAT,
|
||||
STAR,
|
||||
PLUS,
|
||||
OR,
|
||||
QUEST,
|
||||
CHARSET
|
||||
};
|
||||
|
||||
/*
|
||||
* We're never going to be running the regex on non-printable
|
||||
* chars, so we can use a couple of these chars to represent the
|
||||
* start and end of a string.
|
||||
*/
|
||||
#define HAT_CHAR 0x2
|
||||
#define DOLLAR_CHAR 0x3
|
||||
|
||||
#define TARGET_TRANS '\0'
|
||||
|
||||
struct rx_node {
|
||||
int type;
|
||||
dm_bitset_t charset;
|
||||
struct rx_node *left, *right;
|
||||
|
||||
/* used to build the dfa for the toker */
|
||||
unsigned charset_index;
|
||||
int nullable, final;
|
||||
dm_bitset_t firstpos;
|
||||
dm_bitset_t lastpos;
|
||||
dm_bitset_t followpos;
|
||||
};
|
||||
|
||||
struct rx_node *rx_parse_str(struct dm_pool *mem, const char *str);
|
||||
struct rx_node *rx_parse_tok(struct dm_pool *mem,
|
||||
const char *begin, const char *end);
|
||||
|
||||
#endif
|
114
device_mapper/regex/ttree.c
Normal file
114
device_mapper/regex/ttree.c
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "misc/dmlib.h"
|
||||
#include "ttree.h"
|
||||
|
||||
struct node {
|
||||
unsigned k;
|
||||
struct node *l, *m, *r;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct ttree {
|
||||
int klen;
|
||||
struct dm_pool *mem;
|
||||
struct node *root;
|
||||
};
|
||||
|
||||
__attribute__((nonnull(1)))
|
||||
static struct node **_lookup_single(struct node **c, unsigned int k)
|
||||
{
|
||||
while (*c) {
|
||||
if (k < (*c)->k)
|
||||
c = &((*c)->l);
|
||||
|
||||
else if (k > (*c)->k)
|
||||
c = &((*c)->r);
|
||||
|
||||
else {
|
||||
c = &((*c)->m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void *ttree_lookup(struct ttree *tt, unsigned *key)
|
||||
{
|
||||
struct node **c = &tt->root;
|
||||
int count = tt->klen;
|
||||
|
||||
while (*c && count) {
|
||||
c = _lookup_single(c, *key++);
|
||||
count--;
|
||||
}
|
||||
|
||||
return *c ? (*c)->data : NULL;
|
||||
}
|
||||
|
||||
static struct node *_tree_node(struct dm_pool *mem, unsigned int k)
|
||||
{
|
||||
struct node *n = dm_pool_zalloc(mem, sizeof(*n));
|
||||
|
||||
if (n)
|
||||
n->k = k;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int ttree_insert(struct ttree *tt, unsigned int *key, void *data)
|
||||
{
|
||||
struct node **c = &tt->root;
|
||||
int count = tt->klen;
|
||||
unsigned int k;
|
||||
|
||||
do {
|
||||
k = *key++;
|
||||
c = _lookup_single(c, k);
|
||||
count--;
|
||||
|
||||
} while (*c && count);
|
||||
|
||||
if (!*c) {
|
||||
count++;
|
||||
|
||||
while (count--) {
|
||||
if (!(*c = _tree_node(tt->mem, k)))
|
||||
return_0;
|
||||
|
||||
if (count) {
|
||||
k = *key++;
|
||||
c = &((*c)->m);
|
||||
}
|
||||
}
|
||||
}
|
||||
(*c)->data = data;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ttree *ttree_create(struct dm_pool *mem, unsigned int klen)
|
||||
{
|
||||
struct ttree *tt;
|
||||
|
||||
if (!(tt = dm_pool_zalloc(mem, sizeof(*tt))))
|
||||
return_NULL;
|
||||
|
||||
tt->klen = klen;
|
||||
tt->mem = mem;
|
||||
return tt;
|
||||
}
|
26
device_mapper/regex/ttree.h
Normal file
26
device_mapper/regex/ttree.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _DM_TTREE_H
|
||||
#define _DM_TTREE_H
|
||||
|
||||
struct ttree;
|
||||
|
||||
struct ttree *ttree_create(struct dm_pool *mem, unsigned int klen);
|
||||
|
||||
void *ttree_lookup(struct ttree *tt, unsigned *key);
|
||||
int ttree_insert(struct ttree *tt, unsigned *key, void *data);
|
||||
|
||||
#endif
|
@ -1,7 +1,7 @@
|
||||
#include "target.h"
|
||||
|
||||
// For DM_ARRAY_SIZE!
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
@ -16,7 +16,7 @@
|
||||
#ifndef _LVM_CONFIG_H
|
||||
#define _LVM_CONFIG_H
|
||||
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
#include "lib/device/device.h"
|
||||
|
||||
/* 16 bits: 3 bits for major, 4 bits for minor, 9 bits for patchlevel */
|
||||
|
@ -15,7 +15,7 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "lib/device/bcache.h"
|
||||
#include "libdm/misc/dm-logging.h"
|
||||
#include "device_mapper/misc/dm-logging.h"
|
||||
#include "lib/log/log.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -15,7 +15,7 @@
|
||||
#ifndef BCACHE_H
|
||||
#define BCACHE_H
|
||||
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <stdint.h>
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "lib/datastruct/btree.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "libdm/misc/dm-ioctl.h"
|
||||
#include "device_mapper/misc/dm-ioctl.h"
|
||||
#include "lib/misc/lvm-string.h"
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
|
@ -16,7 +16,7 @@
|
||||
#define _LVM_PV_H
|
||||
|
||||
#include "lib/uuid/uuid.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
struct device;
|
||||
struct format_type;
|
||||
|
@ -16,7 +16,7 @@
|
||||
#define _LVM_VG_H
|
||||
|
||||
#include "lib/uuid/uuid.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
struct cmd_context;
|
||||
struct format_instance;
|
||||
|
@ -79,7 +79,7 @@
|
||||
|
||||
|
||||
#include "lib/misc/intl.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
#include "lib/misc/util.h"
|
||||
|
||||
#ifdef DM
|
||||
|
@ -14,7 +14,7 @@
|
||||
#ifndef _LVM_PROPERTIES_H
|
||||
#define _LVM_PROPERTIES_H
|
||||
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/report/report.h"
|
||||
#include "lib/properties/prop_common.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "libdaemon/client/daemon-io.h"
|
||||
#include "libdm/misc/dm-logging.h"
|
||||
#include "device_mapper/misc/dm-logging.h"
|
||||
|
||||
#include <math.h> /* fabs() */
|
||||
#include <float.h> /* DBL_EPSILON */
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include "libdaemon/client/daemon-io.h"
|
||||
#include "libdaemon/client/daemon-client.h"
|
||||
#include "libdm/misc/dm-logging.h"
|
||||
#include "device_mapper/misc/dm-logging.h"
|
||||
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -52,7 +52,7 @@ CFLOW_LIST_TARGET = libdevmapper.cflow
|
||||
EXPORTED_HEADER = $(srcdir)/libdevmapper.h
|
||||
EXPORTED_FN_PREFIX = dm
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
include $(top_builddir)/libdm/make.tmpl
|
||||
|
||||
PROGS_CFLAGS = $(UDEV_CFLAGS)
|
||||
|
||||
|
578
libdm/make.tmpl.in
Normal file
578
libdm/make.tmpl.in
Normal file
@ -0,0 +1,578 @@
|
||||
# @configure_input@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
ifeq ($(V),1)
|
||||
Q=
|
||||
else
|
||||
Q=@
|
||||
endif
|
||||
|
||||
SHELL = @SHELL@
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Allow environment to override any built-in default value for CC.
|
||||
# If there is a built-in default, CC is NOT set to @CC@ here.
|
||||
CC ?= @CC@
|
||||
|
||||
# If $(CC) holds the usual built-in default value of 'cc' then replace it with
|
||||
# the configured value.
|
||||
# (To avoid this and force the use of 'cc' from the environment, supply its
|
||||
# full path.)
|
||||
ifeq ($(CC), cc)
|
||||
CC = @CC@
|
||||
endif
|
||||
|
||||
RANLIB = @RANLIB@
|
||||
INSTALL = @INSTALL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
MSGFMT = @MSGFMT@
|
||||
LCOV = @LCOV@
|
||||
GENHTML = @GENHTML@
|
||||
LN_S = @LN_S@
|
||||
SED = @SED@
|
||||
CFLOW_CMD = @CFLOW_CMD@
|
||||
AWK = @AWK@
|
||||
CHMOD = @CHMOD@
|
||||
EGREP = @EGREP@
|
||||
GREP = @GREP@
|
||||
SORT = @SORT@
|
||||
WC = @WC@
|
||||
AR = @AR@
|
||||
RM = rm -f
|
||||
|
||||
PYTHON2 = @PYTHON2@
|
||||
PYTHON3 = @PYTHON3@
|
||||
PYCOMPILE = $(top_srcdir)/autoconf/py-compile
|
||||
|
||||
LIBS = @LIBS@
|
||||
# Extra libraries always linked with static binaries
|
||||
STATIC_LIBS = $(SELINUX_LIBS) $(UDEV_LIBS) $(BLKID_LIBS)
|
||||
DEFS += @DEFS@
|
||||
# FIXME set this only where it's needed, not globally?
|
||||
CFLAGS ?= @COPTIMISE_FLAG@ @CFLAGS@
|
||||
LDFLAGS ?= @LDFLAGS@
|
||||
CLDFLAGS += @CLDFLAGS@
|
||||
ELDFLAGS += @ELDFLAGS@
|
||||
LDDEPS += @LDDEPS@
|
||||
LIB_SUFFIX = @LIB_SUFFIX@
|
||||
LVMINTERNAL_LIBS = -llvm-internal $(DMEVENT_LIBS) $(DAEMON_LIBS) $(SYSTEMD_LIBS) $(UDEV_LIBS) $(DL_LIBS) $(BLKID_LIBS)
|
||||
DL_LIBS = @DL_LIBS@
|
||||
RT_LIBS = @RT_LIBS@
|
||||
M_LIBS = @M_LIBS@
|
||||
PTHREAD_LIBS = @PTHREAD_LIBS@
|
||||
READLINE_LIBS = @READLINE_LIBS@
|
||||
SELINUX_LIBS = @SELINUX_LIBS@
|
||||
UDEV_CFLAGS = @UDEV_CFLAGS@
|
||||
UDEV_LIBS = @UDEV_LIBS@
|
||||
BLKID_CFLAGS = @BLKID_CFLAGS@
|
||||
BLKID_LIBS = @BLKID_LIBS@
|
||||
SYSTEMD_LIBS = @SYSTEMD_LIBS@
|
||||
VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
|
||||
|
||||
# Setup directory variables
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
udev_prefix = @udev_prefix@
|
||||
sysconfdir = @sysconfdir@
|
||||
rootdir = $(DESTDIR)/
|
||||
bindir = $(DESTDIR)@bindir@
|
||||
confdir = $(DESTDIR)@CONFDIR@/lvm
|
||||
profiledir = $(confdir)/@DEFAULT_PROFILE_SUBDIR@
|
||||
includedir = $(DESTDIR)@includedir@
|
||||
libdir = $(DESTDIR)@libdir@
|
||||
libexecdir = $(DESTDIR)@libexecdir@
|
||||
usrlibdir = $(DESTDIR)@usrlibdir@
|
||||
sbindir = $(DESTDIR)@sbindir@
|
||||
usrsbindir = $(DESTDIR)@usrsbindir@
|
||||
datarootdir = @datarootdir@
|
||||
datadir = $(DESTDIR)@datadir@
|
||||
infodir = $(DESTDIR)@infodir@
|
||||
mandir = $(DESTDIR)@mandir@
|
||||
localedir = $(DESTDIR)@localedir@
|
||||
staticdir = $(DESTDIR)@STATICDIR@
|
||||
udevdir = $(DESTDIR)@udevdir@
|
||||
pkgconfigdir = $(usrlibdir)/pkgconfig
|
||||
initdir = $(DESTDIR)$(sysconfdir)/rc.d/init.d
|
||||
dbusconfdir = $(DESTDIR)$(sysconfdir)/dbus-1/system.d
|
||||
dbusservicedir = $(datadir)/dbus-1/system-services
|
||||
systemd_unit_dir = $(DESTDIR)@systemdsystemunitdir@
|
||||
systemd_generator_dir = $(DESTDIR)$(SYSTEMD_GENERATOR_DIR)
|
||||
systemd_dir = $(DESTDIR)@systemdutildir@
|
||||
tmpfiles_dir = $(DESTDIR)@tmpfilesdir@
|
||||
ocf_scriptdir = $(DESTDIR)@OCFDIR@
|
||||
pythonprefix = $(DESTDIR)$(prefix)
|
||||
|
||||
# N.B. No $(DESTDIR) prefix here.
|
||||
python2dir = @PYTHON2DIR@
|
||||
python3dir = @PYTHON3DIR@
|
||||
|
||||
USRLIB_RELPATH = $(shell echo $(abspath $(usrlibdir) $(libdir)) | \
|
||||
$(AWK) -f $(top_srcdir)/scripts/relpath.awk)
|
||||
|
||||
SYSTEMD_GENERATOR_DIR = @systemdutildir@/system-generators
|
||||
DEFAULT_SYS_DIR = @DEFAULT_SYS_DIR@
|
||||
DEFAULT_ARCHIVE_DIR = $(DEFAULT_SYS_DIR)/@DEFAULT_ARCHIVE_SUBDIR@
|
||||
DEFAULT_BACKUP_DIR = $(DEFAULT_SYS_DIR)/@DEFAULT_BACKUP_SUBDIR@
|
||||
DEFAULT_CACHE_DIR = $(DEFAULT_SYS_DIR)/@DEFAULT_CACHE_SUBDIR@
|
||||
DEFAULT_PROFILE_DIR = $(DEFAULT_SYS_DIR)/@DEFAULT_PROFILE_SUBDIR@
|
||||
DEFAULT_LOCK_DIR = @DEFAULT_LOCK_DIR@
|
||||
DEFAULT_RUN_DIR = @DEFAULT_RUN_DIR@
|
||||
DEFAULT_PID_DIR = @DEFAULT_PID_DIR@
|
||||
DEFAULT_MANGLING = @MANGLING@
|
||||
|
||||
# Setup vpath search paths for some suffixes
|
||||
vpath %.c $(srcdir)
|
||||
vpath %.cpp $(srcdir)
|
||||
vpath %.in $(srcdir)
|
||||
vpath %.po $(srcdir)
|
||||
vpath %.exported_symbols $(srcdir)
|
||||
|
||||
interface = @interface@
|
||||
interfacebuilddir = $(top_builddir)/libdm/$(interface)
|
||||
rpmbuilddir = $(abs_top_builddir)/build
|
||||
|
||||
# The number of jobs to run, if blank, defaults to the make standard
|
||||
ifndef MAKEFLAGS
|
||||
MAKEFLAGS = @JOBS@
|
||||
endif
|
||||
|
||||
# Handle installation of files
|
||||
ifeq ("@WRITE_INSTALL@", "yes")
|
||||
# leaving defaults
|
||||
M_INSTALL_SCRIPT =
|
||||
M_INSTALL_DATA = -m 644
|
||||
else
|
||||
M_INSTALL_PROGRAM = -m 555
|
||||
M_INSTALL_DATA = -m 444
|
||||
endif
|
||||
INSTALL_PROGRAM = $(INSTALL) $(M_INSTALL_PROGRAM) $(STRIP)
|
||||
INSTALL_DATA = $(INSTALL) -p $(M_INSTALL_DATA)
|
||||
INSTALL_WDATA = $(INSTALL) -p -m 644
|
||||
|
||||
INSTALL_DIR = $(INSTALL) -m 755 -d
|
||||
INSTALL_ROOT_DIR = $(INSTALL) -m 700 -d
|
||||
INSTALL_ROOT_DATA = $(INSTALL) -m 600
|
||||
INSTALL_SCRIPT = $(INSTALL) -p $(M_INSTALL_PROGRAM)
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .cpp .d .o .so .a .po .pot .mo .dylib
|
||||
|
||||
ifeq ("$(notdir $(CC))", "gcc")
|
||||
WFLAGS +=\
|
||||
-Wall\
|
||||
-Wcast-align\
|
||||
-Wfloat-equal\
|
||||
-Wformat-security\
|
||||
-Winline\
|
||||
-Wmissing-format-attribute\
|
||||
-Wmissing-include-dirs\
|
||||
-Wmissing-noreturn\
|
||||
-Wpointer-arith\
|
||||
-Wredundant-decls\
|
||||
-Wshadow\
|
||||
-Wundef\
|
||||
-Wwrite-strings
|
||||
|
||||
WCFLAGS +=\
|
||||
-Wmissing-declarations\
|
||||
-Wmissing-prototypes\
|
||||
-Wnested-externs\
|
||||
-Wold-style-definition\
|
||||
-Wstrict-prototypes\
|
||||
-Wuninitialized
|
||||
|
||||
ifeq ("@HAVE_WJUMP@", "yes")
|
||||
WCFLAGS += -Wjump-misses-init
|
||||
endif
|
||||
|
||||
ifeq ("@HAVE_WCLOBBERED@", "yes")
|
||||
WFLAGS +=\
|
||||
-Wclobbered\
|
||||
-Wempty-body\
|
||||
-Wignored-qualifiers\
|
||||
-Wlogical-op\
|
||||
-Wtype-limits
|
||||
|
||||
WCFLAGS +=\
|
||||
-Wmissing-parameter-type\
|
||||
-Wold-style-declaration\
|
||||
-Woverride-init
|
||||
endif
|
||||
|
||||
ifeq ("@HAVE_WSYNCNAND@", "yes")
|
||||
WFLAGS += -Wsync-nand
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ("@STATIC_LINK@", "yes")
|
||||
ifeq ("@HAVE_PIE@", "yes")
|
||||
ifeq ("@HAVE_FULL_RELRO@", "yes")
|
||||
EXTRA_EXEC_CFLAGS += -fPIE
|
||||
EXTRA_EXEC_LDFLAGS += -Wl,-z,relro,-z,now -pie -fPIE
|
||||
CLDFLAGS += -Wl,-z,relro
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
#WFLAGS += -W -Wno-sign-compare -Wno-unused-parameter -Wno-missing-field-initializers
|
||||
#WFLAGS += -Wsign-compare -Wunused-parameter -Wmissing-field-initializers
|
||||
#WFLAGS += -Wconversion -Wbad-function-cast -Wcast-qual -Waggregate-return -Wpacked
|
||||
#WFLAGS += -pedantic -std=gnu99
|
||||
#DEFS += -DDEBUG_CRC32
|
||||
|
||||
#
|
||||
# Avoid recursive extension of CFLAGS
|
||||
# by checking whether CFLAGS already has fPIC string
|
||||
#
|
||||
ifeq (,$(findstring fPIC,$(CFLAGS)))
|
||||
|
||||
CFLAGS += -fPIC
|
||||
|
||||
ifeq ("@DEBUG@", "yes")
|
||||
ifeq (,$(findstring -g,$(CFLAGS)))
|
||||
CFLAGS += -g
|
||||
endif
|
||||
CFLAGS += -fno-omit-frame-pointer
|
||||
DEFS += -DDEBUG
|
||||
# memory debugging is not thread-safe yet
|
||||
ifneq ("@BUILD_DMEVENTD@", "yes")
|
||||
ifneq ("@BUILD_DMFILEMAPD@", "yes")
|
||||
ifneq ("@BUILD_LVMLOCKD@", "yes")
|
||||
ifneq ("@BUILD_LVMPOLLD@", "yes")
|
||||
ifneq ("@BUILD_LVMETAD@", "yes")
|
||||
ifeq ("@CLVMD@", "none")
|
||||
DEFS += -DDEBUG_MEM
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# end of fPIC protection
|
||||
endif
|
||||
|
||||
DEFS += -D_BUILDING_LVM
|
||||
|
||||
LDFLAGS += -L$(top_builddir)/libdm -L$(top_builddir)/lib
|
||||
CLDFLAGS += -L$(top_builddir)/libdm -L$(top_builddir)/lib
|
||||
|
||||
DAEMON_LIBS = -ldaemonclient
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/client
|
||||
CLDFLAGS += -L$(top_builddir)/libdaemon/client
|
||||
|
||||
ifeq ("@BUILD_DMEVENTD@", "yes")
|
||||
DMEVENT_LIBS = -ldevmapper-event
|
||||
LDFLAGS += -L$(top_builddir)/daemons/dmeventd
|
||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
|
||||
endif
|
||||
|
||||
# Combination of DEBUG_POOL and DEBUG_ENFORCE_POOL_LOCKING is not suppored.
|
||||
#DEFS += -DDEBUG_POOL
|
||||
# Default pool locking is using the crc checksum. With mprotect memory
|
||||
# enforcing compilation faulty memory write could be easily found.
|
||||
#DEFS += -DDEBUG_ENFORCE_POOL_LOCKING
|
||||
#DEFS += -DBOUNDS_CHECK
|
||||
|
||||
# LVM is not supposed to use mmap while devices are suspended.
|
||||
# This code causes a core dump if gets called.
|
||||
#DEFS += -DDEBUG_MEMLOCK
|
||||
|
||||
#CFLAGS += -pg
|
||||
#LDFLAGS += -pg
|
||||
|
||||
STRIP=
|
||||
#STRIP = -s
|
||||
|
||||
LVM_VERSION := $(shell cat $(top_srcdir)/VERSION)
|
||||
|
||||
LIB_VERSION_LVM := $(shell $(AWK) -F '.' '{printf "%s.%s",$$1,$$2}' $(top_srcdir)/VERSION)
|
||||
|
||||
LIB_VERSION_DM := $(shell $(AWK) -F '.' '{printf "%s.%s",$$1,$$2}' $(top_srcdir)/VERSION_DM)
|
||||
|
||||
LIB_VERSION_APP := $(shell $(AWK) -F '[(). ]' '{printf "%s.%s",$$1,$$4}' $(top_srcdir)/VERSION)
|
||||
|
||||
INCLUDES += -I$(top_srcdir) -I$(srcdir) -I$(top_builddir)/include
|
||||
|
||||
DEPS = $(top_builddir)/make.tmpl $(top_srcdir)/VERSION \
|
||||
$(top_builddir)/Makefile
|
||||
|
||||
OBJECTS = $(SOURCES:%.c=%.o) $(CXXSOURCES:%.cpp=%.o)
|
||||
POTFILES = $(SOURCES:%.c=%.pot)
|
||||
|
||||
.PHONY: all pofile distclean clean cleandir cflow device-mapper
|
||||
.PHONY: install install_cluster install_device-mapper install_lvm2
|
||||
.PHONY: install_dbus_service
|
||||
.PHONY: install_lib_shared install_dm_plugin install_lvm2_plugin
|
||||
.PHONY: install_ocf install_systemd_generators install_all_man all_man man help
|
||||
.PHONY: python_bindings install_python_bindings
|
||||
.PHONY: $(SUBDIRS) $(SUBDIRS.install) $(SUBDIRS.clean) $(SUBDIRS.distclean)
|
||||
.PHONY: $(SUBDIRS.pofile) $(SUBDIRS.install_cluster) $(SUBDIRS.cflow)
|
||||
.PHONY: $(SUBDIRS.device-mapper) $(SUBDIRS.install-device-mapper)
|
||||
.PHONY: $(SUBDIRS.generate) generate
|
||||
|
||||
SUBDIRS.device-mapper := $(SUBDIRS:=.device-mapper)
|
||||
SUBDIRS.install := $(SUBDIRS:=.install)
|
||||
SUBDIRS.install_cluster := $(SUBDIRS:=.install_cluster)
|
||||
SUBDIRS.install_device-mapper := $(SUBDIRS:=.install_device-mapper)
|
||||
SUBDIRS.install_lvm2 := $(SUBDIRS:=.install_lvm2)
|
||||
SUBDIRS.install_ocf := $(SUBDIRS:=.install_ocf)
|
||||
SUBDIRS.pofile := $(SUBDIRS:=.pofile)
|
||||
SUBDIRS.cflow := $(SUBDIRS:=.cflow)
|
||||
SUBDIRS.clean := $(SUBDIRS:=.clean)
|
||||
SUBDIRS.distclean := $(SUBDIRS:=.distclean)
|
||||
|
||||
TARGETS += $(LIB_SHARED) $(LIB_STATIC)
|
||||
|
||||
all: $(SUBDIRS) $(TARGETS)
|
||||
|
||||
install: all $(SUBDIRS.install)
|
||||
install_cluster: all $(SUBDIRS.install_cluster)
|
||||
install_device-mapper: $(SUBDIRS.install_device-mapper)
|
||||
install_lvm2: $(SUBDIRS.install_lvm2)
|
||||
install_ocf: $(SUBDIRS.install_ocf)
|
||||
cflow: $(SUBDIRS.cflow)
|
||||
|
||||
$(SUBDIRS): $(SUBDIRS.device-mapper)
|
||||
$(MAKE) -C $@
|
||||
|
||||
$(SUBDIRS.device-mapper):
|
||||
$(MAKE) -C $(@:.device-mapper=) device-mapper
|
||||
|
||||
$(SUBDIRS.install): $(SUBDIRS)
|
||||
$(MAKE) -C $(@:.install=) install
|
||||
|
||||
$(SUBDIRS.install_cluster): $(SUBDIRS)
|
||||
$(MAKE) -C $(@:.install_cluster=) install_cluster
|
||||
|
||||
$(SUBDIRS.install_device-mapper): device-mapper
|
||||
$(MAKE) -C $(@:.install_device-mapper=) install_device-mapper
|
||||
|
||||
$(SUBDIRS.install_lvm2): $(SUBDIRS)
|
||||
$(MAKE) -C $(@:.install_lvm2=) install_lvm2
|
||||
|
||||
$(SUBDIRS.install_ocf):
|
||||
$(MAKE) -C $(@:.install_ocf=) install_ocf
|
||||
|
||||
$(SUBDIRS.clean):
|
||||
-$(MAKE) -C $(@:.clean=) clean
|
||||
|
||||
$(SUBDIRS.distclean):
|
||||
-$(MAKE) -C $(@:.distclean=) distclean
|
||||
|
||||
$(SUBDIRS.cflow):
|
||||
$(MAKE) -C $(@:.cflow=) cflow
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
pofile: $(SUBDIRS.pofile) $(POTFILES)
|
||||
|
||||
$(SUBDIRS.pofile):
|
||||
$(MAKE) -C $(@:.pofile=) pofile
|
||||
endif
|
||||
|
||||
$(SUBDIRS.generate):
|
||||
$(MAKE) -C $(@:.generate=) generate
|
||||
|
||||
ifneq ("$(CFLOW_LIST_TARGET)", "")
|
||||
CLEAN_CFLOW += $(CFLOW_LIST_TARGET)
|
||||
$(CFLOW_LIST_TARGET): $(CFLOW_LIST)
|
||||
echo "CFLOW_SOURCES += $(addprefix \
|
||||
\$$(top_srcdir)$(subst $(top_srcdir),,$(srcdir))/, $(CFLOW_LIST))" > $@
|
||||
cflow: $(CFLOW_LIST_TARGET)
|
||||
endif
|
||||
|
||||
ifneq ("$(CFLOW_TARGET)", "")
|
||||
CLEAN_CFLOW += \
|
||||
$(CFLOW_TARGET).cflow \
|
||||
$(CFLOW_TARGET).xref \
|
||||
$(CFLOW_TARGET).tree \
|
||||
$(CFLOW_TARGET).rtree \
|
||||
$(CFLOW_TARGET).rxref
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_FLAGS +=\
|
||||
--cpp="$(CC) -E" \
|
||||
--symbol _ISbit:wrapper \
|
||||
--symbol __attribute__:wrapper \
|
||||
--symbol __const__:wrapper \
|
||||
--symbol __const:type \
|
||||
--symbol __restrict:type \
|
||||
--symbol __extension__:wrapper \
|
||||
--symbol __nonnull:wrapper \
|
||||
--symbol __nothrow__:wrapper \
|
||||
--symbol __pure__:wrapper \
|
||||
--symbol __REDIRECT:wrapper \
|
||||
--symbol __REDIRECT_NTH:wrapper \
|
||||
--symbol __wur:wrapper \
|
||||
-I$(top_srcdir)/libdm \
|
||||
-I$(top_srcdir)/libdm/ioctl \
|
||||
-I$(top_srcdir)/daemons/dmeventd/plugins/lvm2/ \
|
||||
$(INCLUDES) $(DEFS)
|
||||
|
||||
$(CFLOW_TARGET).cflow: $(CFLOW_SOURCES)
|
||||
$(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) $(CFLOW_SOURCES)
|
||||
$(CFLOW_TARGET).rxref: $(CFLOW_SOURCES)
|
||||
$(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) -r --omit-arguments $(CFLOW_SOURCES)
|
||||
$(CFLOW_TARGET).tree: $(CFLOW_SOURCES)
|
||||
$(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) --omit-arguments -T -b $(CFLOW_SOURCES)
|
||||
$(CFLOW_TARGET).xref: $(CFLOW_SOURCES)
|
||||
$(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) --omit-arguments -x $(CFLOW_SOURCES)
|
||||
#$(CFLOW_TARGET).rtree: $(CFLOW_SOURCES)
|
||||
# $(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) -r --omit-arguments -T -b $(CFLOW_SOURCES)
|
||||
cflow: $(CFLOW_TARGET).cflow $(CFLOW_TARGET).tree $(CFLOW_TARGET).rxref $(CFLOW_TARGET).xref
|
||||
#$(CFLOW_TARGET).rtree
|
||||
endif
|
||||
endif
|
||||
|
||||
.LIBPATTERNS = lib%.so lib%.a
|
||||
|
||||
DEPFLAGS=-MT $@ -MMD -MP -MF $*.d
|
||||
|
||||
# still needed in 2018 for 32bit builds
|
||||
DEFS+=-D_FILE_OFFSET_BITS=64
|
||||
|
||||
%.o: %.c
|
||||
@echo " [CC] $<"
|
||||
$(Q) $(CC) $(DEPFLAGS) -c $(INCLUDES) $(VALGRIND_CFLAGS) $(PROGS_CFLAGS) $(DEFS) $(DEFS_$@) $(WFLAGS) $(WCFLAGS) $(CFLAGS) $(CFLAGS_$@) $< -o $@
|
||||
|
||||
%.o: %.cpp
|
||||
@echo " [CXX] $<"
|
||||
$(Q) $(CXX) -c $(INCLUDES) $(VALGRIND_CFLAGS) $(DEFS) $(DEFS_$@) $(WFLAGS) $(CXXFLAGS) $(CXXFLAGS_$@) $< -o $@
|
||||
|
||||
%.pot: %.c Makefile
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) -E $(INCLUDES) $(VALGRIND_CFLAGS) $(PROGS_CFLAGS) -include $(top_builddir)/include/pogen.h $(DEFS) $(WFLAGS) $(CFLAGS) $< >$@
|
||||
|
||||
%.so: %.o
|
||||
@echo " [CC] $<"
|
||||
$(Q) $(CC) -c $(CFLAGS) $(CLDFLAGS) $< $(LIBS) -o $@
|
||||
|
||||
ifneq (,$(LIB_SHARED))
|
||||
|
||||
TARGETS += $(LIB_SHARED).$(LIB_VERSION)
|
||||
$(LIB_SHARED).$(LIB_VERSION): $(OBJECTS) $(LDDEPS)
|
||||
@echo " [CC] $@"
|
||||
ifeq ("@LIB_SUFFIX@","so")
|
||||
$(Q) $(CC) -shared -Wl,-soname,$(notdir $@) \
|
||||
$(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||
endif
|
||||
ifeq ("@LIB_SUFFIX@","dylib")
|
||||
$(Q) $(CC) -dynamiclib -dylib_current_version,$(LIB_VERSION) \
|
||||
$(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||
endif
|
||||
|
||||
$(LIB_SHARED): $(LIB_SHARED).$(LIB_VERSION)
|
||||
@echo " [LN] $<"
|
||||
$(Q) $(LN_S) -f $(<F) $@
|
||||
|
||||
CLEAN_TARGETS += $(LDDEPS) .exported_symbols_generated
|
||||
|
||||
install_lib_shared: $(LIB_SHARED)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D $< $(libdir)/$(<F).$(LIB_VERSION)
|
||||
$(Q) $(INSTALL_DIR) $(usrlibdir)
|
||||
$(Q) $(LN_S) -f $(USRLIB_RELPATH)$(<F).$(LIB_VERSION) $(usrlibdir)/$(<F)
|
||||
|
||||
# FIXME: plugins are installed to subdirs
|
||||
# and for compatibility links in libdir are created
|
||||
# when the code is fixed links could be removed.
|
||||
install_dm_plugin: $(LIB_SHARED)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D $< $(libdir)/device-mapper/$(<F)
|
||||
$(Q) $(LN_S) -f device-mapper/$(<F) $(libdir)/$(<F)
|
||||
|
||||
install_lvm2_plugin: $(LIB_SHARED)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D $< $(libdir)/lvm2/$(<F)
|
||||
$(Q) $(LN_S) -f lvm2/$(<F) $(libdir)/$(<F)
|
||||
$(Q) $(LN_S) -f $(<F) $(libdir)/$(<F).$(LIB_VERSION)
|
||||
endif
|
||||
|
||||
$(LIB_STATIC): $(OBJECTS)
|
||||
@echo " [AR] $@"
|
||||
$(Q) $(RM) $@
|
||||
$(Q) $(AR) rsv $@ $(OBJECTS) > /dev/null
|
||||
|
||||
%.d:
|
||||
.PRECIOUS: %.d
|
||||
|
||||
%.mo: %.po
|
||||
@echo " [MSGFMT] $<"
|
||||
$(Q) $(MSGFMT) -o $@ $<
|
||||
|
||||
CLEAN_TARGETS += \
|
||||
$(SOURCES:%.c=%.d) $(SOURCES:%.c=%.gcno) $(SOURCES:%.c=%.gcda) \
|
||||
$(SOURCES2:%.c=%.o) $(SOURCES2:%.c=%.d) $(SOURCES2:%.c=%.gcno) $(SOURCES2:%.c=%.gcda) \
|
||||
$(POTFILES) $(CLEAN_CFLOW)
|
||||
|
||||
cleandir:
|
||||
ifneq (,$(firstword $(CLEAN_DIRS)))
|
||||
$(RM) -r $(CLEAN_DIRS)
|
||||
endif
|
||||
$(RM) $(OBJECTS) $(TARGETS) $(CLEAN_TARGETS) core
|
||||
|
||||
clean: $(SUBDIRS.clean) cleandir
|
||||
|
||||
distclean: cleandir $(SUBDIRS.distclean)
|
||||
ifneq (,$(firstword $(DISTCLEAN_DIRS)))
|
||||
$(RM) -r $(DISTCLEAN_DIRS)
|
||||
endif
|
||||
$(RM) $(DISTCLEAN_TARGETS) Makefile
|
||||
|
||||
.exported_symbols_generated: $(EXPORTED_HEADER) .exported_symbols $(DEPS)
|
||||
$(Q) set -e; \
|
||||
( cat $(srcdir)/.exported_symbols; \
|
||||
if test -n "$(EXPORTED_HEADER)"; then \
|
||||
$(CC) -E -P $(INCLUDES) $(DEFS) $(EXPORTED_HEADER) | \
|
||||
$(SED) -ne "/^typedef|}/!s/.*[ *]\($(EXPORTED_FN_PREFIX)_[a-z0-9_]*\)(.*/\1/p"; \
|
||||
fi \
|
||||
) > $@
|
||||
|
||||
EXPORTED_UC := $(shell echo $(EXPORTED_FN_PREFIX) | tr '[a-z]' '[A-Z]')
|
||||
EXPORTED_SYMBOLS := $(wildcard $(srcdir)/.exported_symbols.Base $(srcdir)/.exported_symbols.$(EXPORTED_UC)_[0-9_]*[0-9])
|
||||
|
||||
.export.sym: .exported_symbols_generated $(EXPORTED_SYMBOLS)
|
||||
ifeq (,$(firstword $(EXPORTED_SYMBOLS)))
|
||||
$(Q) set -e; (echo "Base {"; echo " global:";\
|
||||
$(SED) "s/^/ /;s/$$/;/" $<;\
|
||||
echo "};";\
|
||||
echo "Local {"; echo " local:"; echo " *;"; echo "};";\
|
||||
) > $@
|
||||
else
|
||||
$(Q) set -e;\
|
||||
R=$$($(SORT) $^ | uniq -u);\
|
||||
test -z "$$R" || { echo "Mismatch between symbols in shared library and lists in .exported_symbols.* files: $$R"; false; } ;\
|
||||
( for i in $$(echo $(EXPORTED_SYMBOLS) | tr ' ' '\n' | $(SORT) -rnt_ -k5 ); do\
|
||||
echo "$${i##*.} {"; echo " global:";\
|
||||
$(SED) "s/^/ /;s/$$/;/" $$i;\
|
||||
echo "};";\
|
||||
done;\
|
||||
echo "Local {"; echo " local:"; echo " *;"; echo "};";\
|
||||
) > $@
|
||||
endif
|
||||
|
||||
ifeq ("@USE_TRACKING@","yes")
|
||||
ifeq (,$(findstring $(MAKECMDGOALS),cscope.out cflow clean distclean lcov \
|
||||
help check check_local check_cluster check_lvmetad check_lvmpolld))
|
||||
ifdef SOURCES
|
||||
-include $(SOURCES:.c=.d) $(CXXSOURCES:.cpp=.d)
|
||||
endif
|
||||
ifdef SOURCES2
|
||||
-include $(SOURCES2:.c=.d)
|
||||
endif
|
||||
endif
|
||||
endif
|
@ -43,7 +43,7 @@ LDDEPS += $(top_builddir)/lib/liblvm-internal.a
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LDFLAGS += -L$(top_builddir)/lib -L$(top_builddir)/daemons/dmeventd
|
||||
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper -laio
|
||||
LIBS += $(LVMINTERNAL_LIBS) -laio
|
||||
|
||||
.PHONY: install_dynamic install_static install_include install_pkgconfig
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
#ifndef _LVM2APP_MISC_H
|
||||
#define _LVM2APP_MISC_H
|
||||
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
#include "liblvm/lvm2app.h"
|
||||
#include "lib/metadata/metadata-exported.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "lvm_prop.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
|
||||
/* lv create parameters */
|
||||
|
@ -68,7 +68,9 @@ CLDFLAGS += @CLDFLAGS@
|
||||
ELDFLAGS += @ELDFLAGS@
|
||||
LDDEPS += @LDDEPS@
|
||||
LIB_SUFFIX = @LIB_SUFFIX@
|
||||
LVMINTERNAL_LIBS = -llvm-internal $(DMEVENT_LIBS) $(DAEMON_LIBS) $(SYSTEMD_LIBS) $(UDEV_LIBS) $(DL_LIBS) $(BLKID_LIBS)
|
||||
LVMINTERNAL_LIBS=\
|
||||
-llvm-internal \
|
||||
$(DMEVENT_LIBS) $(DAEMON_LIBS) $(SYSTEMD_LIBS) $(UDEV_LIBS) $(DL_LIBS) $(BLKID_LIBS)
|
||||
DL_LIBS = @DL_LIBS@
|
||||
RT_LIBS = @RT_LIBS@
|
||||
M_LIBS = @M_LIBS@
|
||||
@ -338,7 +340,7 @@ SUBDIRS.distclean := $(SUBDIRS:=.distclean)
|
||||
|
||||
TARGETS += $(LIB_SHARED) $(LIB_STATIC)
|
||||
|
||||
all: $(SUBDIRS) $(TARGETS)
|
||||
all: $(top_builddir)/device_mapper/libdevice-mapper.a $(SUBDIRS) $(TARGETS)
|
||||
|
||||
install: all $(SUBDIRS.install)
|
||||
install_cluster: all $(SUBDIRS.install_cluster)
|
||||
@ -347,7 +349,7 @@ install_lvm2: $(SUBDIRS.install_lvm2)
|
||||
install_ocf: $(SUBDIRS.install_ocf)
|
||||
cflow: $(SUBDIRS.cflow)
|
||||
|
||||
$(SUBDIRS): $(SUBDIRS.device-mapper)
|
||||
$(SUBDIRS): $(SUBDIRS.device-mapper) $(top_builddir)/device_mapper/libdevice-mapper.a
|
||||
$(MAKE) -C $@
|
||||
|
||||
$(SUBDIRS.device-mapper):
|
||||
|
@ -23,12 +23,12 @@ endif
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
ifeq ("@APPLIB@", "yes")
|
||||
DEPLIBS += $(top_builddir)/liblvm/liblvm2app.so $(top_builddir)/libdm/libdevmapper.so
|
||||
DEPLIBS += $(top_builddir)/liblvm/liblvm2app.so
|
||||
LDFLAGS += -L$(top_builddir)/liblvm
|
||||
ifeq ("@BUILD_DMEVENTD@", "yes")
|
||||
LDFLAGS += -Wl,-rpath-link,$(top_builddir)/daemons/dmeventd
|
||||
endif
|
||||
LVMLIBS = @LVM2APP_LIB@ -ldevmapper -laio
|
||||
LVMLIBS = @LVM2APP_LIB@ -laio
|
||||
endif
|
||||
|
||||
LVM_SCRIPTS = lvmdump.sh lvmconf.sh
|
||||
|
@ -41,9 +41,12 @@ endif
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
DEFS += -D_REENTRANT
|
||||
DEPLIBS += $(top_builddir)/liblvm/liblvm2app.so $(top_builddir)/libdm/libdevmapper.so
|
||||
LDFLAGS += -L$(top_builddir)/liblvm -L$(top_builddir)/daemons/dmeventd
|
||||
LIBS += @LVM2APP_LIB@ $(DMEVENT_LIBS) -ldevmapper
|
||||
DEPLIBS += $(top_builddir)/liblvm/liblvm2app.so
|
||||
LDFLAGS+=\
|
||||
-L$(top_builddir)/liblvm \
|
||||
-L$(top_builddir)/daemons/dmeventd \
|
||||
-L$(top_builddir)/device_mapper/libdevice-mapper.a
|
||||
LIBS += @LVM2APP_LIB@ $(DMEVENT_LIBS)
|
||||
|
||||
%.t: %.o $(DEPLIBS)
|
||||
$(CC) -o $@ $(<) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) $(LIBS)
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
UNIT_SOURCE=\
|
||||
base/data-struct/radix-tree.c \
|
||||
device-mapper/vdo/status.c \
|
||||
device_mapper/vdo/status.c \
|
||||
\
|
||||
test/unit/bcache_t.c \
|
||||
test/unit/bcache_utils_t.c \
|
||||
@ -32,9 +32,9 @@ UNIT_SOURCE=\
|
||||
UNIT_DEPENDS=$(subst .c,.d,$(UNIT_SOURCE))
|
||||
UNIT_OBJECTS=$(UNIT_SOURCE:%.c=%.o)
|
||||
CLEAN_TARGETS+=$(UNIT_DEPENDS) $(UNIT_OBJECTS)
|
||||
UNIT_LDLIBS += $(LVMINTERNAL_LIBS) -ldevmapper -laio
|
||||
UNIT_LDLIBS += $(LVMINTERNAL_LIBS) -laio
|
||||
|
||||
test/unit/unit-test: $(UNIT_OBJECTS) libdm/libdevmapper.$(LIB_SUFFIX) lib/liblvm-internal.a
|
||||
test/unit/unit-test: $(UNIT_OBJECTS) device_mapper/libdevice-mapper.a lib/liblvm-internal.a
|
||||
@echo " [LD] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) -L$(top_builddir)/libdm \
|
||||
-o $@ $(UNIT_OBJECTS) $(UNIT_LDLIBS)
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "units.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
enum {
|
||||
NR_BITS = 137
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "units.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
static void *_mem_init(void)
|
||||
{
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "units.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
static void test_dmlist_splice(void *fixture)
|
||||
{
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "units.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
static void *_mem_init(void)
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef TEST_UNIT_FRAMEWORK_H
|
||||
#define TEST_UNIT_FRAMEWORK_H
|
||||
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "units.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
#include "matcher_data.h"
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "units.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "units.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -12,7 +12,7 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "device-mapper/vdo/target.h"
|
||||
#include "device_mapper/vdo/target.h"
|
||||
#include "framework.h"
|
||||
#include "units.h"
|
||||
|
||||
|
@ -95,7 +95,7 @@ ifeq ("@STATIC_LINK@", "yes")
|
||||
INSTALL_CMDLIB_TARGETS += install_cmdlib_static
|
||||
endif
|
||||
|
||||
LVMLIBS = $(LVMINTERNAL_LIBS) -ldevmapper -laio
|
||||
LVMLIBS = $(LVMINTERNAL_LIBS) -laio
|
||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \
|
||||
@ -122,15 +122,15 @@ device-mapper: $(TARGETS_DM)
|
||||
|
||||
CFLAGS_dmsetup.o += $(UDEV_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
dmsetup: dmsetup.o $(top_builddir)/libdm/libdevmapper.$(LIB_SUFFIX)
|
||||
dmsetup: dmsetup.o $(top_builddir)/device_mapper/libdevice-mapper.a
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
|
||||
-o $@ dmsetup.o -ldevmapper $(LIBS)
|
||||
-o $@ $+ $(LIBS) -lm
|
||||
|
||||
dmsetup.static: dmsetup.o $(interfacebuilddir)/libdevmapper.a
|
||||
dmsetup.static: dmsetup.o $(top_builddir)/device_mapper/libdevice-mapper.a
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) \
|
||||
-o $@ dmsetup.o -ldevmapper $(M_LIBS) $(PTHREAD_LIBS) $(STATIC_LIBS) $(LIBS)
|
||||
-o $@ $+ $(M_LIBS) $(PTHREAD_LIBS) $(STATIC_LIBS) $(LIBS)
|
||||
|
||||
all: device-mapper
|
||||
|
||||
@ -138,10 +138,10 @@ CFLAGS_lvm.o += $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
INCLUDES += -I$(top_builddir)/tools
|
||||
|
||||
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
|
||||
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a $(top_builddir)/device_mapper/libdevice-mapper.a
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
|
||||
$(LVMLIBS) $(READLINE_LIBS) $(LIBS)
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $+ \
|
||||
$(LVMLIBS) $(READLINE_LIBS) $(LIBS) -lm
|
||||
|
||||
DEFS_man-generator.o += -DMAN_PAGE_GENERATOR
|
||||
|
||||
@ -157,7 +157,7 @@ ifeq ("@BUILD_LVMETAD@", "yes")
|
||||
lvm: $(top_builddir)/libdaemon/client/libdaemonclient.a
|
||||
endif
|
||||
|
||||
lvm.static: $(OBJECTS) lvm-static.o $(top_builddir)/lib/liblvm-internal.a $(interfacebuilddir)/libdevmapper.a
|
||||
lvm.static: $(OBJECTS) lvm-static.o $(top_builddir)/lib/liblvm-internal.a $(top_builddir)/device_mapper/libdevice-mapper.a
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) -o $@ \
|
||||
$(OBJECTS) lvm-static.o $(LVMLIBS) $(STATIC_LIBS) $(LIBS)
|
||||
@ -222,7 +222,6 @@ $(SOURCES:%.c=%.o) $(SOURCES2:%.c=%.o): command-lines-input.h command-count.h cm
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
-include $(top_builddir)/libdm/libdevmapper.cflow
|
||||
-include $(top_builddir)/lib/liblvm-internal.cflow
|
||||
endif
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "libdm/misc/dm-logging.h"
|
||||
#include "device_mapper/misc/dm-logging.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libdm/libdevmapper.h"
|
||||
#include "device_mapper/libdevmapper.h"
|
||||
#include "lib/misc/util.h"
|
||||
|
||||
#endif /* _LVM_TOOL_H */
|
||||
|
Loading…
Reference in New Issue
Block a user