--- /dev/null
+name: check-abi
+on:
+ - push
+ - pull_request
+env:
+ ABI_BRANCH: ${{ secrets.ABI_BRANCH }}
+
+jobs:
+ save-and-test-ABI:
+ runs-on: ubuntu-20.04
+ steps:
+ - name: set ABI branch
+ if: ${{ env.ABI_BRANCH == '' }}
+ run: echo "ABI_BRANCH=master" >> $GITHUB_ENV
+ - name: checkout
+ uses: actions/checkout@v2
+ - name: get reference ABI
+ id: reference
+ continue-on-error: true
+ uses: dawidd6/action-download-artifact@v2
+ with:
+ workflow: abi.yaml
+ branch: ${{ env.ABI_BRANCH }}
+ name: abi
+ path: reference-abi
+ - name: update
+ run: sudo apt-get update
+ - name: dependencies
+ run: >
+ sudo apt-get install --yes gcc
+ gcc make pkg-config abigail-tools
+ libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev
+ libudev-dev libjson-c-dev liburcu-dev libcmocka-dev
+ - name: create ABI
+ run: make -O -j$(grep -c ^processor /proc/cpuinfo) abi.tar.gz
+ - name: save ABI
+ uses: actions/upload-artifact@v1
+ with:
+ name: abi
+ path: abi
+ - name: compare ABI against reference
+ id: compare
+ continue-on-error: true
+ if: ${{ steps.reference.outcome == 'success' }}
+ run: make abi-test
+ - name: save differences
+ if: ${{ steps.compare.outcome == 'failure' }}
+ uses: actions/upload-artifact@v1
+ with:
+ name: abi-test
+ path: abi-test
+ - name: fail
+ if: ${{ env.ABI_BRANCH != github.ref_name && steps.compare.outcome == 'failure' }}
+ run: false
--- /dev/null
+name: coverity
+on:
+ push:
+ branches:
+ - coverity
+
+jobs:
+ upload-coverity-scan:
+ runs-on: ubuntu-20.04
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+ - name: dependencies
+ run: >
+ sudo apt-get install --yes
+ gcc make pkg-config
+ libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev
+ libudev-dev libjson-c-dev liburcu-dev libcmocka-dev
+ - name: download coverity
+ run: >
+ curl -o cov-analysis-linux64.tar.gz
+ --form token="$COV_TOKEN"
+ --form project="$COV_PROJECT"
+ https://scan.coverity.com/download/cxx/linux64
+ env:
+ COV_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
+ COV_PROJECT: ${{ secrets.COVERITY_SCAN_PROJECT }}
+ - name: unpack coverity
+ run: |
+ mkdir -p coverity
+ tar xfz cov-analysis-linux64.tar.gz --strip 1 -C coverity
+ - name: build with cov-build
+ run: >
+ PATH="$PWD/coverity/bin:$PATH"
+ cov-build --dir cov-int make -O -j"$(grep -c ^processor /proc/cpuinfo)"
+ - name: pack results
+ run: tar cfz multipath-tools.tgz cov-int
+ - name: submit results
+ run: >
+ curl
+ --form token="$COV_TOKEN"
+ --form email="$COV_EMAIL"
+ --form file="@multipath-tools.tgz"
+ --form version="${{ github.ref_name }}"
+ --form description="$(git describe --tags --match "0.*")"
+ --form project="$COV_PROJECT"
+ https://scan.coverity.com/builds
+ env:
+ COV_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
+ COV_PROJECT: ${{ secrets.COVERITY_SCAN_PROJECT }}
+ COV_EMAIL: ${{ secrets.COVERITY_SCAN_EMAIL }}
pull_request:
jobs:
- build-and-test:
+ stable:
runs-on: ubuntu-20.04
strategy:
matrix:
- os: [buster, jessie, sid, alpine, fedora-34]
+ os: [buster, jessie, bullseye, fedora-35]
arch: ['', '-i386']
exclude:
- os: fedora-34
arch: '-i386'
+ - os: fedora-35
+ arch: '-i386'
container: mwilck/multipath-build-${{ matrix.os }}${{ matrix.arch }}
steps:
- name: checkout
CC: clang
run: make test
+ rolling:
+ runs-on: ubuntu-20.04
+ strategy:
+ matrix:
+ os: ['debian:sid', 'alpine', 'fedora:rawhide']
+ arch: ['amd64', 'i386']
+ exclude:
+ - os: 'fedora:rawhide'
+ arch: 'i386'
+ container: ${{ matrix.arch }}/${{ matrix.os }}
+ steps:
+ - name: update
+ if: ${{ matrix.os == 'debian:sid' }}
+ run: apt-get update
+ - name: dependencies-debian
+ if: ${{ matrix.os == 'debian:sid' }}
+ run: >
+ apt-get install --yes -o APT::Immediate-Configure=0
+ gcc clang make pkg-config
+ libdevmapper-dev
+ libreadline-dev
+ libaio-dev
+ libudev-dev
+ libjson-c-dev
+ liburcu-dev
+ libcmocka-dev
+ - name: dependencies-alpine
+ if: ${{ matrix.os == 'alpine' }}
+ run: >
+ apk add make gcc clang cmocka
+ musl-dev lvm2-dev libaio-dev readline-dev ncurses-dev eudev-dev
+ userspace-rcu-dev json-c-dev cmocka-dev
+ - name: dependencies-fedora
+ if: ${{ matrix.os == 'fedora:rawhide' }}
+ run: >
+ dnf install -y
+ make clang gcc pkgconfig
+ libaio-devel
+ device-mapper-devel
+ libselinux-devel
+ libsepol-devel
+ readline-devel
+ ncurses-devel
+ userspace-rcu-devel
+ json-c-devel
+ libcmocka-devel
+ - name: checkout
+ uses: actions/checkout@v1
+ - name: build and test
+ run: make test
+ - name: clean
+ run: make clean
+ - name: clang
+ env:
+ CC: clang
+ run: make test
*~
*.so
*.so.0
+*.abi
*.a
*.gz
*.d
multipath/multipath
multipathd/multipathd
mpathpersist/mpathpersist
+abi.tar.gz
+abi
+abi-test
+compile_commands.json
.nfs*
*.swp
*.patch
--- /dev/null
+#
+# This list is used by git-shortlog to fix a few botched name translations
+# in the git archive, either because the author's full name was messed up
+# and/or not always written the same way, making contributions from the
+# same person appearing not to be so or badly displayed. Also allows for
+# old email addresses to map to new email addresses.
+#
+# For format details, see "MAPPING AUTHORS" in "man git-shortlog".
+#
+# Please keep this list dictionary sorted.
+#
+Bart Van Assche <bvanassche@acm.org> <bart.vanassche@sandisk.com>
+Bart Van Assche <bvanassche@acm.org> <bart.vanassche@wdc.com>
+Benjamin Marzinski <bmarzins@redhat.com> <bmarzin@redhat.com>
+Benjamin Marzinski <bmarzins@redhat.com> <bmarzins@sourceware.org>
+Benjamin Marzinski <bmarzins@redhat.com> bmarzins@sourceware.org <bmarzins@sourceware.org>
+Chongyun Wu <wucy11@chinatelecom.cn> Wuchongyun <wu.chongyun@h3c.com>
+Chongyun Wu <wucy11@chinatelecom.cn> <wu.chongyun@h3c.com>
+Christophe Varoqui <christophe.varoqui@opensvc.com> <christophe.varoqui@free.fr>
+Christophe Varoqui <christophe.varoqui@opensvc.com> <cvaroqui@cl039.(none)>
+Christophe Varoqui <christophe.varoqui@opensvc.com> <cvaroqui@hera.kernel.org>
+Christophe Varoqui <christophe.varoqui@opensvc.com> <cvaroqui@zezette.localdomain>
+Christophe Varoqui <christophe.varoqui@opensvc.com> root <root@potab.(none)>
+Christophe Varoqui <christophe.varoqui@opensvc.com> root <root@xa-s05.(none)>
+Christophe Varoqui <christophe.varoqui@opensvc.com> root <root@zezette.localdomain>
+Christophe Varoqui <christophe.varoqui@opensvc.com> <root@xa-s05.(none)>
+Hannes Reinecke <hare@suse.de> <hare@acerbis.suse.de>
+Hannes Reinecke <hare@suse.de> <hare@suse.com>
+Martin Wilck <mwilck@suse.com> <Martin.Wilck@suse.com>
+Martin Wilck <mwilck@suse.com> <mwilck@suse.de>
+wei huang <huang.wei56@zte.com.cn> wei.huang <huang.wei56@zte.com.cn>
# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@opensvc.com>
#
-BUILDDIRS := \
+LIB_BUILDDIRS := \
libmpathcmd \
libmultipath \
+ libmpathpersist \
+ libmpathvalid
+
+ifneq ($(ENABLE_LIBDMMP),0)
+LIB_BUILDDIRS += \
+ libdmmp
+endif
+
+BUILDDIRS := $(LIB_BUILDDIRS) \
libmultipath/prioritizers \
libmultipath/checkers \
libmultipath/foreign \
- libmpathpersist \
- libmpathvalid \
multipath \
multipathd \
mpathpersist \
kpartx
-ifneq ($(ENABLE_LIBDMMP),0)
-BUILDDIRS += \
- libdmmp
-endif
BUILDDIRS.clean := $(BUILDDIRS:=.clean) tests.clean
-.PHONY: $(BUILDDIRS) $(BUILDDIRS:=.uninstall) $(BUILDDIRS:=.install) $(BUILDDIRS.clean)
+.PHONY: $(BUILDDIRS) $(BUILDDIRS:=.uninstall) $(BUILDDIRS:=.install) $(BUILDDIRS:=.clean) $(LIB_BUILDDIRS:=.abi)
all: $(BUILDDIRS)
$(BUILDDIRS):
$(MAKE) -C $@
+$(LIB_BUILDDIRS:=.abi): $(LIB_BUILDDIRS)
+ $(MAKE) -C ${@:.abi=} abi
+
+# Create formal representation of the ABI
+# Useful for verifying ABI compatibility
+# Requires abidw from the abigail suite (https://sourceware.org/libabigail/)
+.PHONY: abi
+abi: $(LIB_BUILDDIRS:=.abi)
+ mkdir -p $@
+ ln -ft $@ $(LIB_BUILDDIRS:=/*.abi)
+
+abi.tar.gz: abi
+ tar cfz $@ abi
+
+# Check the ABI against a reference.
+# This requires the ABI from a previous run to be present
+# in the directory "reference-abi"
+# Requires abidiff from the abigail suite
+abi-test: abi reference-abi $(wildcard abi/*.abi)
+ @err=0; \
+ for lib in abi/*.abi; do \
+ diff=$$(abidiff "reference-$$lib" "$$lib") || { \
+ err=1; \
+ echo "==== ABI differences in for $$lib ===="; \
+ echo "$$diff"; \
+ }; \
+ done >$@; \
+ if [ $$err -eq 0 ]; then \
+ echo "*** OK, ABI unchanged ***"; \
+ else \
+ echo "*** WARNING: ABI has changed, see file $@ ***"; \
+ fi; \
+ [ $$err -eq 0 ]
+
+# Create compile_commands.json, useful for using clangd with an IDE
+# Requires bear (https://github.com/rizsotto/Bear)
+compile_commands.json: Makefile Makefile.inc $(BUILDDIRS:=/Makefile)
+ $(MAKE) clean
+ bear -- $(MAKE)
+
libmultipath libdmmp: libmpathcmd
libmpathpersist libmpathvalid multipath multipathd: libmultipath
libmultipath/prioritizers libmultipath/checkers libmultipath/foreign: libmultipath
$(MAKE) -C ${@:.uninstall=} uninstall
clean: $(BUILDDIRS.clean)
+ rm -rf abi abi.tar.gz abi-test compile_commands.json
+
install: all $(BUILDDIRS:=.install)
uninstall: $(BUILDDIRS:=.uninstall)
RM = rm -f
LN = ln -sf
INSTALL_PROGRAM = install
+NV_VERSION_SCRIPT = $(VERSION_SCRIPT:%.version=%-nv.version)
# $(call TEST_CC_OPTION,option,fallback)
# Test if the C compiler supports the option.
%.o: %.c
@echo building $@ because of $?
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+%.abi: %.so.0
+ abidw $< >$@
+
+%.abi: %.so
+ abidw $< >$@
exit (0);
if (!loopdev) {
- loopdev = find_unused_loop_device();
-
- if (set_loop(loopdev, rpath, 0, &ro)) {
+ if (set_loop(&loopdev, rpath, 0, &ro)) {
fprintf(stderr, "can't set up loop\n");
exit (1);
}
#define LOOP_CTL_GET_FREE 0x4C82
#endif
-static char *
-xstrdup (const char *s)
-{
- char *t;
-
- if (s == NULL)
- return NULL;
-
- t = strdup (s);
-
- if (t == NULL) {
- fprintf(stderr, "not enough memory");
- exit(1);
- }
-
- return t;
-}
-
#define SIZE(a) (sizeof(a)/sizeof(a[0]))
char *find_loop_by_file(const char *filename)
return found;
}
-char *find_unused_loop_device(void)
+static char *find_unused_loop_device(int mode, int *loop_fd)
{
- char dev[20], *next_loop_dev = NULL;
+ char dev[21];
int fd, next_loop = 0, somedev = 0, someloop = 0, loop_known = 0;
+ int next_loop_fd;
struct stat statbuf;
struct loop_info loopinfo;
FILE *procdev;
- while (next_loop_dev == NULL) {
- if (stat("/dev/loop-control", &statbuf) == 0 &&
- S_ISCHR(statbuf.st_mode)) {
- int next_loop_fd;
-
- next_loop_fd = open("/dev/loop-control", O_RDWR);
- if (next_loop_fd < 0)
- return NULL;
- next_loop = ioctl(next_loop_fd, LOOP_CTL_GET_FREE);
- close(next_loop_fd);
- if (next_loop < 0)
- return NULL;
- }
+ next_loop_fd = open("/dev/loop-control", O_RDWR);
+ if (next_loop_fd < 0)
+ goto no_loop_fd;
+
+ if (!(fstat(next_loop_fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)))
+ goto nothing_found;
+
+ for (;;) {
+ next_loop = ioctl(next_loop_fd, LOOP_CTL_GET_FREE);
+ if (next_loop < 0)
+ goto nothing_found;
sprintf(dev, "/dev/loop%d", next_loop);
- fd = open (dev, O_RDONLY);
+ fd = open (dev, mode);
if (fd >= 0) {
if (fstat (fd, &statbuf) == 0 &&
S_ISBLK(statbuf.st_mode)) {
somedev++;
if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
someloop++; /* in use */
- else if (errno == ENXIO)
- next_loop_dev = xstrdup(dev);
+ else if (errno == ENXIO) {
+ char *name = strdup(dev);
+
+ if (name == NULL)
+ close(fd);
+ else
+ *loop_fd = fd;
+ close(next_loop_fd);
+ return name;
+ }
}
close (fd);
/* continue trying as long as devices exist */
- continue;
- }
- break;
+ } else
+ break;
}
- if (next_loop_dev)
- return next_loop_dev;
+nothing_found:
+ close(next_loop_fd);
+
+no_loop_fd:
/* Nothing found. Why not? */
if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
char line[100];
}
if (!somedev)
- fprintf(stderr, "mount: could not find any device /dev/loop#");
+ fprintf(stderr, "mount: could not find any device /dev/loop#\n");
else if (!someloop) {
if (loop_known == 1)
fprintf(stderr,
"mount: Could not find any loop device.\n"
- " Maybe /dev/loop# has a wrong major number?");
+ " Maybe /dev/loop# has a wrong major number?\n");
else if (loop_known == -1)
fprintf(stderr,
"mount: Could not find any loop device, and, according to %s,\n"
" this kernel does not know about the loop device.\n"
- " (If so, then recompile or `modprobe loop'.)",
+ " (If so, then recompile or `modprobe loop'.)\n",
PROC_DEVICES);
else
fprintf(stderr,
"mount: Could not find any loop device. Maybe this kernel does not know\n"
" about the loop device (then recompile or `modprobe loop'), or\n"
- " maybe /dev/loop# has the wrong major number?");
+ " maybe /dev/loop# has the wrong major number?\n");
} else
- fprintf(stderr, "mount: could not find any free loop device");
+ fprintf(stderr, "mount: could not find any free loop device\n");
return NULL;
}
-int set_loop(const char *device, const char *file, int offset, int *loopro)
+int set_loop(char **device, const char *file, int offset, int *loopro)
{
struct loop_info loopinfo;
- int fd, ffd, mode;
+ int fd = -1, ret = 1, ffd, mode;
mode = (*loopro ? O_RDONLY : O_RDWR);
}
}
- if ((fd = open (device, mode)) < 0) {
+ *device = find_unused_loop_device(mode, &fd);
+ if (!*device) {
close(ffd);
- perror (device);
return 1;
}
if (ioctl(fd, LOOP_SET_FD, (void*)(uintptr_t)(ffd)) < 0) {
perror ("ioctl: LOOP_SET_FD");
- close (fd);
- close (ffd);
- return 1;
+ goto out;
}
if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
(void) ioctl (fd, LOOP_CLR_FD, 0);
perror ("ioctl: LOOP_SET_STATUS");
- close (fd);
- close (ffd);
- return 1;
+ goto out;
}
+ ret = 0;
+out:
close (fd);
close (ffd);
- return 0;
+ return ret;
}
int del_loop(const char *device)
extern int verbose;
-extern int set_loop (const char *, const char *, int, int *);
+extern int set_loop (char **, const char *, int, int *);
extern int del_loop (const char *);
-extern char * find_unused_loop_device (void);
extern char * find_loop_by_file (const char *);
$(LIBS): $(OBJS)
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS)
- $(LN) $@ $(DEVLIB)
+
+$(DEVLIB): $(LIBS)
+ $(LN) $(LIBS) $@
+
+abi: $(DEVLIB:%.so=%.abi)
install: doc.gz
mkdir -p $(DESTDIR)$(usrlibdir)
$(RM) $(DESTDIR)$(pkgconfdir)/$(PKGFILE)
clean: dep_clean
- $(RM) core *.a *.o *.gz *.so *.so.*
+ $(RM) core *.a *.o *.gz *.so *.so.* *.abi $(NV_VERSION_SCRIPT)
$(RM) docs/man/*.gz
$(MAKE) -C test clean
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \
-Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS)
+$(NV_VERSION_SCRIPT): $(VERSION_SCRIPT)
+ @printf 'NOVERSION {\nglobal:\n' >$@
+ @grep -P '^[ \t]+[a-zA-Z_][a-zA-Z0-9_]*;' $< >>$@
+ @printf 'local:\n\t*;\n};\n' >>$@
+
+$(LIBS:%.so.$(SONAME)=%-nv.so): $(OBJS) $(NV_VERSION_SCRIPT)
+ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \
+ -Wl,--version-script=$(NV_VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS)
+
+abi: $(LIBS:%.so.$(SONAME)=%-nv.abi)
+
$(DEVLIB): $(LIBS)
$(LN) $(LIBS) $@
$(RM) $(DESTDIR)$(includedir)/mpath_cmd.h
clean: dep_clean
- $(RM) core *.a *.o *.so *.so.* *.gz
+ $(RM) core *.a *.o *.so *.so.* *.gz *.abi $(NV_VERSION_SCRIPT)
include $(wildcard $(OBJS:.o=.d))
SONAME = 0
DEVLIB = libmpathpersist.so
LIBS = $(DEVLIB).$(SONAME)
-VERSION_SCRIPT := libmpathpersist.version
+VERSION_SCRIPT:= libmpathpersist.version
CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir)
LDFLAGS += -L$(multipathdir) -L$(mpathcmddir)
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \
-Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS)
+$(NV_VERSION_SCRIPT): $(VERSION_SCRIPT)
+ @printf 'NOVERSION {\nglobal:\n' >$@
+ @grep -P '^[ \t]+[a-zA-Z_][a-zA-Z0-9_]*;' $< >>$@
+ @printf 'local:\n\t*;\n};\n' >>$@
+
+$(LIBS:%.so.$(SONAME)=%-nv.so): $(OBJS) $(NV_VERSION_SCRIPT)
+ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \
+ -Wl,--version-script=$(NV_VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS)
+
+abi: $(LIBS:%.so.$(SONAME)=%-nv.abi)
+
$(DEVLIB): $(LIBS)
$(LN) $(LIBS) $@
$(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
clean: dep_clean
- $(RM) core *.a *.o *.so *.so.* *.gz
+ $(RM) core *.a *.o *.so *.so.* *.gz *.abi $(NV_VERSION_SCRIPT)
include $(wildcard $(OBJS:.o=.d))
*
* See libmultipath.version for general policy about version numbers.
*/
-LIBMPATHPERSIST_1.0.0 {
+LIBMPATHPERSIST_2.0.0 {
global:
__mpath_persistent_reserve_in;
prout_do_scsi_ioctl;
update_map_pr;
-local: *;
-};
-
-LIBMPATHPERSIST_1.1.0 {
-global:
+ /* added in 1.1.0 */
libmpathpersist_init;
libmpathpersist_exit;
-} LIBMPATHPERSIST_1.0.0;
+
+local: *;
+};
alias = NULL;
}
out:
- FREE(alias);
+ free(alias);
return ret;
}
update_prkey(alias, 0);
}
out1:
- FREE(alias);
+ free(alias);
return ret;
}
#include "debug.h"
#include "mpath_cmd.h"
#include "uxsock.h"
-#include "memory.h"
#include "mpathpr.h"
all: $(LIBS)
$(LIBS): $(OBJS) $(VERSION_SCRIPT)
- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) -Wl,--version-script=libmpathvalid.version
+ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) \
+ -Wl,--version-script=$(VERSION_SCRIPT)
$(LN) $(LIBS) $(DEVLIB)
+$(NV_VERSION_SCRIPT): $(VERSION_SCRIPT)
+ @printf 'NOVERSION {\nglobal:\n' >$@
+ @grep -P '^[ \t]+[a-zA-Z_][a-zA-Z0-9_]*;' $< >>$@
+ @printf 'local:\n\t*;\n};\n' >>$@
+
+$(LIBS:%.so.$(SONAME)=%-nv.so): $(OBJS) $(NV_VERSION_SCRIPT)
+ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \
+ -Wl,--version-script=$(NV_VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS)
+
+abi: $(LIBS:%.so.$(SONAME)=%-nv.abi)
+
install: $(LIBS)
$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir)
$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
$(RM) $(DESTDIR)$(includedir)/mpath_valid.h
clean: dep_clean
- $(RM) core *.a *.o *.so *.so.* *.gz
+ $(RM) core *.a *.o *.so *.so.* *.gz *.abi $(NV_VERSION_SCRIPT)
include $(wildcard $(OBJS:.o=.d))
CFLAGS += -DLIBDM_API_HOLD_CONTROL
endif
-OBJS = memory.o parser.o vector.o devmapper.o callout.o \
+OBJS = parser.o vector.o devmapper.o callout.o \
hwtable.o blacklist.o util.o dmparser.o config.o \
structs.o discovery.o propsel.o dict.o \
pgpolicies.o debug.o defaults.o uevent.o time-util.o \
$(DEVLIB): $(LIBS)
$(LN) $(LIBS) $@
+$(NV_VERSION_SCRIPT): $(VERSION_SCRIPT)
+ @printf 'NOVERSION {\nglobal:\n' >$@
+ @grep -P '^[ \t]+[a-zA-Z_][a-zA-Z0-9_]*;' $< >>$@
+ @printf 'local:\n\t*;\n};\n' >>$@
+
+$(LIBS:%.so.$(SONAME)=%-nv.so): $(OBJS) $(NV_VERSION_SCRIPT)
+ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \
+ -Wl,--version-script=$(NV_VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS)
+
+abi: $(LIBS:%.so.$(SONAME)=%-nv.abi)
+
../tests/$(LIBS): $(OBJS) $(VERSION_SCRIPT)
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=`basename $@` \
-o $@ $(OBJS) $(LIBDEPS)
$(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
clean: dep_clean
- $(RM) core *.a *.o *.so *.so.* *.gz nvme-ioctl.c nvme-ioctl.h
+ $(RM) core *.a *.o *.so *.so.* *.gz *.abi nvme-ioctl.c nvme-ioctl.h $(NV_VERSION_SCRIPT)
include $(wildcard $(OBJS:.o=.d))
* allocated correctly
*/
if (strcmp(buff, wwid) == 0)
- alias = STRDUP(alias_old);
+ alias = strdup(alias_old);
else {
alias = NULL;
condlog(0, "alias %s already bound to wwid %s, cannot reuse",
int rc;
long fd;
char tempname[PATH_MAX];
+ mode_t old_umask;
if (safe_sprintf(tempname, "%s.XXXXXX", conf->bindings_file))
return -1;
+ /* coverity: SECURE_TEMP */
+ old_umask = umask(0077);
if ((fd = mkstemp(tempname)) == -1) {
condlog(1, "%s: mkstemp: %m", __func__);
return -1;
}
+ umask(old_umask);
pthread_cleanup_push(close_fd, (void*)fd);
rc = write_bindings_file(bindings, fd);
pthread_cleanup_pop(1);
#include <libudev.h>
#include "checkers.h"
-#include "memory.h"
#include "vector.h"
#include "util.h"
#include "debug.h"
if (!blist)
goto out;
- ble = MALLOC(sizeof(struct blentry));
+ ble = calloc(1, sizeof(struct blentry));
if (!ble)
goto out;
vector_set_slot(blist, ble);
return 0;
out1:
- FREE(ble);
+ free(ble);
out:
- FREE(strdup_str);
+ free(strdup_str);
return 1;
}
if (!blist)
return 1;
- ble = MALLOC(sizeof(struct blentry_device));
+ ble = calloc(1, sizeof(struct blentry_device));
if (!ble)
return 1;
if (!vector_alloc_slot(blist)) {
- FREE(ble);
+ free(ble);
return 1;
}
vector_set_slot(blist, ble);
return 1;
if (vendor) {
- vendor_str = STRDUP(vendor);
+ vendor_str = strdup(vendor);
if (!vendor_str)
goto out;
ble->vendor = vendor_str;
}
if (product) {
- product_str = STRDUP(product);
+ product_str = strdup(product);
if (!product_str)
goto out1;
VECTOR_SIZE(conf->blist_device) - 1);
if (set_ble_device(conf->blist_device, hwe->vendor, hwe->bl_product,
ORIGIN_DEFAULT)) {
- FREE(ble);
+ free(ble);
vector_del_slot(conf->blist_device, VECTOR_SIZE(conf->blist_device) - 1);
return 1;
}
if (!ble)
return;
regfree(&ble->regex);
- FREE(ble->str);
- FREE(ble);
+ free(ble->str);
+ free(ble);
}
void
if (ble) {
if (ble->vendor) {
regfree(&ble->vendor_reg);
- FREE(ble->vendor);
+ free(ble->vendor);
}
if (ble->product) {
regfree(&ble->product_reg);
- FREE(ble->product);
+ free(ble->product);
}
- FREE(ble);
+ free(ble);
}
}
{
struct checker_class *c;
- c = MALLOC(sizeof(struct checker_class));
+ c = calloc(1, sizeof(struct checker_class));
if (c) {
INIT_LIST_HEAD(&c->node);
uatomic_set(&c->refcount, 1);
c->name, dlerror());
}
}
- FREE(c);
+ free(c);
}
void cleanup_checkers (void)
#include <pthread.h>
#include "list.h"
-#include "memory.h"
#include "defaults.h"
/*
short msgid; /* checker-internal extra status */
void * context; /* store for persistent data */
void ** mpcontext; /* store for persistent data shared
- multipath-wide. Use MALLOC if
- you want to stuff data in. */
+ multipath-wide. */
};
static inline int checker_selected(const struct checker *c)
#include "libsg.h"
#include "checkers.h"
#include "debug.h"
-#include "memory.h"
#define INQUIRY_CMD 0x12
#define INQUIRY_CMDLEN 6
/*
* Allocate and initialize the path specific context.
*/
- c->context = MALLOC(sizeof(struct emc_clariion_checker_path_context));
+ c->context = calloc(1, sizeof(struct emc_clariion_checker_path_context));
if (!c->context)
return 1;
((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0;
#include <errno.h>
#include "checkers.h"
-#include "memory.h"
#include "util.h"
#include "debug.h"
#include "parser.h"
return;
if (hwe->vendor)
- FREE(hwe->vendor);
+ free(hwe->vendor);
if (hwe->product)
- FREE(hwe->product);
+ free(hwe->product);
if (hwe->revision)
- FREE(hwe->revision);
+ free(hwe->revision);
if (hwe->getuid)
- FREE(hwe->getuid);
+ free(hwe->getuid);
if (hwe->uid_attribute)
- FREE(hwe->uid_attribute);
+ free(hwe->uid_attribute);
if (hwe->features)
- FREE(hwe->features);
+ free(hwe->features);
if (hwe->hwhandler)
- FREE(hwe->hwhandler);
+ free(hwe->hwhandler);
if (hwe->selector)
- FREE(hwe->selector);
+ free(hwe->selector);
if (hwe->checker_name)
- FREE(hwe->checker_name);
+ free(hwe->checker_name);
if (hwe->prio_name)
- FREE(hwe->prio_name);
+ free(hwe->prio_name);
if (hwe->prio_args)
- FREE(hwe->prio_args);
+ free(hwe->prio_args);
if (hwe->alias_prefix)
- FREE(hwe->alias_prefix);
+ free(hwe->alias_prefix);
if (hwe->bl_product)
- FREE(hwe->bl_product);
+ free(hwe->bl_product);
- FREE(hwe);
+ free(hwe);
}
void
return;
if (mpe->wwid)
- FREE(mpe->wwid);
+ free(mpe->wwid);
if (mpe->selector)
- FREE(mpe->selector);
+ free(mpe->selector);
if (mpe->getuid)
- FREE(mpe->getuid);
+ free(mpe->getuid);
if (mpe->uid_attribute)
- FREE(mpe->uid_attribute);
+ free(mpe->uid_attribute);
if (mpe->alias)
- FREE(mpe->alias);
+ free(mpe->alias);
if (mpe->prio_name)
- FREE(mpe->prio_name);
+ free(mpe->prio_name);
if (mpe->prio_args)
- FREE(mpe->prio_args);
+ free(mpe->prio_args);
- FREE(mpe);
+ free(mpe);
}
void
alloc_mpe (void)
{
struct mpentry * mpe = (struct mpentry *)
- MALLOC(sizeof(struct mpentry));
+ calloc(1, sizeof(struct mpentry));
return mpe;
}
alloc_hwe (void)
{
struct hwentry * hwe = (struct hwentry *)
- MALLOC(sizeof(struct hwentry));
+ calloc(1, sizeof(struct hwentry));
return hwe;
}
if (!len)
return NULL;
- dst = (char *)MALLOC(len + 1);
+ dst = (char *)calloc(1, len + 1);
if (!dst)
return NULL;
static struct config *alloc_config (void)
{
- return (struct config *)MALLOC(sizeof(struct config));
+ return (struct config *)calloc(1, sizeof(struct config));
}
static void _uninit_config(struct config *conf)
conf = &__internal_config;
if (conf->multipath_dir)
- FREE(conf->multipath_dir);
+ free(conf->multipath_dir);
if (conf->selector)
- FREE(conf->selector);
+ free(conf->selector);
if (conf->uid_attribute)
- FREE(conf->uid_attribute);
+ free(conf->uid_attribute);
vector_reset(&conf->uid_attrs);
if (conf->getuid)
- FREE(conf->getuid);
+ free(conf->getuid);
if (conf->features)
- FREE(conf->features);
+ free(conf->features);
if (conf->hwhandler)
- FREE(conf->hwhandler);
+ free(conf->hwhandler);
if (conf->bindings_file)
- FREE(conf->bindings_file);
+ free(conf->bindings_file);
if (conf->wwids_file)
- FREE(conf->wwids_file);
+ free(conf->wwids_file);
if (conf->prkeys_file)
- FREE(conf->prkeys_file);
+ free(conf->prkeys_file);
if (conf->prio_name)
- FREE(conf->prio_name);
+ free(conf->prio_name);
if (conf->alias_prefix)
- FREE(conf->alias_prefix);
+ free(conf->alias_prefix);
if (conf->partition_delim)
- FREE(conf->partition_delim);
+ free(conf->partition_delim);
if (conf->prio_args)
- FREE(conf->prio_args);
+ free(conf->prio_args);
if (conf->checker_name)
- FREE(conf->checker_name);
+ free(conf->checker_name);
if (conf->config_dir)
- FREE(conf->config_dir);
+ free(conf->config_dir);
if (conf->enable_foreign)
- FREE(conf->enable_foreign);
+ free(conf->enable_foreign);
free_blacklist(conf->blist_devnode);
free_blacklist(conf->blist_wwid);
int strict_timing;
int retrigger_tries;
int retrigger_delay;
- int delayed_reconfig;
int uev_wait_timeout;
int skip_kpartx;
int remove_retries;
#include "checkers.h"
#include "vector.h"
-#include "memory.h"
#include "devmapper.h"
#include "defaults.h"
#include "structs.h"
#include "sysfs.h"
#include "io_err_stat.h"
-/* Time in ms to wait for pending checkers in setup_map() */
-#define WAIT_CHECKERS_PENDING_MS 10
-#define WAIT_ALL_CHECKERS_PENDING_MS 90
-
/* group paths in pg by host adapter
*/
int group_by_host_adapter(struct pathgroup *pgp, vector adapters)
return 0;
}
-static int wait_for_pending_paths(struct multipath *mpp,
- struct config *conf,
- int n_pending, int goal, int wait_ms)
-{
- static const struct timespec millisec =
- { .tv_sec = 0, .tv_nsec = 1000*1000 };
- int i, j;
- struct path *pp;
- struct pathgroup *pgp;
- struct timespec ts;
-
- do {
- vector_foreach_slot(mpp->pg, pgp, i) {
- vector_foreach_slot(pgp->paths, pp, j) {
- if (pp->state != PATH_PENDING)
- continue;
- pp->state = get_state(pp, conf,
- 0, PATH_PENDING);
- if (pp->state != PATH_PENDING &&
- --n_pending <= goal)
- return 0;
- }
- }
- ts = millisec;
- while (nanosleep(&ts, &ts) != 0 && errno == EINTR)
- /* nothing */;
- } while (--wait_ms > 0);
-
- return n_pending;
-}
-
int setup_map(struct multipath *mpp, char **params, struct vectors *vecs)
{
struct pathgroup * pgp;
struct config *conf;
- int i, n_paths, marginal_pathgroups;
+ int i, marginal_pathgroups;
char *save_attr;
/*
if (marginal_path_check_enabled(mpp))
start_io_err_stat_thread(vecs);
- n_paths = VECTOR_SIZE(mpp->paths);
/*
* assign paths to path groups -- start with no groups and all paths
* in mpp->paths
if (group_paths(mpp, marginal_pathgroups))
return 1;
- /*
- * If async state detection is used, see if pending state checks
- * have finished, to get nr_active right. We can't wait until the
- * checkers time out, as that may take 30s or more, and we are
- * holding the vecs lock.
- */
- if (conf->force_sync == 0 && n_paths > 0) {
- int n_pending = pathcount(mpp, PATH_PENDING);
-
- if (n_pending > 0)
- n_pending = wait_for_pending_paths(
- mpp, conf, n_pending, 0,
- WAIT_CHECKERS_PENDING_MS);
- /* ALL paths pending - wait some more, but be satisfied
- with only some paths finished */
- if (n_pending == n_paths)
- n_pending = wait_for_pending_paths(
- mpp, conf, n_pending,
- n_paths >= 4 ? 2 : 1,
- WAIT_ALL_CHECKERS_PENDING_MS);
- if (n_pending > 0)
- condlog(2, "%s: setting up map with %d/%d path checkers pending",
- mpp->alias, n_pending, n_paths);
- }
-
/*
* ponders each path group and determine highest prio pg
* to switch over (default to first)
cmpp = find_mp_by_wwid(curmp, mpp->wwid);
cmpp_by_name = find_mp_by_alias(curmp, mpp->alias);
+ if (mpp->need_reload || (cmpp && cmpp->need_reload))
+ force_reload = 1;
if (!cmpp_by_name) {
if (cmpp) {
mpp->wwid, cmpp->alias, mpp->alias,
mpp->alias, cmpp_by_name->wwid);
/* reset alias to existing alias */
- FREE(mpp->alias);
- mpp->alias = STRDUP(cmpp->alias);
+ free(mpp->alias);
+ mpp->alias = strdup(cmpp->alias);
mpp->action = ACT_IMPOSSIBLE;
return;
}
return;
}
- cmpp_feat = STRDUP(cmpp->features);
- mpp_feat = STRDUP(mpp->features);
+ cmpp_feat = strdup(cmpp->features);
+ mpp_feat = strdup(mpp->features);
if (cmpp_feat && mpp_feat) {
remove_feature(&mpp_feat, "queue_if_no_path");
remove_feature(&mpp_feat, "retain_attached_hw_handler");
remove_feature(&cmpp_feat, "retain_attached_hw_handler");
if (strcmp(mpp_feat, cmpp_feat)) {
select_reload_action(mpp, "features change");
- FREE(cmpp_feat);
- FREE(mpp_feat);
+ free(cmpp_feat);
+ free(mpp_feat);
return;
}
}
- FREE(cmpp_feat);
- FREE(mpp_feat);
+ free(cmpp_feat);
+ free(mpp_feat);
if (!cmpp->selector || strncmp(cmpp->selector, mpp->selector,
strlen(mpp->selector))) {
ret = 1;
out_free:
- FREE(reply);
+ free(reply);
out:
mpath_disconnect(fd);
return ret;
* FORCE_RELOAD_NONE: existing maps aren't touched at all
* FORCE_RELOAD_YES: all maps are rebuilt from scratch and (re)loaded in DM
* FORCE_RELOAD_WEAK: existing maps are compared to the current conf and only
- * reloaded in DM if there's a difference. This is useful during startup.
+ * reloaded in DM if there's a difference. This is normally sufficient.
*/
int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
int force_reload, enum mpath_cmds cmd)
}
if (refwwid && strlen(refwwid)) {
- *wwid = STRDUP(refwwid);
+ *wwid = strdup(refwwid);
return PATHINFO_OK;
}
#include <string.h>
#include "defaults.h"
-#include "memory.h"
const char * const default_partition_delim = DEFAULT_PARTITION_DELIM;
#ifndef _DEFAULTS_H
#define _DEFAULTS_H
#include <limits.h>
+#include <string.h>
/*
* If you add or modify a value also update multipath/multipath.conf.5
#include "vector.h"
#include "structs.h"
#include "debug.h"
-#include "memory.h"
#include "devmapper.h"
#include "sysfs.h"
#include "config.h"
dm_task_set_ro(dmt);
if (task == DM_DEVICE_CREATE) {
- prefixed_uuid = MALLOC(UUID_PREFIX_LEN +
+ prefixed_uuid = calloc(1, UUID_PREFIX_LEN +
strlen(mpp->wwid) + 1);
if (!prefixed_uuid) {
condlog(0, "cannot create prefixed uuid : %s",
libmp_udev_wait(cookie);
freeout:
if (prefixed_uuid)
- FREE(prefixed_uuid);
+ free(prefixed_uuid);
addout:
dm_task_destroy (dmt);
+ if (r)
+ mpp->need_reload = false;
return r;
}
if (!mpp)
return NULL;
- mpp->alias = STRDUP(name);
+ mpp->alias = strdup(name);
if (!mpp->alias)
goto out;
if (dm_get_map(name, &mpp->size, NULL) != DMP_OK)
goto out;
- dm_get_uuid(name, mpp->wwid, WWID_SIZE);
- dm_get_info(name, &mpp->dmi);
+ if (dm_get_uuid(name, mpp->wwid, WWID_SIZE) != 0)
+ condlog(2, "%s: failed to get uuid for %s", __func__, name);
+ if (dm_get_info(name, &mpp->dmi) != 0)
+ condlog(2, "%s: failed to get info for %s", __func__, name);
return mpp;
out:
const char *map;
struct dm_task *dmt;
int r;
- int loop = MAX_WAIT * LOOPS_PER_SEC;
if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
return NULL;
goto bad;
dm_task_no_open_count(dmt);
-
- /*
- * device map might not be ready when we get here from
- * daemon uev_trigger -> uev_add_map
- */
- while (--loop) {
- r = libmp_dm_task_run(dmt);
-
- if (r)
- break;
-
- usleep(1000 * 1000 / LOOPS_PER_SEC);
- }
-
+ r = libmp_dm_task_run(dmt);
if (!r) {
dm_log_error(2, DM_DEVICE_STATUS, dmt);
- condlog(0, "%i:%i: timeout fetching map name", major, minor);
goto bad;
}
map = dm_task_get_name(dmt);
if (map && strlen(map))
- response = STRDUP((const char *)map);
+ response = strdup((const char *)map);
dm_task_destroy(dmt);
return response;
static struct dm_info *
alloc_dminfo (void)
{
- return MALLOC(sizeof(struct dm_info));
+ return calloc(1, sizeof(struct dm_info));
}
int
return 1;
if (do_get_info(mapname, *dmi) != 0) {
- FREE(*dmi);
+ free(*dmi);
*dmi = NULL;
return 1;
}
n += strlen(newdep);
p += strlen(dep);
strcat(n, p);
- FREE(newtable);
+ free(newtable);
}
int dm_reassign_table(const char *name, char *old, char *new)
* Copyright (c) 2005 Kiyoshi Ueda, NEC
*/
#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <pwd.h>
#include <string.h>
#include "checkers.h"
#include "parser.h"
#include "config.h"
#include "debug.h"
-#include "memory.h"
#include "pgpolicies.h"
#include "blacklist.h"
#include "defaults.h"
#include "dict.h"
#include "strbuf.h"
-static int
-set_int(vector strvec, void *ptr)
+static void
+do_set_int(vector strvec, void *ptr, int min, int max, const char *file,
+ int line_nr, char *buff)
{
int *int_ptr = (int *)ptr;
- char *buff, *eptr;
+ char *eptr;
long res;
- int rc;
-
- buff = set_value(strvec);
- if (!buff)
- return 1;
res = strtol(buff, &eptr, 10);
if (eptr > buff)
while (isspace(*eptr))
eptr++;
- if (*buff == '\0' || *eptr != '\0' || res > INT_MAX || res < INT_MIN) {
- condlog(1, "%s: invalid value for %s: \"%s\"",
- __func__, (char*)VECTOR_SLOT(strvec, 0), buff);
- rc = 1;
- } else {
- rc = 0;
- *int_ptr = res;
+ if (*buff == '\0' || *eptr != '\0') {
+ condlog(1, "%s line %d, invalid value for %s: \"%s\"",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
+ return;
+ }
+ if (res > max || res < min) {
+ res = (res > max) ? max : min;
+ condlog(1, "%s line %d, value for %s too %s, capping at %ld",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0),
+ (res == max)? "large" : "small", res);
}
+ *int_ptr = res;
+ return;
+}
+
+static int
+set_int(vector strvec, void *ptr, int min, int max, const char *file,
+ int line_nr)
+{
+ char *buff;
- FREE(buff);
- return rc;
+ buff = set_value(strvec);
+ if (!buff)
+ return 1;
+
+ do_set_int(strvec, ptr, min, max, file, line_nr, buff);
+
+ free(buff);
+ return 0;
}
static int
-set_uint(vector strvec, void *ptr)
+set_uint(vector strvec, void *ptr, const char *file, int line_nr)
{
unsigned int *uint_ptr = (unsigned int *)ptr;
char *buff, *eptr, *p;
unsigned long res;
- int rc;
buff = set_value(strvec);
if (!buff)
if (eptr > buff)
while (isspace(*eptr))
eptr++;
- if (*buff == '\0' || *eptr != '\0' || !isdigit(*p) || res > UINT_MAX) {
- condlog(1, "%s: invalid value for %s: \"%s\"",
- __func__, (char*)VECTOR_SLOT(strvec, 0), buff);
- rc = 1;
- } else {
- rc = 0;
+ if (*buff == '\0' || *eptr != '\0' || !isdigit(*p) || res > UINT_MAX)
+ condlog(1, "%s line %d, invalid value for %s: \"%s\"",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
+ else
*uint_ptr = res;
- }
- FREE(buff);
- return rc;
+ free(buff);
+ return 0;
}
static int
-set_str(vector strvec, void *ptr)
+set_str(vector strvec, void *ptr, const char *file, int line_nr)
{
char **str_ptr = (char **)ptr;
if (*str_ptr)
- FREE(*str_ptr);
+ free(*str_ptr);
*str_ptr = set_value(strvec);
if (!*str_ptr)
}
static int
-set_yes_no(vector strvec, void *ptr)
+set_dir(vector strvec, void *ptr, const char *file, int line_nr)
+{
+ char **str_ptr = (char **)ptr;
+ char *old_str = *str_ptr;
+ struct stat sb;
+
+ *str_ptr = set_value(strvec);
+ if (!*str_ptr) {
+ free(old_str);
+ return 1;
+ }
+ if ((*str_ptr)[0] != '/'){
+ condlog(1, "%s line %d, %s is not an absolute directory path. Ignoring", file, line_nr, *str_ptr);
+ *str_ptr = old_str;
+ } else {
+ if (stat(*str_ptr, &sb) == 0 && S_ISDIR(sb.st_mode))
+ free(old_str);
+ else {
+ condlog(1, "%s line %d, %s is not an existing directory. Ignoring", file, line_nr, *str_ptr);
+ *str_ptr = old_str;
+ }
+ }
+ return 0;
+}
+
+static int
+set_path(vector strvec, void *ptr, const char *file, int line_nr)
+{
+ char **str_ptr = (char **)ptr;
+ char *old_str = *str_ptr;
+
+ *str_ptr = set_value(strvec);
+ if (!*str_ptr) {
+ free(old_str);
+ return 1;
+ }
+ if ((*str_ptr)[0] != '/'){
+ condlog(1, "%s line %d, %s is not an absolute path. Ignoring",
+ file, line_nr, *str_ptr);
+ *str_ptr = old_str;
+ } else
+ free(old_str);
+ return 0;
+}
+
+static int
+set_str_noslash(vector strvec, void *ptr, const char *file, int line_nr)
+{
+ char **str_ptr = (char **)ptr;
+ char *old_str = *str_ptr;
+
+ *str_ptr = set_value(strvec);
+ if (!*str_ptr) {
+ free(old_str);
+ return 1;
+ }
+ if (strchr(*str_ptr, '/')) {
+ condlog(1, "%s line %d, %s cannot contain a slash. Ignoring",
+ file, line_nr, *str_ptr);
+ *str_ptr = old_str;
+ } else
+ free(old_str);
+ return 0;
+}
+
+static int
+set_yes_no(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
int *int_ptr = (int *)ptr;
if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
*int_ptr = YN_YES;
- else
+ else if (strcmp(buff, "no") == 0 || strcmp(buff, "0") == 0)
*int_ptr = YN_NO;
+ else
+ condlog(1, "%s line %d, invalid value for %s: \"%s\"",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
- FREE(buff);
+ free(buff);
return 0;
}
static int
-set_yes_no_undef(vector strvec, void *ptr)
+set_yes_no_undef(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
int *int_ptr = (int *)ptr;
else if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
*int_ptr = YNU_YES;
else
- *int_ptr = YNU_UNDEF;
+ condlog(1, "%s line %d, invalid value for %s: \"%s\"",
+ file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff);
- FREE(buff);
+ free(buff);
return 0;
}
#define declare_def_handler(option, function) \
static int \
-def_ ## option ## _handler (struct config *conf, vector strvec) \
+def_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
- return function (strvec, &conf->option); \
+ return function (strvec, &conf->option, file, line_nr); \
+}
+
+#define declare_def_warn_handler(option, function) \
+static int \
+def_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ condlog(2, "%s line %d, \"" #option "\" is deprecated and will be disabled in a future release", file, line_nr); \
+ return function (strvec, &conf->option, file, line_nr); \
+}
+
+#define declare_def_range_handler(option, minval, maxval) \
+static int \
+def_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ return set_int(strvec, &conf->option, minval, maxval, file, line_nr); \
}
#define declare_def_snprint(option, function) \
#define declare_hw_handler(option, function) \
static int \
-hw_ ## option ## _handler (struct config *conf, vector strvec) \
+hw_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable); \
if (!hwe) \
return 1; \
- return function (strvec, &hwe->option); \
+ return function (strvec, &hwe->option, file, line_nr); \
}
+#define declare_hw_range_handler(option, minval, maxval) \
+static int \
+hw_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable); \
+ if (!hwe) \
+ return 1; \
+ return set_int(strvec, &hwe->option, minval, maxval, file, line_nr); \
+}
+
+
#define declare_hw_snprint(option, function) \
static int \
snprint_hw_ ## option (struct config *conf, struct strbuf *buff, \
#define declare_ovr_handler(option, function) \
static int \
-ovr_ ## option ## _handler (struct config *conf, vector strvec) \
+ovr_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ if (!conf->overrides) \
+ return 1; \
+ return function (strvec, &conf->overrides->option, file, line_nr); \
+}
+
+#define declare_ovr_range_handler(option, minval, maxval) \
+static int \
+ovr_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
if (!conf->overrides) \
return 1; \
- return function (strvec, &conf->overrides->option); \
+ return set_int(strvec, &conf->overrides->option, minval, maxval, \
+ file, line_nr); \
}
#define declare_ovr_snprint(option, function) \
#define declare_mp_handler(option, function) \
static int \
-mp_ ## option ## _handler (struct config *conf, vector strvec) \
+mp_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable); \
if (!mpe) \
return 1; \
- return function (strvec, &mpe->option); \
+ return function (strvec, &mpe->option, file, line_nr); \
+}
+
+#define declare_mp_range_handler(option, minval, maxval) \
+static int \
+mp_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable); \
+ if (!mpe) \
+ return 1; \
+ return set_int(strvec, &mpe->option, minval, maxval, file, line_nr); \
}
#define declare_mp_snprint(option, function) \
return function(buff, mpe->option); \
}
-static int checkint_handler(struct config *conf, vector strvec)
+static int checkint_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
- int rc = set_uint(strvec, &conf->checkint);
+ int rc = set_uint(strvec, &conf->checkint, file, line_nr);
if (rc)
return rc;
declare_def_handler(max_checkint, set_uint)
declare_def_snprint(max_checkint, print_int)
-declare_def_handler(verbosity, set_int)
+declare_def_range_handler(verbosity, 0, MAX_VERBOSITY)
declare_def_snprint(verbosity, print_int)
declare_def_handler(reassign_maps, set_yes_no)
declare_def_snprint(reassign_maps, print_yes_no)
-declare_def_handler(multipath_dir, set_str)
+declare_def_warn_handler(multipath_dir, set_dir)
declare_def_snprint(multipath_dir, print_str)
-static int def_partition_delim_handler(struct config *conf, vector strvec)
+static int def_partition_delim_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
- int rc = set_str(strvec, &conf->partition_delim);
+ int rc = set_str_noslash(strvec, &conf->partition_delim, file, line_nr);
if (rc != 0)
return rc;
if (!strcmp(conf->partition_delim, UNSET_PARTITION_DELIM)) {
- FREE(conf->partition_delim);
+ free(conf->partition_delim);
conf->partition_delim = NULL;
}
return 0;
};
static int
-def_find_multipaths_handler(struct config *conf, vector strvec)
+def_find_multipaths_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
char *buff;
int i;
- if (set_yes_no_undef(strvec, &conf->find_multipaths) == 0 &&
- conf->find_multipaths != FIND_MULTIPATHS_UNDEF)
- return 0;
-
buff = set_value(strvec);
if (!buff)
return 1;
}
}
- if (conf->find_multipaths == YNU_UNDEF) {
- condlog(0, "illegal value for find_multipaths: %s", buff);
- conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
+ if (i >= __FIND_MULTIPATHS_LAST) {
+ if (strcmp(buff, "no") == 0 || strcmp(buff, "0") == 0)
+ conf->find_multipaths = FIND_MULTIPATHS_OFF;
+ else if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
+ conf->find_multipaths = FIND_MULTIPATHS_ON;
+ else
+ condlog(1, "%s line %d, invalid value for find_multipaths: \"%s\"",
+ file, line_nr, buff);
}
- FREE(buff);
+ free(buff);
return 0;
}
return total;
}
-static int uid_attrs_handler(struct config *conf, vector strvec)
+static int uid_attrs_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
char *val;
if (!val)
return 1;
if (parse_uid_attrs(val, conf))
- condlog(1, "error parsing uid_attrs: \"%s\"", val);
- condlog(3, "parsed %d uid_attrs", VECTOR_SIZE(&conf->uid_attrs));
- FREE(val);
+ condlog(1, "%s line %d,error parsing uid_attrs: \"%s\"", file,
+ line_nr, val);
+ else
+ condlog(4, "parsed %d uid_attrs", VECTOR_SIZE(&conf->uid_attrs));
+ free(val);
return 0;
}
declare_mp_handler(prio_name, set_str)
declare_mp_snprint(prio_name, print_str)
-declare_def_handler(alias_prefix, set_str)
+declare_def_handler(alias_prefix, set_str_noslash)
declare_def_snprint_defstr(alias_prefix, print_str, DEFAULT_ALIAS_PREFIX)
-declare_ovr_handler(alias_prefix, set_str)
+declare_ovr_handler(alias_prefix, set_str_noslash)
declare_ovr_snprint(alias_prefix, print_str)
-declare_hw_handler(alias_prefix, set_str)
+declare_hw_handler(alias_prefix, set_str_noslash)
declare_hw_snprint(alias_prefix, print_str)
declare_def_handler(prio_args, set_str)
declare_hw_handler(checker_name, set_str)
declare_hw_snprint(checker_name, print_str)
-declare_def_handler(minio, set_int)
+declare_def_range_handler(minio, 0, INT_MAX)
declare_def_snprint_defint(minio, print_int, DEFAULT_MINIO)
-declare_ovr_handler(minio, set_int)
+declare_ovr_range_handler(minio, 0, INT_MAX)
declare_ovr_snprint(minio, print_nonzero)
-declare_hw_handler(minio, set_int)
+declare_hw_range_handler(minio, 0, INT_MAX)
declare_hw_snprint(minio, print_nonzero)
-declare_mp_handler(minio, set_int)
+declare_mp_range_handler(minio, 0, INT_MAX)
declare_mp_snprint(minio, print_nonzero)
-declare_def_handler(minio_rq, set_int)
+declare_def_range_handler(minio_rq, 0, INT_MAX)
declare_def_snprint_defint(minio_rq, print_int, DEFAULT_MINIO_RQ)
-declare_ovr_handler(minio_rq, set_int)
+declare_ovr_range_handler(minio_rq, 0, INT_MAX)
declare_ovr_snprint(minio_rq, print_nonzero)
-declare_hw_handler(minio_rq, set_int)
+declare_hw_range_handler(minio_rq, 0, INT_MAX)
declare_hw_snprint(minio_rq, print_nonzero)
-declare_mp_handler(minio_rq, set_int)
+declare_mp_range_handler(minio_rq, 0, INT_MAX)
declare_mp_snprint(minio_rq, print_nonzero)
declare_def_handler(queue_without_daemon, set_yes_no)
return append_strbuf_quoted(buff, qwd);
}
-declare_def_handler(checker_timeout, set_int)
+declare_def_range_handler(checker_timeout, 0, INT_MAX)
declare_def_snprint(checker_timeout, print_nonzero)
declare_def_handler(allow_usb_devices, set_yes_no)
declare_mp_handler(user_friendly_names, set_yes_no_undef)
declare_mp_snprint(user_friendly_names, print_yes_no_undef)
-declare_def_handler(bindings_file, set_str)
+declare_def_warn_handler(bindings_file, set_path)
declare_def_snprint(bindings_file, print_str)
-declare_def_handler(wwids_file, set_str)
+declare_def_warn_handler(wwids_file, set_path)
declare_def_snprint(wwids_file, print_str)
-declare_def_handler(prkeys_file, set_str)
+declare_def_warn_handler(prkeys_file, set_path)
declare_def_snprint(prkeys_file, print_str)
declare_def_handler(retain_hwhandler, set_yes_no_undef)
declare_mp_handler(deferred_remove, set_yes_no_undef)
declare_mp_snprint(deferred_remove, print_yes_no_undef)
-declare_def_handler(retrigger_tries, set_int)
+declare_def_range_handler(retrigger_tries, 0, INT_MAX)
declare_def_snprint(retrigger_tries, print_int)
-declare_def_handler(retrigger_delay, set_int)
+declare_def_range_handler(retrigger_delay, 0, INT_MAX)
declare_def_snprint(retrigger_delay, print_int)
-declare_def_handler(uev_wait_timeout, set_int)
+declare_def_range_handler(uev_wait_timeout, 0, INT_MAX)
declare_def_snprint(uev_wait_timeout, print_int)
declare_def_handler(strict_timing, set_yes_no)
declare_hw_snprint(skip_kpartx, print_yes_no_undef)
declare_mp_handler(skip_kpartx, set_yes_no_undef)
declare_mp_snprint(skip_kpartx, print_yes_no_undef)
-static int def_disable_changed_wwids_handler(struct config *conf, vector strvec)
+static int def_disable_changed_wwids_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
return 0;
}
return print_ignored(buff);
}
-declare_def_handler(remove_retries, set_int)
+declare_def_range_handler(remove_retries, 0, INT_MAX)
declare_def_snprint(remove_retries, print_int)
-declare_def_handler(max_sectors_kb, set_int)
+declare_def_range_handler(max_sectors_kb, 0, INT_MAX)
declare_def_snprint(max_sectors_kb, print_nonzero)
-declare_ovr_handler(max_sectors_kb, set_int)
+declare_ovr_range_handler(max_sectors_kb, 0, INT_MAX)
declare_ovr_snprint(max_sectors_kb, print_nonzero)
-declare_hw_handler(max_sectors_kb, set_int)
+declare_hw_range_handler(max_sectors_kb, 0, INT_MAX)
declare_hw_snprint(max_sectors_kb, print_nonzero)
-declare_mp_handler(max_sectors_kb, set_int)
+declare_mp_range_handler(max_sectors_kb, 0, INT_MAX)
declare_mp_snprint(max_sectors_kb, print_nonzero)
-declare_def_handler(find_multipaths_timeout, set_int)
+declare_def_range_handler(find_multipaths_timeout, INT_MIN, INT_MAX)
declare_def_snprint_defint(find_multipaths_timeout, print_int,
DEFAULT_FIND_MULTIPATHS_TIMEOUT)
DEFAULT_ENABLE_FOREIGN)
static int
-def_config_dir_handler(struct config *conf, vector strvec)
+def_config_dir_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
/* this is only valid in the main config file */
- if (conf->processed_main_config)
+ if (conf->processed_main_config) {
+ condlog(1, "%s line %d, config_dir option only valid in /etc/multipath.conf",
+ file, line_nr);
return 0;
- return set_str(strvec, &conf->config_dir);
+ }
+ condlog(2, "%s line %d, \"config_dir\" is deprecated and will be disabled in a future release",
+ file, line_nr);
+ return set_path(strvec, &conf->config_dir, file, line_nr);
}
declare_def_snprint(config_dir, print_str)
#define declare_def_attr_handler(option, function) \
static int \
-def_ ## option ## _handler (struct config *conf, vector strvec) \
+def_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
- return function (strvec, &conf->option, &conf->attribute_flags);\
+ return function (strvec, &conf->option, &conf->attribute_flags, \
+ file, line_nr); \
}
#define declare_def_attr_snprint(option, function) \
#define declare_mp_attr_handler(option, function) \
static int \
-mp_ ## option ## _handler (struct config *conf, vector strvec) \
+mp_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable); \
if (!mpe) \
return 1; \
- return function (strvec, &mpe->option, &mpe->attribute_flags); \
+ return function (strvec, &mpe->option, &mpe->attribute_flags, \
+ file, line_nr); \
}
#define declare_mp_attr_snprint(option, function) \
}
static int
-set_mode(vector strvec, void *ptr, int *flags)
+set_mode(vector strvec, void *ptr, int *flags, const char *file, int line_nr)
{
mode_t mode;
mode_t *mode_ptr = (mode_t *)ptr;
if (sscanf(buff, "%o", &mode) == 1 && mode <= 0777) {
*flags |= (1 << ATTR_MODE);
*mode_ptr = mode;
- }
+ } else
+ condlog(1, "%s line %d, invalid value for mode: \"%s\"",
+ file, line_nr, buff);
- FREE(buff);
+ free(buff);
return 0;
}
static int
-set_uid(vector strvec, void *ptr, int *flags)
+set_uid(vector strvec, void *ptr, int *flags, const char *file, int line_nr)
{
uid_t uid;
uid_t *uid_ptr = (uid_t *)ptr;
else if (sscanf(buff, "%u", &uid) == 1){
*flags |= (1 << ATTR_UID);
*uid_ptr = uid;
- }
+ } else
+ condlog(1, "%s line %d, invalid value for uid: \"%s\"",
+ file, line_nr, buff);
- FREE(buff);
+ free(buff);
return 0;
}
static int
-set_gid(vector strvec, void *ptr, int *flags)
+set_gid(vector strvec, void *ptr, int *flags, const char *file, int line_nr)
{
gid_t gid;
gid_t *gid_ptr = (gid_t *)ptr;
else if (sscanf(buff, "%u", &gid) == 1){
*flags |= (1 << ATTR_GID);
*gid_ptr = gid;
- }
- FREE(buff);
+ } else
+ condlog(1, "%s line %d, invalid value for gid: \"%s\"",
+ file, line_nr, buff);
+ free(buff);
return 0;
}
declare_mp_attr_snprint(gid, print_gid)
static int
-set_undef_off_zero(vector strvec, void *ptr)
+set_undef_off_zero(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
int *int_ptr = (int *)ptr;
if (strcmp(buff, "off") == 0)
*int_ptr = UOZ_OFF;
- else if (sscanf(buff, "%d", int_ptr) != 1 ||
- *int_ptr < UOZ_ZERO)
- *int_ptr = UOZ_UNDEF;
- else if (*int_ptr == 0)
+ else if (strcmp(buff, "0") == 0)
*int_ptr = UOZ_ZERO;
+ else
+ do_set_int(strvec, int_ptr, 1, INT_MAX, file, line_nr, buff);
- FREE(buff);
+ free(buff);
return 0;
}
declare_hw_snprint(fast_io_fail, print_undef_off_zero)
static int
-set_dev_loss(vector strvec, void *ptr)
+set_dev_loss(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
unsigned int *uint_ptr = (unsigned int *)ptr;
if (!strcmp(buff, "infinity"))
*uint_ptr = MAX_DEV_LOSS_TMO;
else if (sscanf(buff, "%u", uint_ptr) != 1)
- *uint_ptr = DEV_LOSS_TMO_UNSET;
+ condlog(1, "%s line %d, invalid value for dev_loss_tmo: \"%s\"",
+ file, line_nr, buff);
- FREE(buff);
+ free(buff);
return 0;
}
declare_hw_snprint(eh_deadline, print_undef_off_zero)
static int
-set_pgpolicy(vector strvec, void *ptr)
+set_pgpolicy(vector strvec, void *ptr, const char *file, int line_nr)
{
char * buff;
+ int policy;
int *int_ptr = (int *)ptr;
buff = set_value(strvec);
if (!buff)
return 1;
- *int_ptr = get_pgpolicy_id(buff);
- FREE(buff);
+ policy = get_pgpolicy_id(buff);
+ if (policy != IOPOLICY_UNDEF)
+ *int_ptr = policy;
+ else
+ condlog(1, "%s line %d, invalid value for path_grouping_policy: \"%s\"",
+ file, line_nr, buff);
+ free(buff);
return 0;
}
static int
-max_fds_handler(struct config *conf, vector strvec)
+max_fds_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
char * buff;
- int r = 0, max_fds;
+ int max_fds;
buff = set_value(strvec);
if (!buff)
return 1;
- r = get_sys_max_fds(&max_fds);
- if (r) {
- /* Assume safe limit */
- max_fds = 4096;
- }
- if (strlen(buff) == 3 &&
- !strcmp(buff, "max"))
+ if (get_sys_max_fds(&max_fds) != 0)
+ max_fds = 4096; /* Assume safe limit */
+ if (!strcmp(buff, "max"))
conf->max_fds = max_fds;
else
- conf->max_fds = atoi(buff);
+ do_set_int(strvec, &conf->max_fds, 0, max_fds, file, line_nr,
+ buff);
- if (conf->max_fds > max_fds)
- conf->max_fds = max_fds;
-
- FREE(buff);
+ free(buff);
- return r;
+ return 0;
}
static int
}
static int
-set_rr_weight(vector strvec, void *ptr)
+set_rr_weight(vector strvec, void *ptr, const char *file, int line_nr)
{
int *int_ptr = (int *)ptr;
char * buff;
if (!strcmp(buff, "priorities"))
*int_ptr = RR_WEIGHT_PRIO;
-
- if (!strcmp(buff, "uniform"))
+ else if (!strcmp(buff, "uniform"))
*int_ptr = RR_WEIGHT_NONE;
-
- FREE(buff);
+ else
+ condlog(1, "%s line %d, invalid value for rr_weight: \"%s\"",
+ file, line_nr, buff);
+ free(buff);
return 0;
}
declare_mp_snprint(rr_weight, print_rr_weight)
static int
-set_pgfailback(vector strvec, void *ptr)
+set_pgfailback(vector strvec, void *ptr, const char *file, int line_nr)
{
int *int_ptr = (int *)ptr;
char * buff;
else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
*int_ptr = -FAILBACK_FOLLOWOVER;
else
- *int_ptr = atoi(buff);
+ do_set_int(strvec, ptr, 0, INT_MAX, file, line_nr, buff);
- FREE(buff);
+ free(buff);
return 0;
}
declare_mp_snprint(pgfailback, print_pgfailback)
static int
-no_path_retry_helper(vector strvec, void *ptr)
+no_path_retry_helper(vector strvec, void *ptr, const char *file, int line_nr)
{
int *int_ptr = (int *)ptr;
char * buff;
*int_ptr = NO_PATH_RETRY_FAIL;
else if (!strcmp(buff, "queue"))
*int_ptr = NO_PATH_RETRY_QUEUE;
- else if ((*int_ptr = atoi(buff)) < 1)
- *int_ptr = NO_PATH_RETRY_UNDEF;
+ else
+ do_set_int(strvec, ptr, 1, INT_MAX, file, line_nr, buff);
- FREE(buff);
+ free(buff);
return 0;
}
declare_mp_snprint(no_path_retry, print_no_path_retry)
static int
-def_log_checker_err_handler(struct config *conf, vector strvec)
+def_log_checker_err_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
char * buff;
if (!buff)
return 1;
- if (strlen(buff) == 4 && !strcmp(buff, "once"))
+ if (!strcmp(buff, "once"))
conf->log_checker_err = LOG_CHKR_ERR_ONCE;
- else if (strlen(buff) == 6 && !strcmp(buff, "always"))
+ else if (!strcmp(buff, "always"))
conf->log_checker_err = LOG_CHKR_ERR_ALWAYS;
+ else
+ condlog(1, "%s line %d, invalid value for log_checker_err: \"%s\"",
+ file, line_nr, buff);
free(buff);
return 0;
*source_ptr = PRKEY_SOURCE_FILE;
*flags_ptr = 0;
put_be64(*be64_ptr, 0);
- FREE(buff);
+ free(buff);
return 0;
}
if (parse_prkey_flags(buff, &prkey, &sa_flags) != 0) {
- FREE(buff);
+ free(buff);
return 1;
}
*source_ptr = PRKEY_SOURCE_CONF;
*flags_ptr = sa_flags;
put_be64(*be64_ptr, prkey);
- FREE(buff);
+ free(buff);
return 0;
}
}
static int
-def_reservation_key_handler(struct config *conf, vector strvec)
+def_reservation_key_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
return set_reservation_key(strvec, &conf->reservation_key,
&conf->sa_flags,
}
static int
-mp_reservation_key_handler(struct config *conf, vector strvec)
+mp_reservation_key_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
if (!mpe)
}
static int
-set_off_int_undef(vector strvec, void *ptr)
+set_off_int_undef(vector strvec, void *ptr, const char *file, int line_nr)
{
int *int_ptr = (int *)ptr;
char * buff;
if (!strcmp(buff, "no") || !strcmp(buff, "0"))
*int_ptr = NU_NO;
- else if ((*int_ptr = atoi(buff)) < 1)
- *int_ptr = NU_UNDEF;
+ else
+ do_set_int(strvec, ptr, 1, INT_MAX, file, line_nr, buff);
- FREE(buff);
+ free(buff);
return 0;
}
declare_hw_handler(recheck_wwid, set_yes_no_undef)
declare_hw_snprint(recheck_wwid, print_yes_no_undef)
+declare_def_range_handler(uxsock_timeout, DEFAULT_REPLY_TIMEOUT, INT_MAX)
static int
-def_uxsock_timeout_handler(struct config *conf, vector strvec)
-{
- unsigned int uxsock_timeout;
- char *buff;
-
- buff = set_value(strvec);
- if (!buff)
- return 1;
-
- if (sscanf(buff, "%u", &uxsock_timeout) == 1 &&
- uxsock_timeout > DEFAULT_REPLY_TIMEOUT)
- conf->uxsock_timeout = uxsock_timeout;
- else
- conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
-
- free(buff);
- return 0;
-}
-
-static int
-hw_vpd_vendor_handler(struct config *conf, vector strvec)
+hw_vpd_vendor_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
int i;
char *buff;
goto out;
}
}
- hwe->vpd_vendor_id = 0;
+ condlog(1, "%s line %d, invalid value for vpd_vendor: \"%s\"",
+ file, line_nr, buff);
out:
- FREE(buff);
+ free(buff);
return 0;
}
* blacklist block handlers
*/
static int
-blacklist_handler(struct config *conf, vector strvec)
+blacklist_handler(struct config *conf, vector strvec, const char*file,
+ int line_nr)
{
if (!conf->blist_devnode)
conf->blist_devnode = vector_alloc();
}
static int
-blacklist_exceptions_handler(struct config *conf, vector strvec)
+blacklist_exceptions_handler(struct config *conf, vector strvec,
+ const char *file, int line_nr)
{
if (!conf->elist_devnode)
conf->elist_devnode = vector_alloc();
#define declare_ble_handler(option) \
static int \
-ble_ ## option ## _handler (struct config *conf, vector strvec) \
+ble_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
char *buff; \
int rc; \
#define declare_ble_device_handler(name, option, vend, prod) \
static int \
-ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
+ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
{ \
char * buff; \
int rc; \
}
static int
-ble_device_handler(struct config *conf, vector strvec)
+ble_device_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
return alloc_ble_device(conf->blist_device);
}
static int
-ble_except_device_handler(struct config *conf, vector strvec)
+ble_except_device_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
return alloc_ble_device(conf->elist_device);
}
* devices block handlers
*/
static int
-devices_handler(struct config *conf, vector strvec)
+devices_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
if (!conf->hwtable)
conf->hwtable = vector_alloc();
}
static int
-device_handler(struct config *conf, vector strvec)
+device_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
struct hwentry * hwe;
* overrides handlers
*/
static int
-overrides_handler(struct config *conf, vector strvec)
+overrides_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
if (!conf->overrides)
conf->overrides = alloc_hwe();
* multipaths block handlers
*/
static int
-multipaths_handler(struct config *conf, vector strvec)
+multipaths_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
if (!conf->mptable)
conf->mptable = vector_alloc();
}
static int
-multipath_handler(struct config *conf, vector strvec)
+multipath_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
struct mpentry * mpe;
declare_mp_handler(wwid, set_str)
declare_mp_snprint(wwid, print_str)
-declare_mp_handler(alias, set_str)
+declare_mp_handler(alias, set_str_noslash)
declare_mp_snprint(alias, print_str)
/*
*/
static int
-deprecated_handler(struct config *conf, vector strvec)
+deprecated_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
{
char * buff;
if (!buff)
return 1;
- FREE(buff);
+ free(buff);
return 0;
}
#include "checkers.h"
#include "vector.h"
-#include "memory.h"
#include "util.h"
#include "structs.h"
#include "config.h"
#include "print.h"
#include "strbuf.h"
+#define VPD_BUFLEN 4096
+
struct vpd_vendor_page vpd_vendor_pages[VPD_VP_ARRAY_SIZE] = {
[VPD_VP_UNDEF] = { 0x00, "undef" },
[VPD_VP_HP3PAR] = { 0xc0, "hp3par" },
if (value && !strcmp(value, "usb")) {
pp->sg_id.proto_id = SCSI_PROTOCOL_USB;
tgtname = udev_device_get_sysname(tgtdev);
- strlcpy(node, tgtname, NODE_NAME_SIZE);
- return 0;
+ if (tgtname) {
+ strlcpy(node, tgtname, NODE_NAME_SIZE);
+ return 0;
+ }
}
tgtdev = udev_device_get_parent(tgtdev);
}
parent = udev_device_get_parent(parent)) {
const char *ed = udev_device_get_sysname(parent);
- if (!strncmp(ed, ed_str, sizeof(ed_str) - 1)) {
+ if (ed && !strncmp(ed, ed_str, sizeof(ed_str) - 1)) {
end_dev_id = ed;
break;
}
if (out_len == 0)
return 0;
+ if (len > WWID_SIZE)
+ len = WWID_SIZE;
/*
* Strip leading and trailing whitespace
*/
const unsigned char *d;
const unsigned char *vpd = NULL;
size_t len, vpd_len, i;
- int vpd_type, prio = -1, naa_prio;
+ int vpd_type, prio = -1;
+ int err = -ENODATA;
+ STRBUF_ON_STACK(buf);
+
+ /* Need space at least for one digit */
+ if (out_len <= 1)
+ return 0;
d = in + 4;
- while (d < in + in_len) {
+ while (d <= in + in_len - 4) {
+ bool invalid = false;
+ int new_prio = -1;
+
/* Select 'association: LUN' */
- if ((d[1] & 0x30) != 0) {
- d += d[3] + 4;
- continue;
- }
+ if ((d[1] & 0x30) == 0x30) {
+ invalid = true;
+ goto next_designator;
+ } else if ((d[1] & 0x30) != 0x00)
+ goto next_designator;
+
switch (d[1] & 0xf) {
+ unsigned char good_len;
case 0x3:
/* NAA: Prio 5 */
switch (d[4] >> 4) {
case 6:
/* IEEE Registered Extended: Prio 8 */
- naa_prio = 8;
+ new_prio = 8;
+ good_len = 16;
break;
case 5:
/* IEEE Registered: Prio 7 */
- naa_prio = 7;
+ new_prio = 7;
+ good_len = 8;
break;
case 2:
/* IEEE Extended: Prio 6 */
- naa_prio = 6;
+ new_prio = 6;
+ good_len = 8;
break;
case 3:
/* IEEE Locally assigned: Prio 1 */
- naa_prio = 1;
+ new_prio = 1;
+ good_len = 8;
break;
default:
/* Default: no priority */
- naa_prio = -1;
+ good_len = 0xff;
break;
}
- if (prio < naa_prio) {
- prio = naa_prio;
- vpd = d;
- }
+
+ invalid = good_len == 0xff || good_len != d[3];
break;
case 0x2:
/* EUI-64: Prio 4 */
- if (prio < 4) {
- prio = 4;
- vpd = d;
- }
+ invalid = (d[3] != 8 && d[3] != 12 && d[3] != 16);
+ new_prio = 4;
break;
case 0x8:
/* SCSI Name: Prio 3 */
- if (memcmp(d + 4, "eui.", 4) &&
- memcmp(d + 4, "naa.", 4) &&
- memcmp(d + 4, "iqn.", 4))
- break;
- if (prio < 3) {
- prio = 3;
- vpd = d;
- }
+ invalid = (d[3] < 4 || (memcmp(d + 4, "eui.", 4) &&
+ memcmp(d + 4, "naa.", 4) &&
+ memcmp(d + 4, "iqn.", 4)));
+ new_prio = 3;
break;
case 0x1:
/* T-10 Vendor ID: Prio 2 */
- if (prio < 2) {
- prio = 2;
- vpd = d;
- }
+ invalid = (d[3] < 8);
+ new_prio = 2;
+ break;
+ case 0xa:
+ condlog(2, "%s: UUID identifiers not yet supported",
+ __func__);
+ break;
+ default:
+ invalid = true;
break;
}
+
+ next_designator:
+ if (d + d[3] + 4 - in > (ssize_t)in_len) {
+ condlog(2, "%s: device descriptor length overflow: %zd > %zu",
+ __func__, d + d[3] + 4 - in, in_len);
+ err = -EOVERFLOW;
+ break;
+ } else if (invalid) {
+ condlog(2, "%s: invalid device designator at offset %zd: %02x%02x%02x%02x",
+ __func__, d - in, d[0], d[1], d[2], d[3]);
+ /*
+ * We checked above that the next offset is within limits.
+ * Proceed, fingers crossed.
+ */
+ err = -EINVAL;
+ } else if (new_prio > prio) {
+ vpd = d;
+ prio = new_prio;
+ }
d += d[3] + 4;
}
if (prio <= 0)
- return -ENODATA;
- /* Need space at least for one digit */
- else if (out_len <= 1)
- return 0;
+ return err;
+
+ if (d != in + in_len)
+ /* Should this be fatal? (overflow covered above) */
+ condlog(2, "%s: warning: last descriptor end %zd != VPD length %zu",
+ __func__, d - in, in_len);
len = 0;
vpd_type = vpd[1] & 0xf;
vpd_len = vpd[3];
vpd += 4;
+ /* untaint vpd_len for coverity */
+ if (vpd_len > WWID_SIZE) {
+ condlog(1, "%s: suspicious designator length %zu truncated to %u",
+ __func__, vpd_len, WWID_SIZE);
+ vpd_len = WWID_SIZE;
+ }
if (vpd_type == 0x2 || vpd_type == 0x3) {
size_t i;
- len = sprintf(out, "%d", vpd_type);
- if (2 * vpd_len >= out_len - len) {
- condlog(1, "%s: WWID overflow, type %d, %zu/%zu bytes required",
- __func__, vpd_type,
- 2 * vpd_len + len + 1, out_len);
- vpd_len = (out_len - len - 1) / 2;
- }
+ if ((err = print_strbuf(&buf, "%d", vpd_type)) < 0)
+ return err;
for (i = 0; i < vpd_len; i++)
- len += sprintf(out + len,
- "%02x", vpd[i]);
- } else if (vpd_type == 0x8 && vpd_len < 4) {
- condlog(1, "%s: VPD length %zu too small for designator type 8",
- __func__, vpd_len);
- return -EINVAL;
+ if ((err = print_strbuf(&buf, "%02x", vpd[i])) < 0)
+ return err;
} else if (vpd_type == 0x8) {
+ char type;
+
if (!memcmp("eui.", vpd, 4))
- out[0] = '2';
+ type = '2';
else if (!memcmp("naa.", vpd, 4))
- out[0] = '3';
+ type = '3';
else
- out[0] = '8';
+ type = '8';
+ if ((err = fill_strbuf(&buf, type, 1)) < 0)
+ return err;
vpd += 4;
len = vpd_len - 4;
- while (len > 2 && vpd[len - 2] == '\0')
- --len;
- if (len > out_len - 1) {
- condlog(1, "%s: WWID overflow, type 8/%c, %zu/%zu bytes required",
- __func__, out[0], len + 1, out_len);
- len = out_len - 1;
- }
+ if ((err = __append_strbuf_str(&buf, (const char *)vpd, len)) < 0)
+ return err;
- if (out[0] == '8')
- for (i = 0; i < len; ++i)
- out[1 + i] = vpd[i];
- else
- for (i = 0; i < len; ++i)
- out[1 + i] = tolower(vpd[i]);
+ /* The input is 0-padded, make sure the length is correct */
+ truncate_strbuf(&buf, strlen(get_strbuf_str(&buf)));
+ len = get_strbuf_len(&buf);
+ if (type != '8') {
+ char *buffer = __get_strbuf_buf(&buf);
- /* designator should be 0-terminated, but let's make sure */
- out[len] = '\0';
+ for (i = 0; i < len; ++i)
+ buffer[i] = tolower(buffer[i]);
+ }
} else if (vpd_type == 0x1) {
const unsigned char *p;
size_t p_len;
- out[0] = '1';
- len = 1;
- while ((p = memchr(vpd, ' ', vpd_len))) {
+ if ((err = fill_strbuf(&buf, '1', 1)) < 0)
+ return err;
+ while (vpd && (p = memchr(vpd, ' ', vpd_len))) {
p_len = p - vpd;
- if (len + p_len > out_len - 1) {
- condlog(1, "%s: WWID overflow, type 1, %zu/%zu bytes required",
- __func__, len + p_len, out_len);
- p_len = out_len - len - 1;
- }
- memcpy(out + len, vpd, p_len);
- len += p_len;
- if (len >= out_len - 1) {
- out[len] = '\0';
- break;
- }
- out[len] = '_';
- len ++;
- if (len >= out_len - 1) {
- out[len] = '\0';
- break;
- }
+ if ((err = __append_strbuf_str(&buf, (const char *)vpd,
+ p_len)) < 0)
+ return err;
vpd = p;
vpd_len -= p_len;
- while (vpd && *vpd == ' ') {
+ while (vpd && vpd_len > 0 && *vpd == ' ') {
vpd++;
vpd_len --;
}
+ if (vpd_len > 0 && (err = fill_strbuf(&buf, '_', 1)) < 0)
+ return err;
}
- p_len = vpd_len;
- if (p_len > 0 && len < out_len - 1) {
- if (len + p_len > out_len - 1) {
- condlog(1, "%s: WWID overflow, type 1, %zu/%zu bytes required",
- __func__, len + p_len + 1, out_len);
- p_len = out_len - len - 1;
- }
- memcpy(out + len, vpd, p_len);
- len += p_len;
- out[len] = '\0';
- }
- if (len > 1 && out[len - 1] == '_') {
- out[len - 1] = '\0';
- len--;
+ if (vpd_len > 0) {
+ if ((err = __append_strbuf_str(&buf, (const char *)vpd,
+ vpd_len)) < 0)
+ return err;
}
}
+
+ len = get_strbuf_len(&buf);
+ if (len >= out_len) {
+ condlog(1, "%s: WWID overflow, type %d, %zu/%zu bytes required",
+ __func__, vpd_type, len, out_len);
+ if (vpd_type == 2 || vpd_type == 3)
+ /* designator must have an even number of characters */
+ len = 2 * (out_len / 2) - 1;
+ else
+ len = out_len - 1;
+ }
+ strlcpy(out, get_strbuf_str(&buf), len + 1);
return len;
}
static int
get_vpd_sysfs (struct udev_device *parent, int pg, char * str, int maxlen)
{
- int len, buff_len;
- unsigned char buff[4096];
+ int len;
+ size_t buff_len;
+ unsigned char buff[VPD_BUFLEN];
- memset(buff, 0x0, 4096);
- if (!parent || sysfs_get_vpd(parent, pg, buff, 4096) <= 0) {
+ memset(buff, 0x0, VPD_BUFLEN);
+ if (!parent || sysfs_get_vpd(parent, pg, buff, VPD_BUFLEN) <= 0) {
condlog(3, "failed to read sysfs vpd pg%02x", pg);
return -EINVAL;
}
return -ENODATA;
}
buff_len = get_unaligned_be16(&buff[2]) + 4;
- if (buff_len > 4096)
+ if (buff_len > VPD_BUFLEN) {
condlog(3, "vpd pg%02x page truncated", pg);
+ buff_len = VPD_BUFLEN;
+ }
if (pg == 0x80)
len = parse_vpd_pg80(buff, str, maxlen);
is_vpd_page_supported(int fd, int pg)
{
int i, len;
- unsigned char buff[4096];
+ unsigned char buff[VPD_BUFLEN];
len = fetch_vpd_page(fd, 0x00, buff, sizeof(buff));
if (len < 0)
get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen)
{
int len, buff_len;
- unsigned char buff[4096];
+ unsigned char buff[VPD_BUFLEN];
buff_len = fetch_vpd_page(fd, pg, buff, sizeof(buff));
if (buff_len < 0)
}
if ((mask & DI_WWID) && !strlen(pp->wwid)) {
- get_uid(pp, path_state, pp->udev,
- (pp->retriggers >= conf->retrigger_tries));
+ int allow_fallback = ((mask & DI_NOFALLBACK) == 0 &&
+ pp->retriggers >= conf->retrigger_tries);
+ get_uid(pp, path_state, pp->udev, allow_fallback);
if (!strlen(pp->wwid)) {
if (pp->bus == SYSFS_BUS_UNDEF)
return PATHINFO_SKIPPED;
if (pp->initialized != INIT_FAILED) {
pp->initialized = INIT_MISSING_UDEV;
pp->tick = conf->retrigger_delay;
- } else if (pp->retriggers >= conf->retrigger_tries &&
+ } else if (allow_fallback &&
(pp->state == PATH_UP || pp->state == PATH_GHOST)) {
/*
* We have failed to read udev info for this path
__DI_WWID,
__DI_BLACKLIST,
__DI_NOIO,
+ __DI_NOFALLBACK,
};
#define DI_SYSFS (1 << __DI_SYSFS)
#define DI_WWID (1 << __DI_WWID)
#define DI_BLACKLIST (1 << __DI_BLACKLIST)
#define DI_NOIO (1 << __DI_NOIO) /* Avoid IO on the device */
+#define DI_NOFALLBACK (1 << __DI_NOFALLBACK) /* do not allow wwid fallback */
#define DI_ALL (DI_SYSFS | DI_SERIAL | DI_CHECKER | DI_PRIO | \
DI_WWID)
#include "checkers.h"
#include "vector.h"
-#include "memory.h"
#include "structs.h"
#include "util.h"
#include "debug.h"
dstlen = strlen(*dst);
len = dstlen + strlen(word) + 2;
- *dst = REALLOC(*dst, len);
+ *dst = realloc(*dst, len);
if (!*dst) {
free(p);
return 1;
if (merge_words(&mpp->features, word)) {
- FREE(word);
+ free(word);
return 1;
}
- FREE(word);
+ free(word);
}
/*
return 1;
if (merge_words(&mpp->hwhandler, word)) {
- FREE(word);
+ free(word);
return 1;
}
- FREE(word);
+ free(word);
}
/*
return 1;
num_pg = atoi(word);
- FREE(word);
+ free(word);
if (num_pg > 0) {
if (!mpp->pg) {
goto out;
mpp->nextpg = atoi(word);
- FREE(word);
+ free(word);
for (i = 0; i < num_pg; i++) {
/*
if (merge_words(&mpp->selector, word))
goto out1;
- FREE(word);
+ free(word);
} else {
p += get_word(p, NULL);
p += get_word(p, NULL);
goto out;
num_paths = atoi(word);
- FREE(word);
+ free(word);
p += get_word(p, &word);
goto out;
num_paths_args = atoi(word);
- FREE(word);
+ free(word);
for (j = 0; j < num_paths; j++) {
pp = NULL;
} else if (store_path(pgp->paths, pp))
goto out1;
- FREE(word);
+ free(word);
pgp->id ^= (long)pp;
pp->pgindex = i + 1;
if (k == 0) {
p += get_word(p, &word);
def_minio = atoi(word);
- FREE(word);
+ free(word);
if (!strncmp(mpp->selector,
"round-robin", 11)) {
}
return 0;
out1:
- FREE(word);
+ free(word);
out:
free_pgvec(mpp->pg, KEEP_PATHS);
mpp->pg = NULL;
return 1;
num_feature_args = atoi(word);
- FREE(word);
+ free(word);
for (i = 0; i < num_feature_args; i++) {
if (i == 1) {
return 1;
mpp->queuedio = atoi(word);
- FREE(word);
+ free(word);
continue;
}
/* unknown */
return 1;
num_hwhandler_args = atoi(word);
- FREE(word);
+ free(word);
for (i = 0; i < num_hwhandler_args; i++)
p += get_word(p, NULL);
return 1;
num_pg = atoi(word);
- FREE(word);
+ free(word);
if (num_pg == 0)
return 0;
pgp->status = PGSTATE_UNDEF;
break;
}
- FREE(word);
+ free(word);
/*
* PG Status (discarded, would be '0' anyway)
return 1;
num_paths = atoi(word);
- FREE(word);
+ free(word);
p += get_word(p, &word);
return 1;
num_pg_args = atoi(word);
- FREE(word);
+ free(word);
if (VECTOR_SIZE(pgp->paths) < num_paths)
return 1;
default:
break;
}
- FREE(word);
+ free(word);
/*
* fail count
*/
return 1;
pp->failcount = atoi(word);
- FREE(word);
+ free(word);
/*
* selector args
&def_minio) == 1 &&
def_minio != mpp->minio)
mpp->minio = def_minio;
- FREE(word);
+ free(word);
} else
p += get_word(p, NULL);
}
#include "vector.h"
#include "debug.h"
#include "util.h"
-#include "foreign.h"
#include "structs.h"
#include "structs_vec.h"
#include "print.h"
+#include "foreign.h"
#include "strbuf.h"
static vector foreigns;
}
/* Call this after get_path_layout */
-void foreign_path_layout(void)
+void foreign_path_layout(fieldwidth_t *width)
{
struct foreign *fgn;
int i;
vec = fgn->get_paths(fgn->context);
if (vec != NULL) {
- _get_path_layout(vec, LAYOUT_RESET_NOT);
+ _get_path_layout(vec, LAYOUT_RESET_NOT, width);
}
fgn->release_paths(fgn->context, vec);
}
/* Call this after get_multipath_layout */
-void foreign_multipath_layout(void)
+void foreign_multipath_layout(fieldwidth_t *width)
{
struct foreign *fgn;
int i;
vec = fgn->get_multipaths(fgn->context);
if (vec != NULL) {
- _get_multipath_layout(vec, LAYOUT_RESET_NOT);
+ _get_multipath_layout(vec, LAYOUT_RESET_NOT, width);
}
fgn->release_multipaths(fgn->context, vec);
pthread_cleanup_pop(1);
}
-int snprint_foreign_topology(struct strbuf *buf, int verbosity)
+static int __snprint_foreign_topology(struct strbuf *buf, int verbosity,
+ const fieldwidth_t *width)
{
struct foreign *fgn;
int i;
size_t initial_len = get_strbuf_len(buf);
- rdlock_foreigns();
- if (foreigns == NULL) {
- unlock_foreigns(NULL);
- return 0;
- }
- pthread_cleanup_push(unlock_foreigns, NULL);
-
vector_foreach_slot(foreigns, fgn, i) {
const struct _vector *vec;
const struct gen_multipath *gm;
if (vec != NULL) {
vector_foreach_slot(vec, gm, j) {
if (_snprint_multipath_topology(
- gm, buf, verbosity) < 0)
+ gm, buf, verbosity, width) < 0)
break;
}
}
pthread_cleanup_pop(1);
}
- pthread_cleanup_pop(1);
return get_strbuf_len(buf) - initial_len;
}
+int snprint_foreign_topology(struct strbuf *buf, int verbosity,
+ const fieldwidth_t *width)
+{
+ int rc;
+
+ rdlock_foreigns();
+ if (foreigns == NULL) {
+ unlock_foreigns(NULL);
+ return 0;
+ }
+ pthread_cleanup_push(unlock_foreigns, NULL);
+ rc = __snprint_foreign_topology(buf, verbosity, width);
+ pthread_cleanup_pop(1);
+ return rc;
+}
+
void print_foreign_topology(int verbosity)
{
STRBUF_ON_STACK(buf);
+ struct foreign *fgn;
+ int i;
+ fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
+
+ if ((width = alloc_path_layout()) == NULL)
+ return;
+ rdlock_foreigns();
+ if (foreigns == NULL) {
+ unlock_foreigns(NULL);
+ return;
+ }
+ pthread_cleanup_push(unlock_foreigns, NULL);
+ vector_foreach_slot(foreigns, fgn, i) {
+ const struct _vector *vec;
- snprint_foreign_topology(&buf, verbosity);
+ fgn->lock(fgn->context);
+ pthread_cleanup_push(fgn->unlock, fgn->context);
+ vec = fgn->get_paths(fgn->context);
+ _get_multipath_layout(vec, LAYOUT_RESET_NOT, width);
+ fgn->release_paths(fgn->context, vec);
+ pthread_cleanup_pop(1);
+ }
+ __snprint_foreign_topology(&buf, verbosity, width);
+ pthread_cleanup_pop(1);
printf("%s", get_strbuf_str(&buf));
}
-int snprint_foreign_paths(struct strbuf *buf, const char *style, int pretty)
+int snprint_foreign_paths(struct strbuf *buf, const char *style,
+ const fieldwidth_t *width)
{
struct foreign *fgn;
int i;
vec = fgn->get_paths(fgn->context);
if (vec != NULL) {
vector_foreach_slot(vec, gp, j) {
- ret = _snprint_path(gp, buf, style, pretty);
+ ret = _snprint_path(gp, buf, style, width);
if (ret < 0)
break;
}
return get_strbuf_len(buf) - initial_len;
}
-int snprint_foreign_multipaths(struct strbuf *buf,
- const char *style, int pretty)
+int snprint_foreign_multipaths(struct strbuf *buf, const char *style,
+ const fieldwidth_t *width)
{
struct foreign *fgn;
int i;
if (vec != NULL) {
vector_foreach_slot(vec, gm, j) {
ret = _snprint_multipath(gm, buf,
- style, pretty);
+ style, width);
if (ret < 0)
break;
}
#define _FOREIGN_H
#include <stdbool.h>
#include <libudev.h>
-#define LIBMP_FOREIGN_API ((1 << 8) | 1)
+#define LIBMP_FOREIGN_API ((1 << 8) | 2)
struct strbuf;
struct context;
* foreign_path_layout()
* call this before printing paths, after get_path_layout(), to determine
* output field width.
+ * @param width: an array allocated by alloc_path_layout()
*/
-void foreign_path_layout(void);
+void foreign_path_layout(fieldwidth_t *width);
/**
* foreign_multipath_layout()
* call this before printing maps, after get_multipath_layout(), to determine
* output field width.
+ * @param width: an array allocated by alloc_multipath_layout()
*/
-void foreign_multipath_layout(void);
+void foreign_multipath_layout(fieldwidth_t *width);
/**
* snprint_foreign_topology(buf, len, verbosity);
* '\0' - terminated.
* @param buf: output buffer
* @param verbosity: verbosity level
+ * @param width: an array of field widths, initialized by _get_path_layout()
* @returns: number of printed characters excluding trailing '\0'.
*/
-int snprint_foreign_topology(struct strbuf *buf, int verbosity);
+int snprint_foreign_topology(struct strbuf *buf, int verbosity,
+ const fieldwidth_t *width);
/**
* snprint_foreign_paths(buf, len, style, pad);
* '\0' - terminated.
* @param buf: output buffer
* @param style: format string
- * @param pad: whether to pad field width
+ * @param width: array initialized with get_path_layout(), or NULL for no padding
* @returns: number of printed characters excluding trailing '\0'.
*/
-int snprint_foreign_paths(struct strbuf *buf, const char *style, int pad);
+int snprint_foreign_paths(struct strbuf *buf, const char *style,
+ const fieldwidth_t *width);
/**
* snprint_foreign_multipaths(buf, len, style, pad);
* '\0' - terminated.
* @param buf: output buffer
* @param style: format string
- * @param pad: whether to pad field width
+ * @param width: array initialized with get_path_layout(), or NULL for no padding
* @returns: number of printed characters excluding trailing '\0'.
*/
-int snprint_foreign_multipaths(struct strbuf *buf,
- const char *style, int pretty);
+int snprint_foreign_multipaths(struct strbuf *buf, const char *style,
+ const fieldwidth_t *width);
/**
* print_foreign_topology(v)
"firmware_rev"));
case 'r':
val = udev_device_get_sysattr_value(nvm->udev, "ro");
- if (val[0] == 1)
+ if (!val)
+ return append_strbuf_str(buff, "undef");
+ else if (val[0] == 1)
return append_strbuf_str(buff, "ro");
else
return append_strbuf_str(buff, "rw");
#define _GENERIC_H
#include "vector.h"
+/*
+ * fieldwidth_t is required in print.h and foreign.h.
+ * Defining it twice is not allowed before C11.
+ * So do it here.
+ */
+typedef unsigned char fieldwidth_t;
+#define MAX_FIELD_WIDTH UCHAR_MAX
+
struct strbuf;
struct gen_multipath;
struct gen_pathgroup;
.pgpolicy = MULTIBUS,
},
{
- /*
- * SC Series, formerly Compellent
- *
- * Maintainer: Sean McGinnis <sean_mcginnis@dell.com>
- */
+ /* SC Series, formerly Compellent */
.vendor = "COMPELNT",
.product = "Compellent Vol",
- .pgpolicy = MULTIBUS,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
},
{
.no_path_retry = 3,
.fast_io_fail = 15,
},
+ {
+ /* PowerVault ME4 */
+ .vendor = "DellEMC",
+ .product = "ME4",
+ .pgpolicy = GROUP_BY_PRIO,
+ .prio_name = PRIO_ALUA,
+ .hwhandler = "1 alua",
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ },
/*
* Fujitsu
*/
},
/*
* IBM
- *
- * Maintainer: Hannes Reinecke <hare@suse.de>
*/
{
/* ProFibre 4000R */
.vendor = "IBM",
.product = "^2107900",
.no_path_retry = NO_PATH_RETRY_QUEUE,
- .pgpolicy = MULTIBUS,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
},
{
// Storwize V5000 and V7000 lines / SAN Volume Controller (SVC) / Flex System V7000 /
.vendor = "(XIV|IBM)",
.product = "(NEXTRA|2810XIV)",
.no_path_retry = NO_PATH_RETRY_QUEUE,
- .pgpolicy = MULTIBUS,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = 15,
},
{
/* TMS RamSan / FlashSystem 710/720/810/820/840/900 */
#include <sys/select.h>
#include "vector.h"
-#include "memory.h"
#include "checkers.h"
#include "config.h"
#include "structs.h"
if (p->fd < 0)
return 1;
- p->dio_ctx_array = MALLOC(sizeof(struct dio_ctx) * CONCUR_NR_EVENT);
+ p->dio_ctx_array = calloc(1, sizeof(struct dio_ctx) * CONCUR_NR_EVENT);
if (!p->dio_ctx_array)
goto fail_close;
for (i = 0; i < CONCUR_NR_EVENT; i++)
deinit_each_dio_ctx(p->dio_ctx_array + i);
free_pdctx:
- FREE(p->dio_ctx_array);
+ free(p->dio_ctx_array);
+ p->dio_ctx_array = NULL;
fail_close:
close(p->fd);
for (i = 0; i < CONCUR_NR_EVENT; i++)
deinit_each_dio_ctx(p->dio_ctx_array + i);
- FREE(p->dio_ctx_array);
+ free(p->dio_ctx_array);
if (p->fd > 0)
close(p->fd);
free_path:
- FREE(p);
+ free(p);
}
static struct io_err_stat_path *alloc_io_err_stat_path(void)
{
struct io_err_stat_path *p;
- p = (struct io_err_stat_path *)MALLOC(sizeof(*p));
+ p = (struct io_err_stat_path *)calloc(1, sizeof(*p));
if (!p)
return NULL;
* The new version inherits the previous ones.
*/
-LIBMULTIPATH_9.0.0 {
+LIBMULTIPATH_13.0.0 {
global:
/* symbols referenced by multipath and multipathd */
add_foreign;
add_map_with_path;
adopt_paths;
alloc_multipath;
+ alloc_multipath_layout;
alloc_path;
+ alloc_path_layout;
alloc_path_with_pathinfo;
alloc_strvec;
+ append_strbuf_str;
change_foreign;
check_alias_settings;
+ check_daemon;
checker_clear_message;
checker_disable;
checker_enable;
- checker_is_sync;
checker_message;
checker_name;
checker_state_name;
check_foreign;
+ cleanup_charp;
cleanup_lock;
+ cleanup_ucharp;
close_fd;
coalesce_paths;
convert_dev;
dm_is_mpath;
dm_mapname;
dm_map_present;
+ dm_prereq;
dm_queue_if_no_path;
dm_reassign;
dm_reinstate_path;
free_pathvec;
free_strvec;
get_monotonic_time;
+ get_multipath_config;
get_multipath_layout;
get_path_layout;
get_pgpolicy_id;
get_refwwid;
get_state;
+ get_strbuf_len;
+ get_strbuf_str;
get_udev_device;
get_uid;
get_used_hwes;
+ get_vpd_sgio;
group_by_prio;
init_checkers;
+ init_config;
init_foreign;
init_prio;
io_err_stat_handle_pathfail;
is_quote;
libmp_dm_task_create;
libmp_get_version;
+ libmp_get_multipath_config;
+ libmp_dm_task_run;
+ libmp_put_multipath_config;
libmp_udev_set_sync_support;
+ libmp_verbosity;
+ libmultipath_exit;
+ libmultipath_init;
load_config;
log_thread_reset;
log_thread_start;
log_thread_stop;
+ logsink;
need_io_err_check;
normalize_timespec;
orphan_path;
- orphan_paths;
parse_prkey_flags;
pathcount;
path_discovery;
print_all_paths;
print_foreign_topology;
_print_multipath_topology;
+ print_strbuf;
pthread_cond_init_mono;
+ put_multipath_config;
recv_packet;
- recv_packet_from_client;
reinstate_paths;
remember_wwid;
remove_map;
remove_wwid;
replace_wwids;
reset_checker_classes;
+ reset_strbuf;
select_all_tg_pt;
select_action;
select_find_multipaths_timeout;
setup_map;
setup_thread_attr;
should_multipath;
+ skip_libmp_dm_init;
snprint_blacklist_report;
+ __snprint_config;
snprint_config;
snprint_devices;
snprint_foreign_multipaths;
sysfs_attr_set_value;
sysfs_get_size;
sysfs_is_multipathed;
+ timespeccmp;
timespecsub;
trigger_paths_udev_change;
+ truncate_strbuf;
+ udev;
uevent_dispatch;
uevent_get_dm_str;
uevent_get_env_positive_int;
uevent_is_mpath;
uevent_listen;
+ uninit_config;
update_mpp_paths;
update_multipath_strings;
update_multipath_table;
- update_pathvec_from_dm;
update_queue_mode_add_path;
update_queue_mode_del_path;
ux_socket_listen;
verify_paths;
/* checkers */
+ checker_is_sync;
sg_read;
+ start_checker_thread;
/* prioritizers */
+ fill_strbuf;
get_asymmetric_access_state;
+ get_next_string;
get_prio_timeout;
get_target_port_group;
get_target_port_group_support;
libmp_nvme_identify_ns;
log_nvme_errcode;
nvme_id_ctrl_ana;
+ set_wakeup_fn;
snprint_host_wwnn;
snprint_host_wwpn;
snprint_path_serial;
free_scandir_result;
sysfs_attr_get_value;
- /* added in 2.1.0 */
- libmp_dm_task_run;
- cleanup_mutex;
-
- /* added in 2.2.0 */
- libmp_get_multipath_config;
- get_multipath_config;
- libmp_put_multipath_config;
- put_multipath_config;
- init_config;
- uninit_config;
-
- /* added in 2.3.0 */
- udev;
- logsink;
- libmultipath_init;
- libmultipath_exit;
-
- /* added in 4.1.0 */
- libmp_verbosity;
-
- /* added in 4.2.0 */
- dm_prereq;
- skip_libmp_dm_init;
-
- /* added in 4.3.0 */
- start_checker_thread;
-
- /* added in 4.4.0 */
- get_next_string;
-
- /* added in 4.5.0 */
- get_vpd_sgio;
- trigger_partitions_udev_change;
-
- /* added in 7.0.0 */
- cleanup_charp;
-
- /* added in 8.1.0 */
- reset_strbuf;
- append_strbuf_str;
- get_strbuf_len;
- get_strbuf_str;
- steal_strbuf_str;
- fill_strbuf;
- print_strbuf;
- truncate_strbuf;
-
- /* added in 8.2.0 */
- check_daemon;
-
local:
*;
};
void cleanup_lock (void * data)
{
struct mutex_lock *lock = data;
+ wakeup_fn *fn = lock->wakeup;
- unlock(lock);
+ __unlock(lock);
+ if (fn)
+ fn();
+}
+
+void set_wakeup_fn(struct mutex_lock *lck, wakeup_fn *fn)
+{
+ lock(lck);
+ lck->wakeup = fn;
+ __unlock(lck);
}
#include <pthread.h>
+typedef void (wakeup_fn)(void);
+
struct mutex_lock {
pthread_mutex_t mutex;
+ wakeup_fn *wakeup;
};
static inline void lock(struct mutex_lock *a)
pthread_mutex_lock(&a->mutex);
}
+static inline int trylock(struct mutex_lock *a)
+{
+ return pthread_mutex_trylock(&a->mutex);
+}
+
static inline int timedlock(struct mutex_lock *a, struct timespec *tmo)
{
return pthread_mutex_timedlock(&a->mutex, tmo);
}
-static inline void unlock(struct mutex_lock *a)
+static inline void __unlock(struct mutex_lock *a)
{
pthread_mutex_unlock(&a->mutex);
}
#define lock_cleanup_pop(a) pthread_cleanup_pop(1)
void cleanup_lock (void * data);
+void set_wakeup_fn(struct mutex_lock *lock, wakeup_fn *fn);
#endif /* _LOCK_H */
#include <time.h>
#include <pthread.h>
-#include "memory.h"
#include "log.h"
#include "util.h"
static int logarea_init (int size)
{
logdbg(stderr,"enter logarea_init\n");
- la = (struct logarea *)MALLOC(sizeof(struct logarea));
+ la = (struct logarea *)calloc(1, sizeof(struct logarea));
if (!la)
return 1;
if (size < MAX_MSG_SIZE)
size = DEFAULT_AREA_SIZE;
- la->start = MALLOC(size);
+ la->start = calloc(1, size);
if (!la->start) {
- FREE(la);
+ free(la);
+ la = NULL;
return 1;
}
- memset(la->start, 0, size);
la->empty = 1;
la->end = la->start + size;
la->head = la->start;
la->tail = la->start;
- la->buff = MALLOC(MAX_MSG_SIZE + sizeof(struct logmsg));
+ la->buff = calloc(1, MAX_MSG_SIZE + sizeof(struct logmsg));
if (!la->buff) {
- FREE(la->start);
- FREE(la);
+ free(la->start);
+ free(la);
+ la = NULL;
return 1;
}
return 0;
static void free_logarea (void)
{
- FREE(la->start);
- FREE(la->buff);
- FREE(la);
+ free(la->start);
+ free(la->buff);
+ free(la);
+ la = NULL;
return;
}
#include <pthread.h>
#include <sys/mman.h>
-#include "memory.h"
-
#include "log_pthread.h"
#include "log.h"
#include "lock.h"
+++ /dev/null
-/*
- * Part: Memory management framework. This framework is used to
- * find any memory leak.
- *
- * Version: $Id: memory.c,v 1.1.11 2005/03/01 01:22:13 acassen Exp $
- *
- * Authors: Alexandre Cassen, <acassen@linux-vs.org>
- * Jan Holmberg, <jan@artech.net>
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Copyright (C) 2001-2005 Alexandre Cassen, <acassen@linux-vs.org>
- */
-
-#include <assert.h>
-#include "memory.h"
-
-/*
- * Memory management. in debug mode,
- * help finding eventual memory leak.
- * Allocation memory types manipulated are :
- *
- * +type+--------meaning--------+
- * ! 0 ! Free slot !
- * ! 1 ! Overrun !
- * ! 2 ! free null !
- * ! 3 ! realloc null !
- * ! 4 ! Not previus allocated !
- * ! 8 ! Last free list !
- * ! 9 ! Allocated !
- * +----+-----------------------+
- *
- * global variable debug bit 9 ( 512 ) used to
- * flag some memory error.
- *
- */
-
-#ifdef _DEBUG_
-
-typedef struct {
- int type;
- int line;
- char *func;
- char *file;
- void *ptr;
- unsigned long size;
- long csum;
-} MEMCHECK;
-
-/* Last free pointers */
-static MEMCHECK free_list[256];
-
-static MEMCHECK alloc_list[MAX_ALLOC_LIST];
-static int number_alloc_list = 0;
-static int n = 0; /* Alloc list pointer */
-static int f = 0; /* Free list pointer */
-
-void *
-dbg_malloc(unsigned long size, char *file, char *function, int line)
-{
- void *buf;
- int i = 0;
- long check;
-
- buf = zalloc(size + sizeof (long));
-
- check = 0xa5a5 + size;
- *(long *) ((char *) buf + size) = check;
-
- while (i < number_alloc_list) {
- if (alloc_list[i].type == 0)
- break;
- i++;
- }
-
- if (i == number_alloc_list)
- number_alloc_list++;
-
- assert(number_alloc_list < MAX_ALLOC_LIST);
-
- alloc_list[i].ptr = buf;
- alloc_list[i].size = size;
- alloc_list[i].file = file;
- alloc_list[i].func = function;
- alloc_list[i].line = line;
- alloc_list[i].csum = check;
- alloc_list[i].type = 9;
-
- if (debug & 1)
- printf("zalloc[%3d:%3d], %p, %4ld at %s, %3d, %s\n",
- i, number_alloc_list, buf, size, file, line,
- function);
-
- n++;
- return buf;
-}
-
-char *
-dbg_strdup(char *str, char *file, char *function, int line)
-{
- void *buf;
- int i = 0;
- long check;
- long size;
-
- size = strlen(str) + 1;
- buf = zalloc(size + sizeof (long));
- strcat(buf, str);
-
- check = 0xa5a5 + size;
- *(long *) ((char *) buf + size) = check;
-
- while (i < number_alloc_list) {
- if (alloc_list[i].type == 0)
- break;
- i++;
- }
-
- if (i == number_alloc_list)
- number_alloc_list++;
-
- assert(number_alloc_list < MAX_ALLOC_LIST);
-
- alloc_list[i].ptr = buf;
- alloc_list[i].size = size;
- alloc_list[i].file = file;
- alloc_list[i].func = function;
- alloc_list[i].line = line;
- alloc_list[i].csum = check;
- alloc_list[i].type = 9;
-
- if (debug & 1)
- printf("strdup[%3d:%3d], %p, %4ld at %s, %3d, %s\n",
- i, number_alloc_list, buf, size, file, line,
- function);
-
- n++;
- return buf;
-}
-
-
-
-/* Display a buffer into a HEXA formatted output */
-static void
-dump_buffer(char *buff, int count)
-{
- int i, j, c;
- int printnext = 1;
-
- if (count % 16)
- c = count + (16 - count % 16);
- else
- c = count;
-
- for (i = 0; i < c; i++) {
- if (printnext) {
- printnext--;
- printf("%.4x ", i & 0xffff);
- }
- if (i < count)
- printf("%3.2x", buff[i] & 0xff);
- else
- printf(" ");
- if (!((i + 1) % 8)) {
- if ((i + 1) % 16)
- printf(" -");
- else {
- printf(" ");
- for (j = i - 15; j <= i; j++)
- if (j < count) {
- if ((buff[j] & 0xff) >= 0x20
- && (buff[j] & 0xff) <= 0x7e)
- printf("%c",
- buff[j] & 0xff);
- else
- printf(".");
- } else
- printf(" ");
- printf("\n");
- printnext = 1;
- }
- }
- }
-}
-
-int
-dbg_free(void *buffer, char *file, char *function, int line)
-{
- int i = 0;
- void *buf;
-
- /* If nullpointer remember */
- if (buffer == NULL) {
- i = number_alloc_list++;
-
- assert(number_alloc_list < MAX_ALLOC_LIST);
-
- alloc_list[i].ptr = buffer;
- alloc_list[i].size = 0;
- alloc_list[i].file = file;
- alloc_list[i].func = function;
- alloc_list[i].line = line;
- alloc_list[i].type = 2;
- if (debug & 1)
- printf("free NULL in %s, %3d, %s\n", file,
- line, function);
-
- debug |= 512; /* Memory Error detect */
-
- return n;
- } else
- buf = buffer;
-
- while (i < number_alloc_list) {
- if (alloc_list[i].type == 9 && alloc_list[i].ptr == buf) {
- if (*
- ((long *) ((char *) alloc_list[i].ptr +
- alloc_list[i].size)) ==
- alloc_list[i].csum)
- alloc_list[i].type = 0; /* Release */
- else {
- alloc_list[i].type = 1; /* Overrun */
- if (debug & 1) {
- printf("free corrupt, buffer overrun [%3d:%3d], %p, %4ld at %s, %3d, %s\n",
- i, number_alloc_list,
- buf, alloc_list[i].size, file,
- line, function);
- dump_buffer(alloc_list[i].ptr,
- alloc_list[i].size + sizeof (long));
- printf("Check_sum\n");
- dump_buffer((char *) &alloc_list[i].csum,
- sizeof(long));
-
- debug |= 512; /* Memory Error detect */
- }
- }
- break;
- }
- i++;
- }
-
- /* Not found */
- if (i == number_alloc_list) {
- printf("Free ERROR %p\n", buffer);
- number_alloc_list++;
-
- assert(number_alloc_list < MAX_ALLOC_LIST);
-
- alloc_list[i].ptr = buf;
- alloc_list[i].size = 0;
- alloc_list[i].file = file;
- alloc_list[i].func = function;
- alloc_list[i].line = line;
- alloc_list[i].type = 4;
- debug |= 512;
-
- return n;
- }
-
- if (buffer != NULL)
- xfree(buffer);
-
- if (debug & 1)
- printf("free [%3d:%3d], %p, %4ld at %s, %3d, %s\n",
- i, number_alloc_list, buf,
- alloc_list[i].size, file, line, function);
-
- free_list[f].file = file;
- free_list[f].line = line;
- free_list[f].func = function;
- free_list[f].ptr = buffer;
- free_list[f].type = 8;
- free_list[f].csum = i; /* Using this field for row id */
-
- f++;
- f &= 255;
- n--;
-
- return n;
-}
-
-void
-dbg_free_final(char *banner)
-{
- unsigned int sum = 0, overrun = 0, badptr = 0;
- int i, j;
- i = 0;
-
- printf("\n---[ Memory dump for (%s)]---\n\n", banner);
-
- while (i < number_alloc_list) {
- switch (alloc_list[i].type) {
- case 3:
- badptr++;
- printf
- ("null pointer to realloc(nil,%ld)! at %s, %3d, %s\n",
- alloc_list[i].size, alloc_list[i].file,
- alloc_list[i].line, alloc_list[i].func);
- break;
- case 4:
- badptr++;
- printf
- ("pointer not found in table to free(%p) [%3d:%3d], at %s, %3d, %s\n",
- alloc_list[i].ptr, i, number_alloc_list,
- alloc_list[i].file, alloc_list[i].line,
- alloc_list[i].func);
- for (j = 0; j < 256; j++)
- if (free_list[j].ptr == alloc_list[i].ptr)
- if (free_list[j].type == 8)
- printf
- (" -> pointer already released at [%3d:%3d], at %s, %3d, %s\n",
- (int) free_list[j].csum,
- number_alloc_list,
- free_list[j].file,
- free_list[j].line,
- free_list[j].func);
- break;
- case 2:
- badptr++;
- printf("null pointer to free(nil)! at %s, %3d, %s\n",
- alloc_list[i].file, alloc_list[i].line,
- alloc_list[i].func);
- break;
- case 1:
- overrun++;
- printf("%p [%3d:%3d], %4ld buffer overrun!:\n",
- alloc_list[i].ptr, i, number_alloc_list,
- alloc_list[i].size);
- printf(" --> source of malloc: %s, %3d, %s\n",
- alloc_list[i].file, alloc_list[i].line,
- alloc_list[i].func);
- break;
- case 9:
- sum += alloc_list[i].size;
- printf("%p [%3d:%3d], %4ld not released!:\n",
- alloc_list[i].ptr, i, number_alloc_list,
- alloc_list[i].size);
- printf(" --> source of malloc: %s, %3d, %s\n",
- alloc_list[i].file, alloc_list[i].line,
- alloc_list[i].func);
- break;
- }
- i++;
- }
-
- printf("\n\n---[ Memory dump summary for (%s) ]---\n", banner);
- printf("Total number of bytes not freed...: %d\n", sum);
- printf("Number of entries not freed.......: %d\n", n);
- printf("Maximum allocated entries.........: %d\n", number_alloc_list);
- printf("Number of bad entries.............: %d\n", badptr);
- printf("Number of buffer overrun..........: %d\n\n", overrun);
-
- if (sum || n || badptr || overrun)
- printf("=> Program seems to have some memory problem !!!\n\n");
- else
- printf("=> Program seems to be memory allocation safe...\n\n");
-}
-
-void *
-dbg_realloc(void *buffer, unsigned long size, char *file, char *function,
- int line)
-{
- int i = 0;
- void *buf, *buf2;
- long check;
-
- if (buffer == NULL) {
- printf("realloc %p %s, %3d %s\n", buffer, file, line, function);
- i = number_alloc_list++;
-
- assert(number_alloc_list < MAX_ALLOC_LIST);
-
- alloc_list[i].ptr = NULL;
- alloc_list[i].size = 0;
- alloc_list[i].file = file;
- alloc_list[i].func = function;
- alloc_list[i].line = line;
- alloc_list[i].type = 3;
- return dbg_malloc(size, file, function, line);
- }
-
- buf = buffer;
-
- while (i < number_alloc_list) {
- if (alloc_list[i].ptr == buf) {
- buf = alloc_list[i].ptr;
- break;
- }
- i++;
- }
-
- /* not found */
- if (i == number_alloc_list) {
- printf("realloc ERROR no matching zalloc %p \n", buffer);
- number_alloc_list++;
-
- assert(number_alloc_list < MAX_ALLOC_LIST);
-
- alloc_list[i].ptr = buf;
- alloc_list[i].size = 0;
- alloc_list[i].file = file;
- alloc_list[i].func = function;
- alloc_list[i].line = line;
- alloc_list[i].type = 9;
- debug |= 512; /* Memory Error detect */
- return NULL;
- }
-
- buf2 = ((char *) buf) + alloc_list[i].size;
-
- if (*(long *) (buf2) != alloc_list[i].csum) {
- alloc_list[i].type = 1;
- debug |= 512; /* Memory Error detect */
- }
- buf = realloc(buffer, size + sizeof (long));
-
- check = 0xa5a5 + size;
- *(long *) ((char *) buf + size) = check;
- alloc_list[i].csum = check;
-
- if (debug & 1)
- printf("realloc [%3d:%3d] %p, %4ld %s %d %s -> %p %4ld %s %d %s\n",
- i, number_alloc_list, alloc_list[i].ptr,
- alloc_list[i].size, alloc_list[i].file, alloc_list[i].line, alloc_list[i].func,
- buf, size, file, line, function);
-
- alloc_list[i].ptr = buf;
- alloc_list[i].size = size;
- alloc_list[i].file = file;
- alloc_list[i].line = line;
- alloc_list[i].func = function;
-
- return buf;
-}
-
-#endif
+++ /dev/null
-/*
- * Part: memory.c include file.
- *
- * Version: $Id: memory.h,v 1.1.11 2005/03/01 01:22:13 acassen Exp $
- *
- * Authors: Alexandre Cassen, <acassen@linux-vs.org>
- * Jan Holmberg, <jan@artech.net>
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Copyright (C) 2001-2005 Alexandre Cassen, <acassen@linux-vs.org>
- */
-
-#ifndef _MEMORY_H
-#define _MEMORY_H
-
-/* system includes */
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Local defines */
-#ifdef _DEBUG_
-
-int debug;
-
-#define MAX_ALLOC_LIST 2048
-
-#define MALLOC(n) ( dbg_malloc((n), \
- (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
-#define FREE(b) ( dbg_free((b), \
- (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
-#define REALLOC(b,n) ( dbg_realloc((b), (n), \
- (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
-#define STRDUP(n) ( dbg_strdup((n), \
- (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
-
-/* Memory debug prototypes defs */
-extern void *dbg_malloc(unsigned long, char *, char *, int);
-extern int dbg_free(void *, char *, char *, int);
-extern void *dbg_realloc(void *, unsigned long, char *, char *, int);
-extern char *dbg_strdup(char *, char *, char *, int);
-extern void dbg_free_final(char *);
-
-#else
-
-#define MALLOC(n) (calloc(1,(n)))
-#define FREE(p) do { free(p); p = NULL; } while(0)
-#define REALLOC(p,n) (realloc((p),(n)))
-#define STRDUP(n) (strdup(n))
-
-#endif
-
-/* Common defines */
-#define FREE_PTR(P) if((P)) FREE((P));
-
-#endif
#include "vector.h"
#include "config.h"
#include "parser.h"
-#include "memory.h"
#include "debug.h"
#include "strbuf.h"
int
keyword_alloc(vector keywords, char *string,
- int (*handler) (struct config *, vector),
+ handler_fn *handler,
print_fn *print,
int unique)
{
struct keyword *keyword;
- keyword = (struct keyword *) MALLOC(sizeof (struct keyword));
+ keyword = (struct keyword *)calloc(1, sizeof (struct keyword));
if (!keyword)
return 1;
if (!vector_alloc_slot(keywords)) {
- FREE(keyword);
+ free(keyword);
return 1;
}
keyword->string = string;
int
_install_keyword(vector keywords, char *string,
- int (*handler) (struct config *, vector),
+ handler_fn *handler,
print_fn *print,
int unique)
{
keyword = VECTOR_SLOT(keywords, i);
if (keyword->sub)
free_keywords(keyword->sub);
- FREE(keyword);
+ free(keyword);
}
vector_free(keywords);
}
start = cp;
if (*cp == '"' && !(in_string && *(cp + 1) == '"')) {
cp++;
- token = MALLOC(sizeof(quote_marker));
+ token = calloc(1, sizeof(quote_marker));
if (!token)
goto out;
else
in_string = 1;
} else if (!in_string && (*cp == '{' || *cp == '}')) {
- token = MALLOC(2);
+ token = malloc(2);
if (!token)
goto out;
}
strlen = cp - start;
- token = MALLOC(strlen + 1);
+ token = calloc(1, strlen + 1);
if (!token)
goto out;
(char *)VECTOR_SLOT(strvec, 0));
return NULL;
}
- alloc = MALLOC(sizeof (char) * (size + 1));
+ alloc = calloc(1, sizeof (char) * (size + 1));
if (alloc)
memcpy(alloc, str, size);
else
return alloc;
}
/* Even empty quotes counts as a value (An empty string) */
- alloc = (char *) MALLOC(sizeof (char));
+ alloc = (char *)calloc(1, sizeof (char));
if (!alloc)
goto oom;
for (i = 2; i < VECTOR_SIZE(strvec); i++) {
/* The first +1 is for the NULL byte. The rest are for the
* spaces between words */
len += strlen(str) + 1;
- alloc = REALLOC(alloc, sizeof (char) * len);
+ alloc = realloc(alloc, sizeof (char) * len);
if (!alloc) {
- FREE(tmp);
+ free(tmp);
goto oom;
}
if (*alloc != '\0')
static int
process_stream(struct config *conf, FILE *stream, vector keywords,
- const char *file)
+ const char *section, const char *file)
{
int i;
int r = 0, t;
if (!uniques)
return 1;
- buf = MALLOC(MAXBUF);
+ buf = calloc(1, MAXBUF);
if (!buf) {
vector_free(uniques);
goto out;
}
if (keyword->handler) {
- t = (*keyword->handler) (conf, strvec);
+ t = keyword->handler(conf, strvec, file,
+ line_nr);
r += t;
if (t)
- condlog(1, "multipath.conf +%d, parsing failed: %s",
- line_nr, buf);
+ condlog(1, "%s line %d, parsing failed: %s",
+ file, line_nr, buf);
}
if (keyword->sub) {
kw_level++;
r += process_stream(conf, stream,
- keyword->sub, file);
+ keyword->sub,
+ keyword->string,
+ file);
kw_level--;
}
break;
}
}
- if (i >= VECTOR_SIZE(keywords))
- condlog(1, "%s line %d, invalid keyword: %s",
- file, line_nr, str);
-
+ if (i >= VECTOR_SIZE(keywords)) {
+ if (section)
+ condlog(1, "%s line %d, invalid keyword in the %s section: %s",
+ file, line_nr, section, str);
+ else
+ condlog(1, "%s line %d, invalid keyword: %s",
+ file, line_nr, str);
+ }
free_strvec(strvec);
}
if (kw_level == 1)
condlog(1, "missing '%s' at end of %s", EOB, file);
out:
- FREE(buf);
+ free(buf);
free_uniques(uniques);
return r;
}
/* Stream handling */
line_nr = 0;
- r = process_stream(conf, stream, conf->keywords, file);
+ r = process_stream(conf, stream, conf->keywords, NULL, file);
fclose(stream);
//free_keywords(keywords);
/* keyword definition */
typedef int print_fn(struct config *, struct strbuf *, const void *);
+typedef int handler_fn(struct config *, vector, const char *file, int line_nr);
struct keyword {
char *string;
- int (*handler) (struct config *, vector);
+ handler_fn *handler;
print_fn *print;
vector sub;
int unique;
for (i = 0; i < (k)->sub->allocated && ((p) = (k)->sub->slot[i]); i++)
/* Prototypes */
-extern int keyword_alloc(vector keywords, char *string,
- int (*handler) (struct config *, vector),
- print_fn *print,
- int unique);
+extern int keyword_alloc(vector keywords, char *string, handler_fn *handler,
+ print_fn *print, int unique);
#define install_keyword_root(str, h) keyword_alloc(keywords, str, h, NULL, 1)
extern void install_sublevel(void);
extern void install_sublevel_end(void);
-extern int _install_keyword(vector keywords, char *string,
- int (*handler) (struct config *, vector),
- print_fn *print,
- int unique);
+extern int _install_keyword(vector keywords, char *string, handler_fn *handler,
+ print_fn *print, int unique);
#define install_keyword(str, vec, pri) _install_keyword(keywords, str, vec, pri, 1)
#define install_keyword_multi(str, vec, pri) _install_keyword(keywords, str, vec, pri, 0)
extern void dump_keywords(vector keydump, int level);
#include "checkers.h"
#include "util.h"
-#include "memory.h"
#include "vector.h"
#include "structs.h"
#include "pgpolicies.h"
}
}
}
- FREE(bitmap);
+ free(bitmap);
return 0;
out2:
free_pathgroup(pgp, KEEP_PATHS);
out1:
- FREE(bitmap);
+ free(bitmap);
out:
free_pgvec(mp->pg, KEEP_PATHS);
mp->pg = NULL;
#define PROGRESS_LEN 10
+struct path_data {
+ char wildcard;
+ char * header;
+ int (*snprint)(struct strbuf *, const struct path * pp);
+};
+
+struct multipath_data {
+ char wildcard;
+ char * header;
+ int (*snprint)(struct strbuf *, const struct multipath * mpp);
+};
+
+struct pathgroup_data {
+ char wildcard;
+ char * header;
+ int (*snprint)(struct strbuf *, const struct pathgroup * pgp);
+};
+
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#define MIN(x,y) (((x) > (y)) ? (y) : (x))
/*
}
}
+static int snprint_initialized(struct strbuf *buff, const struct path * pp)
+{
+ static const char *init_state_name[] = {
+ [INIT_NEW] = "new",
+ [INIT_FAILED] = "failed",
+ [INIT_MISSING_UDEV] = "udev-missing",
+ [INIT_REQUESTED_UDEV] = "udev-requested",
+ [INIT_OK] = "ok",
+ [INIT_REMOVED] = "removed",
+ [INIT_PARTIAL] = "partial",
+ };
+ const char *str;
+
+ if (pp->initialized < INIT_NEW || pp->initialized >= __INIT_LAST)
+ str = "undef";
+ else
+ str = init_state_name[pp->initialized];
+ return append_strbuf_str(buff, str);
+}
+
static int
snprint_vpr (struct strbuf *buff, const struct path * pp)
{
}
}
-int
+static int
snprint_path_marginal(struct strbuf *buff, const struct path * pp)
{
if (pp->marginal)
return append_strbuf_str(buff, "[undef]");
}
-struct multipath_data mpd[] = {
- {'n', "name", 0, snprint_name},
- {'w', "uuid", 0, snprint_multipath_uuid},
- {'d', "sysfs", 0, snprint_sysfs},
- {'F', "failback", 0, snprint_failback},
- {'Q', "queueing", 0, snprint_queueing},
- {'N', "paths", 0, snprint_nb_paths},
- {'r', "write_prot", 0, snprint_ro},
- {'t', "dm-st", 0, snprint_dm_map_state},
- {'S', "size", 0, snprint_multipath_size},
- {'f', "features", 0, snprint_features},
- {'x', "failures", 0, snprint_map_failures},
- {'h', "hwhandler", 0, snprint_hwhandler},
- {'A', "action", 0, snprint_action},
- {'0', "path_faults", 0, snprint_path_faults},
- {'1', "switch_grp", 0, snprint_switch_grp},
- {'2', "map_loads", 0, snprint_map_loads},
- {'3', "total_q_time", 0, snprint_total_q_time},
- {'4', "q_timeouts", 0, snprint_q_timeouts},
- {'s', "vend/prod/rev", 0, snprint_multipath_vpr},
- {'v', "vend", 0, snprint_multipath_vend},
- {'p', "prod", 0, snprint_multipath_prod},
- {'e', "rev", 0, snprint_multipath_rev},
- {'G', "foreign", 0, snprint_multipath_foreign},
- {'g', "vpd page data", 0, snprint_multipath_vpd_data},
- {0, NULL, 0 , NULL}
+static const struct multipath_data mpd[] = {
+ {'n', "name", snprint_name},
+ {'w', "uuid", snprint_multipath_uuid},
+ {'d', "sysfs", snprint_sysfs},
+ {'F', "failback", snprint_failback},
+ {'Q', "queueing", snprint_queueing},
+ {'N', "paths", snprint_nb_paths},
+ {'r', "write_prot", snprint_ro},
+ {'t', "dm-st", snprint_dm_map_state},
+ {'S', "size", snprint_multipath_size},
+ {'f', "features", snprint_features},
+ {'x', "failures", snprint_map_failures},
+ {'h', "hwhandler", snprint_hwhandler},
+ {'A', "action", snprint_action},
+ {'0', "path_faults", snprint_path_faults},
+ {'1', "switch_grp", snprint_switch_grp},
+ {'2', "map_loads", snprint_map_loads},
+ {'3', "total_q_time", snprint_total_q_time},
+ {'4', "q_timeouts", snprint_q_timeouts},
+ {'s', "vend/prod/rev", snprint_multipath_vpr},
+ {'v', "vend", snprint_multipath_vend},
+ {'p', "prod", snprint_multipath_prod},
+ {'e', "rev", snprint_multipath_rev},
+ {'G', "foreign", snprint_multipath_foreign},
+ {'g', "vpd page data", snprint_multipath_vpd_data},
};
-struct path_data pd[] = {
- {'w', "uuid", 0, snprint_path_uuid},
- {'i', "hcil", 0, snprint_hcil},
- {'d', "dev", 0, snprint_dev},
- {'D', "dev_t", 0, snprint_dev_t},
- {'t', "dm_st", 0, snprint_dm_path_state},
- {'o', "dev_st", 0, snprint_offline},
- {'T', "chk_st", 0, snprint_chk_state},
- {'s', "vend/prod/rev", 0, snprint_vpr},
- {'c', "checker", 0, snprint_path_checker},
- {'C', "next_check", 0, snprint_next_check},
- {'p', "pri", 0, snprint_pri},
- {'S', "size", 0, snprint_path_size},
- {'z', "serial", 0, snprint_path_serial},
- {'M', "marginal_st", 0, snprint_path_marginal},
- {'m', "multipath", 0, snprint_path_mpp},
- {'N', "host WWNN", 0, snprint_host_wwnn},
- {'n', "target WWNN", 0, snprint_tgt_wwnn},
- {'R', "host WWPN", 0, snprint_host_wwpn},
- {'r', "target WWPN", 0, snprint_tgt_wwpn},
- {'a', "host adapter", 0, snprint_host_adapter},
- {'G', "foreign", 0, snprint_path_foreign},
- {'g', "vpd page data", 0, snprint_path_vpd_data},
- {'0', "failures", 0, snprint_path_failures},
- {'P', "protocol", 0, snprint_path_protocol},
- {0, NULL, 0 , NULL}
+static const struct path_data pd[] = {
+ {'w', "uuid", snprint_path_uuid},
+ {'i', "hcil", snprint_hcil},
+ {'d', "dev", snprint_dev},
+ {'D', "dev_t", snprint_dev_t},
+ {'t', "dm_st", snprint_dm_path_state},
+ {'o', "dev_st", snprint_offline},
+ {'T', "chk_st", snprint_chk_state},
+ {'s', "vend/prod/rev", snprint_vpr},
+ {'c', "checker", snprint_path_checker},
+ {'C', "next_check", snprint_next_check},
+ {'p', "pri", snprint_pri},
+ {'S', "size", snprint_path_size},
+ {'z', "serial", snprint_path_serial},
+ {'M', "marginal_st", snprint_path_marginal},
+ {'m', "multipath", snprint_path_mpp},
+ {'N', "host WWNN", snprint_host_wwnn},
+ {'n', "target WWNN", snprint_tgt_wwnn},
+ {'R', "host WWPN", snprint_host_wwpn},
+ {'r', "target WWPN", snprint_tgt_wwpn},
+ {'a', "host adapter", snprint_host_adapter},
+ {'G', "foreign", snprint_path_foreign},
+ {'g', "vpd page data", snprint_path_vpd_data},
+ {'0', "failures", snprint_path_failures},
+ {'P', "protocol", snprint_path_protocol},
+ {'I', "init_st", snprint_initialized},
};
-struct pathgroup_data pgd[] = {
- {'s', "selector", 0, snprint_pg_selector},
- {'p', "pri", 0, snprint_pg_pri},
- {'t', "dm_st", 0, snprint_pg_state},
- {'M', "marginal_st", 0, snprint_pg_marginal},
- {0, NULL, 0 , NULL}
+static const struct pathgroup_data pgd[] = {
+ {'s', "selector", snprint_pg_selector},
+ {'p', "pri", snprint_pg_pri},
+ {'t', "dm_st", snprint_pg_state},
+ {'M', "marginal_st", snprint_pg_marginal},
};
int snprint_wildcards(struct strbuf *buff)
{
int initial_len = get_strbuf_len(buff);
- int i, rc;
+ unsigned int i;
+ int rc;
if ((rc = append_strbuf_str(buff, "multipath format wildcards:\n")) < 0)
return rc;
- for (i = 0; mpd[i].header; i++)
+ for (i = 0; i < ARRAY_SIZE(mpd); i++)
if ((rc = print_strbuf(buff, "%%%c %s\n",
mpd[i].wildcard, mpd[i].header)) < 0)
return rc;
if ((rc = append_strbuf_str(buff, "\npath format wildcards:\n")) < 0)
return rc;
- for (i = 0; pd[i].header; i++)
+ for (i = 0; i < ARRAY_SIZE(pd); i++)
if ((rc = print_strbuf(buff, "%%%c %s\n",
pd[i].wildcard, pd[i].header)) < 0)
return rc;
if ((rc = append_strbuf_str(buff, "\npathgroup format wildcards:\n")) < 0)
return rc;
- for (i = 0; pgd[i].header; i++)
+ for (i = 0; i < ARRAY_SIZE(pgd); i++)
if ((rc = print_strbuf(buff, "%%%c %s\n",
pgd[i].wildcard, pgd[i].header)) < 0)
return rc;
return get_strbuf_len(buff) - initial_len;
}
-void
-get_path_layout(vector pathvec, int header)
+fieldwidth_t *alloc_path_layout(void) {
+ return calloc(ARRAY_SIZE(pd), sizeof(fieldwidth_t));
+}
+
+void get_path_layout(vector pathvec, int header, fieldwidth_t *width)
{
vector gpvec = vector_convert(NULL, pathvec, struct path,
dm_path_to_gen);
_get_path_layout(gpvec,
- header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
+ header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO,
+ width);
vector_free(gpvec);
}
static void
-reset_width(unsigned int *width, enum layout_reset reset, const char *header)
+reset_width(fieldwidth_t *width, enum layout_reset reset, const char *header)
{
switch (reset) {
case LAYOUT_RESET_HEADER:
}
}
-void
-_get_path_layout (const struct _vector *gpvec, enum layout_reset reset)
+void _get_path_layout (const struct _vector *gpvec, enum layout_reset reset,
+ fieldwidth_t *width)
{
- int i, j;
+ unsigned int i, j;
const struct gen_path *gp;
- for (j = 0; pd[j].header; j++) {
+ if (width == NULL)
+ return;
+
+ for (j = 0; j < ARRAY_SIZE(pd); j++) {
STRBUF_ON_STACK(buff);
- reset_width(&pd[j].width, reset, pd[j].header);
+ reset_width(&width[j], reset, pd[j].header);
if (gpvec == NULL)
continue;
vector_foreach_slot (gpvec, gp, i) {
gp->ops->snprint(gp, &buff, pd[j].wildcard);
- pd[j].width = MAX(pd[j].width, get_strbuf_len(&buff));
+ width[j] = MAX(width[j],
+ MIN(get_strbuf_len(&buff), MAX_FIELD_WIDTH));
truncate_strbuf(&buff, 0);
}
}
}
-static void
-reset_multipath_layout (void)
-{
- int i;
+fieldwidth_t *alloc_multipath_layout(void) {
- for (i = 0; mpd[i].header; i++)
- mpd[i].width = 0;
+ return calloc(ARRAY_SIZE(mpd), sizeof(fieldwidth_t));
}
-void
-get_multipath_layout (vector mpvec, int header) {
+void get_multipath_layout (vector mpvec, int header, fieldwidth_t *width) {
vector gmvec = vector_convert(NULL, mpvec, struct multipath,
dm_multipath_to_gen);
_get_multipath_layout(gmvec,
- header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
+ header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO,
+ width);
vector_free(gmvec);
}
void
-_get_multipath_layout (const struct _vector *gmvec,
- enum layout_reset reset)
+_get_multipath_layout (const struct _vector *gmvec, enum layout_reset reset,
+ fieldwidth_t *width)
{
- int i, j;
+ unsigned int i, j;
const struct gen_multipath * gm;
- for (j = 0; mpd[j].header; j++) {
+ if (width == NULL)
+ return;
+ for (j = 0; j < ARRAY_SIZE(mpd); j++) {
STRBUF_ON_STACK(buff);
- reset_width(&mpd[j].width, reset, mpd[j].header);
+ reset_width(&width[j], reset, mpd[j].header);
if (gmvec == NULL)
continue;
vector_foreach_slot (gmvec, gm, i) {
gm->ops->snprint(gm, &buff, mpd[j].wildcard);
- mpd[j].width = MAX(mpd[j].width, get_strbuf_len(&buff));
+ width[j] = MAX(width[j],
+ MIN(get_strbuf_len(&buff), MAX_FIELD_WIDTH));
truncate_strbuf(&buff, 0);
}
- condlog(4, "%s: width %d", mpd[j].header, mpd[j].width);
+ condlog(4, "%s: width %d", mpd[j].header, width[j]);
}
}
-static struct multipath_data *
-mpd_lookup(char wildcard)
+static int mpd_lookup(char wildcard)
{
- int i;
+ unsigned int i;
- for (i = 0; mpd[i].header; i++)
+ for (i = 0; i < ARRAY_SIZE(mpd); i++)
if (mpd[i].wildcard == wildcard)
- return &mpd[i];
+ return i;
- return NULL;
+ return -1;
}
int snprint_multipath_attr(const struct gen_multipath* gm,
struct strbuf *buf, char wildcard)
{
const struct multipath *mpp = gen_multipath_to_dm(gm);
- struct multipath_data *mpd = mpd_lookup(wildcard);
+ int i = mpd_lookup(wildcard);
- if (mpd == NULL)
+ if (i == -1)
return 0;
- return mpd->snprint(buf, mpp);
+ return mpd[i].snprint(buf, mpp);
}
-static struct path_data *
-pd_lookup(char wildcard)
+static int pd_lookup(char wildcard)
{
- int i;
+ unsigned int i;
- for (i = 0; pd[i].header; i++)
+ for (i = 0; i < ARRAY_SIZE(pd); i++)
if (pd[i].wildcard == wildcard)
- return &pd[i];
+ return i;
- return NULL;
+ return -1;
}
int snprint_path_attr(const struct gen_path* gp,
struct strbuf *buf, char wildcard)
{
const struct path *pp = gen_path_to_dm(gp);
- struct path_data *pd = pd_lookup(wildcard);
+ int i = pd_lookup(wildcard);
- if (pd == NULL)
+ if (i == -1)
return 0;
- return pd->snprint(buf, pp);
+ return pd[i].snprint(buf, pp);
}
-static struct pathgroup_data *
-pgd_lookup(char wildcard)
+static int pgd_lookup(char wildcard)
{
- int i;
+ unsigned int i;
- for (i = 0; pgd[i].header; i++)
+ for (i = 0; i < ARRAY_SIZE(pgd); i++)
if (pgd[i].wildcard == wildcard)
- return &pgd[i];
+ return i;
- return NULL;
+ return -1;
}
int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
struct strbuf *buf, char wildcard)
{
const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
- struct pathgroup_data *pdg = pgd_lookup(wildcard);
+ int i = pgd_lookup(wildcard);
- if (pdg == NULL)
+ if (i == -1)
return 0;
- return pdg->snprint(buf, pg);
+ return pgd[i].snprint(buf, pg);
}
-int snprint_multipath_header(struct strbuf *line, const char *format)
+int snprint_multipath_header(struct strbuf *line, const char *format,
+ const fieldwidth_t *width)
{
int initial_len = get_strbuf_len(line);
const char *f;
- struct multipath_data * data;
+ const struct multipath_data * data;
int rc;
for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
+ int iwc;
+
if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
return rc;
format = f + 1;
- if (!(data = mpd_lookup(*format)))
+ if ((iwc = mpd_lookup(*format)) == -1)
continue; /* unknown wildcard */
+ data = &mpd[iwc];
if ((rc = append_strbuf_str(line, data->header)) < 0)
return rc;
- else if ((unsigned int)rc < data->width)
- if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
+ else if ((unsigned int)rc < width[iwc])
+ if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
return rc;
}
}
int _snprint_multipath(const struct gen_multipath *gmp,
- struct strbuf *line, const char *format, int pad)
+ struct strbuf *line, const char *format,
+ const fieldwidth_t *width)
{
int initial_len = get_strbuf_len(line);
const char *f;
- struct multipath_data * data;
int rc;
for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
+ int iwc;
+
if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
return rc;
format = f + 1;
- if (!(data = mpd_lookup(*format)))
+ if ((iwc = mpd_lookup(*format)) == -1)
continue; /* unknown wildcard */
if ((rc = gmp->ops->snprint(gmp, line, *format)) < 0)
return rc;
- else if (pad && (unsigned int)rc < data->width)
- if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
+ else if (width != NULL && (unsigned int)rc < width[iwc])
+ if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
return rc;
}
return get_strbuf_len(line) - initial_len;
}
-int snprint_path_header(struct strbuf *line, const char *format)
+int snprint_path_header(struct strbuf *line, const char *format,
+ const fieldwidth_t *width)
{
int initial_len = get_strbuf_len(line);
const char *f;
- struct path_data *data;
+ const struct path_data *data;
int rc;
for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
+ int iwc;
+
if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
return rc;
format = f + 1;
- if (!(data = pd_lookup(*format)))
+ if ((iwc = pd_lookup(*format)) == -1)
continue; /* unknown wildcard */
+ data = &pd[iwc];
if ((rc = append_strbuf_str(line, data->header)) < 0)
return rc;
- else if ((unsigned int)rc < data->width)
- if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
+ else if ((unsigned int)rc < width[iwc])
+ if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
return rc;
}
}
int _snprint_path(const struct gen_path *gp, struct strbuf *line,
- const char *format, int pad)
+ const char *format, const fieldwidth_t *width)
{
int initial_len = get_strbuf_len(line);
const char *f;
- struct path_data * data;
int rc;
for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
+ int iwc;
+
if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
return rc;
format = f + 1;
- if (!(data = pd_lookup(*format)))
+ if ((iwc = pd_lookup(*format)) == -1)
continue; /* unknown wildcard */
if ((rc = gp->ops->snprint(gp, line, *format)) < 0)
return rc;
- else if (pad && (unsigned int)rc < data->width)
- if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
+ else if (width != NULL && (unsigned int)rc < width[iwc])
+ if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
return rc;
}
{
int initial_len = get_strbuf_len(line);
const char *f;
- struct pathgroup_data *data;
int rc;
for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
return rc;
format = f + 1;
- if (!(data = pgd_lookup(*format)))
- continue; /* unknown wildcard */
if ((rc = ggp->ops->snprint(ggp, line, *format)) < 0)
return rc;
- else if ((unsigned int)rc < data->width)
- if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
- return rc;
}
if ((rc = print_strbuf(line, "%s\n", format)) < 0)
void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
{
STRBUF_ON_STACK(buff);
+ fieldwidth_t *p_width __attribute__((cleanup(cleanup_ucharp))) = NULL;
+ const struct gen_pathgroup *gpg;
+ const struct _vector *pgvec, *pathvec;
+ int j;
+
+ p_width = alloc_path_layout();
+ pgvec = gmp->ops->get_pathgroups(gmp);
- _snprint_multipath_topology(gmp, &buff, verbosity);
+ if (pgvec != NULL) {
+ vector_foreach_slot (pgvec, gpg, j) {
+ pathvec = gpg->ops->get_paths(gpg);
+ if (pathvec == NULL)
+ continue;
+ _get_path_layout(pathvec, LAYOUT_RESET_NOT, p_width);
+ gpg->ops->rel_paths(gpg, pathvec);
+ }
+ gmp->ops->rel_pathgroups(gmp, pgvec);
+ }
+
+ _snprint_multipath_topology(gmp, &buff, verbosity, p_width);
printf("%s", get_strbuf_str(&buff));
}
}
int _snprint_multipath_topology(const struct gen_multipath *gmp,
- struct strbuf *buff, int verbosity)
+ struct strbuf *buff, int verbosity,
+ const fieldwidth_t *p_width)
{
int j, i, rc;
const struct _vector *pgvec;
const struct gen_pathgroup *gpg;
STRBUF_ON_STACK(style);
size_t initial_len = get_strbuf_len(buff);
+ fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
if (verbosity <= 0)
return 0;
- reset_multipath_layout();
+ if ((width = alloc_multipath_layout()) == NULL)
+ return -ENOMEM;
if (verbosity == 1)
- return _snprint_multipath(gmp, buff, "%n", 1);
+ return _snprint_multipath(gmp, buff, "%n", width);
if(isatty(1) &&
(rc = print_strbuf(&style, "%c[%dm", 0x1B, 1)) < 0) /* bold on */
(rc = print_strbuf(&style, "%c[%dm", 0x1B, 0)) < 0) /* bold off */
return rc;
- if ((rc = _snprint_multipath(gmp, buff, get_strbuf_str(&style), 1)) < 0
- || (rc = _snprint_multipath(gmp, buff, PRINT_MAP_PROPS, 1)) < 0)
+ if ((rc = _snprint_multipath(gmp, buff, get_strbuf_str(&style), width)) < 0
+ || (rc = _snprint_multipath(gmp, buff, PRINT_MAP_PROPS, width)) < 0)
return rc;
pgvec = gmp->ops->get_pathgroups(gmp);
i + 1 == VECTOR_SIZE(pathvec) ?
'`': '|')) < 0 ||
(rc = _snprint_path(gp, buff,
- PRINT_PATH_INDENT, 1)) < 0)
+ PRINT_PATH_INDENT, p_width)) < 0)
return rc;
}
gpg->ops->rel_paths(gpg, pathvec);
return get_strbuf_len(buff) - initial_len;
}
-char *snprint_config(const struct config *conf, int *len,
+int __snprint_config(const struct config *conf, struct strbuf *buff,
const struct _vector *hwtable, const struct _vector *mpvec)
{
- STRBUF_ON_STACK(buff);
- char *reply;
int rc;
- if ((rc = snprint_defaults(conf, &buff)) < 0 ||
- (rc = snprint_blacklist(conf, &buff)) < 0 ||
- (rc = snprint_blacklist_except(conf, &buff)) < 0 ||
- (rc = snprint_hwtable(conf, &buff,
+ if ((rc = snprint_defaults(conf, buff)) < 0 ||
+ (rc = snprint_blacklist(conf, buff)) < 0 ||
+ (rc = snprint_blacklist_except(conf, buff)) < 0 ||
+ (rc = snprint_hwtable(conf, buff,
hwtable ? hwtable : conf->hwtable)) < 0 ||
- (rc = snprint_overrides(conf, &buff, conf->overrides)) < 0)
- return NULL;
+ (rc = snprint_overrides(conf, buff, conf->overrides)) < 0)
+ return rc;
+
if (VECTOR_SIZE(conf->mptable) > 0 ||
(mpvec != NULL && VECTOR_SIZE(mpvec) > 0))
- if ((rc = snprint_mptable(conf, &buff, mpvec)) < 0)
- return NULL;
+ if ((rc = snprint_mptable(conf, buff, mpvec)) < 0)
+ return rc;
+
+ return 0;
+}
+
+char *snprint_config(const struct config *conf, int *len,
+ const struct _vector *hwtable, const struct _vector *mpvec)
+{
+ STRBUF_ON_STACK(buff);
+ char *reply;
+ int rc = __snprint_config(conf, &buff, hwtable, mpvec);
+
+ if (rc < 0)
+ return NULL;
if (len)
*len = get_strbuf_len(&buff);
int i;
struct path * pp;
STRBUF_ON_STACK(line);
+ fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
if (!VECTOR_SIZE(pathvec)) {
if (banner)
return;
}
+ if ((width = alloc_path_layout()) == NULL)
+ return;
+ get_path_layout(pathvec, 1, width);
+
if (banner)
append_strbuf_str(&line, "===== paths list =====\n");
- get_path_layout(pathvec, 1);
- snprint_path_header(&line, fmt);
+ snprint_path_header(&line, fmt, width);
vector_foreach_slot (pathvec, pp, i)
- snprint_path(&line, fmt, pp, 1);
+ snprint_path(&line, fmt, pp, width);
printf("%s", get_strbuf_str(&line));
}
struct strbuf;
-struct path_data {
- char wildcard;
- char * header;
- unsigned int width;
- int (*snprint)(struct strbuf *, const struct path * pp);
-};
-
-struct multipath_data {
- char wildcard;
- char * header;
- unsigned int width;
- int (*snprint)(struct strbuf *, const struct multipath * mpp);
-};
-
-struct pathgroup_data {
- char wildcard;
- char * header;
- unsigned int width;
- int (*snprint)(struct strbuf *, const struct pathgroup * pgp);
-};
-
enum layout_reset {
LAYOUT_RESET_NOT,
LAYOUT_RESET_ZERO,
LAYOUT_RESET_HEADER,
};
-void _get_path_layout (const struct _vector *gpvec, enum layout_reset);
-void get_path_layout (vector pathvec, int header);
-void _get_multipath_layout (const struct _vector *gmvec, enum layout_reset);
-void get_multipath_layout (vector mpvec, int header);
-int snprint_path_header(struct strbuf *, const char *);
-int snprint_multipath_header(struct strbuf *, const char *);
-int _snprint_path (const struct gen_path *, struct strbuf *, const char *, int);
-#define snprint_path(buf, fmt, pp, v) \
- _snprint_path(dm_path_to_gen(pp), buf, fmt, v)
+/* fieldwidth_t is defined in generic.h */
+fieldwidth_t *alloc_path_layout(void);
+void _get_path_layout (const struct _vector *gpvec, enum layout_reset,
+ fieldwidth_t *width);
+void get_path_layout (vector pathvec, int header, fieldwidth_t *width);
+fieldwidth_t *alloc_multipath_layout(void);
+void _get_multipath_layout (const struct _vector *gmvec, enum layout_reset,
+ fieldwidth_t *width);
+void get_multipath_layout (vector mpvec, int header, fieldwidth_t *width);
+int snprint_path_header(struct strbuf *, const char *, const fieldwidth_t *);
+int snprint_multipath_header(struct strbuf *, const char *,
+ const fieldwidth_t *);
+int _snprint_path (const struct gen_path *, struct strbuf *, const char *,
+ const fieldwidth_t *);
+#define snprint_path(buf, fmt, pp, w) \
+ _snprint_path(dm_path_to_gen(pp), buf, fmt, w)
int _snprint_multipath (const struct gen_multipath *, struct strbuf *,
- const char *, int);
-#define snprint_multipath(buf, fmt, mp, v) \
- _snprint_multipath(dm_multipath_to_gen(mp), buf, fmt, v)
+ const char *, const fieldwidth_t *);
+#define snprint_multipath(buf, fmt, mp, w) \
+ _snprint_multipath(dm_multipath_to_gen(mp), buf, fmt, w)
int _snprint_multipath_topology (const struct gen_multipath *, struct strbuf *,
- int verbosity);
-#define snprint_multipath_topology(buf, mpp, v) \
- _snprint_multipath_topology (dm_multipath_to_gen(mpp), buf, v)
+ int verbosity, const fieldwidth_t *);
+#define snprint_multipath_topology(buf, mpp, v, w) \
+ _snprint_multipath_topology (dm_multipath_to_gen(mpp), buf, v, w)
int snprint_multipath_topology_json(struct strbuf *, const struct vectors *vecs);
+int __snprint_config(const struct config *conf, struct strbuf *buff,
+ const struct _vector *hwtable, const struct _vector *mpvec);
char *snprint_config(const struct config *conf, int *len,
const struct _vector *hwtable,
const struct _vector *mpvec);
{
struct prio *p;
- p = MALLOC(sizeof(struct prio));
+ p = calloc(1, sizeof(struct prio));
if (p) {
INIT_LIST_HEAD(&p->node);
p->refcount = 1;
p->name, dlerror());
}
}
- FREE(p);
+ free(p);
}
void cleanup_prio(void)
struct path;
#include "list.h"
-#include "memory.h"
#include "defaults.h"
/*
#include "../structs.h"
#include "../prio.h"
#include "../discovery.h"
-#include "../unaligned.h"
#include "../debug.h"
#include "alua_rtpg.h"
get_target_port_group(const struct path * pp, unsigned int timeout)
{
unsigned char *buf;
- struct vpd83_data * vpd83;
- struct vpd83_dscr * dscr;
+ const struct vpd83_data * vpd83;
+ const struct vpd83_dscr * dscr;
int rc;
int buflen, scsi_buflen;
- buflen = 4096;
+ buflen = VPD_BUFLEN;
buf = (unsigned char *)malloc(buflen);
if (!buf) {
PRINT_DEBUG("malloc failed: could not allocate"
rc = -RTPG_NO_TPG_IDENTIFIER;
FOR_EACH_VPD83_DSCR(vpd83, dscr) {
if (vpd83_dscr_istype(dscr, IDTYPE_TARGET_PORT_GROUP)) {
- struct vpd83_tpg_dscr *p;
+ const struct vpd83_tpg_dscr *p;
if (rc != -RTPG_NO_TPG_IDENTIFIER) {
PRINT_DEBUG("get_target_port_group: more "
"than one TPG identifier found!");
continue;
}
- p = (struct vpd83_tpg_dscr *)dscr->data;
+ p = (const struct vpd83_tpg_dscr *)dscr->data;
rc = get_unaligned_be16(p->tpg);
}
}
uint64_t scsi_buflen;
int fd = pp->fd;
- buflen = 4096;
+ buflen = VPD_BUFLEN;
buf = (unsigned char *)malloc(buflen);
if (!buf) {
PRINT_DEBUG ("malloc failed: could not allocate"
*/
#ifndef __SPC3_H__
#define __SPC3_H__
+#include "../unaligned.h"
/*=============================================================================
* Definitions to support the standard inquiry command as defined in SPC-3.
} __attribute__((packed));
static inline int
-vpd83_dscr_istype(struct vpd83_dscr *d, unsigned char type)
+vpd83_dscr_istype(const struct vpd83_dscr *d, unsigned char type)
{
return ((d->b1 & 7) == type);
}
struct vpd83_dscr data[0];
} __attribute__((packed));
+#define VPD_BUFLEN 4096
+
+/* Returns the max byte offset in the VPD page from the start of the page */
+static inline unsigned int vpd83_max_offs(const struct vpd83_data *p)
+{
+ uint16_t len = get_unaligned_be16(p->length) + 4;
+
+ return len <= VPD_BUFLEN ? len : VPD_BUFLEN;
+}
+
+static inline bool
+vpd83_descr_fits(const struct vpd83_dscr *d, const struct vpd83_data *p)
+{
+ ptrdiff_t max_offs = vpd83_max_offs(p);
+ ptrdiff_t offs = ((const char *)d - (const char *)p);
+
+ /* make sure we can read d->length */
+ if (offs < 0 || offs > max_offs - 4)
+ return false;
+
+ offs += d->length + 4;
+ return offs <= max_offs;
+}
+
+static inline const struct vpd83_dscr *
+vpd83_next_dscr(const struct vpd83_dscr *d, const struct vpd83_data *p)
+{
+ ptrdiff_t offs = ((const char *)d - (const char *)p) + d->length + 4;
+
+ return (const struct vpd83_dscr *)((const char *)p + offs);
+}
+
/*-----------------------------------------------------------------------------
* This macro should be used to walk through all identification descriptors
* defined in the code page 0x83.
*/
#define FOR_EACH_VPD83_DSCR(p, d) \
for( \
- d = p->data; \
- (((char *) d) - ((char *) p)) < \
- get_unaligned_be16(p->length); \
- d = (struct vpd83_dscr *) \
- ((char *) d + d->length + 4) \
+ d = p->data; \
+ vpd83_descr_fits(d, p); \
+ d = vpd83_next_dscr(d, p) \
)
/*=============================================================================
return 0;
}
- arg = temp = STRDUP(args);
+ arg = temp = strdup(args);
if (!arg)
return 0;
if (check_args_valid(*ionum, *basenum) == 0)
goto out;
- FREE(arg);
+ free(arg);
return 1;
out:
- FREE(arg);
+ free(arg);
return 0;
}
#include "weightedpath.h"
#include "config.h"
#include "structs.h"
-#include "memory.h"
#include "debug.h"
#include <regex.h>
#include "structs_vec.h"
if (!prio_args)
return priority;
- arg = temp = STRDUP(prio_args);
+ arg = strdup(prio_args);
+ temp = arg;
regex = get_next_string(&temp, split_char);
/* Return default priority if the argument is not parseable */
if (!regex) {
- FREE(arg);
return priority;
}
#include "nvme-lib.h"
#include "checkers.h"
-#include "memory.h"
#include "vector.h"
#include "structs.h"
#include "config.h"
mp_set_conf(selector);
mp_set_default(selector, DEFAULT_SELECTOR);
out:
- mp->selector = STRDUP(mp->selector);
+ mp->selector = strdup(mp->selector);
condlog(3, "%s: path_selector = \"%s\" %s", mp->alias, mp->selector,
origin);
return 0;
const char *origin = NULL;
if (mp->mpe && mp->mpe->alias) {
- mp->alias = STRDUP(mp->mpe->alias);
+ mp->alias = strdup(mp->mpe->alias);
origin = multipaths_origin;
goto out;
}
}
out:
if (mp->alias == NULL) {
- mp->alias = STRDUP(mp->wwid);
+ mp->alias = strdup(mp->wwid);
origin = "(setting: default to WWID)";
}
if (mp->alias)
mp_set_conf(features);
mp_set_default(features, DEFAULT_FEATURES);
out:
- mp->features = STRDUP(mp->features);
+ mp->features = strdup(mp->features);
reconcile_features_with_options(mp->alias, &mp->features,
&mp->no_path_retry,
mp->hwhandler = DEFAULT_HWHANDLER;
origin = tpgs_origin;
}
- mp->hwhandler = STRDUP(mp->hwhandler);
+ mp->hwhandler = strdup(mp->hwhandler);
condlog(3, "%s: hardware_handler = \"%s\" %s", mp->alias, mp->hwhandler,
origin);
return 0;
ckr_name = RDAC;
goto out;
}
- path_get_tpgs(pp);
+ (void)path_get_tpgs(pp);
if (pp->tpgs != TPGS_NONE && pp->tpgs != TPGS_UNDEF) {
ckr_name = TUR;
goto out;
static const char empty_str[] = "";
+char *__get_strbuf_buf(struct strbuf *buf)
+{
+ return buf->buf;
+}
+
const char *get_strbuf_str(const struct strbuf *buf)
{
return buf->buf ? buf->buf : empty_str;
*/
struct strbuf *new_strbuf(void);
+/**
+ * get_strbuf_buf(): retrieve a pointer to the strbuf's buffer
+ * @param buf: a struct strbuf
+ * @returns: pointer to the string written to the strbuf so far.
+ *
+ * INTERNAL ONLY.
+ * DANGEROUS: Unlike the return value of get_strbuf_str(),
+ * this string can be written to, modifying the strbuf's content.
+ * USE WITH CAUTION.
+ * If @strbuf was never written to, the function returns NULL.
+ * The return value of this function must not be free()d.
+ */
+char *__get_strbuf_buf(struct strbuf *buf);
+
/**
* get_strbuf_str(): retrieve string from strbuf
* @param buf: a struct strbuf
#include <libudev.h>
#include "checkers.h"
-#include "memory.h"
#include "vector.h"
#include "util.h"
#include "structs.h"
{
struct adapter_group *agp;
- agp = (struct adapter_group *)MALLOC(sizeof(struct adapter_group));
+ agp = (struct adapter_group *)calloc(1, sizeof(struct adapter_group));
if (!agp)
return NULL;
agp->host_groups = vector_alloc();
if (!agp->host_groups) {
- FREE(agp);
+ free(agp);
agp = NULL;
}
return agp;
vector_foreach_slot(adapters, agp, i) {
free_hostgroup(agp->host_groups);
- FREE(agp);
+ free(agp);
}
vector_free(adapters);
}
vector_foreach_slot(hostgroups, hgp, i) {
vector_free(hgp->paths);
- FREE(hgp);
+ free(hgp);
}
vector_free(hostgroups);
}
{
struct host_group *hgp;
- hgp = (struct host_group *)MALLOC(sizeof(struct host_group));
+ hgp = (struct host_group *)calloc(1, sizeof(struct host_group));
if (!hgp)
return NULL;
hgp->paths = vector_alloc();
if (!hgp->paths) {
- FREE(hgp);
+ free(hgp);
hgp = NULL;
}
return hgp;
{
struct path * pp;
- pp = (struct path *)MALLOC(sizeof(struct path));
+ pp = (struct path *)calloc(1, sizeof(struct path));
if (pp) {
pp->initialized = INIT_NEW;
vector_free(pp->hwe);
- FREE(pp);
+ free(pp);
}
void
{
struct pathgroup * pgp;
- pgp = (struct pathgroup *)MALLOC(sizeof(struct pathgroup));
+ pgp = (struct pathgroup *)calloc(1, sizeof(struct pathgroup));
if (!pgp)
return NULL;
pgp->paths = vector_alloc();
if (!pgp->paths) {
- FREE(pgp);
+ free(pgp);
return NULL;
}
return;
free_pathvec(pgp->paths, free_paths);
- FREE(pgp);
+ free(pgp);
}
void
{
struct multipath * mpp;
- mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
+ mpp = (struct multipath *)calloc(1, sizeof(struct multipath));
if (mpp) {
mpp->bestpg = 1;
return;
if (mpp->selector) {
- FREE(mpp->selector);
+ free(mpp->selector);
mpp->selector = NULL;
}
if (mpp->features) {
- FREE(mpp->features);
+ free(mpp->features);
mpp->features = NULL;
}
if (mpp->hwhandler) {
- FREE(mpp->hwhandler);
+ free(mpp->hwhandler);
mpp->hwhandler = NULL;
}
}
free_multipath_attributes(mpp);
if (mpp->alias) {
- FREE(mpp->alias);
+ free(mpp->alias);
mpp->alias = NULL;
}
if (mpp->dmi) {
- FREE(mpp->dmi);
+ free(mpp->dmi);
mpp->dmi = NULL;
}
vector_free(mpp->hwe);
mpp->hwe = NULL;
}
- FREE_PTR(mpp->mpcontext);
- FREE(mpp);
+ free(mpp->mpcontext);
+ free(mpp);
}
void
for (d = c; d >= 10; d /= 10)
l++;
- t = MALLOC(l + 1);
+ t = calloc(1, l + 1);
if (!t)
return 1;
snprintf(t, l + 1, "%0d%s %s", c, e, n);
- FREE(*f);
+ free(*f);
*f = t;
return 0;
/* Quick exit if all features have been removed */
if (c == 0) {
- n = MALLOC(2);
+ n = malloc(2);
if (!n)
return 1;
strcpy(n, "0");
/* Update feature count space */
l = strlen(*f) - d;
- n = MALLOC(l + 1);
+ n = malloc(l + 1);
if (!n)
return 1;
p = strchr(*f, ' ');
if (!p) {
/* Internal error, feature string inconsistent */
- FREE(n);
+ free(n);
return 1;
}
while (*p == ' ')
}
out:
- FREE(*f);
+ free(*f);
*f = n;
return 0;
* mapped by some multipath map because of map reload failure.
*/
INIT_REMOVED,
+ /*
+ * INIT_PARTIAL: paths added by update_pathvec_from_dm() will not
+ * be fully initialized. This will be handled when an add or
+ * change uevent is received.
+ */
+ INIT_PARTIAL,
+ __INIT_LAST,
};
enum prkey_sources {
int fd;
int initialized;
int retriggers;
+ int partial_retrigger_delay;
unsigned int path_failures;
time_t dis_reinstate_time;
int disable_reinstate;
int retain_hwhandler;
int deferred_remove;
bool in_recovery;
+ bool need_reload;
int san_path_err_threshold;
int san_path_err_forget_rate;
int san_path_err_recovery_time;
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <libudev.h>
#include "util.h"
#include "checkers.h"
* - may set pp->wwid and / or mpp->wwid
* - calls pathinfo() on existing paths is pathinfo_flags is not 0
*/
-bool update_pathvec_from_dm(vector pathvec, struct multipath *mpp,
+static bool update_pathvec_from_dm(vector pathvec, struct multipath *mpp,
int pathinfo_flags)
{
int i, j;
* uninitialized struct path to pgp->paths, with only
* pp->dev_t filled in. Thus if pp->udev is set here,
* we know that the path is in pathvec already.
- * However, it's possible that the path in pathvec is
- * different from the one the kernel still had in its
- * map.
*/
if (pp->udev) {
if (pathinfo_flags & ~DI_NOIO) {
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config,
conf);
- pathinfo(pp, conf, pathinfo_flags|DI_WWID);
+ if (pathinfo(pp, conf, pathinfo_flags) != PATHINFO_OK)
+ condlog(2, "%s: pathinfo failed for existing path %s (flags=0x%x)",
+ __func__, pp->dev, pathinfo_flags);
pthread_cleanup_pop(1);
}
} else {
} else {
int rc;
- devt2devname(pp->dev, sizeof(pp->dev),
- pp->dev_t);
+ strlcpy(pp->dev, udev_device_get_sysname(pp->udev),
+ sizeof(pp->dev));
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config,
conf);
pp->checkint = conf->checkint;
rc = pathinfo(pp, conf,
- DI_SYSFS|DI_WWID|DI_BLACKLIST|
- pathinfo_flags);
+ DI_SYSFS|DI_WWID|DI_BLACKLIST|DI_NOFALLBACK|pathinfo_flags);
pthread_cleanup_pop(1);
if (rc != PATHINFO_OK) {
condlog(1, "%s: error %d in pathinfo, discarding path",
}
condlog(2, "%s: adding new path %s",
mpp->alias, pp->dev);
+ pp->initialized = INIT_PARTIAL;
+ pp->partial_retrigger_delay = 180;
store_path(pathvec, pp);
pp->tick = 1;
}
free_pathgroup(pgp, KEEP_PATHS);
must_reload = true;
}
+ mpp->need_reload = mpp->need_reload || must_reload;
return must_reload;
}
uninitialize_path(pp);
}
-void orphan_paths(vector pathvec, struct multipath *mpp, const char *reason)
+static void orphan_paths(vector pathvec, struct multipath *mpp, const char *reason)
{
int i;
struct path * pp;
vector_foreach_slot (pathvec, pp, i) {
if (pp->mpp == mpp) {
- if (pp->initialized == INIT_REMOVED) {
- condlog(3, "%s: freeing path in removed state",
- pp->dev);
+ if (pp->initialized == INIT_REMOVED ||
+ pp->initialized == INIT_PARTIAL) {
+ condlog(3, "%s: freeing path in %s state",
+ pp->dev,
+ pp->initialized == INIT_REMOVED ?
+ "removed" : "partial");
vector_del_slot(pathvec, i--);
free_path(pp);
} else
* Keep link to mpp. It will be removed when the path
* is successfully removed from the map.
*/
- if (!mpp) {
+ if (!mpp)
condlog(0, "%s: internal error: mpp == NULL", pp->dev);
- return;
- }
pp->mpp = mpp;
pp->initialized = INIT_REMOVED;
}
{
int i;
+ free_pathvec(mpp->paths, KEEP_PATHS);
+ free_pgvec(mpp->pg, KEEP_PATHS);
+ mpp->paths = mpp->pg = NULL;
+
/*
* clear references to this map
*/
condlog(4, "%s: searching paths for valid hwe", mpp->alias);
/* doing this in two passes seems like paranoia to me */
vector_foreach_slot(mpp->paths, pp, i) {
- if (pp->state == PATH_UP &&
+ if (pp->state == PATH_UP && pp->initialized != INIT_PARTIAL &&
pp->initialized != INIT_REMOVED && pp->hwe)
goto done;
}
vector_foreach_slot(mpp->paths, pp, i) {
- if (pp->state != PATH_UP &&
+ if ((pp->state != PATH_UP || pp->initialized == INIT_PARTIAL) &&
pp->initialized != INIT_REMOVED && pp->hwe)
goto done;
}
int i;
vector_foreach_slot(pathvec, pp, i) {
- if (pp->initialized != INIT_REMOVED || pp->mpp != mpp)
- continue;
- if (!find_devt_in_pathgroups(mpp, pp->dev_t)) {
- condlog(2, "%s: %s: freeing path in removed state",
- __func__, pp->dev);
+ if (pp->mpp == mpp &&
+ (pp->initialized == INIT_REMOVED ||
+ pp->initialized == INIT_PARTIAL) &&
+ !find_devt_in_pathgroups(mpp, pp->dev_t)) {
+ condlog(2, "%s: %s: freeing path in %s state",
+ __func__, pp->dev,
+ pp->initialized == INIT_REMOVED ?
+ "removed" : "partial");
vector_del_slot(pathvec, i--);
free_path(pp);
}
#include "lock.h"
struct vectors {
- struct mutex_lock lock; /* defined in lock.h */
vector pathvec;
vector mpvec;
+ struct mutex_lock lock; /* defined in lock.h */
};
void __set_no_path_retry(struct multipath *mpp, bool check_features);
#define set_no_path_retry(mpp) __set_no_path_retry(mpp, true)
int adopt_paths (vector pathvec, struct multipath * mpp);
-void orphan_paths(vector pathvec, struct multipath *mpp,
- const char *reason);
void orphan_path (struct path * pp, const char *reason);
void set_path_removed(struct path *pp);
int verify_paths(struct multipath *mpp);
-bool update_pathvec_from_dm(vector pathvec, struct multipath *mpp,
- int pathinfo_flags);
int update_mpp_paths(struct multipath * mpp, vector pathvec);
int update_multipath_strings (struct multipath *mpp, vector pathvec);
void extract_hwe_from_path(struct multipath * mpp);
table_name, check_devt, new_devt);
dm_reassign_table(table_name, check_devt, new_devt);
- FREE(table_name);
+ free(table_name);
}
closedir(dirfd);
res->tv_nsec = a->tv_nsec - b->tv_nsec;
normalize_timespec(res);
}
+
+int timespeccmp(const struct timespec *a, const struct timespec *b)
+{
+ struct timespec tmp;
+
+ timespecsub(a, b, &tmp);
+ if (tmp.tv_sec > 0)
+ return 1;
+ if (tmp.tv_sec < 0)
+ return -1;
+ return tmp.tv_nsec > 0 ? 1 : (tmp.tv_nsec < 0 ? -1 : 0);
+}
void normalize_timespec(struct timespec *ts);
void timespecsub(const struct timespec *a, const struct timespec *b,
struct timespec *res);
+int timespeccmp(const struct timespec *a, const struct timespec *b);
#endif /* _TIME_UTIL_H_ */
#include <libudev.h>
#include <errno.h>
-#include "memory.h"
#include "debug.h"
#include "list.h"
#include "uevent.h"
struct uevent * alloc_uevent (void)
{
- struct uevent *uev = MALLOC(sizeof(struct uevent));
+ struct uevent *uev = calloc(1, sizeof(struct uevent));
if (uev) {
INIT_LIST_HEAD(&uev->node);
return uev;
}
+static void uevq_cleanup(struct list_head *tmpq);
+
+static void cleanup_uev(void *arg)
+{
+ struct uevent *uev = arg;
+
+ uevq_cleanup(&uev->merge_node);
+ if (uev->udev)
+ udev_device_unref(uev->udev);
+ free(uev);
+}
+
static void uevq_cleanup(struct list_head *tmpq)
{
struct uevent *uev, *tmp;
list_for_each_entry_safe(uev, tmp, tmpq, node) {
list_del_init(&uev->node);
-
- if (uev->udev)
- udev_device_unref(uev->udev);
- FREE(uev);
+ cleanup_uev(uev);
}
}
list_del_init(&uev->node);
if (uev->udev)
udev_device_unref(uev->udev);
- FREE(uev);
+ free(uev);
continue;
}
list_del_init(&earlier->node);
if (earlier->udev)
udev_device_unref(earlier->udev);
- FREE(earlier);
+ free(earlier);
}
}
}
list_for_each_entry_safe(uev, tmp, tmpq, node) {
list_del_init(&uev->node);
+ pthread_cleanup_push(cleanup_uev, uev);
if (my_uev_trigger && my_uev_trigger(uev, my_trigger_data))
condlog(0, "uevent trigger error");
-
- uevq_cleanup(&uev->merge_node);
-
- if (uev->udev)
- udev_device_unref(uev->udev);
- FREE(uev);
+ pthread_cleanup_pop(1);
}
}
udev_monitor_unref(monitor);
}
+static void cleanup_uevq(void *arg)
+{
+ uevq_cleanup(arg);
+}
+
+static void cleanup_global_uevq(void *arg __attribute__((unused)))
+{
+ pthread_mutex_lock(uevq_lockp);
+ uevq_cleanup(&uevq);
+ pthread_mutex_unlock(uevq_lockp);
+}
+
/*
* Service the uevent queue.
*/
while (1) {
LIST_HEAD(uevq_tmp);
+ pthread_cleanup_push(cleanup_mutex, uevq_lockp);
pthread_mutex_lock(uevq_lockp);
servicing_uev = 0;
/*
}
servicing_uev = 1;
list_splice_init(&uevq, &uevq_tmp);
- pthread_mutex_unlock(uevq_lockp);
+ pthread_cleanup_pop(1);
+
if (!my_uev_trigger)
break;
+
+ pthread_cleanup_push(cleanup_uevq, &uevq_tmp);
merge_uevq(&uevq_tmp);
service_uevq(&uevq_tmp);
+ pthread_cleanup_pop(1);
}
condlog(3, "Terminating uev service queue");
- uevq_cleanup(&uevq);
return 0;
}
if (!uev->devpath || ! uev->action) {
udev_device_unref(dev);
condlog(1, "uevent missing necessary fields");
- FREE(uev);
+ free(uev);
return NULL;
}
uev->udev = dev;
events = 0;
gettimeofday(&start_time, NULL);
+ pthread_cleanup_push(cleanup_global_uevq, NULL);
+ pthread_cleanup_push(cleanup_uevq, &uevlisten_tmp);
while (1) {
struct uevent *uev;
struct udev_device *dev;
gettimeofday(&start_time, NULL);
timeout = 30;
}
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
out:
pthread_cleanup_pop(1);
out_udev:
#include "util.h"
#include "debug.h"
-#include "memory.h"
#include "checkers.h"
#include "vector.h"
#include "structs.h"
if (!word)
return skip + len;
- *word = MALLOC(len + 1);
+ *word = calloc(1, len + 1);
if (!*word) {
condlog(0, "get_word : oom");
int devt2devname(char *devname, int devname_len, const char *devt)
{
struct udev_device *u_dev;
+ const char * dev_name;
int r;
if (!devname || !devname_len || !devt)
condlog(0, "\"%s\": invalid major/minor numbers, not found in sysfs", devt);
return 1;
}
- r = strlcpy(devname, udev_device_get_sysname(u_dev), devname_len);
+
+ dev_name = udev_device_get_sysname(u_dev);
+ if (!dev_name) {
+ udev_device_unref(u_dev);
+ return 1;
+ }
+ r = strlcpy(devname, dev_name, devname_len);
udev_device_unref(u_dev);
return !(r < devname_len);
int i;
for (i = 0; i < res->n; i++)
- FREE(res->di[i]);
- FREE(res->di);
+ free(res->di[i]);
+ free(res->di);
}
void close_fd(void *arg)
{
free(*p);
}
+
+void cleanup_ucharp(unsigned char **p)
+{
+ free(*p);
+}
#include <sys/resource.h>
#include <inttypes.h>
#include <stdbool.h>
+#include <stdio.h>
size_t strchop(char *);
int basenamecpy (const char *src, char *dst, size_t size);
})
void cleanup_charp(char **p);
+void cleanup_ucharp(unsigned char **p);
#endif /* _UTIL_H */
#endif
#include "mpath_cmd.h"
-#include "memory.h"
#include "uxsock.h"
#include "debug.h"
return -errno;
if ((limit > 0) && (len > limit))
return -EINVAL;
- (*buf) = MALLOC(len);
+ (*buf) = calloc(1, len);
if (!*buf)
return -ENOMEM;
err = mpath_recv_reply_data(fd, *buf, len, timeout);
if (err != 0) {
- FREE(*buf);
+ free(*buf);
(*buf) = NULL;
return -errno;
}
{
return _recv_packet(fd, buf, timeout, 0 /* no limit */);
}
-
-int recv_packet_from_client(int fd, char **buf, unsigned int timeout)
-{
- return _recv_packet(fd, buf, timeout, _MAX_CMD_LEN);
-}
#define _MAX_CMD_LEN 512
-/*
- * Used for receiving socket command from untrusted socket client where data
- * size is restricted to 512(_MAX_CMD_LEN) at most.
- * Return -EINVAL if data length requested by client exceeded the _MAX_CMD_LEN.
- */
-int recv_packet_from_client(int fd, char **buf, unsigned int timeout);
* Copyright (c) 2005 Christophe Varoqui
*/
-#include "memory.h"
#include <stdlib.h>
#include "vector.h"
vector
vector_alloc(void)
{
- vector v = (vector) MALLOC(sizeof (struct _vector));
+ vector v = (vector) calloc(1, sizeof (struct _vector));
return v;
}
return false;
new_allocated = v->allocated + VECTOR_DEFAULT_SIZE;
- new_slot = REALLOC(v->slot, sizeof (void *) * new_allocated);
+ new_slot = realloc(v->slot, sizeof (void *) * new_allocated);
if (!new_slot)
return false;
v->allocated -= VECTOR_DEFAULT_SIZE;
if (v->allocated <= 0) {
- FREE(v->slot);
+ free(v->slot);
v->slot = NULL;
v->allocated = 0;
} else {
void *new_slot;
- new_slot = REALLOC(v->slot, sizeof (void *) * v->allocated);
+ new_slot = realloc(v->slot, sizeof (void *) * v->allocated);
if (!new_slot)
v->allocated += VECTOR_DEFAULT_SIZE;
else
return NULL;
if (v->slot)
- FREE(v->slot);
+ free(v->slot);
v->allocated = 0;
v->slot = NULL;
{
if (!vector_reset(v))
return;
- FREE(v);
+ free(v);
}
void
vector_foreach_slot (strvec, str, i)
if (str)
- FREE(str);
+ free(str);
vector_free(strvec);
}
#ifndef _VERSION_H
#define _VERSION_H
-#define VERSION_CODE 0x000807
-#define DATE_CODE 0x090815
+#define VERSION_CODE 0x000808
+#define DATE_CODE 0x030c15
#define PROG "multipath-tools"
.PP
All options listed in this man page, except \fI-f\fR and
\fI-v\fR, are allowed in batch files. Both short and long option formats may be used.
-Using the \fI-f\fR option inside the batch file is an error. The \fI-v\fR
+Using the \fI-f\fR option inside the batch file is an error. The \fI-v\fR
option is ignored in batch files.
.
.PP
.PP
If other options and parameters are used along with
\fI-f\fR on the \fBmpathpersist\fR command line, the command line will be executed first, followed
-by the commands from the the batch file.
+by the commands from the batch file.
.
.PP
Below is an example of a valid batch input file.
#include "checkers.h"
#include "prio.h"
#include "vector.h"
-#include "memory.h"
#include <libdevmapper.h>
#include "devmapper.h"
#include "util.h"
if (reply != NULL) {
printf("%s", reply);
- FREE(reply);
+ free(reply);
return 0;
} else
return 1;
condlog(r == 0 ? 3 : 2, "%s:%s usable paths found",
devpath, r == 0 ? "" : " no");
free:
- FREE(mapname);
+ free(mapname);
free_multipath(mpp, FREE_PATHS);
vector_free(pathvec);
out:
int di_flag = 0;
char * refwwid = NULL;
char * dev = NULL;
+ fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
/*
* allocate core vectors to store paths and multipaths
if (libmp_verbosity > 2)
print_all_paths(pathvec, 1);
- get_path_layout(pathvec, 0);
- foreign_path_layout();
+ if ((width = alloc_path_layout()) == NULL)
+ goto out;
+ get_path_layout(pathvec, 0, width);
+ foreign_path_layout(width);
if (get_dm_mpvec(cmd, curmp, pathvec, refwwid))
goto out;
dump_config(conf, hwes, curmp);
vector_free(hwes);
+ r = RTVL_OK;
goto out;
}
condlog(2, "Warning: multipath devices exist, but multipathd service is not running");
if (refwwid)
- FREE(refwwid);
+ free(refwwid);
free_multipathvec(curmp, KEEP_PATHS);
vecs.mpvec = NULL;
return NOT_DELEGATED;
if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
- p += snprintf(p, n, "reconfigure");
+ p += snprintf(p, n, "reconfigure all");
}
else if (cmd == CMD_FLUSH_ONE && dev && dev_type == DEV_DEVMAP) {
p += snprintf(p, n, "del map %s", dev);
}
out:
- FREE(reply);
+ free(reply);
close(fd);
return r;
}
conf = get_multipath_config();
conf->retrigger_tries = 0;
conf->force_sync = 1;
- atexit(cleanup_vecs);
+ if (atexit(cleanup_vecs))
+ condlog(1, "failed to register cleanup handler for vecs: %m");
while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
switch(arg) {
- case 1: printf("optarg : %s\n",optarg);
- break;
case 'v':
- if (sizeof(optarg) > sizeof(char *) ||
- !isdigit(optarg[0])) {
+ if (!isdigit(optarg[0])) {
usage (argv[0]);
exit(RTVL_FAIL);
}
break;
case 'M':
-#if _DEBUG_
- debug = atoi(optarg);
-#endif
break;
case 'p':
conf->pgpolicy_flag = get_pgpolicy_id(optarg);
exit(RTVL_FAIL);
}
- check_alias_settings(conf);
+ if (check_alias_settings(conf)) {
+ fprintf(stderr, "fatal configuration error, aborting");
+ exit(RTVL_FAIL);
+ }
if (optind < argc) {
- dev = MALLOC(FILE_NAME_SIZE);
+ dev = calloc(1, FILE_NAME_SIZE);
if (!dev)
goto out;
out:
put_multipath_config(conf);
if (dev)
- FREE(dev);
+ free(dev);
if (dev_type == DEV_UEVENT)
closelog();
-#ifdef _DEBUG_
- dbg_free_final(NULL);
-#endif
return r;
}
.
.TP
.BI \-b " file"
-Set \fIuser_friendly_names\fR bindings file location. The default is
+Set \fIuser_friendly_names\fR bindings file location. The default is
\fI/etc/multipath/bindings\fR.
.
.TP
.\" ----------------------------------------------------------------------------
-.\" Update the date below if you make any significant change.
.\" Make sure there are no errors with:
.\" groff -z -wall -b -e -t multipath/multipath.conf.5
.\" man --warnings -E UTF-8 -l -Tutf8 -Z multipath/multipath.conf.5 >/dev/null
.\"
+.\" Update the date below if you make any significant change.
.\" ----------------------------------------------------------------------------
.
-.TH MULTIPATH.CONF 5 2018-05-21 Linux
+.TH MULTIPATH.CONF 5 2021-09-08 Linux
.
.
.\" ----------------------------------------------------------------------------
.
.TP
.B multipath_dir
+This option is deprecated, and will be removed in a future release.
Directory where the dynamic shared objects are stored. Defined at compile time,
commonly \fI/lib64/multipath/\fR or \fI/lib/multipath/\fR.
.RS
.TP
.B path_selector
The default path selector algorithm to use; they are offered by the
-kernel multipath target. There are three selector algorithms:
+kernel multipath target:
.RS
.TP 12
.I "round-robin 0"
of outstanding I/O to the path and its relative throughput.
.TP
.I "historical-service-time 0"
-(Since 5.8 kernel) Choose the path for the next bunch of IOs based on the
+(Since 5.8 kernel) Choose the path for the next bunch of I/O based on the
estimation of future service time based on the history of previous I/O submitted
to each path.
.TP
+.I "io-affinity 0"
+(Since 5.11 kernel) Choose the path for the next bunch of I/O based on a CPU to
+path mapping the user passes in and what CPU we are executing on.
+.TP
The default is: \fBservice-time 0\fR
.RE
.
.
.TP
.B bindings_file
+This option is deprecated, and will be removed in a future release.
The full pathname of the binding file to be used when the user_friendly_names
option is set.
.RS
.
.TP
.B wwids_file
+This option is deprecated, and will be removed in a future release.
The full pathname of the WWIDs file, which is used by multipath to keep track
of the WWIDs for LUNs it has created multipath devices on in the past.
.RS
.
.TP
.B prkeys_file
+This option is deprecated, and will be removed in a future release.
The full pathname of the prkeys file, which is used by multipathd to keep
track of the persistent reservation key used for a specific WWID, when
\fIreservation_key\fR is set to \fBfile\fR.
.
.TP
.B config_dir
+This option is deprecated, and will be removed in a future release.
If set to anything other than "", multipath will search this directory
alphabetically for file ending in ".conf" and it will read configuration
information from them, just as if it was in \fI/etc/multipath.conf\fR.
#include <sys/time.h>
#include <errno.h>
#include <pthread.h>
-#include "memory.h"
+#include <assert.h>
#include "vector.h"
#include "structs.h"
#include "structs_vec.h"
static struct key *
alloc_key (void)
{
- return (struct key *)MALLOC(sizeof(struct key));
+ return (struct key *)calloc(1, sizeof(struct key));
}
static struct handler *
alloc_handler (void)
{
- return (struct handler *)MALLOC(sizeof(struct handler));
+ return (struct handler *)calloc(1, sizeof(struct handler));
}
static int
kw->code = code;
kw->has_param = has_param;
- kw->str = STRDUP(str);
+ kw->str = strdup(str);
if (!kw->str)
goto out;
return 0;
out1:
- FREE(kw->str);
+ free(kw->str);
out:
- FREE(kw);
+ free(kw);
return 1;
}
-int
-add_handler (uint64_t fp, int (*fn)(void *, char **, int *, void *))
+static struct handler *add_handler(uint64_t fp, cli_handler *fn, bool locked)
{
struct handler * h;
h = alloc_handler();
- if (!h)
- return 1;
+ if (h == NULL)
+ return NULL;
if (!vector_alloc_slot(handlers)) {
- FREE(h);
- return 1;
+ free(h);
+ return NULL;
}
vector_set_slot(handlers, h);
h->fingerprint = fp;
h->fn = fn;
+ h->locked = locked;
- return 0;
+ return h;
}
static struct handler *
}
int
-set_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *))
-{
- struct handler * h = find_handler(fp);
-
- if (!h)
- return 1;
- h->fn = fn;
- h->locked = 1;
- return 0;
-}
-
-int
-set_unlocked_handler_callback (uint64_t fp,int (*fn)(void *, char **, int *, void *))
+__set_handler_callback (uint64_t fp, cli_handler *fn, bool locked)
{
- struct handler * h = find_handler(fp);
+ struct handler *h;
- if (!h)
+ assert(find_handler(fp) == NULL);
+ h = add_handler(fp, fn, locked);
+ if (!h) {
+ condlog(0, "%s: failed to set handler for code %"PRIu64,
+ __func__, fp);
return 1;
- h->fn = fn;
- h->locked = 0;
+ }
return 0;
}
free_key (struct key * kw)
{
if (kw->str)
- FREE(kw->str);
+ free(kw->str);
if (kw->param)
- FREE(kw->param);
+ free(kw->param);
- FREE(kw);
+ free(kw);
}
void
struct handler * h;
vector_foreach_slot (handlers, h, i)
- FREE(h);
+ free(h);
vector_free(handlers);
handlers = NULL;
r += add_key(keys, "local", LOCAL, 0);
r += add_key(keys, "setmarginal", SETMARGINAL, 0);
r += add_key(keys, "unsetmarginal", UNSETMARGINAL, 0);
+ r += add_key(keys, "all", ALL, 0);
if (r) {
*
* returns:
* ENOMEM: not enough memory to allocate command
- * EAGAIN: command not found
+ * ESRCH: command not found
* EINVAL: argument missing for command
*/
-static int
-get_cmdvec (char * cmd, vector *v)
+int get_cmdvec (char *cmd, vector *v)
{
int i;
int r = 0;
}
kw = find_key(buff);
if (!kw) {
- r = EAGAIN;
+ r = ESRCH;
goto out;
}
cmdkw = alloc_key();
goto out;
}
if (!vector_alloc_slot(cmdvec)) {
- FREE(cmdkw);
+ free(cmdkw);
r = ENOMEM;
goto out;
}
}
static uint64_t
-fingerprint(vector vec)
+fingerprint(const struct _vector *vec)
{
int i;
uint64_t fp = 0;
return fp;
}
+struct handler *find_handler_for_cmdvec(const struct _vector *v)
+{
+ return find_handler(fingerprint(v));
+}
+
int
alloc_handlers (void)
{
case ENOMEM:
rc = print_strbuf(reply, "%s: Not enough memory\n", cmd);
break;
- case EAGAIN:
+ case ESRCH:
rc = print_strbuf(reply, "%s: not found\n", cmd);
break;
case EINVAL:
}
-static char *
-genhelp_handler (const char *cmd, int error)
+void genhelp_handler(const char *cmd, int error, struct strbuf *reply)
{
- STRBUF_ON_STACK(reply);
-
- if (do_genhelp(&reply, cmd, error) == -1)
+ if (do_genhelp(reply, cmd, error) == -1)
condlog(0, "genhelp_handler: out of memory");
- return steal_strbuf_str(&reply);
-}
-
-int
-parse_cmd (char * cmd, char ** reply, int * len, void * data, int timeout )
-{
- int r;
- struct handler * h;
- vector cmdvec = NULL;
- struct timespec tmo;
-
- r = get_cmdvec(cmd, &cmdvec);
-
- if (r) {
- *reply = genhelp_handler(cmd, r);
- if (*reply == NULL)
- return EINVAL;
- *len = strlen(*reply) + 1;
- return 0;
- }
-
- h = find_handler(fingerprint(cmdvec));
-
- if (!h || !h->fn) {
- free_keys(cmdvec);
- *reply = genhelp_handler(cmd, EINVAL);
- if (*reply == NULL)
- return EINVAL;
- *len = strlen(*reply) + 1;
- return 0;
- }
-
- /*
- * execute handler
- */
- if (clock_gettime(CLOCK_REALTIME, &tmo) == 0) {
- tmo.tv_sec += timeout;
- } else {
- tmo.tv_sec = 0;
- }
- if (h->locked) {
- int locked = 0;
- struct vectors * vecs = (struct vectors *)data;
-
- pthread_cleanup_push(cleanup_lock, &vecs->lock);
- if (tmo.tv_sec) {
- r = timedlock(&vecs->lock, &tmo);
- } else {
- lock(&vecs->lock);
- r = 0;
- }
- if (r == 0) {
- locked = 1;
- pthread_testcancel();
- r = h->fn(cmdvec, reply, len, data);
- }
- pthread_cleanup_pop(locked);
- } else
- r = h->fn(cmdvec, reply, len, data);
- free_keys(cmdvec);
-
- return r;
}
char *
if (alloc_handlers())
return 1;
- add_handler(LIST+PATHS, NULL);
- add_handler(LIST+PATHS+FMT, NULL);
- add_handler(LIST+PATHS+RAW+FMT, NULL);
- add_handler(LIST+PATH, NULL);
- add_handler(LIST+STATUS, NULL);
- add_handler(LIST+DAEMON, NULL);
- add_handler(LIST+MAPS, NULL);
- add_handler(LIST+MAPS+STATUS, NULL);
- add_handler(LIST+MAPS+STATS, NULL);
- add_handler(LIST+MAPS+FMT, NULL);
- add_handler(LIST+MAPS+RAW+FMT, NULL);
- add_handler(LIST+MAPS+TOPOLOGY, NULL);
- add_handler(LIST+MAPS+JSON, NULL);
- add_handler(LIST+TOPOLOGY, NULL);
- add_handler(LIST+MAP+TOPOLOGY, NULL);
- add_handler(LIST+MAP+JSON, NULL);
- add_handler(LIST+MAP+FMT, NULL);
- add_handler(LIST+MAP+RAW+FMT, NULL);
- add_handler(LIST+CONFIG, NULL);
- add_handler(LIST+CONFIG+LOCAL, NULL);
- add_handler(LIST+BLACKLIST, NULL);
- add_handler(LIST+DEVICES, NULL);
- add_handler(LIST+WILDCARDS, NULL);
- add_handler(RESET+MAPS+STATS, NULL);
- add_handler(RESET+MAP+STATS, NULL);
- add_handler(ADD+PATH, NULL);
- add_handler(DEL+PATH, NULL);
- add_handler(ADD+MAP, NULL);
- add_handler(DEL+MAP, NULL);
- add_handler(DEL+MAPS, NULL);
- add_handler(SWITCH+MAP+GROUP, NULL);
- add_handler(RECONFIGURE, NULL);
- add_handler(SUSPEND+MAP, NULL);
- add_handler(RESUME+MAP, NULL);
- add_handler(RESIZE+MAP, NULL);
- add_handler(RESET+MAP, NULL);
- add_handler(RELOAD+MAP, NULL);
- add_handler(DISABLEQ+MAP, NULL);
- add_handler(RESTOREQ+MAP, NULL);
- add_handler(DISABLEQ+MAPS, NULL);
- add_handler(RESTOREQ+MAPS, NULL);
- add_handler(REINSTATE+PATH, NULL);
- add_handler(FAIL+PATH, NULL);
- add_handler(QUIT, NULL);
- add_handler(SHUTDOWN, NULL);
- add_handler(GETPRSTATUS+MAP, NULL);
- add_handler(SETPRSTATUS+MAP, NULL);
- add_handler(UNSETPRSTATUS+MAP, NULL);
- add_handler(GETPRKEY+MAP, NULL);
- add_handler(SETPRKEY+MAP+KEY, NULL);
- add_handler(UNSETPRKEY+MAP, NULL);
- add_handler(FORCEQ+DAEMON, NULL);
- add_handler(RESTOREQ+DAEMON, NULL);
- add_handler(SETMARGINAL+PATH, NULL);
- add_handler(UNSETMARGINAL+PATH, NULL);
- add_handler(UNSETMARGINAL+MAP, NULL);
-
return 0;
}
#include <stdint.h>
enum {
- __LIST,
+ __LIST, /* 0 */
__ADD,
__DEL,
__SWITCH,
__SUSPEND,
- __RESUME,
+ __RESUME, /* 5 */
__REINSTATE,
__FAIL,
__RESIZE,
__RESET,
- __RELOAD,
+ __RELOAD, /* 10 */
__FORCEQ,
__DISABLEQ,
__RESTOREQ,
__PATHS,
- __MAPS,
+ __MAPS, /* 15 */
__PATH,
__MAP,
__GROUP,
__RECONFIGURE,
- __DAEMON,
+ __DAEMON, /* 20 */
__STATUS,
__STATS,
__TOPOLOGY,
__CONFIG,
- __BLACKLIST,
+ __BLACKLIST, /* 25 */
__DEVICES,
__RAW,
__WILDCARDS,
__QUIT,
- __SHUTDOWN,
+ __SHUTDOWN, /* 30 */
__GETPRSTATUS,
__SETPRSTATUS,
__UNSETPRSTATUS,
__FMT,
- __JSON,
+ __JSON, /* 35 */
__GETPRKEY,
__SETPRKEY,
__UNSETPRKEY,
__KEY,
- __LOCAL,
+ __LOCAL, /* 40 */
__SETMARGINAL,
__UNSETMARGINAL,
+ __ALL,
};
-#define LIST (1 << __LIST)
-#define ADD (1 << __ADD)
-#define DEL (1 << __DEL)
-#define SWITCH (1 << __SWITCH)
-#define SUSPEND (1 << __SUSPEND)
-#define RESUME (1 << __RESUME)
-#define REINSTATE (1 << __REINSTATE)
-#define FAIL (1 << __FAIL)
-#define RESIZE (1 << __RESIZE)
-#define RESET (1 << __RESET)
-#define RELOAD (1 << __RELOAD)
-#define FORCEQ (1 << __FORCEQ)
-#define DISABLEQ (1 << __DISABLEQ)
-#define RESTOREQ (1 << __RESTOREQ)
-#define PATHS (1 << __PATHS)
-#define MAPS (1 << __MAPS)
-#define PATH (1 << __PATH)
-#define MAP (1 << __MAP)
-#define GROUP (1 << __GROUP)
-#define RECONFIGURE (1 << __RECONFIGURE)
-#define DAEMON (1 << __DAEMON)
-#define STATUS (1 << __STATUS)
-#define STATS (1 << __STATS)
-#define TOPOLOGY (1 << __TOPOLOGY)
-#define CONFIG (1 << __CONFIG)
-#define BLACKLIST (1 << __BLACKLIST)
-#define DEVICES (1 << __DEVICES)
-#define RAW (1 << __RAW)
-#define COUNT (1 << __COUNT)
-#define WILDCARDS (1 << __WILDCARDS)
-#define QUIT (1 << __QUIT)
-#define SHUTDOWN (1 << __SHUTDOWN)
+#define LIST (1ULL << __LIST)
+#define ADD (1ULL << __ADD)
+#define DEL (1ULL << __DEL)
+#define SWITCH (1ULL << __SWITCH)
+#define SUSPEND (1ULL << __SUSPEND)
+#define RESUME (1ULL << __RESUME)
+#define REINSTATE (1ULL << __REINSTATE)
+#define FAIL (1ULL << __FAIL)
+#define RESIZE (1ULL << __RESIZE)
+#define RESET (1ULL << __RESET)
+#define RELOAD (1ULL << __RELOAD)
+#define FORCEQ (1ULL << __FORCEQ)
+#define DISABLEQ (1ULL << __DISABLEQ)
+#define RESTOREQ (1ULL << __RESTOREQ)
+#define PATHS (1ULL << __PATHS)
+#define MAPS (1ULL << __MAPS)
+#define PATH (1ULL << __PATH)
+#define MAP (1ULL << __MAP)
+#define GROUP (1ULL << __GROUP)
+#define RECONFIGURE (1ULL << __RECONFIGURE)
+#define DAEMON (1ULL << __DAEMON)
+#define STATUS (1ULL << __STATUS)
+#define STATS (1ULL << __STATS)
+#define TOPOLOGY (1ULL << __TOPOLOGY)
+#define CONFIG (1ULL << __CONFIG)
+#define BLACKLIST (1ULL << __BLACKLIST)
+#define DEVICES (1ULL << __DEVICES)
+#define RAW (1ULL << __RAW)
+#define COUNT (1ULL << __COUNT)
+#define WILDCARDS (1ULL << __WILDCARDS)
+#define QUIT (1ULL << __QUIT)
+#define SHUTDOWN (1ULL << __SHUTDOWN)
#define GETPRSTATUS (1ULL << __GETPRSTATUS)
#define SETPRSTATUS (1ULL << __SETPRSTATUS)
#define UNSETPRSTATUS (1ULL << __UNSETPRSTATUS)
#define LOCAL (1ULL << __LOCAL)
#define SETMARGINAL (1ULL << __SETMARGINAL)
#define UNSETMARGINAL (1ULL << __UNSETMARGINAL)
+#define ALL (1ULL << __ALL)
#define INITIAL_REPLY_LEN 1200
free(tmp); \
(r) = NULL; \
} else { \
- (r) = REALLOC((r), (m) * 2); \
+ (r) = realloc((r), (m) * 2); \
if ((r)) { \
memset((r) + (m), 0, (m)); \
(m) *= 2; \
int has_param;
};
+struct strbuf;
+
+typedef int (cli_handler)(void *keywords, struct strbuf *reply, void *data);
+
struct handler {
uint64_t fingerprint;
int locked;
- int (*fn)(void *, char **, int *, void *);
+ cli_handler *fn;
};
int alloc_handlers (void);
-int add_handler (uint64_t fp, int (*fn)(void *, char **, int *, void *));
-int set_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *));
-int set_unlocked_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *));
-int parse_cmd (char * cmd, char ** reply, int * len, void *, int);
+int __set_handler_callback (uint64_t fp, cli_handler *fn, bool locked);
+#define set_handler_callback(fp, fn) __set_handler_callback(fp, fn, true)
+#define set_unlocked_handler_callback(fp, fn) __set_handler_callback(fp, fn, false)
+
+int get_cmdvec (char *cmd, vector *v);
+struct handler *find_handler_for_cmdvec(const struct _vector *v);
+void genhelp_handler (const char *cmd, int error, struct strbuf *reply);
+
int load_keys (void);
char * get_keyparam (vector v, uint64_t code);
void free_keys (vector vec);
#define _GNU_SOURCE
#include "checkers.h"
-#include "memory.h"
#include "vector.h"
#include "structs.h"
#include "structs_vec.h"
#include "strbuf.h"
#include "cli_handlers.h"
-#define SET_REPLY_AND_LEN(__rep, __len, string_literal) \
- do { \
- *(__rep) = strdup(string_literal); \
- *(__len) = *(__rep) ? sizeof(string_literal) : 0; \
- } while (0)
-
-int
-show_paths (char ** r, int * len, struct vectors * vecs, char * style,
- int pretty)
+static int
+show_paths (struct strbuf *reply, struct vectors *vecs, char *style, int pretty)
{
- STRBUF_ON_STACK(reply);
int i;
struct path * pp;
int hdr_len = 0;
+ fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
- get_path_layout(vecs->pathvec, 1);
- foreign_path_layout();
-
- if (pretty && (hdr_len = snprint_path_header(&reply, style)) < 0)
+ if (pretty) {
+ if ((width = alloc_path_layout()) == NULL)
+ return 1;
+ get_path_layout(vecs->pathvec, 1, width);
+ foreign_path_layout(width);
+ }
+ if (pretty && (hdr_len = snprint_path_header(reply, style, width)) < 0)
return 1;
vector_foreach_slot(vecs->pathvec, pp, i) {
- if (snprint_path(&reply, style, pp, pretty) < 0)
+ if (snprint_path(reply, style, pp, width) < 0)
return 1;
}
- if (snprint_foreign_paths(&reply, style, pretty) < 0)
+ if (snprint_foreign_paths(reply, style, width) < 0)
return 1;
- if (pretty && get_strbuf_len(&reply) == (size_t)hdr_len)
+ if (pretty && get_strbuf_len(reply) == (size_t)hdr_len)
/* No output - clear header */
- truncate_strbuf(&reply, 0);
+ truncate_strbuf(reply, 0);
- *len = (int)get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
-int
-show_path (char ** r, int * len, struct vectors * vecs, struct path *pp,
- char * style)
+static int
+show_path (struct strbuf *reply, struct vectors *vecs, struct path *pp,
+ char *style)
{
- STRBUF_ON_STACK(reply);
+ fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
- get_path_layout(vecs->pathvec, 1);
- if (snprint_path(&reply, style, pp, 0) < 0)
+ if ((width = alloc_path_layout()) == NULL)
+ return 1;
+ get_path_layout(vecs->pathvec, 1, width);
+ if (snprint_path(reply, style, pp, 0) < 0)
return 1;
- *len = (int)get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
-
return 0;
}
-int
-show_map_topology (char ** r, int * len, struct multipath * mpp,
- struct vectors * vecs)
+static int
+show_map_topology (struct strbuf *reply, struct multipath *mpp,
+ struct vectors *vecs, const fieldwidth_t *width)
{
- STRBUF_ON_STACK(reply);
-
if (update_multipath(vecs, mpp->alias, 0))
return 1;
- if (snprint_multipath_topology(&reply, mpp, 2) < 0)
+ if (snprint_multipath_topology(reply, mpp, 2, width) < 0)
return 1;
- *len = (int)get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
-int
-show_maps_topology (char ** r, int * len, struct vectors * vecs)
+static int
+show_maps_topology (struct strbuf *reply, struct vectors * vecs)
{
- STRBUF_ON_STACK(reply);
int i;
struct multipath * mpp;
+ fieldwidth_t *p_width __attribute__((cleanup(cleanup_ucharp))) = NULL;
- get_path_layout(vecs->pathvec, 0);
- foreign_path_layout();
+ if ((p_width = alloc_path_layout()) == NULL)
+ return 1;
+ get_path_layout(vecs->pathvec, 0, p_width);
+ foreign_path_layout(p_width);
vector_foreach_slot(vecs->mpvec, mpp, i) {
if (update_multipath(vecs, mpp->alias, 0)) {
i--;
continue;
}
- if (snprint_multipath_topology(&reply, mpp, 2) < 0)
+ if (snprint_multipath_topology(reply, mpp, 2, p_width) < 0)
return 1;
}
- if (snprint_foreign_topology(&reply, 2) < 0)
+ if (snprint_foreign_topology(reply, 2, p_width) < 0)
return 1;
- *len = (int)get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
-int
-show_maps_json (char ** r, int * len, struct vectors * vecs)
+static int
+show_maps_json (struct strbuf *reply, struct vectors * vecs)
{
- STRBUF_ON_STACK(reply);
int i;
struct multipath * mpp;
}
}
- if (snprint_multipath_topology_json(&reply, vecs) < 0)
+ if (snprint_multipath_topology_json(reply, vecs) < 0)
return 1;
- *len = (int)get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
-int
-show_map_json (char ** r, int * len, struct multipath * mpp,
- struct vectors * vecs)
+static int
+show_map_json (struct strbuf *reply, struct multipath * mpp,
+ struct vectors * vecs)
{
- STRBUF_ON_STACK(reply);
-
if (update_multipath(vecs, mpp->alias, 0))
return 1;
- if (snprint_multipath_map_json(&reply, mpp) < 0)
+ if (snprint_multipath_map_json(reply, mpp) < 0)
return 1;
- *len = (int)get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
static int
-show_config (char ** r, int * len, const struct _vector *hwtable,
+show_config (struct strbuf *reply, const struct _vector *hwtable,
const struct _vector *mpvec)
{
struct config *conf;
- char *reply;
+ int rc;
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config, conf);
- reply = snprint_config(conf, len, hwtable, mpvec);
+ rc = __snprint_config(conf, reply, hwtable, mpvec);
pthread_cleanup_pop(1);
- if (reply == NULL)
+ if (rc < 0)
return 1;
- *r = reply;
return 0;
}
mpp->stat_map_failures = 0;
}
-int
-cli_list_config (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_config (void *v, struct strbuf *reply, void *data)
{
condlog(3, "list config (operator)");
- return show_config(reply, len, NULL, NULL);
+ return show_config(reply, NULL, NULL);
}
static void v_free(void *x)
vector_free(x);
}
-int
-cli_list_config_local (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_config_local (void *v, struct strbuf *reply, void *data)
{
- struct vectors * vecs = (struct vectors *)data;
+ struct vectors *vecs = (struct vectors *)data;
vector hwes;
int ret;
hwes = get_used_hwes(vecs->pathvec);
pthread_cleanup_push(v_free, hwes);
- ret = show_config(reply, len, hwes, vecs->mpvec);
+ ret = show_config(reply, hwes, vecs->mpvec);
pthread_cleanup_pop(1);
return ret;
}
-int
-cli_list_paths (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_paths (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
condlog(3, "list paths (operator)");
- return show_paths(reply, len, vecs, PRINT_PATH_CHECKER, 1);
+ return show_paths(reply, vecs, PRINT_PATH_CHECKER, 1);
}
-int
-cli_list_paths_fmt (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_paths_fmt (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
char * fmt = get_keyparam(v, FMT);
condlog(3, "list paths (operator)");
- return show_paths(reply, len, vecs, fmt, 1);
+ return show_paths(reply, vecs, fmt, 1);
}
-int
-cli_list_paths_raw (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_paths_raw (void *v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * fmt = get_keyparam(v, FMT);
condlog(3, "list paths (operator)");
- return show_paths(reply, len, vecs, fmt, 0);
+ return show_paths(reply, vecs, fmt, 0);
}
-int
-cli_list_path (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_path (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
if (!pp)
return 1;
- return show_path(reply, len, vecs, pp, "%o");
+ return show_path(reply, vecs, pp, "%o");
}
-int
-cli_list_map_topology (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_map_topology (void *v, struct strbuf *reply, void *data)
{
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
+ fieldwidth_t *p_width __attribute__((cleanup(cleanup_ucharp))) = NULL;
+ if ((p_width = alloc_path_layout()) == NULL)
+ return 1;
+ get_path_layout(vecs->pathvec, 0, p_width);
param = convert_dev(param, 0);
- get_path_layout(vecs->pathvec, 0);
mpp = find_mp_by_str(vecs->mpvec, param);
if (!mpp)
condlog(3, "list multipath %s (operator)", param);
- return show_map_topology(reply, len, mpp, vecs);
+ return show_map_topology(reply, mpp, vecs, p_width);
}
-int
-cli_list_maps_topology (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_maps_topology (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
condlog(3, "list multipaths (operator)");
- return show_maps_topology(reply, len, vecs);
+ return show_maps_topology(reply, vecs);
}
-int
-cli_list_map_json (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_map_json (void *v, struct strbuf *reply, void *data)
{
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
param = convert_dev(param, 0);
- get_path_layout(vecs->pathvec, 0);
mpp = find_mp_by_str(vecs->mpvec, param);
if (!mpp)
condlog(3, "list multipath json %s (operator)", param);
- return show_map_json(reply, len, mpp, vecs);
+ return show_map_json(reply, mpp, vecs);
}
-int
-cli_list_maps_json (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_maps_json (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
condlog(3, "list multipaths json (operator)");
- return show_maps_json(reply, len, vecs);
+ return show_maps_json(reply, vecs);
}
-int
-cli_list_wildcards (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_wildcards (void *v, struct strbuf *reply, void *data)
{
- STRBUF_ON_STACK(buf);
-
- if (snprint_wildcards(&buf) < 0)
+ if (snprint_wildcards(reply) < 0)
return 1;
- *len = get_strbuf_len(&buf) + 1;
- *reply = steal_strbuf_str(&buf);
return 0;
}
-int
-show_status (char ** r, int *len, struct vectors * vecs)
+static int
+show_status (struct strbuf *reply, struct vectors *vecs)
{
- STRBUF_ON_STACK(reply);
-
- if (snprint_status(&reply, vecs) < 0)
+ if (snprint_status(reply, vecs) < 0)
return 1;
- *len = get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
-int
-show_daemon (char ** r, int *len)
+static int
+show_daemon (struct strbuf *reply)
{
- STRBUF_ON_STACK(reply);
-
- if (print_strbuf(&reply, "pid %d %s\n",
+ if (print_strbuf(reply, "pid %d %s\n",
daemon_pid, daemon_status()) < 0)
return 1;
- *len = get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
-int
-show_map (char ** r, int *len, struct multipath * mpp, char * style,
- int pretty)
+static int
+show_map (struct strbuf *reply, struct multipath *mpp, char *style,
+ const fieldwidth_t *width)
{
- STRBUF_ON_STACK(reply);
-
- if (snprint_multipath(&reply, style, mpp, pretty) < 0)
+ if (snprint_multipath(reply, style, mpp, width) < 0)
return 1;
- *len = get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
-int
-show_maps (char ** r, int *len, struct vectors * vecs, char * style,
+static int
+show_maps (struct strbuf *reply, struct vectors *vecs, char *style,
int pretty)
{
- STRBUF_ON_STACK(reply);
int i;
struct multipath * mpp;
int hdr_len = 0;
+ fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
- get_multipath_layout(vecs->mpvec, 1);
- foreign_multipath_layout();
+ if (pretty) {
+ if ((width = alloc_multipath_layout()) == NULL)
+ return 1;
+ get_multipath_layout(vecs->mpvec, 1, width);
+ foreign_multipath_layout(width);
+ }
- if (pretty && (hdr_len = snprint_multipath_header(&reply, style)) < 0)
+ if (pretty && (hdr_len = snprint_multipath_header(reply, style, width)) < 0)
return 1;
vector_foreach_slot(vecs->mpvec, mpp, i) {
i--;
continue;
}
- if (snprint_multipath(&reply, style, mpp, pretty) < 0)
+ if (snprint_multipath(reply, style, mpp, width) < 0)
return 1;
}
- if (snprint_foreign_multipaths(&reply, style, pretty) < 0)
+ if (snprint_foreign_multipaths(reply, style, width) < 0)
return 1;
- if (pretty && get_strbuf_len(&reply) == (size_t)hdr_len)
+ if (pretty && get_strbuf_len(reply) == (size_t)hdr_len)
/* No output - clear header */
- truncate_strbuf(&reply, 0);
+ truncate_strbuf(reply, 0);
- *len = (int)get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
-int
-cli_list_maps_fmt (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_maps_fmt (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
char * fmt = get_keyparam(v, FMT);
condlog(3, "list maps (operator)");
- return show_maps(reply, len, vecs, fmt, 1);
+ return show_maps(reply, vecs, fmt, 1);
}
-int
-cli_list_maps_raw (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_maps_raw (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
char * fmt = get_keyparam(v, FMT);
condlog(3, "list maps (operator)");
- return show_maps(reply, len, vecs, fmt, 0);
+ return show_maps(reply, vecs, fmt, 0);
}
-int
-cli_list_map_fmt (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_map_fmt (void *v, struct strbuf *reply, void *data)
{
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
char * fmt = get_keyparam(v, FMT);
+ fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
- param = convert_dev(param, 0);
- get_path_layout(vecs->pathvec, 0);
- get_multipath_layout(vecs->mpvec, 1);
- mpp = find_mp_by_str(vecs->mpvec, param);
- if (!mpp)
+ if ((width = alloc_multipath_layout()) == NULL)
return 1;
-
- condlog(3, "list map %s fmt %s (operator)", param, fmt);
-
- return show_map(reply, len, mpp, fmt, 1);
-}
-
-int
-cli_list_map_raw (void * v, char ** reply, int * len, void * data)
-{
- struct multipath * mpp;
- struct vectors * vecs = (struct vectors *)data;
- char * param = get_keyparam(v, MAP);
- char * fmt = get_keyparam(v, FMT);
-
+ get_multipath_layout(vecs->pathvec, 1, width);
param = convert_dev(param, 0);
- get_path_layout(vecs->pathvec, 0);
- get_multipath_layout(vecs->mpvec, 1);
mpp = find_mp_by_str(vecs->mpvec, param);
if (!mpp)
return 1;
condlog(3, "list map %s fmt %s (operator)", param, fmt);
- return show_map(reply, len, mpp, fmt, 0);
+ return show_map(reply, mpp, fmt, width);
}
-int
-cli_list_maps (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_maps (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
condlog(3, "list maps (operator)");
- return show_maps(reply, len, vecs, PRINT_MAP_NAMES, 1);
+ return show_maps(reply, vecs, PRINT_MAP_NAMES, 1);
}
-int
-cli_list_status (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_status (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
condlog(3, "list status (operator)");
- return show_status(reply, len, vecs);
+ return show_status(reply, vecs);
}
-int
-cli_list_maps_status (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_maps_status (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
condlog(3, "list maps status (operator)");
- return show_maps(reply, len, vecs, PRINT_MAP_STATUS, 1);
+ return show_maps(reply, vecs, PRINT_MAP_STATUS, 1);
}
-int
-cli_list_maps_stats (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_maps_stats (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
condlog(3, "list maps stats (operator)");
- return show_maps(reply, len, vecs, PRINT_MAP_STATS, 1);
+ return show_maps(reply, vecs, PRINT_MAP_STATS, 1);
}
-int
-cli_list_daemon (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_daemon (void *v, struct strbuf *reply, void *data)
{
condlog(3, "list daemon (operator)");
- return show_daemon(reply, len);
+ return show_daemon(reply);
}
-int
-cli_reset_maps_stats (void * v, char ** reply, int * len, void * data)
+static int
+cli_reset_maps_stats (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
int i;
return 0;
}
-int
-cli_reset_map_stats (void * v, char ** reply, int * len, void * data)
+static int
+cli_reset_map_stats (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
struct multipath * mpp;
return 0;
}
-int
-cli_add_path (void * v, char ** reply, int * len, void * data)
+static int
+add_partial_path(struct path *pp, struct vectors *vecs)
+{
+ char wwid[WWID_SIZE];
+ struct udev_device *udd;
+
+ udd = get_udev_device(pp->dev_t, DEV_DEVT);
+ if (!udd)
+ return 0;
+ strcpy(wwid, pp->wwid);
+ if (get_uid(pp, pp->state, udd, 0) != 0) {
+ strcpy(pp->wwid, wwid);
+ udev_device_unref(udd);
+ return 0;
+ }
+ if (strlen(wwid) && strncmp(wwid, pp->wwid, WWID_SIZE) != 0) {
+ condlog(0, "%s: path wwid changed from '%s' to '%s'. removing",
+ pp->dev, wwid, pp->wwid);
+ ev_remove_path(pp, vecs, 1);
+ udev_device_unref(udd);
+ return -1;
+ }
+ udev_device_unref(pp->udev);
+ pp->udev = udd;
+ return finish_path_init(pp, vecs);
+}
+
+static int
+cli_add_path (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
if (pp && pp->initialized != INIT_REMOVED) {
condlog(2, "%s: path already in pathvec", param);
- if (pp->recheck_wwid == RECHECK_WWID_ON &&
- check_path_wwid_change(pp)) {
+ if (pp->initialized == INIT_PARTIAL) {
+ if (add_partial_path(pp, vecs) < 0)
+ return 1;
+ }
+ else if (pp->recheck_wwid == RECHECK_WWID_ON &&
+ check_path_wwid_change(pp)) {
condlog(0, "%s: wwid changed. Removing device",
pp->dev);
handle_path_wwid_change(pp, vecs);
}
return ev_add_path(pp, vecs, 1);
blacklisted:
- SET_REPLY_AND_LEN(reply, len, "blacklisted\n");
+ append_strbuf_str(reply, "blacklisted\n");
condlog(2, "%s: path blacklisted", param);
return 0;
}
-int
-cli_del_path (void * v, char ** reply, int * len, void * data)
+static int
+cli_del_path (void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
}
ret = ev_remove_path(pp, vecs, 1);
if (ret == REMOVE_PATH_DELAY)
- SET_REPLY_AND_LEN(reply, len, "delayed\n");
+ append_strbuf_str(reply, "delayed\n");
else if (ret == REMOVE_PATH_MAP_ERROR)
- SET_REPLY_AND_LEN(reply, len, "map reload error. removed\n");
+ append_strbuf_str(reply, "map reload error. removed\n");
return (ret == REMOVE_PATH_FAILURE);
}
-int
-cli_add_map (void * v, char ** reply, int * len, void * data)
+static int
+cli_add_map (void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
invalid = 1;
pthread_cleanup_pop(1);
if (invalid) {
- SET_REPLY_AND_LEN(reply, len, "blacklisted\n");
+ append_strbuf_str(reply, "blacklisted\n");
condlog(2, "%s: map blacklisted", param);
return 1;
}
!= CP_OK)
condlog(2, "%s: coalesce_paths failed",
param);
- FREE(refwwid);
+ free(refwwid);
}
} /*we attempt to create device only once*/
count++;
return 1;
}
rc = ev_add_map(dev_path, alias, vecs);
- FREE(alias);
+ free(alias);
return rc;
}
-int
-cli_del_map (void * v, char ** reply, int * len, void * data)
+static int
+cli_del_map (void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
return 1;
}
rc = ev_remove_map(param, alias, minor, vecs);
- FREE(alias);
+ if (rc == 2)
+ append_strbuf_str(reply, "delayed");
+
+ free(alias);
return rc;
}
-int
-cli_del_maps (void *v, char **reply, int *len, void *data)
+static int
+cli_del_maps (void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
struct multipath *mpp;
return ret;
}
-int
-cli_reload(void *v, char **reply, int *len, void *data)
+static int
+cli_reload(void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
char * mapname = get_keyparam(v, MAP);
return reload_and_sync_map(mpp, vecs, 0);
}
-int resize_map(struct multipath *mpp, unsigned long long size,
+static int resize_map(struct multipath *mpp, unsigned long long size,
struct vectors * vecs)
{
char *params __attribute__((cleanup(cleanup_charp))) = NULL;
return 0;
}
-int
-cli_resize(void *v, char **reply, int *len, void *data)
+static int
+cli_resize(void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
char * mapname = get_keyparam(v, MAP);
return 0;
}
-int
-cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data)
+static int
+cli_force_no_daemon_q(void * v, struct strbuf *reply, void * data)
{
struct config *conf;
return 0;
}
-int
-cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data)
+static int
+cli_restore_no_daemon_q(void * v, struct strbuf *reply, void * data)
{
struct config *conf;
return 0;
}
-int
-cli_restore_queueing(void *v, char **reply, int *len, void *data)
+static int
+cli_restore_queueing(void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
char * mapname = get_keyparam(v, MAP);
return 0;
}
-int
-cli_restore_all_queueing(void *v, char **reply, int *len, void *data)
+static int
+cli_restore_all_queueing(void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
struct multipath *mpp;
return 0;
}
-int
-cli_disable_queueing(void *v, char **reply, int *len, void *data)
+static int
+cli_disable_queueing(void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
char * mapname = get_keyparam(v, MAP);
return 0;
}
-int
-cli_disable_all_queueing(void *v, char **reply, int *len, void *data)
+static int
+cli_disable_all_queueing(void *v, struct strbuf *reply, void *data)
{
struct vectors * vecs = (struct vectors *)data;
struct multipath *mpp;
return 0;
}
-int
-cli_switch_group(void * v, char ** reply, int * len, void * data)
+static int
+cli_switch_group(void * v, struct strbuf *reply, void * data)
{
char * mapname = get_keyparam(v, MAP);
int groupnum = atoi(get_keyparam(v, GROUP));
return dm_switchgroup(mapname, groupnum);
}
-int
-cli_reconfigure(void * v, char ** reply, int * len, void * data)
+static int
+cli_reconfigure(void * v, struct strbuf *reply, void * data)
{
- int rc;
-
condlog(2, "reconfigure (operator)");
- rc = set_config_state(DAEMON_CONFIGURE);
- if (rc == ETIMEDOUT) {
- condlog(2, "timeout starting reconfiguration");
- return 1;
- } else if (rc == EINVAL)
- /* daemon shutting down */
- return 1;
+ schedule_reconfigure(FORCE_RELOAD_WEAK);
return 0;
}
int
-cli_suspend(void * v, char ** reply, int * len, void * data)
+cli_reconfigure_all(void * v, struct strbuf *reply, void * data)
+{
+ condlog(2, "reconfigure all (operator)");
+
+ schedule_reconfigure(FORCE_RELOAD_YES);
+ return 0;
+}
+
+static int
+cli_suspend(void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
return 0;
}
-int
-cli_resume(void * v, char ** reply, int * len, void * data)
+static int
+cli_resume(void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
return 0;
}
-int
-cli_reinstate(void * v, char ** reply, int * len, void * data)
+static int
+cli_reinstate(void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
}
-int
-cli_reassign (void * v, char ** reply, int * len, void * data)
+static int
+cli_reassign (void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
return 0;
}
-int
-cli_fail(void * v, char ** reply, int * len, void * data)
+static int
+cli_fail(void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
return r;
}
-int
-show_blacklist (char ** r, int * len)
+static int
+show_blacklist (struct strbuf *reply)
{
- STRBUF_ON_STACK(reply);
struct config *conf;
bool fail;
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config, conf);
- fail = snprint_blacklist_report(conf, &reply) < 0;
+ fail = snprint_blacklist_report(conf, reply) < 0;
pthread_cleanup_pop(1);
if (fail)
return 1;
- *len = (int)get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
return 0;
}
-int
-cli_list_blacklist (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_blacklist (void * v, struct strbuf *reply, void * data)
{
condlog(3, "list blacklist (operator)");
- return show_blacklist(reply, len);
+ return show_blacklist(reply);
}
-int
-show_devices (char ** r, int * len, struct vectors *vecs)
+static int
+show_devices (struct strbuf *reply, struct vectors *vecs)
{
- STRBUF_ON_STACK(reply);
struct config *conf;
bool fail;
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config, conf);
- fail = snprint_devices(conf, &reply, vecs) < 0;
+ fail = snprint_devices(conf, reply, vecs) < 0;
pthread_cleanup_pop(1);
if (fail)
return 1;
- *len = (int)get_strbuf_len(&reply) + 1;
- *r = steal_strbuf_str(&reply);
-
return 0;
}
-int
-cli_list_devices (void * v, char ** reply, int * len, void * data)
+static int
+cli_list_devices (void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
condlog(3, "list devices (operator)");
- return show_devices(reply, len, vecs);
+ return show_devices(reply, vecs);
}
-int
-cli_quit (void * v, char ** reply, int * len, void * data)
+static int
+cli_quit (void * v, struct strbuf *reply, void * data)
{
return 0;
}
-int
-cli_shutdown (void * v, char ** reply, int * len, void * data)
+static int
+cli_shutdown (void * v, struct strbuf *reply, void * data)
{
condlog(3, "shutdown (operator)");
exit_daemon();
return 0;
}
-int
-cli_getprstatus (void * v, char ** reply, int * len, void * data)
+static int
+cli_getprstatus (void * v, struct strbuf *reply, void * data)
{
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
param = convert_dev(param, 0);
- get_path_layout(vecs->pathvec, 0);
mpp = find_mp_by_str(vecs->mpvec, param);
if (!mpp)
condlog(3, "%s: prflag = %u", param, (unsigned int)mpp->prflag);
- *len = asprintf(reply, "%d", mpp->prflag);
- if (*len < 0)
+ if (print_strbuf(reply, "%d", mpp->prflag) < 0)
return 1;
- condlog(3, "%s: reply = %s", param, *reply);
+ condlog(3, "%s: reply = %s", param, get_strbuf_str(reply));
return 0;
}
-int
-cli_setprstatus(void * v, char ** reply, int * len, void * data)
+static int
+cli_setprstatus(void * v, struct strbuf *reply, void * data)
{
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
param = convert_dev(param, 0);
- get_path_layout(vecs->pathvec, 0);
mpp = find_mp_by_str(vecs->mpvec, param);
if (!mpp)
return 0;
}
-int
-cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
+static int
+cli_unsetprstatus(void * v, struct strbuf *reply, void * data)
{
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
param = convert_dev(param, 0);
- get_path_layout(vecs->pathvec, 0);
mpp = find_mp_by_str(vecs->mpvec, param);
if (!mpp)
return 0;
}
-int
-cli_getprkey(void * v, char ** reply, int * len, void * data)
+static int
+cli_getprkey(void * v, struct strbuf *reply, void * data)
{
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
if (!mpp)
return 1;
- *reply = malloc(26);
- if (!*reply)
- return 1;
-
key = get_be64(mpp->reservation_key);
if (!key) {
- sprintf(*reply, "none\n");
- *len = sizeof("none\n");
+ append_strbuf_str(reply, "none\n");
return 0;
}
- /* This snprintf() can't overflow - PRIx64 needs max 16 chars */
- *len = snprintf(*reply, 26, "0x%" PRIx64 "%s\n", key,
- mpp->sa_flags & MPATH_F_APTPL_MASK ? ":aptpl" : "") + 1;
+ if (print_strbuf(reply, "0x%" PRIx64 "%s\n", key,
+ mpp->sa_flags & MPATH_F_APTPL_MASK ? ":aptpl" : "") < 0)
+ return 1;
return 0;
}
-int
-cli_unsetprkey(void * v, char ** reply, int * len, void * data)
+static int
+cli_unsetprkey(void * v, struct strbuf *reply, void * data)
{
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
return ret;
}
-int
-cli_setprkey(void * v, char ** reply, int * len, void * data)
+static int
+cli_setprkey(void * v, struct strbuf *reply, void * data)
{
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
return ret;
}
-int cli_set_marginal(void * v, char ** reply, int * len, void * data)
+static int cli_set_marginal(void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
return reload_and_sync_map(pp->mpp, vecs, 0);
}
-int cli_unset_marginal(void * v, char ** reply, int * len, void * data)
+static int cli_unset_marginal(void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
return reload_and_sync_map(pp->mpp, vecs, 0);
}
-int cli_unset_all_marginal(void * v, char ** reply, int * len, void * data)
+static int cli_unset_all_marginal(void * v, struct strbuf *reply, void * data)
{
struct vectors * vecs = (struct vectors *)data;
char * mapname = get_keyparam(v, MAP);
return reload_and_sync_map(mpp, vecs, 0);
}
+
+void init_handler_callbacks(void)
+{
+ set_handler_callback(LIST+PATHS, cli_list_paths);
+ set_handler_callback(LIST+PATHS+FMT, cli_list_paths_fmt);
+ set_handler_callback(LIST+PATHS+RAW+FMT, cli_list_paths_raw);
+ set_handler_callback(LIST+PATH, cli_list_path);
+ set_handler_callback(LIST+MAPS, cli_list_maps);
+ set_handler_callback(LIST+STATUS, cli_list_status);
+ set_unlocked_handler_callback(LIST+DAEMON, cli_list_daemon);
+ set_handler_callback(LIST+MAPS+STATUS, cli_list_maps_status);
+ set_handler_callback(LIST+MAPS+STATS, cli_list_maps_stats);
+ set_handler_callback(LIST+MAPS+FMT, cli_list_maps_fmt);
+ set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw);
+ set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
+ set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology);
+ set_handler_callback(LIST+MAPS+JSON, cli_list_maps_json);
+ set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology);
+ set_handler_callback(LIST+MAP+FMT, cli_list_map_fmt);
+ set_handler_callback(LIST+MAP+RAW+FMT, cli_list_map_fmt);
+ set_handler_callback(LIST+MAP+JSON, cli_list_map_json);
+ set_handler_callback(LIST+CONFIG+LOCAL, cli_list_config_local);
+ set_handler_callback(LIST+CONFIG, cli_list_config);
+ set_handler_callback(LIST+BLACKLIST, cli_list_blacklist);
+ set_handler_callback(LIST+DEVICES, cli_list_devices);
+ set_handler_callback(LIST+WILDCARDS, cli_list_wildcards);
+ set_handler_callback(RESET+MAPS+STATS, cli_reset_maps_stats);
+ set_handler_callback(RESET+MAP+STATS, cli_reset_map_stats);
+ set_handler_callback(ADD+PATH, cli_add_path);
+ set_handler_callback(DEL+PATH, cli_del_path);
+ set_handler_callback(ADD+MAP, cli_add_map);
+ set_handler_callback(DEL+MAP, cli_del_map);
+ set_handler_callback(DEL+MAPS, cli_del_maps);
+ set_handler_callback(SWITCH+MAP+GROUP, cli_switch_group);
+ set_unlocked_handler_callback(RECONFIGURE, cli_reconfigure);
+ set_unlocked_handler_callback(RECONFIGURE+ALL, cli_reconfigure_all);
+ set_handler_callback(SUSPEND+MAP, cli_suspend);
+ set_handler_callback(RESUME+MAP, cli_resume);
+ set_handler_callback(RESIZE+MAP, cli_resize);
+ set_handler_callback(RELOAD+MAP, cli_reload);
+ set_handler_callback(RESET+MAP, cli_reassign);
+ set_handler_callback(REINSTATE+PATH, cli_reinstate);
+ set_handler_callback(FAIL+PATH, cli_fail);
+ set_handler_callback(DISABLEQ+MAP, cli_disable_queueing);
+ set_handler_callback(RESTOREQ+MAP, cli_restore_queueing);
+ set_handler_callback(DISABLEQ+MAPS, cli_disable_all_queueing);
+ set_handler_callback(RESTOREQ+MAPS, cli_restore_all_queueing);
+ set_unlocked_handler_callback(QUIT, cli_quit);
+ set_unlocked_handler_callback(SHUTDOWN, cli_shutdown);
+ set_handler_callback(GETPRSTATUS+MAP, cli_getprstatus);
+ set_handler_callback(SETPRSTATUS+MAP, cli_setprstatus);
+ set_handler_callback(UNSETPRSTATUS+MAP, cli_unsetprstatus);
+ set_handler_callback(FORCEQ+DAEMON, cli_force_no_daemon_q);
+ set_handler_callback(RESTOREQ+DAEMON, cli_restore_no_daemon_q);
+ set_handler_callback(GETPRKEY+MAP, cli_getprkey);
+ set_handler_callback(SETPRKEY+MAP+KEY, cli_setprkey);
+ set_handler_callback(UNSETPRKEY+MAP, cli_unsetprkey);
+ set_handler_callback(SETMARGINAL+PATH, cli_set_marginal);
+ set_handler_callback(UNSETMARGINAL+PATH, cli_unset_marginal);
+ set_handler_callback(UNSETMARGINAL+MAP, cli_unset_all_marginal);
+}
-int cli_list_paths (void * v, char ** reply, int * len, void * data);
-int cli_list_paths_fmt (void * v, char ** reply, int * len, void * data);
-int cli_list_paths_raw (void * v, char ** reply, int * len, void * data);
-int cli_list_path (void * v, char ** reply, int * len, void * data);
-int cli_list_status (void * v, char ** reply, int * len, void * data);
-int cli_list_daemon (void * v, char ** reply, int * len, void * data);
-int cli_list_maps (void * v, char ** reply, int * len, void * data);
-int cli_list_maps_fmt (void * v, char ** reply, int * len, void * data);
-int cli_list_maps_raw (void * v, char ** reply, int * len, void * data);
-int cli_list_map_fmt (void * v, char ** reply, int * len, void * data);
-int cli_list_map_raw (void * v, char ** reply, int * len, void * data);
-int cli_list_maps_status (void * v, char ** reply, int * len, void * data);
-int cli_list_maps_stats (void * v, char ** reply, int * len, void * data);
-int cli_list_map_topology (void * v, char ** reply, int * len, void * data);
-int cli_list_maps_topology (void * v, char ** reply, int * len, void * data);
-int cli_list_map_json (void * v, char ** reply, int * len, void * data);
-int cli_list_maps_json (void * v, char ** reply, int * len, void * data);
-int cli_list_config (void * v, char ** reply, int * len, void * data);
-int cli_list_config_local (void * v, char ** reply, int * len, void * data);
-int cli_list_blacklist (void * v, char ** reply, int * len, void * data);
-int cli_list_devices (void * v, char ** reply, int * len, void * data);
-int cli_list_wildcards (void * v, char ** reply, int * len, void * data);
-int cli_reset_maps_stats (void * v, char ** reply, int * len, void * data);
-int cli_reset_map_stats (void * v, char ** reply, int * len, void * data);
-int cli_add_path (void * v, char ** reply, int * len, void * data);
-int cli_del_path (void * v, char ** reply, int * len, void * data);
-int cli_add_map (void * v, char ** reply, int * len, void * data);
-int cli_del_map (void * v, char ** reply, int * len, void * data);
-int cli_del_maps (void * v, char ** reply, int * len, void * data);
-int cli_switch_group(void * v, char ** reply, int * len, void * data);
-int cli_reconfigure(void * v, char ** reply, int * len, void * data);
-int cli_resize(void * v, char ** reply, int * len, void * data);
-int cli_reload(void * v, char ** reply, int * len, void * data);
-int cli_disable_queueing(void * v, char ** reply, int * len, void * data);
-int cli_disable_all_queueing(void * v, char ** reply, int * len, void * data);
-int cli_restore_queueing(void * v, char ** reply, int * len, void * data);
-int cli_restore_all_queueing(void * v, char ** reply, int * len, void * data);
-int cli_suspend(void * v, char ** reply, int * len, void * data);
-int cli_resume(void * v, char ** reply, int * len, void * data);
-int cli_reinstate(void * v, char ** reply, int * len, void * data);
-int cli_fail(void * v, char ** reply, int * len, void * data);
-int cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data);
-int cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data);
-int cli_quit(void * v, char ** reply, int * len, void * data);
-int cli_shutdown(void * v, char ** reply, int * len, void * data);
-int cli_reassign (void * v, char ** reply, int * len, void * data);
-int cli_getprstatus(void * v, char ** reply, int * len, void * data);
-int cli_setprstatus(void * v, char ** reply, int * len, void * data);
-int cli_unsetprstatus(void * v, char ** reply, int * len, void * data);
-int cli_getprkey(void * v, char ** reply, int * len, void * data);
-int cli_setprkey(void * v, char ** reply, int * len, void * data);
-int cli_unsetprkey(void * v, char ** reply, int * len, void * data);
-int cli_set_marginal(void * v, char ** reply, int * len, void * data);
-int cli_unset_marginal(void * v, char ** reply, int * len, void * data);
-int cli_unset_all_marginal(void * v, char ** reply, int * len, void * data);
+#ifndef _CLI_HANDLERS_H
+#define _CLI_HANDLERS_H
+
+void init_handler_callbacks(void);
+
+#endif
*/
#include "parser.h"
#include "vector.h"
-#include "memory.h"
#include "config.h"
#include "util.h"
#include "hwtable.h"
#endif
/* Don't access this variable without holding config_lock */
static volatile enum daemon_status running_state = DAEMON_INIT;
+/* Don't access this variable without holding config_lock */
+static bool __delayed_reconfig;
pid_t daemon_pid;
static pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t config_cond;
return get_running_state() == DAEMON_SHUTDOWN;
}
+static bool get_delayed_reconfig(void)
+{
+ bool val;
+
+ pthread_mutex_lock(&config_lock);
+ val = __delayed_reconfig;
+ pthread_mutex_unlock(&config_lock);
+ return val;
+}
+
/*
* global copy of vecs for use in sig handlers
*/
if (msg && !safe_sprintf(notify_msg, "STATUS=%s", msg))
sd_notify(0, notify_msg);
- if (new_state == DAEMON_SHUTDOWN)
+ if (new_state == DAEMON_SHUTDOWN) {
+ /* Tell systemd that we're not RELOADING any more */
+ if (old_state == DAEMON_CONFIGURE && startup_done)
+ sd_notify(0, "READY=1");
sd_notify(0, "STOPPING=1");
- else if (new_state == DAEMON_IDLE && old_state == DAEMON_CONFIGURE) {
+ } else if (new_state == DAEMON_IDLE && old_state == DAEMON_CONFIGURE) {
sd_notify(0, "READY=1");
startup_done = true;
} else if (new_state == DAEMON_CONFIGURE && startup_done)
sd_notify(0, "RELOADING=1");
}
+#else
+static void do_sd_notify(__attribute__((unused)) enum daemon_status old_state,
+ __attribute__((unused)) enum daemon_status new_state)
+{}
#endif
static void config_cleanup(__attribute__((unused)) void *arg)
return st;
}
+/* Don't access this variable without holding config_lock */
+static enum force_reload_types reconfigure_pending = FORCE_RELOAD_NONE;
+/* Only set while changing to DAEMON_CONFIGURE, and only access while
+ * reconfiguring or scheduling a delayed reconfig in DAEMON_CONFIGURE */
+static volatile enum force_reload_types reload_type = FORCE_RELOAD_NONE;
+
+static void enable_delayed_reconfig(void)
+{
+ pthread_mutex_lock(&config_lock);
+ reconfigure_pending = reload_type;
+ __delayed_reconfig = true;
+ pthread_mutex_unlock(&config_lock);
+}
+
/* must be called with config_lock held */
static void __post_config_state(enum daemon_status state)
{
if (state != running_state && running_state != DAEMON_SHUTDOWN) {
-#ifdef USE_SYSTEMD
enum daemon_status old_state = running_state;
-#endif
+ /*
+ * Handle a pending reconfigure request.
+ * DAEMON_IDLE is set from child() after reconfigure(),
+ * or from checkerloop() after completing checkers.
+ * In either case, child() will see DAEMON_CONFIGURE
+ * again and start another reconfigure cycle.
+ */
+ if (reconfigure_pending != FORCE_RELOAD_NONE &&
+ state == DAEMON_IDLE &&
+ (old_state == DAEMON_CONFIGURE ||
+ old_state == DAEMON_RUNNING)) {
+ /*
+ * notify systemd of transient idle state, lest systemd
+ * thinks the reload lasts forever.
+ */
+ do_sd_notify(old_state, DAEMON_IDLE);
+ old_state = DAEMON_IDLE;
+ state = DAEMON_CONFIGURE;
+ }
+ if (state == DAEMON_CONFIGURE) {
+ reload_type = (reconfigure_pending == FORCE_RELOAD_YES) ? FORCE_RELOAD_YES : FORCE_RELOAD_WEAK;
+ reconfigure_pending = FORCE_RELOAD_NONE;
+ __delayed_reconfig = false;
+ }
running_state = state;
pthread_cond_broadcast(&config_cond);
-#ifdef USE_SYSTEMD
do_sd_notify(old_state, state);
-#endif
}
}
pthread_cleanup_pop(1);
}
-int set_config_state(enum daemon_status state)
+void schedule_reconfigure(enum force_reload_types requested_type)
+{
+ pthread_mutex_lock(&config_lock);
+ pthread_cleanup_push(config_cleanup, NULL);
+ enum force_reload_types type;
+
+ type = (reconfigure_pending == FORCE_RELOAD_YES ||
+ requested_type == FORCE_RELOAD_YES) ?
+ FORCE_RELOAD_YES : FORCE_RELOAD_WEAK;
+ switch (running_state)
+ {
+ case DAEMON_SHUTDOWN:
+ break;
+ case DAEMON_IDLE:
+ reconfigure_pending = type;
+ __post_config_state(DAEMON_CONFIGURE);
+ break;
+ case DAEMON_CONFIGURE:
+ case DAEMON_RUNNING:
+ reconfigure_pending = type;
+ break;
+ default:
+ break;
+ }
+ pthread_cleanup_pop(1);
+}
+
+static enum daemon_status set_config_state(enum daemon_status state)
{
int rc = 0;
+ enum daemon_status st;
pthread_cleanup_push(config_cleanup, NULL);
pthread_mutex_lock(&config_lock);
- if (running_state != state) {
- if (running_state == DAEMON_SHUTDOWN)
- rc = EINVAL;
- else
- rc = __wait_for_state_change(
- running_state != DAEMON_IDLE, 1000);
- if (!rc)
- __post_config_state(state);
+ while (rc == 0 &&
+ running_state != state &&
+ running_state != DAEMON_SHUTDOWN &&
+ running_state != DAEMON_IDLE) {
+ rc = pthread_cond_wait(&config_cond, &config_lock);
}
+
+ if (rc == 0 && running_state == DAEMON_IDLE && state != DAEMON_IDLE)
+ __post_config_state(state);
+ st = running_state;
+
pthread_cleanup_pop(1);
- return rc;
+ return st;
}
struct config *get_multipath_config(void)
{
int retries = 3;
char *params __attribute__((cleanup(cleanup_charp))) = NULL;
+ struct path *pp;
+ int i;
retry:
condlog(4, "%s: updating new map", mpp->alias);
verify_paths(mpp);
mpp->action = ACT_RELOAD;
+ if (mpp->prflag) {
+ vector_foreach_slot(mpp->paths, pp, i) {
+ if ((pp->state == PATH_UP) || (pp->state == PATH_GHOST)) {
+ /* persistent reseravtion check*/
+ mpath_pr_event_handle(pp);
+ }
+ }
+ }
+
if (setup_map(mpp, ¶ms, vecs)) {
condlog(0, "%s: failed to setup new map in update", mpp->alias);
retries = -1;
if (!mpp)
return NULL;
if (!alias) {
- FREE(mpp);
+ free(mpp);
return NULL;
}
- mpp->alias = STRDUP(alias);
+ mpp->alias = strdup(alias);
if (dm_get_info(mpp->alias, &mpp->dmi)) {
condlog(3, "%s: cannot access table", mpp->alias);
pthread_testcancel();
rc = ev_add_map(uev->kernel, alias, vecs);
lock_cleanup_pop(vecs->lock);
- FREE(alias);
+ free(alias);
return rc;
}
ev_add_map (char * dev, const char * alias, struct vectors * vecs)
{
struct multipath * mpp;
- int delayed_reconfig, reassign_maps;
+ int reassign_maps;
struct config *conf;
if (dm_is_mpath(alias) != 1) {
return 1;
}
conf = get_multipath_config();
- delayed_reconfig = conf->delayed_reconfig;
reassign_maps = conf->reassign_maps;
put_multipath_config(conf);
if (mpp->wait_for_udev) {
mpp->wait_for_udev = 0;
- if (delayed_reconfig &&
+ if (get_delayed_reconfig() &&
!need_to_delay_reconfig(vecs)) {
condlog(2, "reconfigure (delayed)");
- set_config_state(DAEMON_CONFIGURE);
+ schedule_reconfigure(FORCE_RELOAD_WEAK);
return 0;
}
}
remove_map_and_stop_waiter(mpp, vecs);
out:
lock_cleanup_pop(vecs->lock);
- FREE(alias);
+ free(alias);
return 0;
}
return false;
}
+/*
+ * uev_add_path can call uev_update_path, and uev_update_path can call
+ * uev_add_path
+ */
+static int uev_update_path (struct uevent *uev, struct vectors * vecs);
+
static int
uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
{
struct path *pp;
int ret = 0, i;
struct config *conf;
+ bool partial_init = false;
condlog(3, "%s: add path (uevent)", uev->kernel);
if (strstr(uev->kernel, "..") != NULL) {
int r;
struct multipath *prev_mpp = NULL;
- if (pp->initialized == INIT_REMOVED) {
+ if (pp->initialized == INIT_PARTIAL) {
+ partial_init = true;
+ goto out;
+ } else if (pp->initialized == INIT_REMOVED) {
condlog(3, "%s: re-adding removed path", pp->dev);
pp->initialized = INIT_NEW;
prev_mpp = pp->mpp;
}
out:
lock_cleanup_pop(vecs->lock);
+ if (partial_init)
+ return uev_update_path(uev, vecs);
return ret;
}
return REMOVE_PATH_MAP_ERROR;
}
+int
+finish_path_init(struct path *pp, struct vectors * vecs)
+{
+ int r;
+ struct config *conf;
+
+ if (pp->udev && pp->uid_attribute && *pp->uid_attribute &&
+ !udev_device_get_is_initialized(pp->udev))
+ return 0;
+ conf = get_multipath_config();
+ pthread_cleanup_push(put_multipath_config, conf);
+ r = pathinfo(pp, conf, DI_ALL|DI_BLACKLIST);
+ pthread_cleanup_pop(1);
+
+ if (r == PATHINFO_OK)
+ return 0;
+
+ condlog(0, "%s: error fully initializing path, removing", pp->dev);
+ ev_remove_path(pp, vecs, 1);
+ return -1;
+}
+
static int
uev_update_path (struct uevent *uev, struct vectors * vecs)
{
}
/* Don't deal with other types of failed initialization
* now. check_path will handle it */
- if (!strlen(pp->wwid))
+ if (!strlen(pp->wwid) && pp->initialized != INIT_PARTIAL)
goto out;
strcpy(wwid, pp->wwid);
if (rc != 0)
strcpy(pp->wwid, wwid);
- else if (strncmp(wwid, pp->wwid, WWID_SIZE) != 0) {
+ else if (strlen(wwid) &&
+ strncmp(wwid, pp->wwid, WWID_SIZE) != 0) {
condlog(0, "%s: path wwid changed from '%s' to '%s'",
uev->kernel, wwid, pp->wwid);
ev_remove_path(pp, vecs, 1);
needs_reinit = 1;
goto out;
+ } else if (pp->initialized == INIT_PARTIAL) {
+ udev_device_unref(pp->udev);
+ pp->udev = udev_device_ref(uev->udev);
+ if (finish_path_init(pp, vecs) < 0) {
+ retval = 1;
+ goto out;
+ }
} else {
udev_device_unref(pp->udev);
pp->udev = udev_device_ref(uev->udev);
condlog(0, "%s: spurious uevent, path not found", uev->kernel);
}
+ /* pp->initalized must not be INIT_PARTIAL if needs_reinit is set */
if (needs_reinit)
retval = uev_add_path(uev, vecs, 1);
return retval;
pp->dev);
out_lock:
lock_cleanup_pop(vecs->lock);
- FREE(devt);
- FREE(action);
+ free(devt);
+ free(action);
return r;
out:
- FREE(action);
+ free(action);
return 1;
}
return 0;
}
-int
-uxsock_trigger (char * str, char ** reply, int * len, bool is_root,
- void * trigger_data)
-{
- struct vectors * vecs;
- int r;
-
- *reply = NULL;
- *len = 0;
- vecs = (struct vectors *)trigger_data;
-
- if ((str != NULL) && (is_root == false) &&
- (strncmp(str, "list", strlen("list")) != 0) &&
- (strncmp(str, "show", strlen("show")) != 0)) {
- *reply = STRDUP("permission deny: need to be root");
- if (*reply)
- *len = strlen(*reply) + 1;
- return 1;
- }
-
- r = parse_cmd(str, reply, len, vecs, uxsock_timeout / 1000);
-
- if (r > 0) {
- if (r == ETIMEDOUT)
- *reply = STRDUP("timeout\n");
- else
- *reply = STRDUP("fail\n");
- if (*reply)
- *len = strlen(*reply) + 1;
- r = 1;
- }
- else if (!r && *len == 0) {
- *reply = STRDUP("ok\n");
- if (*reply)
- *len = strlen(*reply) + 1;
- r = 0;
- }
- /* else if (r < 0) leave *reply alone */
-
- return r;
-}
-
int
uev_trigger (struct uevent * uev, void * trigger_data)
{
/* Tell main thread that thread has started */
post_config_state(DAEMON_CONFIGURE);
- set_handler_callback(LIST+PATHS, cli_list_paths);
- set_handler_callback(LIST+PATHS+FMT, cli_list_paths_fmt);
- set_handler_callback(LIST+PATHS+RAW+FMT, cli_list_paths_raw);
- set_handler_callback(LIST+PATH, cli_list_path);
- set_handler_callback(LIST+MAPS, cli_list_maps);
- set_handler_callback(LIST+STATUS, cli_list_status);
- set_unlocked_handler_callback(LIST+DAEMON, cli_list_daemon);
- set_handler_callback(LIST+MAPS+STATUS, cli_list_maps_status);
- set_handler_callback(LIST+MAPS+STATS, cli_list_maps_stats);
- set_handler_callback(LIST+MAPS+FMT, cli_list_maps_fmt);
- set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw);
- set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
- set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology);
- set_handler_callback(LIST+MAPS+JSON, cli_list_maps_json);
- set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology);
- set_handler_callback(LIST+MAP+FMT, cli_list_map_fmt);
- set_handler_callback(LIST+MAP+RAW+FMT, cli_list_map_fmt);
- set_handler_callback(LIST+MAP+JSON, cli_list_map_json);
- set_handler_callback(LIST+CONFIG+LOCAL, cli_list_config_local);
- set_handler_callback(LIST+CONFIG, cli_list_config);
- set_handler_callback(LIST+BLACKLIST, cli_list_blacklist);
- set_handler_callback(LIST+DEVICES, cli_list_devices);
- set_handler_callback(LIST+WILDCARDS, cli_list_wildcards);
- set_handler_callback(RESET+MAPS+STATS, cli_reset_maps_stats);
- set_handler_callback(RESET+MAP+STATS, cli_reset_map_stats);
- set_handler_callback(ADD+PATH, cli_add_path);
- set_handler_callback(DEL+PATH, cli_del_path);
- set_handler_callback(ADD+MAP, cli_add_map);
- set_handler_callback(DEL+MAP, cli_del_map);
- set_handler_callback(DEL+MAPS, cli_del_maps);
- set_handler_callback(SWITCH+MAP+GROUP, cli_switch_group);
- set_unlocked_handler_callback(RECONFIGURE, cli_reconfigure);
- set_handler_callback(SUSPEND+MAP, cli_suspend);
- set_handler_callback(RESUME+MAP, cli_resume);
- set_handler_callback(RESIZE+MAP, cli_resize);
- set_handler_callback(RELOAD+MAP, cli_reload);
- set_handler_callback(RESET+MAP, cli_reassign);
- set_handler_callback(REINSTATE+PATH, cli_reinstate);
- set_handler_callback(FAIL+PATH, cli_fail);
- set_handler_callback(DISABLEQ+MAP, cli_disable_queueing);
- set_handler_callback(RESTOREQ+MAP, cli_restore_queueing);
- set_handler_callback(DISABLEQ+MAPS, cli_disable_all_queueing);
- set_handler_callback(RESTOREQ+MAPS, cli_restore_all_queueing);
- set_unlocked_handler_callback(QUIT, cli_quit);
- set_unlocked_handler_callback(SHUTDOWN, cli_shutdown);
- set_handler_callback(GETPRSTATUS+MAP, cli_getprstatus);
- set_handler_callback(SETPRSTATUS+MAP, cli_setprstatus);
- set_handler_callback(UNSETPRSTATUS+MAP, cli_unsetprstatus);
- set_handler_callback(FORCEQ+DAEMON, cli_force_no_daemon_q);
- set_handler_callback(RESTOREQ+DAEMON, cli_restore_no_daemon_q);
- set_handler_callback(GETPRKEY+MAP, cli_getprkey);
- set_handler_callback(SETPRKEY+MAP+KEY, cli_setprkey);
- set_handler_callback(UNSETPRKEY+MAP, cli_unsetprkey);
- set_handler_callback(SETMARGINAL+PATH, cli_set_marginal);
- set_handler_callback(UNSETMARGINAL+PATH, cli_unset_marginal);
- set_handler_callback(UNSETMARGINAL+MAP, cli_unset_all_marginal);
-
+ init_handler_callbacks();
umask(077);
- uxsock_listen(&uxsock_trigger, ux_sock, ap);
+
+ /*
+ * Wait for initial reconfiguration to finish, while
+ * hadling signals
+ */
+ while (wait_for_state_change_if(DAEMON_CONFIGURE, 50)
+ == DAEMON_CONFIGURE)
+ handle_signals(false);
+
+ uxsock_listen(ux_sock, ap);
out_sock:
pthread_cleanup_pop(1); /* uxsock_cleanup */
{
struct multipath * mpp;
unsigned int i;
- int timed_out = 0, delayed_reconfig;
- struct config *conf;
+ int timed_out = 0;
vector_foreach_slot (vecs->mpvec, mpp, i) {
if (mpp->wait_for_udev && --mpp->uev_wait_tick <= 0) {
}
}
- conf = get_multipath_config();
- delayed_reconfig = conf->delayed_reconfig;
- put_multipath_config(conf);
- if (timed_out && delayed_reconfig &&
+ if (timed_out && get_delayed_reconfig() &&
!need_to_delay_reconfig(vecs)) {
condlog(2, "reconfigure (delayed)");
- set_config_state(DAEMON_CONFIGURE);
+ schedule_reconfigure(FORCE_RELOAD_WEAK);
}
}
}
}
+static void
+partial_retrigger_tick(vector pathvec)
+{
+ struct path *pp;
+ unsigned int i;
+
+ vector_foreach_slot (pathvec, pp, i) {
+ if (pp->initialized == INIT_PARTIAL && pp->udev &&
+ pp->partial_retrigger_delay > 0 &&
+ --pp->partial_retrigger_delay == 0) {
+ const char *msg = udev_device_get_is_initialized(pp->udev) ?
+ "change" : "add";
+
+ sysfs_attr_set_value(pp->udev, "uevent", msg,
+ strlen(msg));
+ }
+ }
+}
+
int update_prio(struct path *pp, int refresh_all)
{
int oldpriority;
int marginal_pathgroups, marginal_changed = 0;
int ret;
- if (((pp->initialized == INIT_OK ||
+ if (((pp->initialized == INIT_OK || pp->initialized == INIT_PARTIAL ||
pp->initialized == INIT_REQUESTED_UDEV) && !pp->mpp) ||
pp->initialized == INIT_REMOVED)
return 0;
int num_paths = 0, strict_timing, rc = 0;
unsigned int ticks = 0;
+ if (set_config_state(DAEMON_RUNNING) != DAEMON_RUNNING)
+ /* daemon shutdown */
+ break;
+
get_monotonic_time(&start_time);
if (start_time.tv_sec && last_time.tv_sec) {
timespecsub(&start_time, &last_time, &diff_time);
if (use_watchdog)
sd_notify(0, "WATCHDOG=1");
#endif
- rc = set_config_state(DAEMON_RUNNING);
- if (rc == ETIMEDOUT) {
- condlog(4, "timeout waiting for DAEMON_IDLE");
- continue;
- } else if (rc == EINVAL)
- /* daemon shutdown */
- break;
pthread_cleanup_push(cleanup_lock, &vecs->lock);
lock(&vecs->lock);
retry_count_tick(vecs->mpvec);
missing_uev_wait_tick(vecs);
ghost_delay_tick(vecs);
+ partial_retrigger_tick(vecs->pathvec);
lock_cleanup_pop(vecs->lock);
if (count)
vector mpvec;
int i, ret;
struct config *conf;
- static int force_reload = FORCE_RELOAD_WEAK;
if (!vecs->pathvec && !(vecs->pathvec = vector_alloc())) {
condlog(0, "couldn't allocate path vec in configure");
if (should_exit())
goto fail;
- /*
- * create new set of maps & push changed ones into dm
- * In the first call, use FORCE_RELOAD_WEAK to avoid making
- * superfluous ACT_RELOAD ioctls. Later calls are done
- * with FORCE_RELOAD_YES.
- */
- ret = coalesce_paths(vecs, mpvec, NULL, force_reload, CMD_NONE);
- if (force_reload == FORCE_RELOAD_WEAK)
- force_reload = FORCE_RELOAD_YES;
+ ret = coalesce_paths(vecs, mpvec, NULL, reload_type, CMD_NONE);
if (ret != CP_OK) {
condlog(0, "configure failed while coalescing paths");
goto fail;
reset_checker_classes();
if (bindings_read_only)
conf->bindings_read_only = bindings_read_only;
- check_alias_settings(conf);
+
+ if (check_alias_settings(conf))
+ return 1;
uxsock_timeout = conf->uxsock_timeout;
{
struct vectors * vecs;
- vecs = (struct vectors *)MALLOC(sizeof(struct vectors));
+ vecs = (struct vectors *)calloc(1, sizeof(struct vectors));
if (!vecs)
return NULL;
return;
if (reconfig_sig) {
condlog(2, "reconfigure (signal)");
- set_config_state(DAEMON_CONFIGURE);
+ schedule_reconfigure(FORCE_RELOAD_WEAK);
}
if (log_reset_sig) {
condlog(2, "reset log (signal)");
return;
}
-static void
-set_oom_adj (void)
+static void set_oom_adj(void)
{
-#ifdef OOM_SCORE_ADJ_MIN
- int retry = 1;
- char *file = "/proc/self/oom_score_adj";
- int score = OOM_SCORE_ADJ_MIN;
-#else
- int retry = 0;
- char *file = "/proc/self/oom_adj";
- int score = OOM_ADJUST_MIN;
-#endif
FILE *fp;
- struct stat st;
- char *envp;
- envp = getenv("OOMScoreAdjust");
- if (envp) {
+ if (getenv("OOMScoreAdjust")) {
condlog(3, "Using systemd provided OOMScoreAdjust");
return;
}
- do {
- if (stat(file, &st) == 0){
- fp = fopen(file, "w");
- if (!fp) {
- condlog(0, "couldn't fopen %s : %s", file,
- strerror(errno));
- return;
- }
- fprintf(fp, "%i", score);
- fclose(fp);
- return;
- }
- if (errno != ENOENT) {
- condlog(0, "couldn't stat %s : %s", file,
- strerror(errno));
- return;
- }
-#ifdef OOM_ADJUST_MIN
- file = "/proc/self/oom_adj";
- score = OOM_ADJUST_MIN;
-#else
- retry = 0;
+#ifdef OOM_SCORE_ADJ_MIN
+ fp = fopen("/proc/self/oom_score_adj", "w");
+ if (fp) {
+ fprintf(fp, "%i", OOM_SCORE_ADJ_MIN);
+ fclose(fp);
+ return;
+ }
#endif
- } while (retry--);
+ fp = fopen("/proc/self/oom_adj", "w");
+ if (fp) {
+ fprintf(fp, "%i", OOM_ADJUST_MIN);
+ fclose(fp);
+ return;
+ }
condlog(0, "couldn't adjust oom score");
}
cleanup_maps(gvecs);
cleanup_paths(gvecs);
pthread_mutex_destroy(&gvecs->lock.mutex);
- FREE(gvecs);
+ free(gvecs);
+ gvecs = NULL;
}
static void cleanup_threads(void)
log_thread_stop();
cleanup_conf();
-
-#ifdef _DEBUG_
- dbg_free_final(NULL);
-#endif
}
static int sd_notify_exit(int err)
if (state == DAEMON_SHUTDOWN)
break;
if (state == DAEMON_CONFIGURE) {
+ int rc = 0;
+
pthread_cleanup_push(cleanup_lock, &vecs->lock);
lock(&vecs->lock);
pthread_testcancel();
- if (!need_to_delay_reconfig(vecs)) {
- reconfigure(vecs);
- } else {
- conf = get_multipath_config();
- conf->delayed_reconfig = 1;
- put_multipath_config(conf);
- }
+ if (!need_to_delay_reconfig(vecs))
+ rc = reconfigure(vecs);
+ else
+ enable_delayed_reconfig();
lock_cleanup_pop(vecs->lock);
- post_config_state(DAEMON_IDLE);
+ if (!rc)
+ post_config_state(DAEMON_IDLE);
+ else {
+ condlog(0, "fatal error applying configuration - aborting");
+ exit_daemon();
+ }
}
}
return sd_notify_exit(exit_code);
}
+static void cleanup_close(int *pfd)
+{
+ if (*pfd != -1 && *pfd != STDIN_FILENO && *pfd != STDOUT_FILENO &&
+ *pfd != STDERR_FILENO)
+ close(*pfd);
+}
+
static int
daemonize(void)
{
int pid;
- int dev_null_fd;
+ int dev_null_fd __attribute__((cleanup(cleanup_close))) = -1;
if( (pid = fork()) < 0){
fprintf(stderr, "Failed first fork : %s\n", strerror(errno));
_exit(0);
}
- close(STDIN_FILENO);
- if (dup(dev_null_fd) < 0) {
- fprintf(stderr, "cannot dup /dev/null to stdin : %s\n",
+ if (dup2(dev_null_fd, STDIN_FILENO) < 0) {
+ fprintf(stderr, "cannot dup2 /dev/null to stdin : %s\n",
strerror(errno));
_exit(0);
}
- close(STDOUT_FILENO);
- if (dup(dev_null_fd) < 0) {
- fprintf(stderr, "cannot dup /dev/null to stdout : %s\n",
+ if (dup2(dev_null_fd, STDOUT_FILENO) < 0) {
+ fprintf(stderr, "cannot dup2 /dev/null to stdout : %s\n",
strerror(errno));
_exit(0);
}
- close(STDERR_FILENO);
- if (dup(dev_null_fd) < 0) {
+ if (dup2(dev_null_fd, STDERR_FILENO) < 0) {
fprintf(stderr, "cannot dup /dev/null to stderr : %s\n",
strerror(errno));
_exit(0);
}
- close(dev_null_fd);
daemon_pid = getpid();
return 0;
}
logsink = LOGSINK_SYSLOG;
- if (getuid() != 0) {
- fprintf(stderr, "need to be root\n");
- exit(1);
- }
-
/* make sure we don't lock any path */
if (chdir("/") < 0)
fprintf(stderr, "can't chdir to root directory : %s\n",
return err;
}
+ if (getuid() != 0) {
+ fprintf(stderr, "need to be root\n");
+ exit(1);
+ }
+
if (foreground) {
if (!isatty(fileno(stdout)))
setbuf(stdout, NULL);
goto out;
}
- param = (struct prout_param_descriptor *)MALLOC(sizeof(struct prout_param_descriptor));
+ param = (struct prout_param_descriptor *)calloc(1, sizeof(struct prout_param_descriptor));
if (!param)
goto out;
const char * daemon_status(void);
enum daemon_status wait_for_state_change_if(enum daemon_status oldstate,
unsigned long ms);
+void schedule_reconfigure(enum force_reload_types requested_type);
int need_to_delay_reconfig (struct vectors *);
-int reconfigure (struct vectors *);
int ev_add_path (struct path *, struct vectors *, int);
int ev_remove_path (struct path *, struct vectors *, int);
int ev_add_map (char *, const char *, struct vectors *);
int ev_remove_map (char *, char *, int, struct vectors *);
int flush_map(struct multipath *, struct vectors *, int);
-int set_config_state(enum daemon_status);
void * mpath_alloc_prin_response(int prin_sa);
int prin_do_scsi_ioctl(char *, int rq_servact, struct prin_resp * resp,
int noisy);
void handle_path_wwid_change(struct path *pp, struct vectors *vecs);
bool check_path_wwid_change(struct path *pp);
+int finish_path_init(struct path *pp, struct vectors * vecs);
#endif /* MAIN_H */
.
.TP
.BI \-v " level"
-Verbosity level. Print additional information while running multipathd. A level
+Verbosity level. Print additional information while running multipathd. A level
of 0 means only print errors. A level of 3 or greater prints debugging information
as well.
.
.
.TP
.B reconfigure
-Reconfigures the multipaths. This should be triggered automatically after anyi
-hotplug event.
+Rereads the configuration, and reloads all changed multipath devices. This
+also happens at startup, when the service is reload, or when a SIGHUP is
+received.
.
.TP
+.B reconfigure all
+Rereads the configuration, and reloads all multipath devices regardless of
+whether or not they have changed. This also happens when \fImultipath -r\fR is
+run.
+.TP
.B suspend map|multipath $map
Sets map $map into suspend state.
.
.
.TP
.B reset map|multipath $map
-Reassign existing device-mapper table(s) use use the multipath device, instead
+Reassign existing device-mapper table(s) use the multipath device, instead
of its path devices.
.
.TP
[Unit]
Description=Device-Mapper Multipath Device Controller
-Wants=systemd-udev-trigger.service systemd-udev-settle.service
Before=iscsi.service iscsid.service lvm2-activation-early.service
Before=local-fs-pre.target blk-availability.service shutdown.target
-After=multipathd.socket systemd-udev-trigger.service systemd-udev-settle.service
+Wants=systemd-udevd-kernel.socket
+After=systemd-udevd-kernel.socket
+After=multipathd.socket systemd-remount-fs.service
DefaultDependencies=no
Conflicts=shutdown.target
ConditionKernelCommandLine=!nompath
[Unit]
Description=multipathd control socket
DefaultDependencies=no
+ConditionKernelCommandLine=!nompath
+ConditionKernelCommandLine=!multipath=off
+ConditionVirtualization=!container
Before=sockets.target
[Socket]
#include "mpath_cmd.h"
#include "uxsock.h"
-#include "memory.h"
#include "defaults.h"
#include "vector.h"
add_history(line);
free(line);
- FREE(reply);
+ free(reply);
}
}
} else {
printf("%s", reply);
ret = (strcmp(reply, "fail\n") == 0);
- FREE(reply);
+ free(reply);
return ret;
}
}
#include <signal.h>
#include <stdbool.h>
#include <sys/inotify.h>
+#include <sys/eventfd.h>
#include "checkers.h"
-#include "memory.h"
#include "debug.h"
#include "vector.h"
#include "structs.h"
#include "main.h"
#include "cli.h"
#include "uxlsnr.h"
+#include "strbuf.h"
+
+/* state of client connection */
+enum {
+ CLT_RECV,
+ CLT_PARSE,
+ CLT_LOCKED_WORK,
+ CLT_WORK,
+ CLT_SEND,
+};
struct client {
struct list_head node;
+ struct timespec expires;
+ int state;
int fd;
+ vector cmdvec;
+ /* NUL byte at end */
+ char cmd[_MAX_CMD_LEN + 1];
+ struct strbuf reply;
+ struct handler *handler;
+ size_t cmd_len, len;
+ int error;
+ bool is_root;
+};
+
+/* Indices for array of poll fds */
+enum {
+ POLLFD_UX = 0,
+ POLLFD_NOTIFY,
+ POLLFD_IDLE,
+ POLLFDS_BASE,
};
-/* The number of fds we poll on, other than individual client connections */
-#define POLLFDS_BASE 2
#define POLLFD_CHUNK (4096 / sizeof(struct pollfd))
/* Minimum mumber of pollfds to reserve for clients */
#define MIN_POLLS (POLLFD_CHUNK - POLLFDS_BASE)
static __attribute__((unused)) char ___a[-(MIN_POLLS <= 0)];
static LIST_HEAD(clients);
-static pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER;
static struct pollfd *polls;
static int notify_fd = -1;
+static int idle_fd = -1;
static char *watch_config_dir;
-static bool _socket_client_is_root(int fd);
-
static bool _socket_client_is_root(int fd)
{
socklen_t len = 0;
if (fd == -1)
return;
- c = (struct client *)MALLOC(sizeof(*c));
+ c = (struct client *)calloc(1, sizeof(*c));
if (!c) {
close(fd);
return;
}
- memset(c, 0, sizeof(*c));
INIT_LIST_HEAD(&c->node);
c->fd = fd;
+ c->state = CLT_RECV;
+ c->is_root = _socket_client_is_root(c->fd);
/* put it in our linked list */
- pthread_mutex_lock(&client_lock);
list_add_tail(&c->node, &clients);
- pthread_mutex_unlock(&client_lock);
}
/*
* kill off a dead client
*/
-static void _dead_client(struct client *c)
+static void dead_client(struct client *c)
{
int fd = c->fd;
list_del_init(&c->node);
c->fd = -1;
- FREE(c);
+ reset_strbuf(&c->reply);
+ if (c->cmdvec)
+ free_keys(c->cmdvec);
+ free(c);
close(fd);
}
-static void dead_client(struct client *c)
-{
- pthread_cleanup_push(cleanup_mutex, &client_lock);
- pthread_mutex_lock(&client_lock);
- _dead_client(c);
- pthread_cleanup_pop(1);
-}
-
static void free_polls (void)
{
if (polls)
- FREE(polls);
-}
-
-static void check_timeout(struct timespec start_time, char *inbuf,
- unsigned int timeout)
-{
- struct timespec diff_time, end_time;
-
- if (start_time.tv_sec) {
- unsigned long msecs;
-
- get_monotonic_time(&end_time);
- timespecsub(&end_time, &start_time, &diff_time);
- msecs = diff_time.tv_sec * 1000 +
- diff_time.tv_nsec / (1000 * 1000);
- if (msecs > timeout)
- condlog(2, "cli cmd '%s' timeout reached "
- "after %ld.%06lu secs", inbuf,
- (long)diff_time.tv_sec, diff_time.tv_nsec / 1000);
- }
+ free(polls);
+ polls = NULL;
}
void uxsock_cleanup(void *arg)
close(notify_fd);
free(watch_config_dir);
- pthread_mutex_lock(&client_lock);
list_for_each_entry_safe(client_loop, client_tmp, &clients, node) {
- _dead_client(client_loop);
+ dead_client(client_loop);
}
- pthread_mutex_unlock(&client_lock);
cli_exit();
free_polls();
}
+void wakeup_cleanup(void *arg)
+{
+ struct mutex_lock *lck = arg;
+ int fd = idle_fd;
+
+ idle_fd = -1;
+ set_wakeup_fn(lck, NULL);
+ if (fd != -1)
+ close(fd);
+}
+
struct watch_descriptors {
int conf_wd;
int dir_wd;
condlog(1, "Multipath configuration updated.\nReload multipathd for changes to take effect");
}
+static const struct timespec ts_zero = { .tv_sec = 0, };
+static const struct timespec ts_max = { .tv_sec = LONG_MAX, .tv_nsec = 999999999 };
+
+static struct timespec *get_soonest_timeout(struct timespec *ts)
+{
+ struct timespec ts_min = ts_max, now;
+ bool any = false;
+ struct client *c;
+
+ list_for_each_entry(c, &clients, node) {
+ if (timespeccmp(&c->expires, &ts_zero) != 0 &&
+ timespeccmp(&c->expires, &ts_min) < 0) {
+ ts_min = c->expires;
+ any = true;
+ }
+ }
+
+ if (!any)
+ return NULL;
+
+ get_monotonic_time(&now);
+ timespecsub(&ts_min, &now, ts);
+ if (timespeccmp(ts, &ts_zero) < 0)
+ *ts = ts_zero;
+
+ condlog(4, "%s: next client expires in %ld.%03lds", __func__,
+ (long)ts->tv_sec, ts->tv_nsec / 1000000);
+ return ts;
+}
+
+static bool need_vecs_lock(void)
+{
+ struct client *c;
+
+ list_for_each_entry(c, &clients, node) {
+ if (c->state == CLT_LOCKED_WORK)
+ return true;
+ }
+ return false;
+}
+
+static int parse_cmd(struct client *c)
+{
+ int r;
+
+ r = get_cmdvec(c->cmd, &c->cmdvec);
+
+ if (r)
+ return -r;
+
+ c->handler = find_handler_for_cmdvec(c->cmdvec);
+
+ if (!c->handler || !c->handler->fn)
+ return -EINVAL;
+
+ return r;
+}
+
+static int execute_handler(struct client *c, struct vectors *vecs)
+{
+
+ if (!c->handler || !c->handler->fn)
+ return -EINVAL;
+
+ return c->handler->fn(c->cmdvec, &c->reply, vecs);
+}
+
+static void wakeup_listener(void)
+{
+ uint64_t one = 1;
+
+ if (idle_fd != -1 &&
+ write(idle_fd, &one, sizeof(one)) != sizeof(one))
+ condlog(1, "%s: failed", __func__);
+}
+
+static void drain_idle_fd(int fd)
+{
+ uint64_t val;
+ int rc;
+
+ rc = read(fd, &val, sizeof(val));
+ condlog(4, "%s: %d, %"PRIu64, __func__, rc, val);
+}
+
+void default_reply(struct client *c, int r)
+{
+ switch(r) {
+ case -EINVAL:
+ case -ESRCH:
+ case -ENOMEM:
+ /* return codes from get_cmdvec() */
+ genhelp_handler(c->cmd, -r, &c->reply);
+ break;
+ case -EPERM:
+ append_strbuf_str(&c->reply,
+ "permission deny: need to be root\n");
+ break;
+ case -ETIMEDOUT:
+ append_strbuf_str(&c->reply, "timeout\n");
+ break;
+ case 0:
+ append_strbuf_str(&c->reply, "ok\n");
+ break;
+ default:
+ /* cli_handler functions return 1 on unspecified error */
+ append_strbuf_str(&c->reply, "fail\n");
+ break;
+ }
+}
+
+static void set_client_state(struct client *c, int state)
+{
+ switch(state)
+ {
+ case CLT_RECV:
+ reset_strbuf(&c->reply);
+ memset(c->cmd, '\0', sizeof(c->cmd));
+ c->expires = ts_zero;
+ c->error = 0;
+ /* fallthrough */
+ case CLT_SEND:
+ /* reuse these fields for next data transfer */
+ c->len = c->cmd_len = 0;
+ break;
+ default:
+ break;
+ }
+ c->state = state;
+}
+
+enum {
+ STM_CONT,
+ STM_BREAK,
+};
+
+static int client_state_machine(struct client *c, struct vectors *vecs,
+ short revents)
+{
+ ssize_t n;
+
+ condlog(4, "%s: cli[%d] poll=%x state=%d cmd=\"%s\" repl \"%s\"", __func__,
+ c->fd, revents, c->state, c->cmd, get_strbuf_str(&c->reply));
+
+ switch (c->state) {
+ case CLT_RECV:
+ if (!(revents & POLLIN))
+ return STM_BREAK;
+ if (c->cmd_len == 0) {
+ size_t len;
+ /*
+ * We got POLLIN; assume that at least the length can
+ * be read immediately.
+ */
+ get_monotonic_time(&c->expires);
+ c->expires.tv_sec += uxsock_timeout / 1000;
+ c->expires.tv_nsec += (uxsock_timeout % 1000) * 1000000;
+ normalize_timespec(&c->expires);
+ n = recv(c->fd, &len, sizeof(len), 0);
+ if (n < (ssize_t)sizeof(len)) {
+ condlog(1, "%s: cli[%d]: failed to receive reply len: %zd",
+ __func__, c->fd, n);
+ c->error = -ECONNRESET;
+ } else if (len <= 0 || len > _MAX_CMD_LEN) {
+ condlog(1, "%s: cli[%d]: invalid command length (%zu bytes)",
+ __func__, c->fd, len);
+ c->error = -ECONNRESET;
+ } else {
+ c->cmd_len = len;
+ condlog(4, "%s: cli[%d]: connected", __func__, c->fd);
+ }
+ /* poll for data */
+ return STM_BREAK;
+ } else if (c->len < c->cmd_len) {
+ n = recv(c->fd, c->cmd + c->len, c->cmd_len - c->len, 0);
+ if (n <= 0 && errno != EINTR && errno != EAGAIN) {
+ condlog(1, "%s: cli[%d]: error in recv: %m",
+ __func__, c->fd);
+ c->error = -ECONNRESET;
+ return STM_BREAK;
+ }
+ c->len += n;
+ if (c->len < c->cmd_len)
+ /* continue polling */
+ return STM_BREAK;
+ }
+ condlog(4, "cli[%d]: Got request [%s]", c->fd, c->cmd);
+ set_client_state(c, CLT_PARSE);
+ return STM_CONT;
+
+ case CLT_PARSE:
+ c->error = parse_cmd(c);
+ if (!c->error) {
+ /* Permission check */
+ struct key *kw = VECTOR_SLOT(c->cmdvec, 0);
+
+ if (!c->is_root && kw->code != LIST) {
+ c->error = -EPERM;
+ condlog(0, "%s: cli[%d]: unauthorized cmd \"%s\"",
+ __func__, c->fd, c->cmd);
+ }
+ }
+ if (c->error)
+ set_client_state(c, CLT_SEND);
+ else if (c->handler->locked)
+ set_client_state(c, CLT_LOCKED_WORK);
+ else
+ set_client_state(c, CLT_WORK);
+ return STM_CONT;
+
+ case CLT_LOCKED_WORK:
+ if (trylock(&vecs->lock) == 0) {
+ /* don't use cleanup_lock(), lest we wakeup ourselves */
+ pthread_cleanup_push_cast(__unlock, &vecs->lock);
+ c->error = execute_handler(c, vecs);
+ pthread_cleanup_pop(1);
+ condlog(4, "%s: cli[%d] grabbed lock", __func__, c->fd);
+ free_keys(c->cmdvec);
+ c->cmdvec = NULL;
+ set_client_state(c, CLT_SEND);
+ /* Wait for POLLOUT */
+ return STM_BREAK;
+ } else {
+ condlog(4, "%s: cli[%d] waiting for lock", __func__, c->fd);
+ return STM_BREAK;
+ }
+
+ case CLT_WORK:
+ c->error = execute_handler(c, vecs);
+ free_keys(c->cmdvec);
+ c->cmdvec = NULL;
+ set_client_state(c, CLT_SEND);
+ /* Wait for POLLOUT */
+ return STM_BREAK;
+
+ case CLT_SEND:
+ if (get_strbuf_len(&c->reply) == 0)
+ default_reply(c, c->error);
+
+ if (c->cmd_len == 0) {
+ size_t len = get_strbuf_len(&c->reply) + 1;
+
+ if (send(c->fd, &len, sizeof(len), MSG_NOSIGNAL)
+ != sizeof(len))
+ c->error = -ECONNRESET;
+ c->cmd_len = len;
+ return STM_BREAK;
+ }
+
+ if (c->len < c->cmd_len) {
+ const char *buf = get_strbuf_str(&c->reply);
+
+ n = send(c->fd, buf + c->len, c->cmd_len, MSG_NOSIGNAL);
+ if (n == -1) {
+ if (!(errno == EAGAIN || errno == EINTR))
+ c->error = -ECONNRESET;
+ } else
+ c->len += n;
+ }
+
+ if (c->len >= c->cmd_len) {
+ condlog(4, "cli[%d]: Reply [%zu bytes]", c->fd, c->cmd_len);
+ set_client_state(c, CLT_RECV);
+ }
+ return STM_BREAK;
+
+ default:
+ return STM_BREAK;
+ }
+}
+
+static void check_timeout(struct client *c)
+{
+ struct timespec now;
+
+ if (timespeccmp(&c->expires, &ts_zero) == 0)
+ return;
+
+ get_monotonic_time(&now);
+ if (timespeccmp(&c->expires, &now) > 0)
+ return;
+
+ condlog(2, "%s: cli[%d]: timed out at %ld.%03ld", __func__,
+ c->fd, (long)c->expires.tv_sec, c->expires.tv_nsec / 1000000);
+
+ c->error = -ETIMEDOUT;
+ set_client_state(c, CLT_SEND);
+}
+
+static void handle_client(struct client *c, struct vectors *vecs, short revents)
+{
+ if (revents & (POLLHUP|POLLERR)) {
+ c->error = -ECONNRESET;
+ return;
+ }
+
+ check_timeout(c);
+ while (client_state_machine(c, vecs, revents) == STM_CONT);
+}
+
/*
* entry point
*/
-void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
- void * trigger_data)
+void *uxsock_listen(long ux_sock, void *trigger_data)
{
- int rlen;
- char *inbuf;
- char *reply;
sigset_t mask;
int max_pfds = MIN_POLLS + POLLFDS_BASE;
/* conf->sequence_nr will be 1 when uxsock_listen is first called */
unsigned int sequence_nr = 0;
struct watch_descriptors wds = { .conf_wd = -1, .dir_wd = -1 };
+ struct vectors *vecs = trigger_data;
condlog(3, "uxsock: startup listener");
- polls = MALLOC(max_pfds * sizeof(*polls));
+ polls = calloc(1, max_pfds * sizeof(*polls));
if (!polls) {
condlog(0, "uxsock: failed to allocate poll fds");
exit_daemon();
+ return NULL;
}
notify_fd = inotify_init1(IN_NONBLOCK);
if (notify_fd == -1) /* it's fine if notifications fail */
condlog(3, "failed to start up configuration notifications");
+
+ pthread_cleanup_push(wakeup_cleanup, &vecs->lock);
+ idle_fd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC);
+ if (idle_fd == -1) {
+ condlog(1, "failed to create idle fd");
+ exit_daemon();
+ } else
+ set_wakeup_fn(&vecs->lock, wakeup_listener);
+
sigfillset(&mask);
sigdelset(&mask, SIGINT);
sigdelset(&mask, SIGTERM);
while (1) {
struct client *c, *tmp;
int i, n_pfds, poll_count, num_clients;
+ struct timespec __timeout, *timeout;
/* setup for a poll */
- pthread_mutex_lock(&client_lock);
- pthread_cleanup_push(cleanup_mutex, &client_lock);
num_clients = 0;
list_for_each_entry(c, &clients, node) {
num_clients++;
struct pollfd *new;
int n_new = max_pfds + POLLFD_CHUNK;
- new = REALLOC(polls, n_new * sizeof(*polls));
+ new = realloc(polls, n_new * sizeof(*polls));
if (new) {
max_pfds = n_new;
polls = new;
}
}
if (num_clients < MAX_CLIENTS) {
- polls[0].fd = ux_sock;
- polls[0].events = POLLIN;
+ polls[POLLFD_UX].fd = ux_sock;
+ polls[POLLFD_UX].events = POLLIN;
} else {
/*
* New clients can't connect, num_clients won't grow
*/
condlog(1, "%s: max client connections reached, pausing polling",
__func__);
- polls[0].fd = -1;
+ polls[POLLFD_UX].fd = -1;
}
reset_watch(notify_fd, &wds, &sequence_nr);
+ polls[POLLFD_NOTIFY].fd = notify_fd;
if (notify_fd == -1 || (wds.conf_wd == -1 && wds.dir_wd == -1))
- polls[1].fd = -1;
+ polls[POLLFD_NOTIFY].events = 0;
else
- polls[1].fd = notify_fd;
- polls[1].events = POLLIN;
+ polls[POLLFD_NOTIFY].events = POLLIN;
+
+ polls[POLLFD_IDLE].fd = idle_fd;
+ if (need_vecs_lock())
+ polls[POLLFD_IDLE].events = POLLIN;
+ else
+ polls[POLLFD_IDLE].events = 0;
/* setup the clients */
i = POLLFDS_BASE;
list_for_each_entry(c, &clients, node) {
+ switch(c->state) {
+ case CLT_RECV:
+ polls[i].events = POLLIN;
+ break;
+ case CLT_SEND:
+ polls[i].events = POLLOUT;
+ break;
+ default:
+ /* don't poll for this client */
+ continue;
+ }
polls[i].fd = c->fd;
- polls[i].events = POLLIN;
i++;
if (i >= max_pfds)
break;
}
n_pfds = i;
- pthread_cleanup_pop(1);
+ timeout = get_soonest_timeout(&__timeout);
/* most of our life is spent in this call */
- poll_count = ppoll(polls, n_pfds, NULL, &mask);
+ poll_count = ppoll(polls, n_pfds, timeout, &mask);
handle_signals(false);
if (poll_count == -1) {
break;
}
- if (poll_count == 0) {
- handle_signals(true);
- continue;
- }
+ if (polls[POLLFD_IDLE].fd != -1 &&
+ polls[POLLFD_IDLE].revents & POLLIN)
+ drain_idle_fd(idle_fd);
- /*
- * Client connection. We shouldn't answer while we're
- * configuring - nothing may be configured yet.
- * But we can't wait forever either, because this thread
- * must handle signals. So wait a short while only.
- */
- if (wait_for_state_change_if(DAEMON_CONFIGURE, 10)
- == DAEMON_CONFIGURE) {
- handle_signals(false);
- continue;
- }
+ /* see if a client needs handling */
+ list_for_each_entry_safe(c, tmp, &clients, node) {
+ short revents = 0;
- /* see if a client wants to speak to us */
- for (i = POLLFDS_BASE; i < n_pfds; i++) {
- if (polls[i].revents & POLLIN) {
- struct timespec start_time;
-
- c = NULL;
- pthread_mutex_lock(&client_lock);
- list_for_each_entry(tmp, &clients, node) {
- if (tmp->fd == polls[i].fd) {
- c = tmp;
- break;
- }
+ for (i = POLLFDS_BASE; i < n_pfds; i++) {
+ if (polls[i].fd == c->fd) {
+ revents = polls[i].revents;
+ break;
}
- pthread_mutex_unlock(&client_lock);
- if (!c) {
- condlog(4, "cli%d: new fd %d",
- i, polls[i].fd);
- continue;
- }
- get_monotonic_time(&start_time);
- if (recv_packet_from_client(c->fd, &inbuf,
- uxsock_timeout)
- != 0) {
- dead_client(c);
- continue;
- }
- if (!inbuf) {
- condlog(4, "recv_packet_from_client "
- "get null request");
- continue;
- }
- condlog(4, "cli[%d]: Got request [%s]",
- i, inbuf);
- uxsock_trigger(inbuf, &reply, &rlen,
- _socket_client_is_root(c->fd),
- trigger_data);
- if (reply) {
- if (send_packet(c->fd,
- reply) != 0) {
- dead_client(c);
- } else {
- condlog(4, "cli[%d]: "
- "Reply [%d bytes]",
- i, rlen);
- }
- FREE(reply);
- reply = NULL;
- }
- check_timeout(start_time, inbuf,
- uxsock_timeout);
- FREE(inbuf);
+ }
+
+ handle_client(c, trigger_data, revents);
+
+ if (c->error == -ECONNRESET) {
+ condlog(4, "cli[%d]: disconnected", c->fd);
+ dead_client(c);
+ if (i < n_pfds)
+ polls[i].fd = -1;
}
}
/* see if we got a non-fatal signal */
handle_signals(true);
/* see if we got a new client */
- if (polls[0].revents & POLLIN) {
+ if (polls[POLLFD_UX].revents & POLLIN) {
new_client(ux_sock);
}
/* handle inotify events on config files */
- if (polls[1].revents & POLLIN)
+ if (polls[POLLFD_NOTIFY].revents & POLLIN)
handle_inotify(notify_fd, &wds);
}
+ pthread_cleanup_pop(1);
return NULL;
}
#include <stdbool.h>
-typedef int (uxsock_trigger_fn)(char *, char **, int *, bool, void *);
-
void uxsock_cleanup(void *arg);
-void *uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
+void *uxsock_listen(long ux_sock,
void * trigger_data);
#endif
#include "util.h"
#include "vector.h"
-#include "memory.h"
#include "checkers.h"
#include "config.h"
#include "structs.h"
struct event_thread *wp;
- wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
- memset(wp, 0, sizeof(struct event_thread));
+ wp = (struct event_thread *)calloc(1, sizeof(struct event_thread));
return wp;
}
dm_task_destroy(wp->dmt);
rcu_unregister_thread();
- FREE(wp);
+ free(wp);
}
void stop_waiter_thread (struct multipath *mpp)
#include <setjmp.h>
#include <stdlib.h>
#include <cmocka.h>
+#include <stdio.h>
#include "globals.c"
#include "pgpolicies.h"
char *name = uevent_get_dm_name(uev);
assert_string_equal(name, DM_NAME);
- FREE(name);
+ free(name);
}
static void test_dm_name_bad_0(void **state)
uev->envp[3] = "DM_NAME" DM_NAME;
name = uevent_get_dm_name(uev);
assert_ptr_equal(name, NULL);
- FREE(name);
+ free(name);
}
static void test_dm_name_bad_1(void **state)
uev->envp[3] = "DM_NAMES=" DM_NAME;
name = uevent_get_dm_name(uev);
assert_ptr_equal(name, NULL);
- FREE(name);
+ free(name);
}
static void test_dm_name_good_1(void **state)
uev->envp[2] = "DM_NAME=" DM_NAME;
name = uevent_get_dm_name(uev);
assert_string_equal(name, DM_NAME);
- FREE(name);
+ free(name);
}
static void test_dm_uuid_false_0(void **state)
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
+#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
unsigned char *desc;
int n = 0;
- memset(buf, 0, bufsiz);
+ /* Fill with large number, which will cause length overflow */
+ memset(buf, 0xed, bufsiz);
+ buf[0] = 0;
buf[1] = 0x83;
desc = buf + 4;
test_id, vt->wwid); \
}
+/**
+ * test_cpd_naa_NAA_badlen_BAD() - test detection of bad length fields
+ * @NAA: Network Name Authority (2, 3, 5, 16)
+ * @BAD: Value for designator length field
+ * @ERR: Expected error code
+ */
+#define make_test_vpd_naa_badlen(NAA, BAD, ERR) \
+static void test_vpd_naa_##NAA##_badlen_##BAD(void **state) \
+{ \
+ struct vpdtest *vt = *state; \
+ int n, ret; \
+ \
+ n = create_vpd83(vt->vpdbuf, sizeof(vt->vpdbuf), test_id, 3, NAA, 0); \
+ \
+ vt->vpdbuf[7] = BAD; \
+ will_return(__wrap_ioctl, n); \
+ will_return(__wrap_ioctl, vt->vpdbuf); \
+ ret = get_vpd_sgio(10, 0x83, 0, vt->wwid, 40); \
+ assert_int_equal(-ret, -ERR); \
+}
+
/**
* test_vpd_eui_LEN_WLEN() - test code for VPD 83, EUI64
* @LEN: EUI64 length (8, 12, or 16)
test_id, vt->wwid); \
}
+/**
+ * test_cpd_eui_LEN_badlen_BAD() - test detection of bad length fields
+ * @NAA: correct length(8, 12, 16)
+ * @BAD: value for designator length field
+ * @ERR: expected error code
+ */
+#define make_test_vpd_eui_badlen(LEN, BAD, ERR) \
+static void test_vpd_eui_badlen_##LEN##_##BAD(void **state) \
+{ \
+ struct vpdtest *vt = *state; \
+ int n, ret; \
+ \
+ n = create_vpd83(vt->vpdbuf, sizeof(vt->vpdbuf), test_id, 2, 0, LEN); \
+ \
+ vt->vpdbuf[7] = BAD; \
+ will_return(__wrap_ioctl, n); \
+ will_return(__wrap_ioctl, vt->vpdbuf); \
+ ret = get_vpd_sgio(10, 0x83, 0, vt->wwid, 40); \
+ assert_int_equal(ret, ERR); \
+ if (ERR >= 0) \
+ assert_correct_wwid("test_vpd_eui_badlen_"#LEN"_"#BAD, \
+ 2 * BAD + 1, ret, '2', 0, true, \
+ test_id, vt->wwid); \
+}
+
/**
* test_vpd80_SIZE_LEN_WLEN() - test code for VPD 80
* @SIZE, @LEN: see create_vpd80()
make_test_vpd_eui(8, 16, 0);
make_test_vpd_eui(8, 10, 0);
+make_test_vpd_eui_badlen(8, 8, 17);
+/* Invalid entry, length overflow */
+make_test_vpd_eui_badlen(8, 12, -EOVERFLOW);
+make_test_vpd_eui_badlen(8, 9, -EOVERFLOW);
+/* invalid entry, no length overflow, but no full next entry */
+make_test_vpd_eui_badlen(8, 7, -EINVAL);
+make_test_vpd_eui_badlen(8, 5, -EINVAL);
+/* invalid entry, length of next one readable but too long */
+make_test_vpd_eui_badlen(8, 4, -EOVERFLOW);
+make_test_vpd_eui_badlen(8, 0, -EOVERFLOW);
+
/* 96 bit, WWID size: 26 */
make_test_vpd_eui(12, 32, 0);
make_test_vpd_eui(12, 26, 0);
make_test_vpd_eui(12, 20, 0);
make_test_vpd_eui(12, 10, 0);
+make_test_vpd_eui_badlen(12, 12, 25);
+make_test_vpd_eui_badlen(12, 16, -EOVERFLOW);
+make_test_vpd_eui_badlen(12, 13, -EOVERFLOW);
+/* invalid entry, no length overflow, but no full next entry */
+make_test_vpd_eui_badlen(12, 11, -EINVAL);
+make_test_vpd_eui_badlen(12, 9, -EINVAL);
+/* non-fatal - valid 8-byte descriptor */
+make_test_vpd_eui_badlen(12, 8, 17);
+/* invalid entry, length of next one readable but too long */
+make_test_vpd_eui_badlen(12, 7, -EOVERFLOW);
+make_test_vpd_eui_badlen(12, 0, -EOVERFLOW);
+
/* 128 bit, WWID size: 34 */
make_test_vpd_eui(16, 40, 0);
make_test_vpd_eui(16, 34, 0);
make_test_vpd_eui(16, 33, 0);
make_test_vpd_eui(16, 20, 0);
+make_test_vpd_eui_badlen(16, 16, 33);
+make_test_vpd_eui_badlen(16, 17, -EOVERFLOW);
+make_test_vpd_eui_badlen(16, 15, -EINVAL);
+make_test_vpd_eui_badlen(16, 13, -EINVAL);
+/* non-fatal - valid 12-byte descriptor */
+make_test_vpd_eui_badlen(16, 12, 25);
+/* invalid entry, length of next one readable but too long */
+make_test_vpd_eui_badlen(16, 11, -EOVERFLOW);
+/* non-fatal - valid 8-byte descriptor */
+make_test_vpd_eui_badlen(16, 8, 17);
+/* invalid entry, length of next one readable but too long */
+make_test_vpd_eui_badlen(16, 7, -EOVERFLOW);
+make_test_vpd_eui_badlen(16, 0, -EOVERFLOW);
+
/* NAA IEEE registered extended (36), WWID size: 34 */
make_test_vpd_naa(6, 40);
make_test_vpd_naa(6, 34);
make_test_vpd_naa(6, 32);
make_test_vpd_naa(6, 20);
+/* NAA IEEE registered extended with bad designator length */
+make_test_vpd_naa_badlen(6, 16, 33);
+/* offset overflow */
+make_test_vpd_naa_badlen(6, 17, -EOVERFLOW);
+/* invalid entry, no length overflow, but no full next entry */
+make_test_vpd_naa_badlen(6, 15, -EINVAL);
+/* invalid entry, length of next one readable but too long */
+make_test_vpd_naa_badlen(6, 8, -EOVERFLOW);
+make_test_vpd_naa_badlen(6, 0, -EOVERFLOW);
+
/* NAA IEEE registered (35), WWID size: 18 */
make_test_vpd_naa(5, 20);
make_test_vpd_naa(5, 18);
make_test_vpd_naa(5, 17);
make_test_vpd_naa(5, 16);
+/* NAA IEEE registered with bad designator length */
+make_test_vpd_naa_badlen(5, 8, 17);
+/* offset overflow */
+make_test_vpd_naa_badlen(5, 16, -EOVERFLOW);
+make_test_vpd_naa_badlen(5, 9, -EOVERFLOW);
+/* invalid entry, no length overflow, but no full next entry */
+make_test_vpd_naa_badlen(5, 7, -EINVAL);
+/* invalid entry, length of next one readable but too long */
+make_test_vpd_naa_badlen(5, 4, -EOVERFLOW);
+make_test_vpd_naa_badlen(5, 0, -EOVERFLOW);
+
/* NAA local (33), WWID size: 18 */
make_test_vpd_naa(3, 20);
make_test_vpd_naa(3, 18);
cmocka_unit_test(test_vpd_eui_8_17_0),
cmocka_unit_test(test_vpd_eui_8_16_0),
cmocka_unit_test(test_vpd_eui_8_10_0),
+ cmocka_unit_test(test_vpd_eui_badlen_8_8),
+ cmocka_unit_test(test_vpd_eui_badlen_8_12),
+ cmocka_unit_test(test_vpd_eui_badlen_8_9),
+ cmocka_unit_test(test_vpd_eui_badlen_8_7),
+ cmocka_unit_test(test_vpd_eui_badlen_8_5),
+ cmocka_unit_test(test_vpd_eui_badlen_8_4),
+ cmocka_unit_test(test_vpd_eui_badlen_8_0),
cmocka_unit_test(test_vpd_eui_12_32_0),
cmocka_unit_test(test_vpd_eui_12_26_0),
cmocka_unit_test(test_vpd_eui_12_25_0),
cmocka_unit_test(test_vpd_eui_12_20_0),
cmocka_unit_test(test_vpd_eui_12_10_0),
+ cmocka_unit_test(test_vpd_eui_badlen_12_12),
+ cmocka_unit_test(test_vpd_eui_badlen_12_16),
+ cmocka_unit_test(test_vpd_eui_badlen_12_13),
+ cmocka_unit_test(test_vpd_eui_badlen_12_11),
+ cmocka_unit_test(test_vpd_eui_badlen_12_9),
+ cmocka_unit_test(test_vpd_eui_badlen_12_8),
+ cmocka_unit_test(test_vpd_eui_badlen_12_7),
+ cmocka_unit_test(test_vpd_eui_badlen_12_0),
cmocka_unit_test(test_vpd_eui_16_40_0),
cmocka_unit_test(test_vpd_eui_16_34_0),
cmocka_unit_test(test_vpd_eui_16_33_0),
cmocka_unit_test(test_vpd_eui_16_20_0),
+ cmocka_unit_test(test_vpd_eui_badlen_16_16),
+ cmocka_unit_test(test_vpd_eui_badlen_16_17),
+ cmocka_unit_test(test_vpd_eui_badlen_16_15),
+ cmocka_unit_test(test_vpd_eui_badlen_16_13),
+ cmocka_unit_test(test_vpd_eui_badlen_16_12),
+ cmocka_unit_test(test_vpd_eui_badlen_16_11),
+ cmocka_unit_test(test_vpd_eui_badlen_16_8),
+ cmocka_unit_test(test_vpd_eui_badlen_16_7),
+ cmocka_unit_test(test_vpd_eui_badlen_16_0),
cmocka_unit_test(test_vpd_naa_6_40),
cmocka_unit_test(test_vpd_naa_6_34),
cmocka_unit_test(test_vpd_naa_6_33),
cmocka_unit_test(test_vpd_naa_6_32),
cmocka_unit_test(test_vpd_naa_6_20),
+ cmocka_unit_test(test_vpd_naa_6_badlen_16),
+ cmocka_unit_test(test_vpd_naa_6_badlen_15),
+ cmocka_unit_test(test_vpd_naa_6_badlen_8),
+ cmocka_unit_test(test_vpd_naa_6_badlen_17),
+ cmocka_unit_test(test_vpd_naa_6_badlen_0),
cmocka_unit_test(test_vpd_naa_5_20),
cmocka_unit_test(test_vpd_naa_5_18),
cmocka_unit_test(test_vpd_naa_5_17),
cmocka_unit_test(test_vpd_naa_5_16),
+ cmocka_unit_test(test_vpd_naa_5_badlen_8),
+ cmocka_unit_test(test_vpd_naa_5_badlen_7),
+ cmocka_unit_test(test_vpd_naa_5_badlen_4),
+ cmocka_unit_test(test_vpd_naa_5_badlen_16),
+ cmocka_unit_test(test_vpd_naa_5_badlen_9),
+ cmocka_unit_test(test_vpd_naa_5_badlen_0),
cmocka_unit_test(test_vpd_naa_3_20),
cmocka_unit_test(test_vpd_naa_3_18),
cmocka_unit_test(test_vpd_naa_3_17),