Imported Upstream version 0.8.8 upstream/0.8.8
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:20 +0000 (13:50 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:20 +0000 (13:50 +0900)
94 files changed:
.github/workflows/abi.yaml [new file with mode: 0644]
.github/workflows/coverity.yaml [new file with mode: 0644]
.github/workflows/native.yaml
.gitignore
.mailmap [new file with mode: 0644]
Makefile
Makefile.inc
kpartx/kpartx.c
kpartx/lopart.c
kpartx/lopart.h
libdmmp/Makefile
libmpathcmd/Makefile
libmpathpersist/Makefile
libmpathpersist/libmpathpersist.version
libmpathpersist/mpath_persist.c
libmpathpersist/mpath_updatepr.c
libmpathvalid/Makefile
libmultipath/Makefile
libmultipath/alias.c
libmultipath/blacklist.c
libmultipath/checkers.c
libmultipath/checkers.h
libmultipath/checkers/emc_clariion.c
libmultipath/config.c
libmultipath/config.h
libmultipath/configure.c
libmultipath/defaults.c
libmultipath/defaults.h
libmultipath/devmapper.c
libmultipath/dict.c
libmultipath/discovery.c
libmultipath/discovery.h
libmultipath/dmparser.c
libmultipath/foreign.c
libmultipath/foreign.h
libmultipath/foreign/nvme.c
libmultipath/generic.h
libmultipath/hwtable.c
libmultipath/io_err_stat.c
libmultipath/libmultipath.version
libmultipath/lock.c
libmultipath/lock.h
libmultipath/log.c
libmultipath/log_pthread.c
libmultipath/memory.c [deleted file]
libmultipath/memory.h [deleted file]
libmultipath/parser.c
libmultipath/parser.h
libmultipath/pgpolicies.c
libmultipath/print.c
libmultipath/print.h
libmultipath/prio.c
libmultipath/prio.h
libmultipath/prioritizers/alua_rtpg.c
libmultipath/prioritizers/alua_spc3.h
libmultipath/prioritizers/path_latency.c
libmultipath/prioritizers/weightedpath.c
libmultipath/propsel.c
libmultipath/strbuf.c
libmultipath/strbuf.h
libmultipath/structs.c
libmultipath/structs.h
libmultipath/structs_vec.c
libmultipath/structs_vec.h
libmultipath/sysfs.c
libmultipath/time-util.c
libmultipath/time-util.h
libmultipath/uevent.c
libmultipath/util.c
libmultipath/util.h
libmultipath/uxsock.c
libmultipath/uxsock.h
libmultipath/vector.c
libmultipath/version.h
mpathpersist/mpathpersist.8
multipath/main.c
multipath/multipath.8
multipath/multipath.conf.5
multipathd/cli.c
multipathd/cli.h
multipathd/cli_handlers.c
multipathd/cli_handlers.h
multipathd/main.c
multipathd/main.h
multipathd/multipathd.8
multipathd/multipathd.service
multipathd/multipathd.socket
multipathd/uxclnt.c
multipathd/uxlsnr.c
multipathd/uxlsnr.h
multipathd/waiter.c
tests/pgpolicy.c
tests/uevent.c
tests/vpd.c

diff --git a/.github/workflows/abi.yaml b/.github/workflows/abi.yaml
new file mode 100644 (file)
index 0000000..0a40104
--- /dev/null
@@ -0,0 +1,54 @@
+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
diff --git a/.github/workflows/coverity.yaml b/.github/workflows/coverity.yaml
new file mode 100644 (file)
index 0000000..a8b56d4
--- /dev/null
@@ -0,0 +1,51 @@
+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 }}
index 2bb1886e7f4a1a3d9ca92e6071d7b44467f76539..19c9e297a9d9bb65a1a01e499ec54ee4aa53972f 100644 (file)
@@ -8,15 +8,17 @@ on:
   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
@@ -30,3 +32,59 @@ jobs:
           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
index 087dffc216c09a2209198d47c6eeb3ca9619e286..8e09f952e901794f633347c02fc23811d1299c56 100644 (file)
@@ -3,6 +3,7 @@
 *~
 *.so
 *.so.0
+*.abi
 *.a
 *.gz
 *.d
@@ -13,6 +14,10 @@ kpartx/kpartx
 multipath/multipath
 multipathd/multipathd
 mpathpersist/mpathpersist
+abi.tar.gz
+abi
+abi-test
+compile_commands.json
 .nfs*
 *.swp
 *.patch
diff --git a/.mailmap b/.mailmap
new file mode 100644 (file)
index 0000000..14996ab
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,31 @@
+#
+# 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>
index 7f21db8aecd4077a357107b28bf4322990aae01a..82e0ea37c2a75cc007490a22c7a52a2bad1b577e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,33 +2,76 @@
 # 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
@@ -48,6 +91,8 @@ $(BUILDDIRS:=.uninstall):
        $(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)
 
index d0ec9b441e8ad230783210b3874022ae86ddabb7..b340f2ae69e0d9717301afd15f4c0f70b0ee2fba 100644 (file)
@@ -79,6 +79,7 @@ GZIP          = gzip -9 -c
 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.
@@ -140,3 +141,9 @@ check_file = $(shell \
 %.o:   %.c
        @echo building $@ because of $?
        $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+%.abi:  %.so.0
+       abidw $< >$@
+
+%.abi:  %.so
+       abidw $< >$@
index 7bc645438016ace2a58808769b3c687e2b22d0ce..3c4999959e889462f006e986b6137b5bc4a74171 100644 (file)
@@ -359,9 +359,7 @@ main(int argc, char **argv){
                        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);
                        }
index 9b65255499f3810ecdf698410ff13794e262c998..512a59fffe7cd449f71d57f08e5cd0f750d8cae0 100644 (file)
 #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)
@@ -157,51 +139,59 @@ 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];
@@ -220,33 +210,33 @@ char *find_unused_loop_device(void)
        }
 
        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);
 
@@ -261,9 +251,9 @@ int set_loop(const char *device, const char *file, int offset, int *loopro)
                }
        }
 
-       if ((fd = open (device, mode)) < 0) {
+       *device = find_unused_loop_device(mode, &fd);
+       if (!*device) {
                close(ffd);
-               perror (device);
                return 1;
        }
 
@@ -277,22 +267,20 @@ int set_loop(const char *device, const char *file, int offset, int *loopro)
 
        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)
index d3bad10adf52f7a0dfbd015bb4225ffc51c799e5..c73ab236701dfa9ba295a1ed78fa881dfc0574ec 100644 (file)
@@ -1,5 +1,4 @@
 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 *);
index 79b92fb2edbddab24506dbb0a154437ac41ba91c..de6166894e8b9ac3138d90b83f458a2f984e4667 100644 (file)
@@ -25,7 +25,11 @@ all: $(LIBS) doc
 
 $(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)
@@ -54,7 +58,7 @@ uninstall:
        $(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
 
index 25910194a76b71c8d149efcc5c7a3478f3e176d6..72cab1e328f355500670b8cf72284bdbe3eafa29 100644 (file)
@@ -15,6 +15,17 @@ $(LIBS): $(OBJS) $(VERSION_SCRIPT)
        $(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) $@
 
@@ -31,7 +42,7 @@ uninstall:
        $(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))
 
index 57103e58e78eae8daf2befdc7d51be96a828944a..1e6399d6139398ea3e041136b727aa93eff96182 100644 (file)
@@ -3,7 +3,7 @@ include ../Makefile.inc
 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)
@@ -18,6 +18,17 @@ $(LIBS): $(OBJS) $(VERSION_SCRIPT)
        $(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) $@
 
@@ -44,7 +55,7 @@ uninstall:
        $(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))
 
index e0748138b59f5153273a23e943ae519f6dd5da0e..fa312f6b235fbb6bfffe31629aa19ffc6f0c4732 100644 (file)
@@ -10,7 +10,7 @@
  *
  * See libmultipath.version for general policy about version numbers.
  */
-LIBMPATHPERSIST_1.0.0 {
+LIBMPATHPERSIST_2.0.0 {
 global:
 
        __mpath_persistent_reserve_in;
@@ -28,11 +28,9 @@ global:
        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: *;
+};
index 803a2a284874c85a633f9114000b7d7f875367dd..3097c81398000d61cd28b6ec9fbe93a142d9f832 100644 (file)
@@ -239,7 +239,7 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
                alias = NULL;
        }
 out:
-       FREE(alias);
+       free(alias);
        return ret;
 }
 
@@ -342,7 +342,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
                update_prkey(alias, 0);
        }
 out1:
-       FREE(alias);
+       free(alias);
        return ret;
 }
 
index 0aca28ebb2cfcda488c3d4132c11c8fd006b4985..bdecaa05de09a1936ffea0c6611f338134cacacd 100644 (file)
@@ -14,7 +14,6 @@
 #include "debug.h"
 #include "mpath_cmd.h"
 #include "uxsock.h"
-#include "memory.h"
 #include "mpathpr.h"
 
 
index 6bea4bcdd960718e3622010990e120ea6537c609..dce261033cb90caeecde70292d6ff33933cbdc9f 100644 (file)
@@ -15,9 +15,21 @@ OBJS = mpath_valid.o
 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)
@@ -31,7 +43,7 @@ uninstall:
        $(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))
 
index 7f3921c517f6e9134a738fce96746e7411dc798f..d4af1a542f3f4a10117f3a857cccd4760dd66cc7 100644 (file)
@@ -45,7 +45,7 @@ ifneq ($(call check_func,dm_hold_control_dev,/usr/include/libdevmapper.h),0)
        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 \
@@ -81,6 +81,17 @@ $(LIBS): $(OBJS) $(VERSION_SCRIPT)
 $(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)
@@ -99,7 +110,7 @@ uninstall:
        $(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))
 
index ad7e512ba143ad8d97e394db4bfdd224a1eab805..87c33afcf6b52b5472c83b8b09794a0d1279e4be 100644 (file)
@@ -356,7 +356,7 @@ use_existing_alias (const char *wwid, const char *file, const char *alias_old,
                 * 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",
@@ -578,13 +578,17 @@ static int fix_bindings_file(const struct config *conf,
        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);
index 4e315c9732eef427b092d537cd58378a05ea8646..8d15d2ea5b8a96e77c538367d36cdceca27bde62 100644 (file)
@@ -5,7 +5,6 @@
 #include <libudev.h>
 
 #include "checkers.h"
-#include "memory.h"
 #include "vector.h"
 #include "util.h"
 #include "debug.h"
@@ -46,7 +45,7 @@ int store_ble(vector blist, const char *str, int origin)
        if (!blist)
                goto out;
 
-       ble = MALLOC(sizeof(struct blentry));
+       ble = calloc(1, sizeof(struct blentry));
 
        if (!ble)
                goto out;
@@ -63,9 +62,9 @@ int store_ble(vector blist, const char *str, int origin)
        vector_set_slot(blist, ble);
        return 0;
 out1:
-       FREE(ble);
+       free(ble);
 out:
-       FREE(strdup_str);
+       free(strdup_str);
        return 1;
 }
 
@@ -77,12 +76,12 @@ int alloc_ble_device(vector blist)
        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);
@@ -105,7 +104,7 @@ int set_ble_device(vector blist, const char *vendor, const char *product, int or
                return 1;
 
        if (vendor) {
-               vendor_str = STRDUP(vendor);
+               vendor_str = strdup(vendor);
                if (!vendor_str)
                        goto out;
 
@@ -116,7 +115,7 @@ int set_ble_device(vector blist, const char *vendor, const char *product, int or
                ble->vendor = vendor_str;
        }
        if (product) {
-               product_str = STRDUP(product);
+               product_str = strdup(product);
                if (!product_str)
                        goto out1;
 
@@ -216,7 +215,7 @@ setup_default_blist (struct config * conf)
                                          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;
                        }
@@ -445,8 +444,8 @@ static void free_ble(struct blentry *ble)
        if (!ble)
                return;
        regfree(&ble->regex);
-       FREE(ble->str);
-       FREE(ble);
+       free(ble->str);
+       free(ble);
 }
 
 void
@@ -488,13 +487,13 @@ static void free_ble_device(struct blentry_device *ble)
        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);
        }
 }
 
