@@ -13,6 +13,7 @@ cscope.out
kpartx/kpartx
multipath/multipath
multipathd/multipathd
+multipathd/multipathc
mpathpersist/mpathpersist
abi.tar.gz
abi
@@ -27,12 +27,12 @@ LIBDEPS += -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \
ifeq ($(READLINE),libedit)
-CPPFLAGS += -DUSE_LIBEDIT
-LIBDEPS += -ledit
+RL_CPPFLAGS = -DUSE_LIBEDIT
+RL_LIBDEPS += -ledit
endif
ifeq ($(READLINE),libreadline)
-CPPFLAGS += -DUSE_LIBREADLINE
-LIBDEPS += -lreadline
+RL_CPPFLAGS += -DUSE_LIBREADLINE
+RL_LIBDEPS += -lreadline
endif
ifdef SYSTEMD
@@ -50,6 +50,8 @@ endif
OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o \
dmevents.o init_unwinder.o
+CLI_OBJS = multipathc.o cli.o
+
ifeq ($(FPIN_SUPPORT),1)
OBJS += fpin_handlers.o
endif
@@ -57,18 +59,26 @@ endif
EXEC = multipathd
+CLI = multipathc
-all : $(EXEC)
+all : $(EXEC) $(CLI)
$(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(EXEC) $(LIBDEPS)
+multipathc.o: multipathc.c
+ $(CC) $(CPPFLAGS) $(RL_CPPFLAGS) $(CFLAGS) -Wno-unused-parameter -c -o $@ $<
+
+$(CLI): $(CLI_OBJS)
+ $(CC) $(CFLAGS) $(CLI_OBJS) $(LDFLAGS) -o $@ $(CLI_LIBDEPS) $(RL_LIBDEPS)
+
cli_handlers.o: cli_handlers.c
$(CC) $(CPPFLAGS) $(CFLAGS) -Wno-unused-parameter -c -o $@ $<
install:
$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
+ $(INSTALL_PROGRAM) -m 755 $(CLI) $(DESTDIR)$(bindir)
ifdef SYSTEMD
$(INSTALL_PROGRAM) -d $(DESTDIR)$(unitdir)
$(INSTALL_PROGRAM) -m 644 $(EXEC).service $(DESTDIR)$(unitdir)
@@ -78,13 +88,13 @@ endif
$(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(man8dir)
uninstall:
- $(RM) $(DESTDIR)$(bindir)/$(EXEC)
+ $(RM) $(DESTDIR)$(bindir)/$(EXEC) $(DESTDIR)$(bindir)/$(CLI)
$(RM) $(DESTDIR)$(man8dir)/$(EXEC).8
$(RM) $(DESTDIR)$(unitdir)/$(EXEC).service
$(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket
clean: dep_clean
- $(RM) core *.o $(EXEC)
+ $(RM) core *.o $(EXEC) $(CLI)
include $(wildcard $(OBJS:.o=.d))
@@ -11,12 +11,6 @@
#include "parser.h"
#include "util.h"
#include "version.h"
-#ifdef USE_LIBEDIT
-#include <editline/readline.h>
-#endif
-#ifdef USE_LIBREADLINE
-#include <readline/readline.h>
-#endif
#include "mpath_cmd.h"
#include "cli.h"
@@ -26,6 +20,16 @@
static vector keys;
static vector handlers;
+vector get_keys(void)
+{
+ return keys;
+}
+
+vector get_handlers(void)
+{
+ return handlers;
+}
+
static struct key *
alloc_key (void)
{
@@ -225,8 +229,7 @@ load_keys (void)
return 0;
}
-static struct key *
-find_key (const char * str)
+struct key *find_key (const char * str)
{
int i;
int len, klen;
@@ -323,8 +326,7 @@ out:
return r;
}
-static uint64_t
-fingerprint(const struct _vector *vec)
+uint64_t fingerprint(const struct _vector *vec)
{
int i;
uint64_t fp = 0;
@@ -458,111 +460,3 @@ void cli_exit(void)
free_keys(keys);
keys = NULL;
}
-
-#if defined(USE_LIBREADLINE) || defined(USE_LIBEDIT)
-static int
-key_match_fingerprint (struct key * kw, uint64_t fp)
-{
- if (!fp)
- return 0;
-
- return ((fp & kw->code) == kw->code);
-}
-
-/*
- * This is the readline completion handler
- */
-char *
-key_generator (const char * str, int state)
-{
- static int index, len, has_param;
- static uint64_t rlfp;
- struct key * kw;
- int i;
- struct handler *h;
- vector v = NULL;
-
- if (!state) {
- index = 0;
- has_param = 0;
- rlfp = 0;
- len = strlen(str);
- int r = get_cmdvec(rl_line_buffer, &v);
- /*
- * If a word completion is in progress, we don't want
- * to take an exact keyword match in the fingerprint.
- * For ex "show map[tab]" would validate "map" and discard
- * "maps" as a valid candidate.
- */
- if (v && len)
- vector_del_slot(v, VECTOR_SIZE(v) - 1);
- /*
- * Clean up the mess if we dropped the last slot of a 1-slot
- * vector
- */
- if (v && !VECTOR_SIZE(v)) {
- vector_free(v);
- v = NULL;
- }
- /*
- * If last keyword takes a param, don't even try to guess
- */
- if (r == EINVAL) {
- has_param = 1;
- return (strdup("(value)"));
- }
- /*
- * Compute a command fingerprint to find out possible completions.
- * Once done, the vector is useless. Free it.
- */
- if (v) {
- rlfp = fingerprint(v);
- free_keys(v);
- }
- }
- /*
- * No more completions for parameter placeholder.
- * Brave souls might try to add parameter completion by walking paths and
- * multipaths vectors.
- */
- if (has_param)
- return ((char *)NULL);
- /*
- * Loop through keywords for completion candidates
- */
- vector_foreach_slot_after (keys, kw, index) {
- if (!strncmp(kw->str, str, len)) {
- /*
- * Discard keywords already in the command line
- */
- if (key_match_fingerprint(kw, rlfp)) {
- struct key * curkw = find_key(str);
- if (!curkw || (curkw != kw))
- continue;
- }
- /*
- * Discard keywords making syntax errors.
- *
- * nfp is the candidate fingerprint we try to
- * validate against all known command fingerprints.
- */
- uint64_t nfp = rlfp | kw->code;
- vector_foreach_slot(handlers, h, i) {
- if (!rlfp || ((h->fingerprint & nfp) == nfp)) {
- /*
- * At least one full command is
- * possible with this keyword :
- * Consider it validated
- */
- index++;
- return (strdup(kw->str));
- }
- }
- }
- }
- /*
- * No more candidates
- */
- return ((char *)NULL);
-}
-#endif
@@ -151,6 +151,9 @@ void free_keys (vector vec);
void free_handlers (void);
int cli_init (void);
void cli_exit(void);
-char * key_generator (const char * str, int state);
+uint64_t fingerprint(const struct _vector *vec);
+vector get_keys(void);
+vector get_handlers(void);
+struct key *find_key (const char * str);
#endif /* _CLI_H_ */
new file mode 100644
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2022 SUSE LLC
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "mpath_cmd.h"
+#include "uxclnt.h"
+#include "vector.h"
+#include "uxsock.h"
+#include "util.h"
+#include "cli.h"
+
+#ifdef USE_LIBEDIT
+#include <editline/readline.h>
+#endif
+#ifdef USE_LIBREADLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+/*
+ * Versions of libedit prior to 2016 were using a wrong
+ * prototype for rl_completion_entry_function in readline.h.
+ * Internally, libedit casts this to the correct type
+ * (char *)(*)(const char *, int).
+ * So we simply cast to the wrong prototype here.
+ * See http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libedit/readline/readline.h.diff?r1=1.34&r2=1.35
+ * Unfortunately, this change isn't reflected in the libedit version.
+ */
+#ifdef BROKEN_RL_COMPLETION_FUNC
+#define RL_COMP_ENTRY_CAST(x) ((int (*)(const char *, int)) (x))
+#else
+#define RL_COMP_ENTRY_CAST(x) (x)
+#endif
+
+#if defined(USE_LIBREADLINE) || defined(USE_LIBEDIT)
+static int
+key_match_fingerprint (struct key * kw, uint64_t fp)
+{
+ if (!fp)
+ return 0;
+
+ return ((fp & kw->code) == kw->code);
+}
+
+/*
+ * This is the readline completion handler
+ */
+char *
+key_generator (const char * str, int state)
+{
+ static int index, len, has_param;
+ static uint64_t rlfp;
+ struct key * kw;
+ int i;
+ struct handler *h;
+ vector v = NULL;
+ const vector keys = get_keys();
+ const vector handlers = get_handlers();
+
+ if (!state) {
+ index = 0;
+ has_param = 0;
+ rlfp = 0;
+ len = strlen(str);
+ int r = get_cmdvec(rl_line_buffer, &v);
+ /*
+ * If a word completion is in progress, we don't want
+ * to take an exact keyword match in the fingerprint.
+ * For ex "show map[tab]" would validate "map" and discard
+ * "maps" as a valid candidate.
+ */
+ if (v && len)
+ vector_del_slot(v, VECTOR_SIZE(v) - 1);
+ /*
+ * Clean up the mess if we dropped the last slot of a 1-slot
+ * vector
+ */
+ if (v && !VECTOR_SIZE(v)) {
+ vector_free(v);
+ v = NULL;
+ }
+ /*
+ * If last keyword takes a param, don't even try to guess
+ */
+ if (r == EINVAL) {
+ has_param = 1;
+ return (strdup("(value)"));
+ }
+ /*
+ * Compute a command fingerprint to find out possible completions.
+ * Once done, the vector is useless. Free it.
+ */
+ if (v) {
+ rlfp = fingerprint(v);
+ free_keys(v);
+ }
+ }
+ /*
+ * No more completions for parameter placeholder.
+ * Brave souls might try to add parameter completion by walking paths and
+ * multipaths vectors.
+ */
+ if (has_param)
+ return ((char *)NULL);
+ /*
+ * Loop through keywords for completion candidates
+ */
+ vector_foreach_slot_after (keys, kw, index) {
+ if (!strncmp(kw->str, str, len)) {
+ /*
+ * Discard keywords already in the command line
+ */
+ if (key_match_fingerprint(kw, rlfp)) {
+ struct key * curkw = find_key(str);
+ if (!curkw || (curkw != kw))
+ continue;
+ }
+ /*
+ * Discard keywords making syntax errors.
+ *
+ * nfp is the candidate fingerprint we try to
+ * validate against all known command fingerprints.
+ */
+ uint64_t nfp = rlfp | kw->code;
+ vector_foreach_slot(handlers, h, i) {
+ if (!rlfp || ((h->fingerprint & nfp) == nfp)) {
+ /*
+ * At least one full command is
+ * possible with this keyword :
+ * Consider it validated
+ */
+ index++;
+ return (strdup(kw->str));
+ }
+ }
+ }
+ }
+ /*
+ * No more candidates
+ */
+ return ((char *)NULL);
+}
+#endif
+
+static void print_reply(char *s)
+{
+ if (!s)
+ return;
+
+ if (isatty(1)) {
+ printf("%s", s);
+ return;
+ }
+ /* strip ANSI color markers */
+ while (*s != '\0') {
+ if ((*s == 0x1b) && (*(s+1) == '['))
+ while ((*s++ != 'm') && (*s != '\0')) {};
+ putchar(*s++);
+ }
+}
+
+static int need_quit(char *str, size_t len)
+{
+ char *ptr, *start;
+ size_t trimed_len = len;
+
+ for (ptr = str; trimed_len && isspace(*ptr);
+ trimed_len--, ptr++)
+ ;
+
+ start = ptr;
+
+ for (ptr = str + len - 1; trimed_len && isspace(*ptr);
+ trimed_len--, ptr--)
+ ;
+
+ if ((trimed_len == 4 && !strncmp(start, "exit", 4)) ||
+ (trimed_len == 4 && !strncmp(start, "quit", 4)))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * process the client
+ */
+static void process(int fd, unsigned int timeout)
+{
+
+#if defined(USE_LIBREADLINE) || defined(USE_LIBEDIT)
+ rl_readline_name = "multipathd";
+ rl_completion_entry_function = RL_COMP_ENTRY_CAST(key_generator);
+#endif
+
+ cli_init();
+ for(;;)
+ {
+ char *line __attribute__((cleanup(cleanup_charp))) = NULL;
+ char *reply __attribute__((cleanup(cleanup_charp))) = NULL;
+ ssize_t llen;
+ int ret;
+
+#if defined(USE_LIBREADLINE) || defined(USE_LIBEDIT)
+ line = readline("multipathd> ");
+ if (!line)
+ break;
+ llen = strlen(line);
+ if (!llen)
+ continue;
+#else
+ size_t lsize = 0;
+
+ fputs("multipathd> ", stdout);
+ errno = 0;
+ llen = getline(&line, &lsize, stdin);
+ if (llen == -1) {
+ if (errno != 0)
+ fprintf(stderr, "Error in getline: %m");
+ break;
+ }
+ if (!llen || !strcmp(line, "\n"))
+ continue;
+#endif
+
+ if (need_quit(line, llen))
+ break;
+
+ if (send_packet(fd, line) != 0)
+ break;
+ ret = recv_packet(fd, &reply, timeout);
+ if (ret != 0)
+ break;
+
+ print_reply(reply);
+ }
+}
+
+int main (void)
+{
+ int fd = mpath_connect();
+
+ if (fd == -1)
+ return 1;
+
+ process(fd, DEFAULT_REPLY_TIMEOUT + 100);
+ mpath_disconnect(fd);
+ return 0;
+}
@@ -5,128 +5,14 @@
* Copyright (c) 2005 Benjamin Marzinski, Redhat
*/
#include <stdio.h>
+#include <string.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <fcntl.h>
#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <poll.h>
-
-#ifdef USE_LIBEDIT
-#include <editline/readline.h>
-#endif
-#ifdef USE_LIBREADLINE
-#include <readline/readline.h>
-#include <readline/history.h>
-#endif
#include "mpath_cmd.h"
#include "uxsock.h"
-#include "defaults.h"
-
-#include "vector.h"
-#include "util.h"
-#include "cli.h"
#include "uxclnt.h"
-static void print_reply(char *s)
-{
- if (!s)
- return;
-
- if (isatty(1)) {
- printf("%s", s);
- return;
- }
- /* strip ANSI color markers */
- while (*s != '\0') {
- if ((*s == 0x1b) && (*(s+1) == '['))
- while ((*s++ != 'm') && (*s != '\0')) {};
- putchar(*s++);
- }
-}
-
-static int need_quit(char *str, size_t len)
-{
- char *ptr, *start;
- size_t trimed_len = len;
-
- for (ptr = str; trimed_len && isspace(*ptr);
- trimed_len--, ptr++)
- ;
-
- start = ptr;
-
- for (ptr = str + len - 1; trimed_len && isspace(*ptr);
- trimed_len--, ptr--)
- ;
-
- if ((trimed_len == 4 && !strncmp(start, "exit", 4)) ||
- (trimed_len == 4 && !strncmp(start, "quit", 4)))
- return 1;
-
- return 0;
-}
-
-/*
- * process the client
- */
-static void process(int fd, unsigned int timeout)
-{
-
-#if defined(USE_LIBREADLINE) || defined(USE_LIBEDIT)
- rl_readline_name = "multipathd";
- rl_completion_entry_function = key_generator;
-#endif
-
- cli_init();
- for(;;)
- {
- char *line __attribute__((cleanup(cleanup_charp))) = NULL;
- char *reply __attribute__((cleanup(cleanup_charp))) = NULL;
- ssize_t llen;
- int ret;
-
-#if defined(USE_LIBREADLINE) || defined(USE_LIBEDIT)
- line = readline("multipathd> ");
- if (!line)
- break;
- llen = strlen(line);
- if (!llen)
- continue;
-#else
- size_t lsize = 0;
-
- fputs("multipathd> ", stdout);
- errno = 0;
- llen = getline(&line, &lsize, stdin);
- if (llen == -1) {
- if (errno != 0)
- fprintf(stderr, "Error in getline: %m");
- break;
- }
- if (!llen || !strcmp(line, "\n"))
- continue;
-#endif
-
- if (need_quit(line, llen))
- break;
-
- if (send_packet(fd, line) != 0)
- break;
- ret = recv_packet(fd, &reply, timeout);
- if (ret != 0)
- break;
-
- print_reply(reply);
- }
-}
-
static int process_req(int fd, char * inbuf, unsigned int timeout)
{
char *reply;
@@ -159,13 +45,11 @@ int uxclnt(char * inbuf, unsigned int timeout)
int fd, ret = 0;
fd = mpath_connect();
- if (fd == -1)
- exit(1);
+ if (fd == -1 || !inbuf)
+ return 1;
+
+ ret = process_req(fd, inbuf, timeout);
- if (inbuf)
- ret = process_req(fd, inbuf, timeout);
- else
- process(fd, timeout);
mpath_disconnect(fd);
return ret;
}