From 8212a2704781b7d66c055d438c5c6ecb7802356e Mon Sep 17 00:00:00 2001 From: root Date: Mon, 20 Jun 2005 09:44:49 +0200 Subject: [PATCH] [multipathd] unix socket daemon control interface The client is wrapped in the daemon. You can call it through : - multipathd -k"$cmd" : one shot - multipathd -k : interactive The synthax is somewhat rude :/ - lp : list paths - lm : list maps - ap $path : add path checker, $path is in the "sdb" form - rp $path : remove path checker - am $map : add map event thread, $map is in the "dm-0" form - rm $map : remove map event thread --- libmultipath/Makefile | 2 +- libmultipath/dmparser.c | 39 ------------- libmultipath/util.c | 42 ++++++++++++++ libmultipath/util.h | 2 + multipathd/Makefile | 5 +- multipathd/main.c | 129 ++++++++++++++++++++++++++++++++++++++++- multipathd/uxclnt.c | 69 ++++++++++++++++++++++ multipathd/uxclnt.h | 1 + multipathd/uxlsnr.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++ multipathd/uxlsnr.h | 4 ++ 10 files changed, 396 insertions(+), 45 deletions(-) create mode 100644 multipathd/uxclnt.c create mode 100644 multipathd/uxclnt.h create mode 100644 multipathd/uxlsnr.c create mode 100644 multipathd/uxlsnr.h diff --git a/libmultipath/Makefile b/libmultipath/Makefile index 1dc3c51..1aa587a 100644 --- a/libmultipath/Makefile +++ b/libmultipath/Makefile @@ -10,7 +10,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \ hwtable.o blacklist.o util.o dmparser.o config.o \ structs.o cache.o discovery.o propsel.o dict.o \ pgpolicies.o debug.o regex.o defaults.o uevent.o \ - switchgroup.o + switchgroup.o uxsock.o CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c index a801a0a..0d53fb1 100644 --- a/libmultipath/dmparser.c +++ b/libmultipath/dmparser.c @@ -16,45 +16,6 @@ #define WORD_SIZE 64 static int -get_word (char * sentence, char ** word) -{ - char * p; - int len; - int skip = 0; - - while (*sentence == ' ') { - sentence++; - skip++; - } - if (*sentence == '\0') - return 0; - - p = sentence; - - while (*p != ' ' && *p != '\0') - p++; - - len = (int) (p - sentence); - - if (!word) - return skip + len; - - *word = MALLOC(len + 1); - - if (!*word) { - condlog(0, "get_word : oom\n"); - return 0; - } - strncpy(*word, sentence, len); - condlog(4, "*word = %s, len = %i", *word, len); - - if (*p == '\0') - return 0; - - return skip + len; -} - -static int merge_words (char ** dst, char * word, int space) { char * p; diff --git a/libmultipath/util.c b/libmultipath/util.c index 8a3f790..53d8c3e 100644 --- a/libmultipath/util.c +++ b/libmultipath/util.c @@ -4,6 +4,9 @@ #include #include +#include "debug.h" +#include "memory.h" + #define PARAMS_SIZE 255 int @@ -49,3 +52,42 @@ filepresent (char * run) { return 0; } +int +get_word (char * sentence, char ** word) +{ + char * p; + int len; + int skip = 0; + + while (*sentence == ' ') { + sentence++; + skip++; + } + if (*sentence == '\0') + return 0; + + p = sentence; + + while (*p != ' ' && *p != '\0') + p++; + + len = (int) (p - sentence); + + if (!word) + return skip + len; + + *word = MALLOC(len + 1); + + if (!*word) { + condlog(0, "get_word : oom\n"); + return 0; + } + strncpy(*word, sentence, len); + condlog(4, "*word = %s, len = %i", *word, len); + + if (*p == '\0') + return 0; + + return skip + len; +} + diff --git a/libmultipath/util.h b/libmultipath/util.h index f7f6fc3..51f052a 100644 --- a/libmultipath/util.h +++ b/libmultipath/util.h @@ -4,6 +4,8 @@ int strcmp_chomp(char *, char *); void basename (char * src, char * dst); int filepresent (char * run); +int get_word (char * sentence, char ** word); + #define safe_sprintf(var, format, args...) \ snprintf(var, sizeof(var), format, ##args) >= sizeof(var) diff --git a/multipathd/Makefile b/multipathd/Makefile index 2226d10..5af3f83 100644 --- a/multipathd/Makefile +++ b/multipathd/Makefile @@ -26,9 +26,8 @@ LDFLAGS = -lpthread -ldevmapper -lsysfs # # object files # -OBJS = main.o copy.o log.o log_pthread.o pidfile.o \ - $(MULTIPATHLIB)-glibc.a \ - $(CHECKERSLIB)-glibc.a \ +OBJS = main.o copy.o log.o log_pthread.o pidfile.o uxlsnr.o uxclnt.o \ + $(MULTIPATHLIB)-glibc.a $(CHECKERSLIB)-glibc.a \ # diff --git a/multipathd/main.c b/multipathd/main.c index 5e76ff2..0288f90 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -53,9 +53,12 @@ #include "copy.h" #include "clone_platform.h" #include "pidfile.h" +#include "uxlsnr.h" +#include "uxclnt.h" #define FILE_NAME_SIZE 256 #define CMDSIZE 160 +#define MAX_REPLY_LEN 1000 #define CALLOUT_DIR "/var/cache/multipathd" @@ -561,6 +564,115 @@ uev_remove_path (char * devname, struct paths * allpaths) return 0; } +static char * +show_paths (struct paths * allpaths) +{ + int i, j, k; + struct path * pp; + char * c; + char * reply; + + reply = MALLOC(MAX_REPLY_LEN); + + if (!reply) + return NULL; + + c = reply; + c += sprintf(c, "\n"); + + vector_foreach_slot(allpaths->pathvec, pp, i) { + c += sprintf(c, "%10s: ", pp->dev); + c += sprintf(c, "state %i, ", pp->state); + + j = pp->tick; + k = pp->checkint - pp->tick; + c += sprintf(c, "%3i/%3i ", j, pp->checkint); + + while (j-- > 0) + c += sprintf(c, "X"); + + + while (k-- > 0) + c += sprintf(c, "."); + + c += sprintf(c, "\n"); + } + + return reply; +} + +static char * +show_maps (struct paths * allpaths) +{ + int i, j, k; + struct multipath * mpp; + char * c; + char * reply; + + reply = MALLOC(MAX_REPLY_LEN); + + if (!reply) + return NULL; + + c = reply; + c += sprintf(c, "\n"); + + vector_foreach_slot(allpaths->mpvec, mpp, i) { + c += sprintf(c, "%20s: ", mpp->alias); + + j = mpp->failback_tick; + k = mpp->pgfailback - mpp->failback_tick; + c += sprintf(c, "%3i/%3i ", j, mpp->pgfailback); + + while (j-- > 0) + c += sprintf(c, "X"); + + + while (k-- > 0) + c += sprintf(c, "."); + + c += sprintf(c, "\n"); + } + + return reply; +} + +char * +uxsock_trigger (char * str, void * trigger_data) +{ + struct paths * allpaths; + char * reply = NULL; + + allpaths = (struct paths *)trigger_data; + + lock(allpaths->lock); + + if (*str == 'l' && *(str + 1) == 'p') + reply = show_paths(allpaths); + + else if (*str == 'l' && *(str + 1) == 'm') + reply = show_maps(allpaths); + + else if (*str == 'r' && *(str + 1) == 'p') + uev_remove_path(str + 3, allpaths); + + else if (*str == 'a' && *(str + 1) == 'p') + uev_add_path(str + 3, allpaths); + + else if (*str == 'r' && *(str + 1) == 'm') + uev_remove_map(str + 3, allpaths); + + else if (*str == 'a' && *(str + 1) == 'm') + uev_add_map(str + 3, allpaths); + + if (!reply) + asprintf(&reply, "ok\n"); + + unlock(allpaths->lock); + + return reply; +} + int uev_trigger (struct uevent * uev, void * trigger_data) { @@ -622,6 +734,14 @@ ueventloop (void * ap) return NULL; } +static void * +uxlsnrloop (void * ap) +{ + uxsock_listen(&uxsock_trigger, ap); + + return NULL; +} + static void strvec_free (vector vec) { @@ -1045,7 +1165,7 @@ set_oom_adj (int val) static int child (void * param) { - pthread_t check_thr, uevent_thr; + pthread_t check_thr, uevent_thr, uxlsnr_thr; pthread_attr_t attr; struct paths * allpaths; @@ -1120,8 +1240,10 @@ child (void * param) pthread_create(&check_thr, &attr, checkerloop, allpaths); pthread_create(&uevent_thr, &attr, ueventloop, allpaths); + pthread_create(&uxlsnr_thr, &attr, uxlsnrloop, allpaths); pthread_join(check_thr, NULL); pthread_join(uevent_thr, NULL); + pthread_join(uxlsnr_thr, NULL); return 0; } @@ -1156,7 +1278,7 @@ main (int argc, char *argv[]) if (!conf) exit(1); - while ((arg = getopt(argc, argv, ":dv:")) != EOF ) { + while ((arg = getopt(argc, argv, ":dv:k::")) != EOF ) { switch(arg) { case 'd': logsink = 0; @@ -1168,6 +1290,9 @@ main (int argc, char *argv[]) conf->verbosity = atoi(optarg); break; + case 'k': + uxclnt(optarg); + exit(0); default: ; } diff --git a/multipathd/uxclnt.c b/multipathd/uxclnt.c new file mode 100644 index 0000000..fc019dc --- /dev/null +++ b/multipathd/uxclnt.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * process the client + */ +static void process(int fd) +{ + char line[1000]; + char *reply; + + while (fgets(line, sizeof(line), stdin)) { + size_t len = strlen(line); + + if (line[len-1] == '\n') { + line[len-1] = 0; + len--; + } + + if (send_packet(fd, line, strlen(line)) != 0) break; + if (recv_packet(fd, &reply, &len) != 0) break; + + printf("%*.*s\n", (int)len, (int)len, reply); + free(reply); + } +} + +static void process_req(int fd, char * inbuf) +{ + char *reply; + size_t len; + + send_packet(fd, inbuf, strlen(inbuf)); + recv_packet(fd, &reply, &len); + + printf("%*.*s\n", (int)len, (int)len, reply); + free(reply); +} + +/* + * entry point + */ +int uxclnt(char * inbuf) +{ + int fd; + + fd = ux_socket_connect(SOCKET_NAME); + if (fd == -1) { + perror("ux_socket_connect"); + exit(1); + } + + if (inbuf) + process_req(fd, inbuf); + else + process(fd); + + return 0; +} diff --git a/multipathd/uxclnt.h b/multipathd/uxclnt.h new file mode 100644 index 0000000..0667a24 --- /dev/null +++ b/multipathd/uxclnt.h @@ -0,0 +1 @@ +int uxclnt(char * inbuf); diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c new file mode 100644 index 0000000..faaa2e9 --- /dev/null +++ b/multipathd/uxlsnr.c @@ -0,0 +1,148 @@ +/* + * A simple domain socket listener + * Original author : tridge@samba.org, January 2002 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define SLEEP_TIME 5000 + +struct client { + int fd; + struct client *next, *prev; +}; + +static struct client *clients; +static unsigned num_clients; + +/* + * handle a new client joining + */ +static void new_client(int ux_sock) +{ + struct client *c; + struct sockaddr addr; + socklen_t len = sizeof(addr); + int fd; + + fd = accept(ux_sock, &addr, &len); + + if (fd == -1) + return; + + /* put it in our linked list */ + c = (struct client *)MALLOC(sizeof(*c)); + memset(c, 0, sizeof(*c)); + c->fd = fd; + c->next = clients; + clients = c; + num_clients++; +} + +/* + * kill off a dead client + */ +static void dead_client(struct client *c) +{ + close(c->fd); + if (c->prev) c->prev->next = c->next; + if (c->next) c->next->prev = c->prev; + if (c == clients) clients = c->next; + FREE(c); + num_clients--; +} + +/* + * entry point + */ +void * uxsock_listen(char * (*uxsock_trigger)(char *, void * trigger_data), + void * trigger_data) +{ + int ux_sock; + size_t len; + char *inbuf; + struct pollfd *polls = NULL; + char *reply; + + ux_sock = ux_socket_listen(SOCKET_NAME); + + if (ux_sock == -1) { + condlog(0, "ux_socket_listen error"); + exit(1); + } + + while (1) { + struct client *c; + int i, poll_count; + + /* setup for a poll */ + polls = REALLOC(polls, (1+num_clients) * sizeof(*polls)); + polls[0].fd = ux_sock; + polls[0].events = POLLIN; + + /* setup the clients */ + for (i=1, c = clients; c; i++, c = c->next) { + polls[i].fd = c->fd; + polls[i].events = POLLIN; + } + + /* most of our life is spent in this call */ + poll_count = poll(polls, i, SLEEP_TIME); + + if (poll_count == -1) { + /* something went badly wrong! */ + condlog(0, "poll"); + exit(1); + } + + if (poll_count == 0) + continue; + + /* see if a client wants to speak to us */ + for (i=1, c = clients; c; i++) { + struct client *next = c->next; + + if (polls[i].revents & POLLIN) { + if (recv_packet(c->fd, &inbuf, &len) != 0) { + dead_client(c); + } else { + condlog(4, "Got request [%*.*s]", + (int)len, (int)len, inbuf); + reply = uxsock_trigger(inbuf, + trigger_data); + + if (reply) { + if (send_packet(c->fd, reply, + strlen(reply)) != 0) { + dead_client(c); + } + FREE(reply); + } + FREE(inbuf); + } + } + c = next; + } + + /* see if we got a new client */ + if (polls[0].revents & POLLIN) { + new_client(ux_sock); + } + } + + return NULL; +} diff --git a/multipathd/uxlsnr.h b/multipathd/uxlsnr.h new file mode 100644 index 0000000..2afade1 --- /dev/null +++ b/multipathd/uxlsnr.h @@ -0,0 +1,4 @@ +void * uxsock_listen(char * (*uxsock_trigger) + (char *, void * trigger_data), + void * trigger_data); + -- 2.7.4