index 8039c2bf1fa9193c2998d756baf2d42eab540487..ef346d795f31440d0d17a5dfaee0893da3e0e5be 100644 (file)
@@ -55,7 +55,7 @@ static struct checker_class *alloc_checker_class(void)
 {
        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);
@@ -96,7 +96,7 @@ void free_checker_class(struct checker_class *c)
                                c->name, dlerror());
                }
        }
-       FREE(c);
+       free(c);
 }
 
 void cleanup_checkers (void)
index 2fd1d1c69d5413e1de49b9d0d8aafa99bd0f1389..f4600ed360ad07bc2a348522fa7a03af520b397a 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <pthread.h>
 #include "list.h"
-#include "memory.h"
 #include "defaults.h"
 
 /*
@@ -127,8 +126,7 @@ struct checker {
        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)
index 5cd63acab3f12ee06db133052f6ffd480c46bab7..aa636e7bc0a053e5114bcc42137073515fc1749d 100644 (file)
@@ -15,7 +15,6 @@
 #include "libsg.h"
 #include "checkers.h"
 #include "debug.h"
-#include "memory.h"
 
 #define INQUIRY_CMD     0x12
 #define INQUIRY_CMDLEN  6
@@ -102,7 +101,7 @@ int libcheck_init (struct checker * c)
        /*
         * 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;
index 30046a17a858ffd0e17388f928984f549fc645ed..c595e768dc78fe649bf99c057a58280ef7e55029 100644 (file)
@@ -11,7 +11,6 @@
 #include <errno.h>
 
 #include "checkers.h"
-#include "memory.h"
 #include "util.h"
 #include "debug.h"
 #include "parser.h"
@@ -245,45 +244,45 @@ free_hwe (struct hwentry * hwe)
                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
@@ -308,27 +307,27 @@ free_mpe (struct mpentry * mpe)
                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
@@ -350,7 +349,7 @@ struct mpentry *
 alloc_mpe (void)
 {
        struct mpentry * mpe = (struct mpentry *)
-                               MALLOC(sizeof(struct mpentry));
+                               calloc(1, sizeof(struct mpentry));
 
        return mpe;
 }
@@ -359,7 +358,7 @@ struct hwentry *
 alloc_hwe (void)
 {
        struct hwentry * hwe = (struct hwentry *)
-                               MALLOC(sizeof(struct hwentry));
+                               calloc(1, sizeof(struct hwentry));
 
        return hwe;
 }
@@ -378,7 +377,7 @@ set_param_str(const char * str)
        if (!len)
                return NULL;
 
-       dst = (char *)MALLOC(len + 1);
+       dst = (char *)calloc(1, len + 1);
 
        if (!dst)
                return NULL;
@@ -652,7 +651,7 @@ restart:
 
 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)
@@ -661,52 +660,52 @@ 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);
index 933fe0d12a91d2bde43dcd6e5058d692b30ed6c9..c73389b543466a2c338db78b5500bd2305d07a2b 100644 (file)
@@ -178,7 +178,6 @@ struct config {
        int strict_timing;
        int retrigger_tries;
        int retrigger_delay;
-       int delayed_reconfig;
        int uev_wait_timeout;
        int skip_kpartx;
        int remove_retries;
index 7edb355b63e5d0af2da7aa21b4d356331ffdb87f..67459769c146825cac56515ece8723c66844b409 100644 (file)
@@ -19,7 +19,6 @@
 
 #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)
@@ -261,42 +256,11 @@ int rr_optimize_path_order(struct pathgroup *pgp)
        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;
 
        /*
@@ -395,7 +359,6 @@ int setup_map(struct multipath *mpp, char **params, struct vectors *vecs)
        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
@@ -410,31 +373,6 @@ int setup_map(struct multipath *mpp, char **params, struct vectors *vecs)
        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)
@@ -715,6 +653,8 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
 
        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) {
@@ -751,8 +691,8 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
                        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;
        }
@@ -803,8 +743,8 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
                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");
@@ -812,13 +752,13 @@ void select_action (struct multipath *mpp, const struct _vector *curmp,
                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))) {
@@ -1087,7 +1027,7 @@ check_daemon(void)
        ret = 1;
 
 out_free:
-       FREE(reply);
+       free(reply);
 out:
        mpath_disconnect(fd);
        return ret;
@@ -1098,7 +1038,7 @@ out:
  * 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)
@@ -1430,7 +1370,7 @@ static int _get_refwwid(enum mpath_cmds cmd, const char *dev,
        }
 
        if (refwwid && strlen(refwwid)) {
-               *wwid = STRDUP(refwwid);
+               *wwid = strdup(refwwid);
                return PATHINFO_OK;
        }
 
index 082640d383f86025d246e57494effe25d0506925..aad8357a19701cbdce062c31d182ca2c9760285b 100644 (file)
@@ -4,6 +4,5 @@
 #include <string.h>
 
 #include "defaults.h"
-#include "memory.h"
 
 const char * const default_partition_delim = DEFAULT_PARTITION_DELIM;
index c27946c76b8f9a9fc9d0647d84b630fece6763b9..7d95413dbece739deb3c9f8c96d7dd2710eaf857 100644 (file)
@@ -1,6 +1,7 @@
 #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
index c05dc201e5a086665819c12cdb97d03c53cfeed4..c0eb33510de919c8a4fef1cdc563cb82133ddd7f 100644 (file)
@@ -21,7 +21,6 @@
 #include "vector.h"
 #include "structs.h"
 #include "debug.h"
-#include "memory.h"
 #include "devmapper.h"
 #include "sysfs.h"
 #include "config.h"
@@ -474,7 +473,7 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
                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",
@@ -517,11 +516,13 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
                        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;
 }
 
@@ -1285,7 +1286,7 @@ struct multipath *dm_get_multipath(const char *name)
        if (!mpp)
                return NULL;
 
-       mpp->alias = STRDUP(name);
+       mpp->alias = strdup(name);
 
        if (!mpp->alias)
                goto out;
@@ -1293,8 +1294,10 @@ struct multipath *dm_get_multipath(const char *name)
        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:
@@ -1388,7 +1391,6 @@ dm_mapname(int major, int minor)
        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;
@@ -1398,29 +1400,15 @@ dm_mapname(int major, int minor)
                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;
@@ -1598,7 +1586,7 @@ dm_cancel_deferred_remove (struct multipath *mpp __attribute__((unused)))
 static struct dm_info *
 alloc_dminfo (void)
 {
-       return MALLOC(sizeof(struct dm_info));
+       return calloc(1, sizeof(struct dm_info));
 }
 
 int
@@ -1614,7 +1602,7 @@ dm_get_info (const char * mapname, struct dm_info ** dmi)
                return 1;
 
        if (do_get_info(mapname, *dmi) != 0) {
-               FREE(*dmi);
+               free(*dmi);
                *dmi = NULL;
                return 1;
        }
@@ -1715,7 +1703,7 @@ void dm_reassign_deps(char *table, const char *dep, const char *newdep)
        n += strlen(newdep);
        p += strlen(dep);
        strcat(n, p);
-       FREE(newtable);
+       free(newtable);
 }
 
 int dm_reassign_table(const char *name, char *old, char *new)
index 7a72738931d1c1e49a24f201f73b8cf0fc44485e..7ad9f6e261e775259989c8bb1945a1e5c43cc704 100644 (file)
@@ -5,6 +5,8 @@
  * 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"
@@ -14,7 +16,6 @@
 #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)
@@ -76,26 +90,23 @@ set_uint(vector strvec, void *ptr)
        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)
@@ -105,7 +116,73 @@ set_str(vector strvec, void *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;
@@ -116,15 +193,18 @@ set_yes_no(vector strvec, void *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;
@@ -138,9 +218,10 @@ set_yes_no_undef(vector strvec, void *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;
 }
 
@@ -187,9 +268,27 @@ static int print_yes_no_undef(struct strbuf *buff, long v)
 
 #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)                          \
@@ -224,14 +323,27 @@ snprint_def_ ## option (struct config *conf, struct strbuf *buff, \
 
 #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,       \
@@ -243,11 +355,23 @@ 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)                          \
@@ -260,12 +384,24 @@ snprint_ovr_ ## option (struct config *conf, struct strbuf *buff, \
 
 #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)                           \
@@ -277,9 +413,10 @@ snprint_mp_ ## option (struct config *conf, struct strbuf *buff,   \
        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;
@@ -293,24 +430,25 @@ declare_def_snprint(checkint, print_int)
 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;
@@ -334,15 +472,12 @@ static const char * const find_multipaths_optvals[] = {
 };
 
 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;
@@ -355,12 +490,17 @@ def_find_multipaths_handler(struct config *conf, vector strvec)
                }
        }
 
-       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;
 }
 
@@ -396,7 +536,8 @@ static int snprint_uid_attrs(struct config *conf, struct strbuf *buff,
        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;
 
@@ -405,9 +546,11 @@ static int uid_attrs_handler(struct config *conf, vector strvec)
        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;
 }
 
@@ -434,11 +577,11 @@ declare_hw_snprint(prio_name, print_str)
 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)
@@ -466,22 +609,22 @@ declare_ovr_snprint(checker_name, print_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)
@@ -505,7 +648,7 @@ snprint_def_queue_without_daemon(struct config *conf, struct strbuf *buff,
        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)
@@ -530,13 +673,13 @@ declare_hw_snprint(user_friendly_names, print_yes_no_undef)
 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)
@@ -576,13 +719,13 @@ declare_hw_snprint(deferred_remove, print_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)
@@ -597,7 +740,8 @@ declare_hw_handler(skip_kpartx, set_yes_no_undef)
 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;
 }
@@ -608,19 +752,19 @@ static int snprint_def_disable_changed_wwids(struct config *conf,
        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)
 
@@ -629,20 +773,28 @@ declare_def_snprint_defstr(enable_foreign, print_str,
                           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)                     \
@@ -655,12 +807,14 @@ snprint_def_ ## option (struct config *conf, struct strbuf *buff, \
 
 #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)                      \
@@ -673,7 +827,7 @@ snprint_mp_ ## option (struct config *conf, struct strbuf *buff,    \
 }
 
 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;
@@ -687,14 +841,16 @@ set_mode(vector strvec, void *ptr, int *flags)
        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;
@@ -712,14 +868,16 @@ set_uid(vector strvec, void *ptr, int *flags)
        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;
@@ -738,8 +896,10 @@ set_gid(vector strvec, void *ptr, int *flags)
        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;
 }
 
@@ -786,7 +946,7 @@ declare_mp_attr_handler(gid, set_gid)
 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;
@@ -797,13 +957,12 @@ set_undef_off_zero(vector strvec, void *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;
 }
 
@@ -827,7 +986,7 @@ declare_hw_handler(fast_io_fail, set_undef_off_zero)
 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;
@@ -839,9 +998,10 @@ set_dev_loss(vector strvec, void *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;
 }
 
@@ -870,17 +1030,23 @@ declare_hw_handler(eh_deadline, set_undef_off_zero)
 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;
 }
@@ -936,33 +1102,28 @@ get_sys_max_fds(int *max_fds)
 
 
 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
@@ -981,7 +1142,7 @@ snprint_max_fds (struct config *conf, struct strbuf *buff, const void *data)
 }
 
 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;
@@ -993,11 +1154,12 @@ set_rr_weight(vector strvec, void *ptr)
 
        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;
 }
@@ -1025,7 +1187,7 @@ declare_mp_handler(rr_weight, set_rr_weight)
 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;
@@ -1041,9 +1203,9 @@ set_pgfailback(vector strvec, void *ptr)
        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;
 }
@@ -1075,7 +1237,7 @@ declare_mp_handler(pgfailback, set_pgfailback)
 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;
@@ -1088,10 +1250,10 @@ no_path_retry_helper(vector strvec, void *ptr)
                *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;
 }
 
@@ -1120,7 +1282,8 @@ declare_mp_handler(no_path_retry, no_path_retry_helper)
 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;
 
@@ -1129,10 +1292,13 @@ def_log_checker_err_handler(struct config *conf, vector strvec)
        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;
@@ -1163,18 +1329,18 @@ set_reservation_key(vector strvec, struct be64 *be64_ptr, uint8_t *flags_ptr,
                *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;
 }
 
@@ -1193,7 +1359,8 @@ print_reservation_key(struct strbuf *buff,
 }
 
 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,
@@ -1209,7 +1376,8 @@ snprint_def_reservation_key (struct config *conf, struct strbuf *buff,
 }
 
 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)
@@ -1229,7 +1397,7 @@ snprint_mp_reservation_key (struct config *conf, struct strbuf *buff,
 }
 
 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;
@@ -1240,10 +1408,10 @@ set_off_int_undef(vector strvec, void *ptr)
 
        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;
 }
 
@@ -1368,29 +1536,11 @@ declare_ovr_snprint(recheck_wwid, print_yes_no_undef)
 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;
@@ -1408,9 +1558,10 @@ hw_vpd_vendor_handler(struct config *conf, vector strvec)
                        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;
 }
 
@@ -1430,7 +1581,8 @@ snprint_hw_vpd_vendor(struct config *conf, struct strbuf *buff,
  * 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();
@@ -1452,7 +1604,8 @@ blacklist_handler(struct config *conf, vector strvec)
 }
 
 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();
@@ -1475,7 +1628,8 @@ blacklist_exceptions_handler(struct config *conf, vector strvec)
 
 #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;                                                         \
@@ -1494,7 +1648,8 @@ ble_ ## option ## _handler (struct config *conf, vector strvec)           \
 
 #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;                                                         \
@@ -1536,13 +1691,15 @@ snprint_ble_simple (struct config *conf, struct strbuf *buff, const void *data)
 }
 
 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);
 }
@@ -1574,7 +1731,8 @@ static int snprint_bled_product(struct config *conf, struct strbuf *buff,
  * 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();
@@ -1586,7 +1744,8 @@ devices_handler(struct config *conf, vector strvec)
 }
 
 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;
 
@@ -1623,7 +1782,8 @@ declare_hw_snprint(hwhandler, print_str)
  * 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();
@@ -1640,7 +1800,8 @@ overrides_handler(struct config *conf, vector strvec)
  * 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();
@@ -1652,7 +1813,8 @@ multipaths_handler(struct config *conf, vector strvec)
 }
 
 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;
 
@@ -1673,7 +1835,7 @@ multipath_handler(struct config *conf, vector strvec)
 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)
 
 /*
@@ -1681,7 +1843,8 @@ 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;
 
@@ -1690,7 +1853,7 @@ deprecated_handler(struct config *conf, vector strvec)
        if (!buff)
                return 1;
 
-       FREE(buff);
+       free(buff);
        return 0;
 }
 
index f25fe9e3496a836cffd9a7571bdfd997168dc2a4..7d939ae08004ec318a718b574001d0f7633fa3ba 100644 (file)
@@ -17,7 +17,6 @@
 
 #include "checkers.h"
 #include "vector.h"
-#include "memory.h"
 #include "util.h"
 #include "structs.h"
 #include "config.h"
@@ -37,6 +36,8 @@
 #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" },
@@ -388,8 +389,10 @@ sysfs_get_tgt_nodename(struct path *pp, char *node)
                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);
        }
@@ -803,7 +806,7 @@ sysfs_set_nexus_loss_tmo(struct multipath *mpp, struct path *pp)
             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;
                }
@@ -1085,6 +1088,8 @@ parse_vpd_pg80(const unsigned char *in, char *out, size_t out_len)
        if (out_len == 0)
                return 0;
 
+       if (len > WWID_SIZE)
+               len = WWID_SIZE;
        /*
         * Strip leading and trailing whitespace
         */
