#
# object files
#
-OBJS = main.o copy.o log.o log_pthread.o pidfile.o uxlsnr.o uxclnt.o \
+OBJS = main.o copy.o log.o log_pthread.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o \
$(MULTIPATHLIB)-glibc.a $(CHECKERSLIB)-glibc.a \
--- /dev/null
+#include <memory.h>
+#include <vector.h>
+#include <util.h>
+
+#include "cli.h"
+
+static struct key *
+alloc_key (void)
+{
+ return MALLOC(sizeof(struct key));
+}
+
+static struct handler *
+alloc_handler (void)
+{
+ return MALLOC(sizeof(struct handler));
+}
+
+static int
+add_key (vector vec, char * str, int code, int has_param)
+{
+ struct key * kw;
+
+ kw = alloc_key();
+
+ if (!kw)
+ return 1;
+
+ kw->code = code;
+ kw->has_param = has_param;
+ kw->str = strdup(str);
+
+ if (!kw->str)
+ goto out;
+
+ if (!vector_alloc_slot(vec))
+ goto out1;
+
+ vector_set_slot(vec, kw);
+
+ return 0;
+
+out1:
+ FREE(kw->str);
+out:
+ FREE(kw);
+ return 1;
+}
+
+int
+add_handler (int fp, char * (*fn)(void *, void *))
+{
+ struct handler * h;
+
+ h = alloc_handler();
+
+ if (!h)
+ return 1;
+
+ if (!vector_alloc_slot(handlers)) {
+ FREE(h);
+ return 1;
+ }
+
+ vector_set_slot(handlers, h);
+ h->fingerprint = fp;
+ h->fn = fn;
+
+ return 0;
+}
+
+static void
+free_key (struct key * kw)
+{
+ FREE(kw->str);
+
+ if (kw->param)
+ FREE(kw->param);
+
+ FREE(kw);
+}
+
+static void
+free_keys (vector vec)
+{
+ int i;
+ struct key * kw;
+
+ vector_foreach_slot(vec, kw, i)
+ free_key(kw);
+
+ FREE(vec);
+}
+
+int
+load_keys (void)
+{
+ int r = 0;
+ keys = vector_alloc();
+
+ if (!keys)
+ return 1;
+
+ r += add_key(keys, "list", LIST, 0);
+ r += add_key(keys, "show", LIST, 0);
+ r += add_key(keys, "add", ADD, 0);
+ r += add_key(keys, "remove", DEL, 0);
+ r += add_key(keys, "del", DEL, 0);
+ r += add_key(keys, "switch", SWITCH, 0);
+ r += add_key(keys, "switchgroup", SWITCH, 0);
+ r += add_key(keys, "paths", PATHS, 0);
+ r += add_key(keys, "maps", MAPS, 0);
+ r += add_key(keys, "path", PATH, 1);
+ r += add_key(keys, "map", MAP, 1);
+ r += add_key(keys, "group", GROUP, 1);
+
+ if (r) {
+ free_keys(keys);
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct key *
+find_key (char * str)
+{
+ int i;
+ struct key * kw = NULL;
+
+ vector_foreach_slot (keys, kw, i)
+ if (!strncmp(kw->str, str, strlen(kw->str)))
+ return kw;
+
+ return NULL;
+}
+
+static struct handler *
+find_handler (int fp)
+{
+ int i;
+ struct handler *h;
+
+ vector_foreach_slot (handlers, h, i)
+ if (h->fingerprint == fp)
+ return h;
+
+ return NULL;
+}
+
+static vector
+get_cmdvec (char * cmd)
+{
+ int fwd = 1;
+ char * p = cmd;
+ char * buff;
+ struct key * kw = NULL;
+ struct key * cmdkw = NULL;
+ vector cmdvec;
+
+ cmdvec = vector_alloc();
+
+ if (!cmdvec)
+ return NULL;
+
+ while (fwd) {
+ fwd = get_word(p, &buff);
+
+ if (!buff)
+ break;
+
+ p += fwd;
+ kw = find_key(buff);
+ FREE(buff);
+
+ if (!kw)
+ goto out; /* synthax error */
+
+ cmdkw = alloc_key();
+
+ if (!cmdkw)
+ goto out;
+
+ if (!vector_alloc_slot(cmdvec)) {
+ FREE(cmdkw);
+ goto out;
+ }
+
+ vector_set_slot(cmdvec, cmdkw);
+ cmdkw->code = kw->code;
+ cmdkw->has_param = kw->has_param;
+
+ if (kw->has_param) {
+ if (*p == '\0')
+ goto out;
+
+ fwd = get_word(p, &buff);
+
+ if (!buff)
+ goto out;
+
+ p += fwd;
+ cmdkw->param = buff;
+ }
+ }
+
+ return cmdvec;
+
+out:
+ free_keys(cmdvec);
+ return NULL;
+}
+
+static int
+fingerprint(vector vec)
+{
+ int i;
+ int fp = 0;
+ struct key * kw;
+
+ vector_foreach_slot(vec, kw, i)
+ fp += kw->code;
+
+ return fp;
+}
+
+int
+alloc_handlers (void)
+{
+ handlers = vector_alloc();
+
+ if (!handlers)
+ return 1;
+
+ return 0;
+}
+
+static int
+genhelp_sprint_aliases (char * reply, vector keys, struct key * refkw)
+{
+ int i, fwd = 0;
+ struct key * kw;
+
+ vector_foreach_slot (keys, kw, i)
+ if (kw->code == refkw->code && kw != refkw)
+ fwd += sprintf(reply, "|%s", kw->str);
+
+ return fwd;
+}
+
+static char *
+genhelp_handler (void)
+{
+ int i, j;
+ int fp;
+ struct handler * h;
+ struct key * kw;
+ char * reply;
+ char * p;
+
+ reply = MALLOC(MAX_REPLY_LEN);
+
+ if (!reply)
+ return NULL;
+
+ p = reply;
+
+ vector_foreach_slot (handlers, h, i) {
+ fp = h->fingerprint;
+ vector_foreach_slot (keys, kw, j) {
+ if ((kw->code & fp)) {
+ fp -= kw->code;
+ p += sprintf(p, " %s", kw->str);
+ p += genhelp_sprint_aliases(p, keys, kw);
+
+ if (kw->has_param)
+ p += sprintf(p, " $%s", kw->str);
+ }
+ }
+ p += sprintf(p, "\n");
+ }
+
+ return reply;
+}
+
+char *
+parse_cmd (char * cmd, void * data)
+{
+ char * reply;
+ struct handler * h;
+ vector cmdvec = get_cmdvec(cmd);
+
+ if (!cmdvec)
+ return genhelp_handler();
+
+ h = find_handler(fingerprint(cmdvec));
+
+ if (!h)
+ return genhelp_handler();
+
+ /*
+ * execute handler
+ */
+ reply = h->fn(cmdvec, data);
+ free_keys(cmdvec);
+
+ return reply;
+}
+
+char *
+get_keyparam (vector v, int code)
+{
+ struct key * kw;
+ int i;
+
+ vector_foreach_slot(v, kw, i)
+ if (kw->code == code)
+ return kw->param;
+
+ return NULL;
+}
--- /dev/null
+#define LIST 1
+#define ADD (1 << 1)
+#define DEL (1 << 2)
+#define SWITCH (1 << 3)
+#define PATHS (1 << 4)
+#define MAPS (1 << 5)
+#define PATH (1 << 6)
+#define MAP (1 << 7)
+#define GROUP (1 << 8)
+
+#define MAX_REPLY_LEN 1000
+
+struct key {
+ char * str;
+ char * param;
+ int code;
+ int has_param;
+};
+
+struct handler {
+ int fingerprint;
+ char * (*fn)(void *, void *);
+};
+
+vector keys;
+vector handlers;
+
+int alloc_handlers (void);
+int add_handler (int fp, char * (*fn)(void *, void *));
+char * parse_cmd (char * cmd, void *);
+int load_keys (void);
+char * get_keyparam (vector v, int code);
--- /dev/null
+#include <memory.h>
+#include <vector.h>
+#include <structs.h>
+#include <devmapper.h>
+
+#include "main.h"
+#include "cli.h"
+
+char *
+list_paths (void * v, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+
+ return show_paths(allpaths);
+}
+
+char *
+list_maps (void * v, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+
+ return show_maps(allpaths);
+}
+
+char *
+add_path (void * v, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+ char * param = get_keyparam(v, PATH);
+
+ if (uev_add_path(param, allpaths))
+ return NULL;
+
+ return strdup("ok");
+}
+
+char *
+del_path (void * v, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+ char * param = get_keyparam(v, PATH);
+
+ if (uev_remove_path(param, allpaths))
+ return NULL;
+
+ return strdup("ok");
+}
+
+char *
+add_map (void * v, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+ char * param = get_keyparam(v, MAP);
+
+ if (uev_add_map(param, allpaths))
+ return NULL;
+
+ return strdup("ok");
+}
+
+char *
+del_map (void * v, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+ char * param = get_keyparam(v, MAP);
+
+ if (uev_remove_map(param, allpaths))
+ return NULL;
+
+ return strdup("ok");
+}
+
+char *
+switch_group(void * v, void * data)
+{
+ char * mapname = get_keyparam(v, MAP);
+ int groupnum = atoi(get_keyparam(v, GROUP));
+
+ dm_switchgroup(mapname, groupnum);
+
+ return strdup("ok");
+}
--- /dev/null
+char * list_paths (void * v, void * data);
+char * list_maps (void * v, void * data);
+char * add_path (void * v, void * data);
+char * del_path (void * v, void * data);
+char * add_map (void * v, void * data);
+char * del_map (void * v, void * data);
+char * switch_group (void * v, void * data);
#include "pidfile.h"
#include "uxlsnr.h"
#include "uxclnt.h"
+#include "cli.h"
+#include "cli_handlers.h"
#define FILE_NAME_SIZE 256
#define CMDSIZE 160
-#define MAX_REPLY_LEN 1000
#define CALLOUT_DIR "/var/cache/multipathd"
/*
* structs
*/
-struct paths {
- pthread_mutex_t *lock;
- vector pathvec;
- vector mpvec;
-};
-
struct event_thread {
struct dm_task *dmt;
pthread_t thread;
return 1;
}
-static int
-switch_to_pathgroup (char * str)
-{
- char * mapname;
- char * buff = NULL;
- char * p = NULL;
- int r = 0;
- int pg;
-
- p = str;
- p += get_word(p, &mapname);
-
- if (!mapname)
- return 1;
-
- p += get_word(p, &buff);
-
- if (!buff)
- goto out;
-
- if (sscanf(buff, "%d", &pg) != 1)
- goto out1;
-
- r = !dm_switchgroup(mapname, pg);
-out1:
- FREE(buff);
-out:
- FREE(mapname);
- return r;
-}
-
static void
switch_pathgroup (struct multipath * mpp)
{
pthread_testcancel();
dm_task_run(waiter->dmt);
pthread_testcancel();
+ dm_task_destroy(waiter->dmt);
waiter->event_nr++;
/*
* stop the DM event waiter thread
*/
- if (stop_waiter_thread(mpp, allpaths))
+ if (stop_waiter_thread(mpp, allpaths)) {
condlog(0, "%s: error canceling waiter thread", mpp->alias);
+ /*
+ * warrior mode
+ */
+ free_waiter(mpp->waiter);
+ }
/*
* clear references to this map
mpp = NULL;
}
-static int
+int
uev_add_map (char * devname, struct paths * allpaths)
{
int major, minor;
return 1;
}
-static int
+int
uev_remove_map (char * devname, struct paths * allpaths)
{
int minor;
return 0;
}
-static int
+int
uev_add_path (char * devname, struct paths * allpaths)
{
struct path * pp;
return 0;
}
-static int
+int
uev_remove_path (char * devname, struct paths * allpaths)
{
int i;
return 0;
}
-static char *
+char *
show_paths (struct paths * allpaths)
{
int i, j, k;
return reply;
}
-static char *
+char *
show_maps (struct paths * allpaths)
{
int i, j, k;
char *
uxsock_trigger (char * str, void * trigger_data)
{
- int r;
struct paths * allpaths;
char * reply = NULL;
lock(allpaths->lock);
- if (strlen(str) < 2)
- r = 1;
- else if (*str == 'l' && *(str + 1) == 'p')
- reply = show_paths(allpaths);
-
- else if (*str == 'l' && *(str + 1) == 'm')
- reply = show_maps(allpaths);
-
- else if (strlen(str) < 4)
- r = 1;
+ reply = parse_cmd(str, allpaths);
- else if (*str == 'r' && *(str + 1) == 'p')
- r = uev_remove_path(str + 3, allpaths);
-
- else if (*str == 'a' && *(str + 1) == 'p')
- r = uev_add_path(str + 3, allpaths);
-
- else if (*str == 'r' && *(str + 1) == 'm') {
- if (!strncmp(str +3, "dm-", 3)) {
- r = uev_remove_map(str + 3, allpaths);
- }
- }
-
- else if (*str == 'a' && *(str + 1) == 'm') {
- if (!strncmp(str +3, "dm-", 3)) {
- r = uev_add_map(str + 3, allpaths);
- }
- }
-
- else if (*str == 's' && *(str + 1) == 'g')
- r = switch_to_pathgroup(str + 3);
+ if (!reply)
+ reply = strdup("fail\n");
- else
- r = 1;
-
- if (!reply) {
- if (r)
- reply = strdup("fail\n");
- else
- reply = strdup("ok\n");
- }
+ else if (strlen(reply) == 0)
+ reply = strdup("ok\n");
unlock(allpaths->lock);
static void *
uxlsnrloop (void * ap)
{
+ if (load_keys())
+ return NULL;
+
+ if (alloc_handlers())
+ return NULL;
+
+ add_handler(LIST+PATHS, list_paths);
+ add_handler(LIST+MAPS, list_maps);
+ add_handler(ADD+PATH, add_path);
+ add_handler(DEL+PATH, del_path);
+ add_handler(ADD+MAP, add_map);
+ add_handler(DEL+MAP, del_map);
+ add_handler(SWITCH+MAP+GROUP, switch_group);
+
uxsock_listen(&uxsock_trigger, ap);
return NULL;
conf->binvec = vector_alloc();
push_callout("/sbin/scsi_id");
}
- if (!conf->multipath) {
- conf->multipath = MULTIPATH;
- push_callout(conf->multipath);
- }
+
if (!conf->checkint) {
conf->checkint = CHECKINT;
conf->max_checkint = MAX_CHECKINT;
-#ifndef HWTABLE_H
-#define HWTABLE_H
+#ifndef MAIN_H
+#define MAIN_H
#define DAEMON 1
#define CHECKINT 5
#define MAPGCINT 5
#define MAX_CHECKINT CHECKINT << 2
-#define MULTIPATH "/sbin/multipath -v0"
-#endif
+struct paths {
+ pthread_mutex_t *lock;
+ vector pathvec;
+ vector mpvec;
+};
+
+char * show_paths (struct paths *);
+char * show_maps (struct paths *);
+int uev_add_path (char *, struct paths *);
+int uev_remove_path (char *, struct paths *);
+int uev_add_map (char *, struct paths *);
+int uev_remove_map (char *, struct paths *);
+
+#endif /* MAIN_H */