@@ -1114,177 +1119,197 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
        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;
 }
 
@@ -1315,11 +1340,12 @@ parse_vpd_c0_hp3par(const unsigned char *in, size_t in_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;
        }
@@ -1330,8 +1356,10 @@ get_vpd_sysfs (struct udev_device *parent, int pg, char * str, int maxlen)
                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);
@@ -1375,7 +1403,7 @@ bool
 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)
@@ -1391,7 +1419,7 @@ int
 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)
@@ -2363,15 +2391,16 @@ int pathinfo(struct path *pp, struct config *conf, int mask)
        }
 
        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
index a5446b4d5c723543b674fa13afd355aec9a4d742..095657bb9de4119082c1a350ec0cf9d8edfd9eb0 100644 (file)
@@ -70,6 +70,7 @@ enum discovery_mode {
        __DI_WWID,
        __DI_BLACKLIST,
        __DI_NOIO,
+       __DI_NOFALLBACK,
 };
 
 #define DI_SYSFS       (1 << __DI_SYSFS)
@@ -79,6 +80,7 @@ enum discovery_mode {
 #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)
index 4ba7f339940d1a252c762f5f33c7ca46a7a1ad19..74c9215506ddd171e58b518682c850a3e75c4f1c 100644 (file)
@@ -10,7 +10,6 @@
 
 #include "checkers.h"
 #include "vector.h"
-#include "memory.h"
 #include "structs.h"
 #include "util.h"
 #include "debug.h"
@@ -27,7 +26,7 @@ merge_words(char **dst, const char *word)
 
        dstlen = strlen(*dst);
        len = dstlen + strlen(word) + 2;
-       *dst = REALLOC(*dst, len);
+       *dst = realloc(*dst, len);
 
        if (!*dst) {
                free(p);
@@ -146,11 +145,11 @@ int disassemble_map(const struct _vector *pathvec,
                        return 1;
 
                if (merge_words(&mpp->features, word)) {
-                       FREE(word);
+                       free(word);
                        return 1;
                }
 
-               FREE(word);
+               free(word);
        }
 
        /*
@@ -170,10 +169,10 @@ int disassemble_map(const struct _vector *pathvec,
                        return 1;
 
                if (merge_words(&mpp->hwhandler, word)) {
-                       FREE(word);
+                       free(word);
                        return 1;
                }
-               FREE(word);
+               free(word);
        }
 
        /*
@@ -185,7 +184,7 @@ int disassemble_map(const struct _vector *pathvec,
                return 1;
 
        num_pg = atoi(word);
-       FREE(word);
+       free(word);
 
        if (num_pg > 0) {
                if (!mpp->pg) {
@@ -207,7 +206,7 @@ int disassemble_map(const struct _vector *pathvec,
                goto out;
 
        mpp->nextpg = atoi(word);
-       FREE(word);
+       free(word);
 
        for (i = 0; i < num_pg; i++) {
                /*
@@ -232,7 +231,7 @@ int disassemble_map(const struct _vector *pathvec,
 
                        if (merge_words(&mpp->selector, word))
                                goto out1;
-                       FREE(word);
+                       free(word);
                } else {
                        p += get_word(p, NULL);
                        p += get_word(p, NULL);
@@ -260,7 +259,7 @@ int disassemble_map(const struct _vector *pathvec,
                        goto out;
 
                num_paths = atoi(word);
-               FREE(word);
+               free(word);
 
                p += get_word(p, &word);
 
@@ -268,7 +267,7 @@ int disassemble_map(const struct _vector *pathvec,
                        goto out;
 
                num_paths_args = atoi(word);
-               FREE(word);
+               free(word);
 
                for (j = 0; j < num_paths; j++) {
                        pp = NULL;
@@ -294,7 +293,7 @@ int disassemble_map(const struct _vector *pathvec,
                        } else if (store_path(pgp->paths, pp))
                                goto out1;
 
-                       FREE(word);
+                       free(word);
 
                        pgp->id ^= (long)pp;
                        pp->pgindex = i + 1;
@@ -303,7 +302,7 @@ int disassemble_map(const struct _vector *pathvec,
                                if (k == 0) {
                                        p += get_word(p, &word);
                                        def_minio = atoi(word);
-                                       FREE(word);
+                                       free(word);
 
                                        if (!strncmp(mpp->selector,
                                                     "round-robin", 11)) {
@@ -324,7 +323,7 @@ int disassemble_map(const struct _vector *pathvec,
        }
        return 0;
 out1:
-       FREE(word);
+       free(word);
 out:
        free_pgvec(mpp->pg, KEEP_PATHS);
        mpp->pg = NULL;
@@ -358,7 +357,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                return 1;
 
        num_feature_args = atoi(word);
-       FREE(word);
+       free(word);
 
        for (i = 0; i < num_feature_args; i++) {
                if (i == 1) {
@@ -368,7 +367,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                                return 1;
 
                        mpp->queuedio = atoi(word);
-                       FREE(word);
+                       free(word);
                        continue;
                }
                /* unknown */
@@ -383,7 +382,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                return 1;
 
        num_hwhandler_args = atoi(word);
-       FREE(word);
+       free(word);
 
        for (i = 0; i < num_hwhandler_args; i++)
                p += get_word(p, NULL);
@@ -397,7 +396,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                return 1;
 
        num_pg = atoi(word);
-       FREE(word);
+       free(word);
 
        if (num_pg == 0)
                return 0;
@@ -434,7 +433,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                        pgp->status = PGSTATE_UNDEF;
                        break;
                }
-               FREE(word);
+               free(word);
 
                /*
                 * PG Status (discarded, would be '0' anyway)
@@ -447,7 +446,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                        return 1;
 
                num_paths = atoi(word);
-               FREE(word);
+               free(word);
 
                p += get_word(p, &word);
 
@@ -455,7 +454,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                        return 1;
 
                num_pg_args = atoi(word);
-               FREE(word);
+               free(word);
 
                if (VECTOR_SIZE(pgp->paths) < num_paths)
                        return 1;
@@ -485,7 +484,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                        default:
                                break;
                        }
-                       FREE(word);
+                       free(word);
                        /*
                         * fail count
                         */
@@ -495,7 +494,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                                return 1;
 
                        pp->failcount = atoi(word);
-                       FREE(word);
+                       free(word);
 
                        /*
                         * selector args
@@ -508,7 +507,7 @@ int disassemble_status(const char *params, struct multipath *mpp)
                                                   &def_minio) == 1 &&
                                            def_minio != mpp->minio)
                                                        mpp->minio = def_minio;
-                                       FREE(word);
+                                       free(word);
                                } else
                                        p += get_word(p, NULL);
                        }
index e091a1dc3868897112af21afc3bec6111e8a25da..e80eb3e8cd124eadc44b71e9bddb88089574b89d 100644 (file)
 #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;
@@ -437,7 +437,7 @@ void check_foreign(void)
 }
 
 /* Call this after get_path_layout */
-void foreign_path_layout(void)
+void foreign_path_layout(fieldwidth_t *width)
 {
        struct foreign *fgn;
        int i;
@@ -457,7 +457,7 @@ void foreign_path_layout(void)
 
                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);
 
@@ -468,7 +468,7 @@ void foreign_path_layout(void)
 }
 
 /* Call this after get_multipath_layout */
-void foreign_multipath_layout(void)
+void foreign_multipath_layout(fieldwidth_t *width)
 {
        struct foreign *fgn;
        int i;
@@ -488,7 +488,7 @@ void foreign_multipath_layout(void)
 
                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);
 
@@ -498,19 +498,13 @@ void foreign_multipath_layout(void)
        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;
@@ -523,7 +517,7 @@ int snprint_foreign_topology(struct strbuf *buf, int verbosity)
                if (vec != NULL) {
                        vector_foreach_slot(vec, gm, j) {
                                if (_snprint_multipath_topology(
-                                           gm, buf, verbosity) < 0)
+                                           gm, buf, verbosity, width) < 0)
                                        break;
                        }
                }
@@ -531,19 +525,57 @@ int snprint_foreign_topology(struct strbuf *buf, int verbosity)
                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;
@@ -567,7 +599,7 @@ int snprint_foreign_paths(struct strbuf *buf, const char *style, int pretty)
                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;
                        }
@@ -582,8 +614,8 @@ int snprint_foreign_paths(struct strbuf *buf, const char *style, int pretty)
        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;
@@ -608,7 +640,7 @@ int snprint_foreign_multipaths(struct strbuf *buf,
                if (vec != NULL) {
                        vector_foreach_slot(vec, gm, j) {
                                ret = _snprint_multipath(gm, buf,
-                                                        style, pretty);
+                                                        style, width);
                                if (ret < 0)
                                        break;
                        }
index 77fc4851c9156afa7c51647d775a5b7dad2de854..cf8f570d736c75b2e36b606605d4d84d58d74c23 100644 (file)
@@ -18,7 +18,7 @@
 #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;
@@ -252,15 +252,17 @@ void check_foreign(void);
  * 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);
@@ -268,9 +270,11 @@ void foreign_multipath_layout(void);
  * '\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);
@@ -278,10 +282,11 @@ int snprint_foreign_topology(struct strbuf *buf, int verbosity);
  * '\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);
@@ -289,11 +294,11 @@ int snprint_foreign_paths(struct strbuf *buf, const char *style, int 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)
index d40c0869fc913bcee67f757c87cc232f05bdd6d3..499b881d7463661ef312e973562fb15807e22883 100644 (file)
@@ -184,7 +184,9 @@ static int snprint_nvme_map(const struct gen_multipath *gmp,
                                                              "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");
index 57c123ca39e56a3e0f73a98842c1eaa816ccdd8f..e89848f37e372927f3a71a9f0100117d8064cea5 100644 (file)
 #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;
index 0caac0da9c558d14fb98ee54d218c5cf68ba67ca..c65e5e10dafc327a7247b85b9d6092d0c14fa0e4 100644 (file)
@@ -359,14 +359,11 @@ static struct hwentry default_hw[] = {
                .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,
        },
        {
@@ -399,6 +396,15 @@ static struct hwentry default_hw[] = {
                .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
         */
@@ -483,8 +489,6 @@ static struct hwentry default_hw[] = {
        },
        /*
         * IBM
-        *
-        * Maintainer: Hannes Reinecke <hare@suse.de>
         */
        {
                /* ProFibre 4000R */
@@ -656,7 +660,8 @@ static struct hwentry default_hw[] = {
                .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 /
@@ -712,7 +717,8 @@ static struct hwentry default_hw[] = {
                .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 */
index d8d91f641e810ae0dd8d0de2e8e172ff884b2579..dc1c2521da966b7c983e15b86d5e27cd41467917 100644 (file)
@@ -24,7 +24,6 @@
 #include <sys/select.h>
 
 #include "vector.h"
-#include "memory.h"
 #include "checkers.h"
 #include "config.h"
 #include "structs.h"
@@ -132,7 +131,7 @@ static int setup_directio_ctx(struct io_err_stat_path *p)
        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;
 
@@ -154,7 +153,8 @@ deinit:
        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);
 
@@ -174,19 +174,19 @@ static void free_io_err_stat_path(struct io_err_stat_path *p)
 
        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;
 
index eb5b5b55a74649af7b3d8ae146f8b240869d42cd..9c7ffa71828ca32c9c21103d6d91ecc8bde99258 100644 (file)
  *   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;
@@ -74,6 +79,7 @@ global:
        dm_is_mpath;
        dm_mapname;
        dm_map_present;
+       dm_prereq;
        dm_queue_if_no_path;
        dm_reassign;
        dm_reinstate_path;
@@ -102,16 +108,21 @@ global:
        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;
@@ -119,15 +130,21 @@ global:
        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;
@@ -137,9 +154,10 @@ global:
        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;
@@ -148,6 +166,7 @@ global:
        remove_wwid;
        replace_wwids;
        reset_checker_classes;
+       reset_strbuf;
        select_all_tg_pt;
        select_action;
        select_find_multipaths_timeout;
@@ -162,7 +181,9 @@ global:
        setup_map;
        setup_thread_attr;
        should_multipath;
+       skip_libmp_dm_init;
        snprint_blacklist_report;
+       __snprint_config;
        snprint_config;
        snprint_devices;
        snprint_foreign_multipaths;
@@ -186,17 +207,20 @@ global:
        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;
@@ -210,10 +234,14 @@ global:
        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;
@@ -222,6 +250,7 @@ global:
        libmp_nvme_identify_ns;
        log_nvme_errcode;
        nvme_id_ctrl_ana;
+       set_wakeup_fn;
        snprint_host_wwnn;
        snprint_host_wwpn;
        snprint_path_serial;
@@ -233,57 +262,6 @@ global:
        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:
        *;
 };
index 72c70e34686d995721d1e66a28d95d64f0b00008..93b48dbbdc1011a1eb52606765bf4f7b1e01b56c 100644 (file)
@@ -3,6 +3,16 @@
 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);
 }
index a170efe9e4a29860932f1761104b4eb938a39350..d7b779e773ac5af52448548a885ec2e815cd2d26 100644 (file)
@@ -3,8 +3,11 @@
 
 #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)
@@ -12,12 +15,17 @@ 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);
 }
@@ -25,5 +33,6 @@ static inline void unlock(struct mutex_lock *a)
 #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 */
index 10fa32cde7cb0d45070fe92a65413be4730e8a9c..45b3ed8883c8f660ff10184052201f048e0c4633 100644 (file)
@@ -11,7 +11,6 @@
 #include <time.h>
 #include <pthread.h>
 
-#include "memory.h"
 #include "log.h"
 #include "util.h"
 
@@ -44,7 +43,7 @@ static void dump_logarea (void)
 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;
@@ -52,23 +51,24 @@ static int logarea_init (int size)
        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;
@@ -95,9 +95,10 @@ int log_init(char *program_name, int size)
 
 static void free_logarea (void)
 {
-       FREE(la->start);
-       FREE(la->buff);
-       FREE(la);
+       free(la->start);
+       free(la->buff);
+       free(la);
+       la = NULL;
        return;
 }
 
index 6599210184388734250519dc1f7afbf1bfb17f32..69b441bf69a5c124c84728b378b1cc3d2e02356a 100644 (file)
@@ -8,8 +8,6 @@
 #include <pthread.h>
 #include <sys/mman.h>
 
-#include "memory.h"
-
 #include "log_pthread.h"
 #include "log.h"
 #include "lock.h"
diff --git a/libmultipath/memory.c b/libmultipath/memory.c
deleted file mode 100644 (file)
index 7514642..0000000
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * 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
diff --git a/libmultipath/memory.h b/libmultipath/memory.h
deleted file mode 100644 (file)
index a3c478e..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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
index 8ca91bf252842a964808cc9ed5c9bb2a5f419e8b..014d9b8360610251c3a1f1289d4326b44150139c 100644 (file)
@@ -23,7 +23,6 @@
 #include "vector.h"
 #include "config.h"
 #include "parser.h"
-#include "memory.h"
 #include "debug.h"
 #include "strbuf.h"
 
@@ -33,19 +32,19 @@ static int line_nr;
 
 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;
@@ -72,7 +71,7 @@ install_sublevel_end(void)
 
 int
 _install_keyword(vector keywords, char *string,
-                int (*handler) (struct config *, vector),
+                handler_fn *handler,
                 print_fn *print,
                 int unique)
 {
@@ -115,7 +114,7 @@ free_keywords(vector keywords)
                keyword = VECTOR_SLOT(keywords, i);
                if (keyword->sub)
                        free_keywords(keyword->sub);
-               FREE(keyword);
+               free(keyword);
        }
        vector_free(keywords);
 }
@@ -245,7 +244,7 @@ alloc_strvec(char *string)
                start = cp;
                if (*cp == '"' && !(in_string && *(cp + 1) == '"')) {
                        cp++;
-                       token = MALLOC(sizeof(quote_marker));
+                       token = calloc(1, sizeof(quote_marker));
 
                        if (!token)
                                goto out;
@@ -256,7 +255,7 @@ alloc_strvec(char *string)
                        else
                                in_string = 1;
                } else if (!in_string && (*cp == '{' || *cp == '}')) {
-                       token = MALLOC(2);
+                       token = malloc(2);
 
                        if (!token)
                                goto out;
@@ -283,7 +282,7 @@ alloc_strvec(char *string)
                        }
 
                        strlen = cp - start;
-                       token = MALLOC(strlen + 1);
+                       token = calloc(1, strlen + 1);
 
                        if (!token)
                                goto out;
@@ -350,7 +349,7 @@ set_value(vector strvec)
                                (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
@@ -358,7 +357,7 @@ set_value(vector strvec)
                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++) {
@@ -375,9 +374,9 @@ set_value(vector strvec)
                /* 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')
@@ -504,7 +503,7 @@ validate_config_strvec(vector strvec, const char *file)
 
 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;
@@ -518,7 +517,7 @@ process_stream(struct config *conf, FILE *stream, vector keywords,
        if (!uniques)
                return 1;
 
-       buf = MALLOC(MAXBUF);
+       buf = calloc(1, MAXBUF);
 
        if (!buf) {
                vector_free(uniques);
@@ -558,32 +557,39 @@ process_stream(struct config *conf, FILE *stream, vector keywords,
                                                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;
 }
@@ -608,7 +614,7 @@ process_file(struct config *conf, const char *file)
 
        /* 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);
 
index b43d46f88ce0f229a6b0e02f331b0304f8c33114..11ea22788b2430ea75a22b276070714be256d9d6 100644 (file)
@@ -43,10 +43,11 @@ struct strbuf;
 
 /* 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;
@@ -62,18 +63,14 @@ struct keyword {
        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);
index 0e5510980988fca2161886549f0c82e61a5f24cf..10b44d373d1171704bb0558fb3bf1feb9b38dc4e 100644 (file)
@@ -8,7 +8,6 @@
 
 #include "checkers.h"
 #include "util.h"
-#include "memory.h"
 #include "vector.h"
 #include "structs.h"
 #include "pgpolicies.h"
@@ -244,12 +243,12 @@ int group_by_match(struct multipath * mp, vector paths,
                        }
                }
        }
-       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;
index 2fb9f4efdab8158ed4bcfc8d6df5ce5271595c70..221b515f23d319cc6034ede373e9c13f64e056b0 100644 (file)
 
 #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))
 /*
@@ -504,6 +522,26 @@ snprint_dm_path_state (struct strbuf *buff, const struct path * pp)
        }
 }
 
+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)
 {
@@ -735,7 +773,7 @@ snprint_path_protocol(struct strbuf *buff, const struct path * pp)
        }
 }
 
-int
+static int
 snprint_path_marginal(struct strbuf *buff, const struct path * pp)
 {
        if (pp->marginal)
@@ -751,92 +789,91 @@ snprint_path_vpd_data(struct strbuf *buff, const struct path * pp)
        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;
@@ -844,18 +881,22 @@ int snprint_wildcards(struct strbuf *buff)
        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:
@@ -870,158 +911,162 @@ reset_width(unsigned int *width, enum layout_reset reset, const char *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;
        }
 
@@ -1031,25 +1076,27 @@ int snprint_multipath_header(struct strbuf *line, const char *format)
 }
 
 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;
        }
 
@@ -1058,25 +1105,29 @@ int _snprint_multipath(const struct gen_multipath *gmp,
        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;
        }
 
@@ -1086,25 +1137,26 @@ int snprint_path_header(struct strbuf *line, const char *format)
 }
 
 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;
        }
 
@@ -1118,7 +1170,6 @@ int _snprint_pathgroup(const struct gen_pathgroup *ggp, struct strbuf *line,
 {
        int initial_len = get_strbuf_len(line);
        const char *f;
-       struct pathgroup_data *data;
        int rc;
 
        for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
@@ -1126,14 +1177,9 @@ int _snprint_pathgroup(const struct gen_pathgroup *ggp, struct strbuf *line,
                        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)
@@ -1147,8 +1193,26 @@ int _snprint_pathgroup(const struct gen_pathgroup *ggp, struct strbuf *line,
 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));
 }
 
@@ -1168,21 +1232,24 @@ int snprint_multipath_style(const struct gen_multipath *gmp,
 }
 
 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 */
@@ -1193,8 +1260,8 @@ int _snprint_multipath_topology(const struct gen_multipath *gmp,
           (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);
@@ -1221,7 +1288,7 @@ int _snprint_multipath_topology(const struct gen_multipath *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);
@@ -1756,24 +1823,36 @@ static int snprint_blacklist_except(const struct config *conf,
        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);
@@ -1894,6 +1973,7 @@ static void print_all_paths_custo(vector pathvec, int banner, const char *fmt)
        int i;
        struct path * pp;
        STRBUF_ON_STACK(line);
+       fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
 
        if (!VECTOR_SIZE(pathvec)) {
                if (banner)
@@ -1901,14 +1981,17 @@ static void print_all_paths_custo(vector pathvec, int banner, const char *fmt)
                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));
 }
index c6674a5a6a433601d94a8f8c4cc0b88532a74910..52f5b2566cf831ee205b432b2f60bfcfa6686804 100644 (file)
@@ -9,51 +9,39 @@
 
 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);
index c92bde7ff498729937a4591e06484c100c03eae0..ef68cd0323634c0bea249f4bc448680a8fce8671 100644 (file)
@@ -51,7 +51,7 @@ static struct prio * alloc_prio (void)
 {
        struct prio *p;
 
-       p = MALLOC(sizeof(struct prio));
+       p = calloc(1, sizeof(struct prio));
        if (p) {
                INIT_LIST_HEAD(&p->node);
                p->refcount = 1;
@@ -77,7 +77,7 @@ void free_prio (struct prio * p)
                                p->name, dlerror());
                }
        }
-       FREE(p);
+       free(p);
 }
 
 void cleanup_prio(void)
index 26754f78b04319d3b781a557d69a0813dd63b911..66c7936ee4ab734f84f759f04910425ec17b83be 100644 (file)
@@ -11,7 +11,6 @@
 struct path;
 
 #include "list.h"
-#include "memory.h"
 #include "defaults.h"
 
 /*
index 420a2e390f63da4c2a039a91b96410bec744f924..3f9c0e73e3439e2364d1c099c41565c14534568a 100644 (file)
@@ -27,7 +27,6 @@
 #include "../structs.h"
 #include "../prio.h"
 #include "../discovery.h"
-#include "../unaligned.h"
 #include "../debug.h"
 #include "alua_rtpg.h"
 
@@ -252,12 +251,12 @@ int
 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"
@@ -298,13 +297,13 @@ get_target_port_group(const struct path * pp, unsigned int timeout)
        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);
                }
        }
@@ -377,7 +376,7 @@ get_asymmetric_access_state(const struct path *pp, unsigned int 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"
index 7ba2cf4cb6c611499ce3439d114bb175efa706fa..f0a4bc441cf33672df8a2095581e6d12ca8a73ad 100644 (file)
@@ -14,6 +14,7 @@
  */
 #ifndef __SPC3_H__
 #define __SPC3_H__
+#include "../unaligned.h"
 
 /*=============================================================================
  * Definitions to support the standard inquiry command as defined in SPC-3.
@@ -177,7 +178,7 @@ struct vpd83_dscr {
 } __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);
 }
@@ -190,6 +191,38 @@ struct vpd83_data {
        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.
@@ -199,11 +232,9 @@ struct vpd83_data {
  */
 #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) \
                )
 
 /*=============================================================================
index eeee01e1cd7c1abd8790c52dfed7f56a3f452679..078226df50d340de2e51a3a7e062605119afcc9d 100644 (file)
@@ -158,7 +158,7 @@ static int get_ionum_and_basenum(char *args, int *ionum, double *basenum)
                return 0;
        }
 
-       arg = temp = STRDUP(args);
+       arg = temp = strdup(args);
        if (!arg)
                return 0;
 
@@ -185,10 +185,10 @@ static int get_ionum_and_basenum(char *args, int *ionum, double *basenum)
        if (check_args_valid(*ionum, *basenum) == 0)
                goto out;
 
-       FREE(arg);
+       free(arg);
        return 1;
 out:
-       FREE(arg);
+       free(arg);
        return 0;
 }
 
index ea03fc3db60d97d905e3bf408b1a0801423acf91..561ebb48837ddcc41525380fac4cf81d847e421d 100644 (file)
@@ -29,7 +29,6 @@
 #include "weightedpath.h"
 #include "config.h"
 #include "structs.h"
-#include "memory.h"
 #include "debug.h"
 #include <regex.h>
 #include "structs_vec.h"
@@ -75,13 +74,13 @@ int prio_path_weight(struct path *pp, char *prio_args)
        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;
        }
 
index b287667049398075356f796e66dc12915922447a..a842fc39b2df6f9a700e63b5037f812016241de6 100644 (file)
@@ -7,7 +7,6 @@
 
 #include "nvme-lib.h"
 #include "checkers.h"
-#include "memory.h"
 #include "vector.h"
 #include "structs.h"
 #include "config.h"
@@ -255,7 +254,7 @@ int select_selector(struct config *conf, struct multipath * mp)
        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;
@@ -303,7 +302,7 @@ int select_alias(struct config *conf, struct multipath * mp)
        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;
        }
@@ -329,7 +328,7 @@ int select_alias(struct config *conf, struct multipath * mp)
        }
 out:
        if (mp->alias == NULL) {
-               mp->alias = STRDUP(mp->wwid);
+               mp->alias = strdup(mp->wwid);
                origin = "(setting: default to WWID)";
        }
        if (mp->alias)
@@ -399,7 +398,7 @@ int select_features(struct config *conf, struct multipath *mp)
        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,
@@ -477,7 +476,7 @@ out:
                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;
@@ -525,7 +524,7 @@ int select_checker(struct config *conf, struct path *pp)
                        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;
index a24a57d119456c729c57ceec3e51176a6a55b2bc..f654594dad40b732e0a1c0639de005ad446b9e3e 100644 (file)
 
 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;
index 59035726b7a401101f507f8ef439818bba3594e2..41d7d54fdce4044e6a990574dd2c9982e8ac378f 100644 (file)
@@ -54,6 +54,20 @@ void free_strbuf(struct strbuf *buf);
  */
 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
index 6e5a1038c329727e76e21a9361ec21e3dd6afc87..d1b8aa33d9fe1c92e6831a8de9b87b1de985751e 100644 (file)
@@ -8,7 +8,6 @@
 #include <libudev.h>
 
 #include "checkers.h"
-#include "memory.h"
 #include "vector.h"
 #include "util.h"
 #include "structs.h"
@@ -25,14 +24,14 @@ alloc_adaptergroup(void)
 {
        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;
@@ -45,7 +44,7 @@ void free_adaptergroup(vector adapters)
 
        vector_foreach_slot(adapters, agp, i) {
                free_hostgroup(agp->host_groups);
-               FREE(agp);
+               free(agp);
        }
        vector_free(adapters);
 }
@@ -60,7 +59,7 @@ void free_hostgroup(vector hostgroups)
 
        vector_foreach_slot(hostgroups, hgp, i) {
                vector_free(hgp->paths);
-               FREE(hgp);
+               free(hgp);
        }
        vector_free(hostgroups);
 }
@@ -70,7 +69,7 @@ alloc_hostgroup(void)
 {
        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;
@@ -78,7 +77,7 @@ alloc_hostgroup(void)
        hgp->paths = vector_alloc();
 
        if (!hgp->paths) {
-               FREE(hgp);
+               free(hgp);
                hgp = NULL;
        }
        return hgp;
@@ -89,7 +88,7 @@ alloc_path (void)
 {
        struct path * pp;
 
-       pp = (struct path *)MALLOC(sizeof(struct path));
+       pp = (struct path *)calloc(1, sizeof(struct path));
 
        if (pp) {
                pp->initialized = INIT_NEW;
@@ -152,7 +151,7 @@ free_path (struct path * pp)
 
        vector_free(pp->hwe);
 
-       FREE(pp);
+       free(pp);
 }
 
 void
@@ -176,7 +175,7 @@ alloc_pathgroup (void)
 {
        struct pathgroup * pgp;
 
-       pgp = (struct pathgroup *)MALLOC(sizeof(struct pathgroup));
+       pgp = (struct pathgroup *)calloc(1, sizeof(struct pathgroup));
 
        if (!pgp)
                return NULL;
@@ -184,7 +183,7 @@ alloc_pathgroup (void)
        pgp->paths = vector_alloc();
 
        if (!pgp->paths) {
-               FREE(pgp);
+               free(pgp);
                return NULL;
        }
 
@@ -199,7 +198,7 @@ free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths)
                return;
 
        free_pathvec(pgp->paths, free_paths);
-       FREE(pgp);
+       free(pgp);
 }
 
 void
@@ -222,7 +221,7 @@ alloc_multipath (void)
 {
        struct multipath * mpp;
 
-       mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
+       mpp = (struct multipath *)calloc(1, sizeof(struct multipath));
 
        if (mpp) {
                mpp->bestpg = 1;
@@ -251,17 +250,17 @@ void free_multipath_attributes(struct multipath *mpp)
                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;
        }
 }
@@ -275,12 +274,12 @@ free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
        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;
        }
 
@@ -305,8 +304,8 @@ free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
                vector_free(mpp->hwe);
                mpp->hwe = NULL;
        }
-       FREE_PTR(mpp->mpcontext);
-       FREE(mpp);
+       free(mpp->mpcontext);
+       free(mpp);
 }
 
 void
@@ -633,7 +632,7 @@ int add_feature(char **f, const char *n)
        for (d = c; d >= 10; d /= 10)
                l++;
 
-       t = MALLOC(l + 1);
+       t = calloc(1, l + 1);
        if (!t)
                return 1;
 
@@ -644,7 +643,7 @@ int add_feature(char **f, const char *n)
 
        snprintf(t, l + 1, "%0d%s %s", c, e, n);
 
-       FREE(*f);
+       free(*f);
        *f = t;
 
        return 0;
@@ -696,7 +695,7 @@ int remove_feature(char **f, const char *o)
 
        /* Quick exit if all features have been removed */
        if (c == 0) {
-               n = MALLOC(2);
+               n = malloc(2);
                if (!n)
                        return 1;
                strcpy(n, "0");
@@ -711,7 +710,7 @@ int remove_feature(char **f, const char *o)
 
        /* Update feature count space */
        l = strlen(*f) - d;
-       n =  MALLOC(l + 1);
+       n =  malloc(l + 1);
        if (!n)
                return 1;
 
@@ -724,7 +723,7 @@ int remove_feature(char **f, const char *o)
        p = strchr(*f, ' ');
        if (!p) {
                /* Internal error, feature string inconsistent */
-               FREE(n);
+               free(n);
                return 1;
        }
        while (*p == ' ')
@@ -753,7 +752,7 @@ int remove_feature(char **f, const char *o)
        }
 
 out:
-       FREE(*f);
+       free(*f);
        *f = n;
 
        return 0;
index 399540e784ce1f7f72754329fbc74ac4552f6145..c0f8929c2921bb710e20e304989c697214f47f8e 100644 (file)
@@ -200,6 +200,13 @@ enum initialized_states {
         * 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 {
@@ -312,6 +319,7 @@ struct path {
        int fd;
        int initialized;
        int retriggers;
+       int partial_retrigger_delay;
        unsigned int path_failures;
        time_t dis_reinstate_time;
        int disable_reinstate;
@@ -355,6 +363,7 @@ struct multipath {
        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;
index 85d97ac1cbb035219f9c8bae532711f34efe4fdd..cb0ebae6901672fad1d8e0512461a3a0258ff81a 100644 (file)
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <libudev.h>
 
 #include "util.h"
 #include "checkers.h"
@@ -98,7 +99,7 @@ static bool guess_mpp_wwid(struct multipath *mpp)
  * - 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;
@@ -148,16 +149,15 @@ bool update_pathvec_from_dm(vector pathvec, struct multipath *mpp,
                         * 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 {
@@ -174,15 +174,14 @@ bool update_pathvec_from_dm(vector pathvec, struct multipath *mpp,
                                } 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",
@@ -194,6 +193,8 @@ bool update_pathvec_from_dm(vector pathvec, struct multipath *mpp,
                                        }
                                        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;
                                }
@@ -237,6 +238,7 @@ bool update_pathvec_from_dm(vector pathvec, struct multipath *mpp,
                free_pathgroup(pgp, KEEP_PATHS);
                must_reload = true;
        }
+       mpp->need_reload = mpp->need_reload || must_reload;
        return must_reload;
 }
 
@@ -298,16 +300,19 @@ void orphan_path(struct path *pp, const char *reason)
        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
@@ -325,10 +330,8 @@ void set_path_removed(struct path *pp)
         * 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;
 }
@@ -338,6 +341,10 @@ remove_map(struct multipath *mpp, vector pathvec, vector mpvec)
 {
        int i;
 
+       free_pathvec(mpp->paths, KEEP_PATHS);
+       free_pgvec(mpp->pg, KEEP_PATHS);
+       mpp->paths = mpp->pg = NULL;
+
        /*
         * clear references to this map
         */
@@ -393,12 +400,12 @@ extract_hwe_from_path(struct multipath * mpp)
        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;
        }
@@ -468,11 +475,14 @@ static void check_removed_paths(const struct multipath *mpp, vector pathvec)
        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);
                }
index 29ede454fff8a0bc01c709839f149cf22c00cccc..d33fe9848124f66e2ca7e491137954a308f18eb3 100644 (file)
@@ -6,23 +6,19 @@
 #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);
index 9ff145f26c9bf9f354edb87127eaaaa6f85b4ccf..f45dbee1069c38946cc0077ff8bb610267a748ad 100644 (file)
@@ -287,7 +287,7 @@ int sysfs_check_holders(char * check_devt, char * new_devt)
                        table_name, check_devt, new_devt);
 
                dm_reassign_table(table_name, check_devt, new_devt);
-               FREE(table_name);
+               free(table_name);
        }
        closedir(dirfd);
 
index 55f366cc795a847c4a54d6f7c96c05100e4d8c02..29193009031c711a8f784cb5620e9096f3032aff 100644 (file)
@@ -49,3 +49,15 @@ void timespecsub(const struct timespec *a, const struct timespec *b,
        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);
+}
index b23d328a35f14dffdb7bc9774affbc6b8bedf041..4a80ebd32edfd1b488bdac80a3ee7505fae255cf 100644 (file)
@@ -10,5 +10,6 @@ void pthread_cond_init_mono(pthread_cond_t *cond);
 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_ */
index 4265904b6fd81fab9efd8ab90008ad2aabd92b49..70ad21759cc0011b5f2ee902460dab8362f755ce 100644 (file)
@@ -43,7 +43,6 @@
 #include <libudev.h>
 #include <errno.h>
 
-#include "memory.h"
 #include "debug.h"
 #include "list.h"
 #include "uevent.h"
@@ -81,7 +80,7 @@ int is_uevent_busy(void)
 
 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);
@@ -91,16 +90,25 @@ struct uevent * alloc_uevent (void)
        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);
        }
 }
 
@@ -309,7 +317,7 @@ uevent_prepare(struct list_head *tmpq)
                        list_del_init(&uev->node);
                        if (uev->udev)
                                udev_device_unref(uev->udev);
-                       FREE(uev);
+                       free(uev);
                        continue;
                }
 
@@ -337,7 +345,7 @@ uevent_filter(struct uevent *later, struct list_head *tmpq)
                        list_del_init(&earlier->node);
                        if (earlier->udev)
                                udev_device_unref(earlier->udev);
-                       FREE(earlier);
+                       free(earlier);
                }
        }
 }
@@ -384,14 +392,10 @@ service_uevq(struct list_head *tmpq)
        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);
        }
 }
 
@@ -411,6 +415,18 @@ static void monitor_cleanup(void *arg)
        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.
  */
@@ -425,6 +441,7 @@ int uevent_dispatch(int (*uev_trigger)(struct uevent *, void * trigger_data),
        while (1) {
                LIST_HEAD(uevq_tmp);
 
+               pthread_cleanup_push(cleanup_mutex, uevq_lockp);
                pthread_mutex_lock(uevq_lockp);
                servicing_uev = 0;
                /*
@@ -436,14 +453,17 @@ int uevent_dispatch(int (*uev_trigger)(struct uevent *, void * trigger_data),
                }
                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;
 }
 
@@ -492,7 +512,7 @@ static struct uevent *uevent_from_udev_device(struct udev_device *dev)
        if (!uev->devpath || ! uev->action) {
                udev_device_unref(dev);
                condlog(1, "uevent missing necessary fields");
-               FREE(uev);
+               free(uev);
                return NULL;
        }
        uev->udev = dev;
@@ -600,6 +620,8 @@ int uevent_listen(struct udev *udev)
 
        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;
@@ -650,6 +672,8 @@ int uevent_listen(struct udev *udev)
                gettimeofday(&start_time, NULL);
                timeout = 30;
        }
+       pthread_cleanup_pop(1);
+       pthread_cleanup_pop(1);
 out:
        pthread_cleanup_pop(1);
 out_udev:
index ea858409cf66c107bc307c7a0c551454cf472001..ce5ea73e103e44ba4460c982f30506b31bf90526 100644 (file)
@@ -17,7 +17,6 @@
 
 #include "util.h"
 #include "debug.h"
-#include "memory.h"
 #include "checkers.h"
 #include "vector.h"
 #include "structs.h"
@@ -110,7 +109,7 @@ get_word (const char *sentence, char **word)
        if (!word)
                return skip + len;
 
-       *word = MALLOC(len + 1);
+       *word = calloc(1, len + 1);
 
        if (!*word) {
                condlog(0, "get_word : oom");
@@ -168,6 +167,7 @@ size_t strlcat(char * restrict dst, const char * restrict src, size_t size)
 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)
@@ -178,7 +178,13 @@ int devt2devname(char *devname, int devname_len, const char *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);
@@ -407,8 +413,8 @@ void free_scandir_result(struct scandir_result *res)
        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)
@@ -460,3 +466,8 @@ void cleanup_charp(char **p)
 {
        free(*p);
 }
+
+void cleanup_ucharp(unsigned char **p)
+{
+       free(*p);
+}
index 89027f80588f0d5960934454d95735f36f0b26fc..79d9f32aec58f6bec85d1bed07ba329473363b72 100644 (file)
@@ -9,6 +9,7 @@
 #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);
@@ -124,4 +125,5 @@ static inline void clear_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
        })
 
 void cleanup_charp(char **p);
+void cleanup_ucharp(unsigned char **p);
 #endif /* _UTIL_H */
index 6adeedfc4024cec4e9907a185dc8a9fa9eb989b5..2135476d3ae183c34d8e216645b1951e9830314e 100644 (file)
@@ -21,7 +21,6 @@
 #endif
 #include "mpath_cmd.h"
 
-#include "memory.h"
 #include "uxsock.h"
 #include "debug.h"
 
@@ -110,12 +109,12 @@ static int _recv_packet(int fd, char **buf, unsigned int timeout, ssize_t limit)
                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;
        }
@@ -129,8 +128,3 @@ int recv_packet(int fd, char **buf, unsigned int timeout)
 {
        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);
-}
index 8e7401d25254c48928122b50fb81434321e0fa16..e3d28cf5ffd4df9db5db5e254ebca72cf2350b72 100644 (file)
@@ -5,9 +5,3 @@ int recv_packet(int fd, char **buf, unsigned int timeout);
 
 #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);
index 6605eb2def23d9c7fb4b210291df5723c3e458ad..e2d1ec9300eb4056eea54b629b06139af907a8c8 100644 (file)
@@ -19,7 +19,6 @@
  * Copyright (c) 2005 Christophe Varoqui
  */
 
-#include "memory.h"
 #include <stdlib.h>
 #include "vector.h"
 
@@ -30,7 +29,7 @@
 vector
 vector_alloc(void)
 {
-       vector v = (vector) MALLOC(sizeof (struct _vector));
+       vector v = (vector) calloc(1, sizeof (struct _vector));
        return v;
 }
 
@@ -46,7 +45,7 @@ vector_alloc_slot(vector 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;
 
@@ -119,13 +118,13 @@ vector_del_slot(vector v, int slot)
        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
@@ -153,7 +152,7 @@ vector_reset(vector v)
                return NULL;
 
        if (v->slot)
-               FREE(v->slot);
+               free(v->slot);
 
        v->allocated = 0;
        v->slot = NULL;
@@ -166,7 +165,7 @@ vector_free(vector v)
 {
        if (!vector_reset(v))
                return;
-       FREE(v);
+       free(v);
 }
 
 void
@@ -180,7 +179,7 @@ free_strvec(vector strvec)
 
        vector_foreach_slot (strvec, str, i)
                if (str)
-                       FREE(str);
+                       free(str);
 
        vector_free(strvec);
 }
index 34e1d903fe2c5837e0c85b1b51e2f257077081a1..e86a3cc86e4e2bdde94149c7209fdbdcdc5fce0d 100644 (file)
@@ -20,8 +20,8 @@
 #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"
 
index 882043ae040429caf0f625dbc733a4a54c507cf6..7b574592d228d142bc6645e8b778ea2833c42d31 100644 (file)
@@ -235,7 +235,7 @@ multiple lines is not supported.
 .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
@@ -253,7 +253,7 @@ of the first failed command, or 0 if all commands succeeded.
 .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.
index 65ece830cdf643e42c2ce37fa1402d5dd3d13467..0a9377e5f65ce508a4ba6d07e47162e2eef12afb 100644 (file)
@@ -35,7 +35,6 @@
 #include "checkers.h"
 #include "prio.h"
 #include "vector.h"
-#include "memory.h"
 #include <libdevmapper.h>
 #include "devmapper.h"
 #include "util.h"
@@ -82,7 +81,7 @@ dump_config (struct config *conf, vector hwes, vector mpvec)
 
        if (reply != NULL) {
                printf("%s", reply);
-               FREE(reply);
+               free(reply);
                return 0;
        } else
                return 1;
@@ -286,7 +285,7 @@ found:
        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:
@@ -461,6 +460,7 @@ configure (struct config *conf, enum mpath_cmds cmd,
        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
@@ -547,8 +547,10 @@ configure (struct config *conf, enum mpath_cmds cmd,
        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;
@@ -560,6 +562,7 @@ configure (struct config *conf, enum mpath_cmds cmd,
 
                dump_config(conf, hwes, curmp);
                vector_free(hwes);
+               r = RTVL_OK;
                goto out;
        }
 
@@ -584,7 +587,7 @@ 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;
@@ -759,7 +762,7 @@ int delegate_to_multipathd(enum mpath_cmds cmd,
                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);
@@ -807,7 +810,7 @@ int delegate_to_multipathd(enum mpath_cmds cmd,
        }
 
 out:
-       FREE(reply);
+       free(reply);
        close(fd);
        return r;
 }
@@ -837,14 +840,12 @@ main (int argc, char *argv[])
        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);
                        }
@@ -887,9 +888,6 @@ main (int argc, char *argv[])
 
                        break;
                case 'M':
-#if _DEBUG_
-                       debug = atoi(optarg);
-#endif
                        break;
                case 'p':
                        conf->pgpolicy_flag = get_pgpolicy_id(optarg);
@@ -960,10 +958,13 @@ main (int argc, char *argv[])
                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;
@@ -1074,13 +1075,10 @@ main (int argc, char *argv[])
 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;
 }
index 17df59f5f18d7ab0d0965868cd7aebd081b0188b..4c7e988563834e10a0b0cdc4bec4ca94e6ee65e5 100644 (file)
@@ -245,7 +245,7 @@ Treat the bindings file as read only.
 .
 .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
index d6b8c7f674e3eae67e2317b61b09f390fba8003c..88d2a1df99d111222a0233ccd4f7188235e10539 100644 (file)
@@ -1,12 +1,12 @@
 .\" ----------------------------------------------------------------------------
-.\" 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
 .
 .
 .\" ----------------------------------------------------------------------------
@@ -178,6 +178,7 @@ The default is: \fBno\fR
 .
 .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
@@ -189,7 +190,7 @@ The default is: \fB<system dependent>\fR
 .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"
@@ -206,10 +207,14 @@ of outstanding I/O to the path.
 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
 .
@@ -738,6 +743,7 @@ The default is: \fB<unset>\fR
 .
 .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
@@ -748,6 +754,7 @@ The default is: \fB/etc/multipath/bindings\fR
 .
 .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
@@ -758,6 +765,7 @@ The default is: \fB/etc/multipath/wwids\fR
 .
 .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.
@@ -929,6 +937,7 @@ The default is: \fB<unset>\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.
index 4d6c37c98523acef2d080050a0727a682da7adba..b2ee9a99f08847a8c4661f8b727a3c3b36c07ebe 100644 (file)
@@ -4,7 +4,7 @@
 #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"
@@ -24,13 +24,13 @@ static vector handlers;
 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
@@ -45,7 +45,7 @@ add_key (vector vec, char * str, uint64_t code, int has_param)
 
        kw->code = code;
        kw->has_param = has_param;
-       kw->str = STRDUP(str);
+       kw->str = strdup(str);
 
        if (!kw->str)
                goto out;
@@ -58,32 +58,32 @@ add_key (vector vec, char * str, uint64_t code, int has_param)
        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 *
@@ -100,26 +100,17 @@ find_handler (uint64_t fp)
 }
 
 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;
 }
 
@@ -127,12 +118,12 @@ static void
 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
@@ -154,7 +145,7 @@ free_handlers (void)
        struct handler * h;
 
        vector_foreach_slot (handlers, h, i)
-               FREE(h);
+               free(h);
 
        vector_free(handlers);
        handlers = NULL;
@@ -218,6 +209,7 @@ load_keys (void)
        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) {
@@ -259,11 +251,10 @@ find_key (const char * str)
  *
  * 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;
@@ -294,7 +285,7 @@ get_cmdvec (char * cmd, vector *v)
                }
                kw = find_key(buff);
                if (!kw) {
-                       r = EAGAIN;
+                       r = ESRCH;
                        goto out;
                }
                cmdkw = alloc_key();
@@ -303,7 +294,7 @@ get_cmdvec (char * cmd, vector *v)
                        goto out;
                }
                if (!vector_alloc_slot(cmdvec)) {
-                       FREE(cmdkw);
+                       free(cmdkw);
                        r = ENOMEM;
                        goto out;
                }
@@ -328,7 +319,7 @@ out:
 }
 
 static uint64_t
-fingerprint(vector vec)
+fingerprint(const struct _vector *vec)
 {
        int i;
        uint64_t fp = 0;
@@ -343,6 +334,11 @@ fingerprint(vector vec)
        return fp;
 }
 
+struct handler *find_handler_for_cmdvec(const struct _vector *v)
+{
+       return find_handler(fingerprint(v));
+}
+
 int
 alloc_handlers (void)
 {
@@ -384,7 +380,7 @@ do_genhelp(struct strbuf *reply, const char *cmd, int error) {
        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:
@@ -421,75 +417,10 @@ do_genhelp(struct strbuf *reply, const char *cmd, int error) {
 }
 
 
-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 *
@@ -513,63 +444,6 @@ cli_init (void) {
        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;
 }
 
index fdfb9aedf163bee44b7b49a91a506328116a6686..a6082ac0d17ca38262895b2fe2d6880fa5faf0a0 100644 (file)
@@ -4,83 +4,84 @@
 #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)
@@ -93,6 +94,7 @@ enum {
 #define LOCAL          (1ULL << __LOCAL)
 #define SETMARGINAL    (1ULL << __SETMARGINAL)
 #define UNSETMARGINAL  (1ULL << __UNSETMARGINAL)
+#define ALL            (1ULL << __ALL)
 
 #define INITIAL_REPLY_LEN      1200
 
@@ -106,7 +108,7 @@ enum {
                                free(tmp);                      \
                                (r) = NULL;                     \
                        } else {                                \
-                               (r) = REALLOC((r), (m) * 2);    \
+                               (r) = realloc((r), (m) * 2);    \
                                if ((r)) {                      \
                                        memset((r) + (m), 0, (m)); \
                                        (m) *= 2;               \
@@ -124,17 +126,25 @@ struct key {
        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);
index 6d3a0ae2ecd0a1e4b53c9191e9209117dfc682d6..d79cdd7c895785a102fae857ff232e5c9c466004 100644 (file)
@@ -5,7 +5,6 @@
 #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;
 
@@ -141,45 +128,38 @@ show_maps_json (char ** r, int * len, struct vectors * vecs)
                }
        }
 
-       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;
 }
 
@@ -194,12 +174,12 @@ reset_stats(struct multipath * mpp)
        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)
@@ -207,10 +187,10 @@ 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;
 
@@ -218,45 +198,45 @@ cli_list_config_local (void * v, char ** reply, int * len, void * data)
 
        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);
@@ -269,18 +249,21 @@ cli_list_path (void * v, char ** reply, int * len, void * data)
        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)
@@ -288,28 +271,27 @@ cli_list_map_topology (void * v, char ** reply, int * len, void * data)
 
        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)
@@ -317,86 +299,74 @@ cli_list_map_json (void * v, char ** reply, int * len, void * data)
 
        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) {
@@ -404,133 +374,113 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
                        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;
@@ -544,8 +494,8 @@ cli_reset_maps_stats (void * v, char ** reply, int * len, void * data)
        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;
@@ -562,8 +512,35 @@ cli_reset_map_stats (void * v, char ** reply, int * len, void * data)
        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);
@@ -587,8 +564,12 @@ cli_add_path (void * v, char ** reply, int * len, void * data)
        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);
@@ -673,13 +654,13 @@ cli_add_path (void * v, char ** reply, int * len, void * data)
        }
        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);
@@ -695,14 +676,14 @@ cli_del_path (void * v, char ** reply, int * len, void * data)
        }
        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);
@@ -722,7 +703,7 @@ cli_add_map (void * v, char ** reply, int * len, void * data)
                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;
        }
@@ -746,7 +727,7 @@ cli_add_map (void * v, char ** reply, int * len, void * data)
                                    != CP_OK)
                                        condlog(2, "%s: coalesce_paths failed",
                                                                        param);
-                               FREE(refwwid);
+                               free(refwwid);
                        }
                } /*we attempt to create device only once*/
                count++;
@@ -757,12 +738,12 @@ cli_add_map (void * v, char ** reply, int * len, void * data)
                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);
@@ -783,12 +764,15 @@ cli_del_map (void * v, char ** reply, int * len, void * data)
                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;
@@ -806,8 +790,8 @@ cli_del_maps (void *v, char **reply, int *len, void *data)
        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);
@@ -834,7 +818,7 @@ cli_reload(void *v, char **reply, int *len, void *data)
        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;
@@ -859,8 +843,8 @@ int resize_map(struct multipath *mpp, unsigned long long size,
        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);
@@ -924,8 +908,8 @@ cli_resize(void *v, char **reply, int *len, void *data)
        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;
 
@@ -937,8 +921,8 @@ cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data)
        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;
 
@@ -950,8 +934,8 @@ cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data)
        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);
@@ -991,8 +975,8 @@ cli_restore_queueing(void *v, char **reply, int *len, void *data)
        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;
@@ -1013,8 +997,8 @@ cli_restore_all_queueing(void *v, char **reply, int *len, void *data)
        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);
@@ -1042,8 +1026,8 @@ cli_disable_queueing(void *v, char **reply, int *len, void *data)
        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;
@@ -1061,8 +1045,8 @@ cli_disable_all_queueing(void *v, char **reply, int *len, void *data)
        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));
@@ -1073,25 +1057,26 @@ cli_switch_group(void * v, char ** reply, int * len, void * data)
        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);
@@ -1120,8 +1105,8 @@ cli_suspend(void * v, char ** reply, int * len, void * data)
        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);
@@ -1152,8 +1137,8 @@ cli_resume(void * v, char ** reply, int * len, void * data)
        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);
@@ -1175,8 +1160,8 @@ cli_reinstate(void * v, char ** reply, int * len, void * data)
        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);
@@ -1199,8 +1184,8 @@ cli_reassign (void * v, char ** reply, int * len, void * data)
        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);
@@ -1228,88 +1213,80 @@ cli_fail(void * v, char ** reply, int * len, void * data)
        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)
@@ -1317,24 +1294,22 @@ cli_getprstatus (void * v, char ** reply, int * len, void * data)
 
        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)
@@ -1349,15 +1324,14 @@ cli_setprstatus(void * v, char ** reply, int * len, void * data)
        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)
@@ -1371,8 +1345,8 @@ cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
        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;
@@ -1386,25 +1360,20 @@ cli_getprkey(void * v, char ** reply, int * len, void * 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;
@@ -1427,8 +1396,8 @@ cli_unsetprkey(void * v, char ** reply, int * len, void * 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;
@@ -1459,7 +1428,7 @@ cli_setprkey(void * v, char ** reply, int * len, void * 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);
@@ -1486,7 +1455,7 @@ int cli_set_marginal(void * v, char ** reply, int * len, void * data)
        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);
@@ -1513,7 +1482,7 @@ int cli_unset_marginal(void * v, char ** reply, int * len, void * data)
        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);
@@ -1549,3 +1518,64 @@ int cli_unset_all_marginal(void * v, char ** reply, int * len, void * data)
 
        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);
+}
index 6f57b429cff61a26c9d0cb4d01303fdcfd6450c4..7eaf847e2c1d87ed19b392589529bf3882d309e1 100644 (file)
@@ -1,55 +1,6 @@
-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
index 3aff241d8caffe66f267026618cb446d6a91f7ce..7a57a798070608e374d7a792804aa6a0994b36c1 100644 (file)
@@ -38,7 +38,6 @@
  */
 #include "parser.h"
 #include "vector.h"
-#include "memory.h"
 #include "config.h"
 #include "util.h"
 #include "hwtable.h"
@@ -127,6 +126,8 @@ static int poll_dmevents = 1;
 #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;
@@ -150,6 +151,16 @@ int should_exit(void)
        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
  */
@@ -210,14 +221,21 @@ static void do_sd_notify(enum daemon_status old_state,
        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)
@@ -263,19 +281,53 @@ enum daemon_status wait_for_state_change_if(enum daemon_status oldstate,
        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
        }
 }
 
@@ -287,24 +339,54 @@ void post_config_state(enum daemon_status state)
        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)
@@ -490,6 +572,8 @@ update_map (struct multipath *mpp, struct vectors *vecs, int new_map)
 {
        int retries = 3;
        char *params __attribute__((cleanup(cleanup_charp))) = NULL;
+       struct path *pp;
+       int i;
 
 retry:
        condlog(4, "%s: updating new map", mpp->alias);
@@ -502,6 +586,15 @@ retry:
        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, &params, vecs)) {
                condlog(0, "%s: failed to setup new map in update", mpp->alias);
                retries = -1;
@@ -541,11 +634,11 @@ add_map_without_path (struct vectors *vecs, const char *alias)
        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);
@@ -691,7 +784,7 @@ uev_add_map (struct uevent * uev, struct vectors * vecs)
        pthread_testcancel();
        rc = ev_add_map(uev->kernel, alias, vecs);
        lock_cleanup_pop(vecs->lock);
-       FREE(alias);
+       free(alias);
        return rc;
 }
 
@@ -704,7 +797,7 @@ int
 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) {
@@ -723,15 +816,14 @@ ev_add_map (char * dev, const char * alias, struct vectors * vecs)
                                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;
                        }
                }
@@ -797,7 +889,7 @@ uev_remove_map (struct uevent * uev, struct vectors * vecs)
        remove_map_and_stop_waiter(mpp, vecs);
 out:
        lock_cleanup_pop(vecs->lock);
-       FREE(alias);
+       free(alias);
        return 0;
 }
 
@@ -884,12 +976,19 @@ check_path_wwid_change(struct path *pp)
        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) {
@@ -908,7 +1007,10 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
                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;
@@ -1018,6 +1120,8 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
        }
 out:
        lock_cleanup_pop(vecs->lock);
+       if (partial_init)
+               return uev_update_path(uev, vecs);
        return ret;
 }
 
@@ -1313,6 +1417,28 @@ fail:
        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)
 {
@@ -1351,7 +1477,7 @@ 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);
@@ -1359,12 +1485,20 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
 
                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);
@@ -1415,6 +1549,7 @@ out:
 
                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;
@@ -1450,11 +1585,11 @@ uev_pathfail_check(struct uevent *uev, struct vectors *vecs)
                                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;
 }
 
@@ -1476,48 +1611,6 @@ map_discovery (struct vectors * vecs)
        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)
 {
@@ -1643,65 +1736,18 @@ uxlsnrloop (void * ap)
        /* 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 */
@@ -1819,8 +1865,7 @@ missing_uev_wait_tick(struct vectors *vecs)
 {
        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) {
@@ -1836,13 +1881,10 @@ missing_uev_wait_tick(struct vectors *vecs)
                }
        }
 
-       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);
        }
 }
 
@@ -1906,6 +1948,25 @@ retry_count_tick(vector mpvec)
        }
 }
 
+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;
@@ -2117,7 +2178,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
        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;
@@ -2481,6 +2542,10 @@ checkerloop (void *ap)
                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);
@@ -2496,13 +2561,6 @@ checkerloop (void *ap)
                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);
@@ -2527,6 +2585,7 @@ checkerloop (void *ap)
                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)
@@ -2610,7 +2669,6 @@ configure (struct vectors * vecs)
        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");
@@ -2658,15 +2716,7 @@ configure (struct vectors * vecs)
        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;
@@ -2769,7 +2819,9 @@ reconfigure (struct vectors * vecs)
        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;
 
@@ -2789,7 +2841,7 @@ init_vecs (void)
 {
        struct vectors * vecs;
 
-       vecs = (struct vectors *)MALLOC(sizeof(struct vectors));
+       vecs = (struct vectors *)calloc(1, sizeof(struct vectors));
 
        if (!vecs)
                return NULL;
@@ -2830,7 +2882,7 @@ handle_signals(bool nonfatal)
                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)");
@@ -2900,51 +2952,28 @@ setscheduler (void)
        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");
 }
 
@@ -3001,7 +3030,8 @@ static void cleanup_vecs(void)
        cleanup_maps(gvecs);
        cleanup_paths(gvecs);
        pthread_mutex_destroy(&gvecs->lock.mutex);
-       FREE(gvecs);
+       free(gvecs);
+       gvecs = NULL;
 }
 
 static void cleanup_threads(void)
@@ -3099,10 +3129,6 @@ static void cleanup_child(void)
                log_thread_stop();
 
        cleanup_conf();
-
-#ifdef _DEBUG_
-       dbg_free_final(NULL);
-#endif
 }
 
 static int sd_notify_exit(int err)
@@ -3285,18 +3311,22 @@ child (__attribute__((unused)) void *param)
                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();
+                       }
                }
        }
 
@@ -3307,11 +3337,18 @@ failed:
        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));
@@ -3337,25 +3374,21 @@ daemonize(void)
                _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;
 }
@@ -3379,11 +3412,6 @@ main (int argc, char *argv[])
 
        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",
@@ -3470,6 +3498,11 @@ main (int argc, char *argv[])
                return err;
        }
 
+       if (getuid() != 0) {
+               fprintf(stderr, "need to be root\n");
+               exit(1);
+       }
+
        if (foreground) {
                if (!isatty(fileno(stdout)))
                        setbuf(stdout, NULL);
@@ -3544,7 +3577,7 @@ void *  mpath_pr_event_handler_fn (void * pathp )
                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;
 
index bc1f938f1dd20a9167100d15a32788b6752ad54f..8356b250faae129faa137e2131ba9f5fe5f857f2 100644 (file)
@@ -37,14 +37,13 @@ void exit_daemon(void);
 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);
@@ -66,4 +65,5 @@ int reload_and_sync_map(struct multipath *mpp, struct vectors *vecs,
 
 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 */
index 048a838d4bf486b61baf3f259d79810acf63ff18..293e7f2246798b5f9ade9f463e34de42083985f0 100644 (file)
@@ -55,7 +55,7 @@ Suppress timestamps. Do not prefix logging messages with a timestamp.
 .
 .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.
 .
@@ -195,10 +195,16 @@ group index, starting with 1.
 .
 .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.
 .
@@ -208,7 +214,7 @@ Resumes map $map from 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
index 0b2ac8147108c9de2701f4df104d86529be4bfcd..1919b380c8e4afe5d4f9ffb336f6e32a86e0114e 100644 (file)
@@ -1,9 +1,10 @@
 [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
index 0ed4a1f7958bafb6b84e99240c11e02b4469d33b..c777e5e3cc2b16bfc169f722256b349694bfe23a 100644 (file)
@@ -1,6 +1,9 @@
 [Unit]
 Description=multipathd control socket
 DefaultDependencies=no
+ConditionKernelCommandLine=!nompath
+ConditionKernelCommandLine=!multipath=off
+ConditionVirtualization=!container
 Before=sockets.target
 
 [Socket]
index a76f8e29910246f189a14b6afc3e0f696690c602..b1b058bd586e95d968e6da9c2fb80defcbdfc342 100644 (file)
@@ -20,7 +20,6 @@
 
 #include "mpath_cmd.h"
 #include "uxsock.h"
-#include "memory.h"
 #include "defaults.h"
 
 #include "vector.h"
@@ -99,7 +98,7 @@ static void process(int fd, unsigned int timeout)
                        add_history(line);
 
                free(line);
-               FREE(reply);
+               free(reply);
        }
 }
 
@@ -122,7 +121,7 @@ static int process_req(int fd, char * inbuf, unsigned int timeout)
        } else {
                printf("%s", reply);
                ret = (strcmp(reply, "fail\n") == 0);
-               FREE(reply);
+               free(reply);
                return ret;
        }
 }
index dbee0d6fe1ed07d667a986bdd1c511e31add1332..912ac3c5f190e5b468e55bef8e8449c9da039896 100644 (file)
@@ -24,8 +24,8 @@
 #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)
@@ -62,13 +88,11 @@ struct client {
 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;
@@ -99,64 +123,40 @@ static void new_client(int ux_sock)
        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)
@@ -169,16 +169,25 @@ 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;
@@ -283,30 +292,337 @@ static void handle_inotify(int fd, struct watch_descriptors *wds)
                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);
@@ -315,10 +631,9 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
        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++;
@@ -327,7 +642,7 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
                        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;
@@ -339,8 +654,8 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
                        }
                }
                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
@@ -348,30 +663,46 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
                         */
                        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) {
@@ -386,88 +717,43 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
                        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;
 }
index 18f008d783058504e48949153bc5541107a8f2c5..60c3a2c7b5490c6c541c48cafb29c9248c25e9a9 100644 (file)
@@ -3,10 +3,8 @@
 
 #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
index bbe6c2a1f6c4e2d7ebd573fa7c51dd9a2e7d39be..2a2214652617876335992f9610b0cc386a2e66e0 100644 (file)
@@ -13,7 +13,6 @@
 
 #include "util.h"
 #include "vector.h"
-#include "memory.h"
 #include "checkers.h"
 #include "config.h"
 #include "structs.h"
@@ -32,8 +31,7 @@ static struct event_thread *alloc_waiter (void)
 
        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;
 }
@@ -46,7 +44,7 @@ static void free_waiter (void *data)
                dm_task_destroy(wp->dmt);
 
        rcu_unregister_thread();
-       FREE(wp);
+       free(wp);
 }
 
 void stop_waiter_thread (struct multipath *mpp)
index 57ad3381f8d14a554d95a3977fc28cbb93a569f9..f116d12c918ae8b48c54241f83add70c497c9a3b 100644 (file)
@@ -23,6 +23,7 @@
 #include <setjmp.h>
 #include <stdlib.h>
 #include <cmocka.h>
+#include <stdio.h>
 
 #include "globals.c"
 #include "pgpolicies.h"
index 648ff2682cf416f6971624786cc1e084922e94c8..7523fec7b2b44860c39149c710f3e00cf969b285 100644 (file)
@@ -194,7 +194,7 @@ static void test_dm_name_good(void **state)
        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)
@@ -205,7 +205,7 @@ 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)
@@ -216,7 +216,7 @@ 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)
@@ -228,7 +228,7 @@ 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)
index 8e730d37b7272b5a388c8ac2d9eedd7ccb7869f9..a7d2092c833367a81d825215bb3f69c915d1e5e1 100644 (file)
@@ -9,6 +9,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <errno.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <setjmp.h>
@@ -291,7 +292,9 @@ static int create_vpd83(unsigned char *buf, size_t bufsiz, const char *id,
        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;
@@ -500,6 +503,27 @@ static void test_vpd_naa_ ## naa ## _ ## wlen(void **state)             \
                            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)
@@ -532,6 +556,31 @@ static void test_vpd_eui_ ## len ## _ ## wlen ## _ ## sml(void **state)    \
                            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()
@@ -621,6 +670,17 @@ make_test_vpd_eui(8, 17, 0);
 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);
@@ -628,12 +688,38 @@ make_test_vpd_eui(12, 25, 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);
@@ -641,12 +727,33 @@ make_test_vpd_naa(6, 33);
 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);
@@ -741,24 +848,59 @@ static int test_vpd(void)
                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),