fence-agents: master - fence_kdump: New fence agent for use with kdump
by rohara
Gitweb: http://git.fedorahosted.org/git/fence-agents.git?p=fence-agents.git;a=com...
Commit: fa94ecf1ecd9de7a15e607e85b29f1ad9b2f8d5c
Parent: 7e570a1773f11afa9982ee1ed72c3482640dc52a
Author: Ryan O'Hara <rohara(a)redhat.com>
AuthorDate: Tue Jul 26 08:43:57 2011 -0500
Committer: Ryan O'Hara <rohara(a)redhat.com>
CommitterDate: Tue Jul 26 08:43:57 2011 -0500
fence_kdump: New fence agent for use with kdump
The fence_kdump agent provides a way to detect a failed node that has
enterted the kdump crash recovery service.
Signed-off-by: Ryan O'Hara <rohara(a)redhat.com>
---
fence/agents/kdump/Makefile.am | 13 +
fence/agents/kdump/fence_kdump.8 | 85 +++++
fence/agents/kdump/fence_kdump.c | 497 ++++++++++++++++++++++++++++
fence/agents/kdump/fence_kdump_send.8 | 50 +++
fence/agents/kdump/fence_kdump_send.c | 251 ++++++++++++++
fence/agents/kdump/list.h | 573 +++++++++++++++++++++++++++++++++
fence/agents/kdump/message.h | 42 +++
fence/agents/kdump/options.h | 241 ++++++++++++++
fence/agents/kdump/version.h | 33 ++
9 files changed, 1785 insertions(+), 0 deletions(-)
diff --git a/fence/agents/kdump/Makefile.am b/fence/agents/kdump/Makefile.am
new file mode 100644
index 0000000..c8234b8
--- /dev/null
+++ b/fence/agents/kdump/Makefile.am
@@ -0,0 +1,13 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+sbin_PROGRAMS = fence_kdump fence_kdump_send
+
+noinst_HEADERS = list.h message.h options.h version.h
+
+fence_kdump_SOURCES = fence_kdump.c
+fence_kdump_CFLAGS = -D_GNU_SOURCE
+
+fence_kdump_send_SOURCES = fence_kdump_send.c
+fence_kdump_send_CFLAGS = -D_GNU_SOURCE
+
+man_MANS = fence_kdump.8 fence_kdump_send.8
diff --git a/fence/agents/kdump/fence_kdump.8 b/fence/agents/kdump/fence_kdump.8
new file mode 100644
index 0000000..768f2d3
--- /dev/null
+++ b/fence/agents/kdump/fence_kdump.8
@@ -0,0 +1,85 @@
+.TH fence_kdump 8
+.SH NAME
+fence_kdump - fencing agent for use with kdump crash recovery service
+.SH SYNOPSIS
+.B
+fence_kdump
+[\fIOPTIONS\fR]...
+.SH DESCRIPTION
+\fIfence_kdump\fP is an I/O fencing agent to be used with the kdump
+crash recovery service. When the \fIfence_kdump\fP agent is invoked,
+it will listen for a message from the failed node that acknowledges
+that the failed node it executing the kdump crash kernel.
+Note that \fIfence_kdump\fP is not a replacement for traditional
+fencing methods. The \fIfence_kdump\fP agent can only detect that a
+node has entered the kdump crash recovery service. This allows the
+kdump crash recovery service complete without being preempted by
+traditional power fencing methods.
+.SH OPTIONS
+.TP
+.B -n, --nodename=\fINODE\fP
+Name or IP address of node to be fenced. This option is required for
+the "off" action. (default: none)
+.TP
+.B -p, --ipport=\fIPORT\fP
+IP port number that the \fIfence_kdump\fP agent will use to listen for
+messages. (default: 7410)
+.TP
+.B -f, --family=\fIFAMILY\fP
+IP network family. Force the \fIfence_kdump\fP agent to use a specific
+family. The value for \fIFAMILY\fP can be "auto", "ipv4", or
+"ipv6". (default: auto)
+.TP
+.B -o, --action=\fIACTION\fP
+Fencing action to perform. The value for \fIACTION\fP can be either
+"off" or "metadata". (default: off)
+.TP
+.B -t, --timeout=\fITIMEOUT\fP
+Numer of seconds to wait for message from failed node. If no message
+is received within \fITIMEOUT\fP seconds, the \fIfence_kdump\fP agent
+returns failure. (default: 60)
+.TP
+.B -v, --verbose
+Print verbose output.
+.TP
+.B -V, --version
+Print version and exit.
+.TP
+.B -h, --help
+Print usage and exit.
+.SH STDIN PARAMETERS
+.PP
+These parameters are passed to \fIfence_kdump\fP via standard input if
+no command-line options are present.
+.TP
+.B nodename=\fINODE\fP
+Name or IP address of node to be fenced. This option is required for
+the "off" action. (default: none)
+.TP
+.B ipport=\fIPORT\fP
+IP port number that the \fIfence_kdump\fP agent will use to listen for
+messages. (default: 7410)
+.TP
+.B action=\fIACTION\fP
+Fencing action to perform. The value for \fIACTION\fP can be either
+"off" or "metadata". (default: off)
+.TP
+.B timeout=\fITIMEOUT\fP
+Numer of seconds to wait for message from failed node. If no message
+is received within \fITIMEOUT\fP seconds, the \fIfence_kdump\fP agent
+returns failure. (default: 60)
+.SH ACTIONS
+.TP
+.B off
+Listen for message from failed node that acknowledges node has entered
+kdump crash recovery service. If a valid message is received from the
+failed node, the node is considered to be fenced and the agent returns
+success. Failure to receive a valid message from the failed node in
+the given timeout period results in fencing failure.
+.TP
+.B metadata
+Print XML metadata to standard output.
+.SH AUTHOR
+Ryan O'Hara <rohara(a)redhat.com>
+.SH SEE ALSO
+fence_kdump_send(8), fenced(8), fence_node(8)
diff --git a/fence/agents/kdump/fence_kdump.c b/fence/agents/kdump/fence_kdump.c
new file mode 100644
index 0000000..7df9f90
--- /dev/null
+++ b/fence/agents/kdump/fence_kdump.c
@@ -0,0 +1,497 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (c) Ryan O'Hara (rohara(a)redhat.com)
+ * Copyright (c) Red Hat, Inc.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "options.h"
+#include "message.h"
+#include "version.h"
+
+static int verbose = 0;
+
+#define log_debug(lvl, fmt, args...) \
+do { \
+ if (lvl <= verbose) \
+ fprintf (stdout, fmt, ##args); \
+} while (0);
+
+#define log_error(lvl, fmt, args...) \
+do { \
+ if (lvl <= verbose) \
+ fprintf (stderr, fmt, ##args); \
+} while (0);
+
+static int
+trim (char *str)
+{
+ char *p;
+ int len;
+
+ if (!str) return (0);
+
+ len = strlen (str);
+
+ while (len--) {
+ if (isspace (str[len])) {
+ str[len] = 0;
+ } else {
+ break;
+ }
+ }
+
+ for (p = str; *p && isspace (*p); p++);
+
+ memmove (str, p, strlen (p) + 1);
+
+ return (strlen (str));
+}
+
+static int
+read_message (const fence_kdump_node_t *node, void *msg, int len)
+{
+ int error;
+ char addr[NI_MAXHOST];
+ char port[NI_MAXSERV];
+ struct sockaddr_storage ss;
+ socklen_t size = sizeof (ss);
+
+ error = recvfrom (node->socket, msg, len, 0, (struct sockaddr *) &ss, &size);
+ if (error < 0) {
+ log_error (1, "[error]: recvfrom (%s)\n", strerror (errno));
+ goto out;
+ }
+
+ error = getnameinfo ((struct sockaddr *) &ss, size,
+ addr, sizeof (addr),
+ port, sizeof (port),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error != 0) {
+ log_error (1, "[error]: getnameinfo (%s)\n", gai_strerror (error));
+ goto out;
+ }
+
+ error = strcasecmp (node->addr, addr);
+ if (error != 0) {
+ log_debug (1, "[debug]: discard message from '%s'\n", addr);
+ }
+
+out:
+ return (error);
+}
+
+static int
+do_action_off (const fence_kdump_opts_t *opts)
+{
+ int error;
+ fd_set rfds;
+ fence_kdump_msg_t msg;
+ fence_kdump_node_t *node;
+ struct timeval timeout;
+
+ if (list_empty (&opts->nodes)) {
+ return (1);
+ } else {
+ node = list_first_entry (&opts->nodes, fence_kdump_node_t, list);
+ }
+
+ timeout.tv_sec = opts->timeout;
+ timeout.tv_usec = 0;
+
+ FD_ZERO (&rfds);
+ FD_SET (node->socket, &rfds);
+
+ log_debug (1, "[debug]: waiting for message from %s\n", node->addr);
+
+ for (;;) {
+ error = select (node->socket + 1, &rfds, NULL, NULL, &timeout);
+ if (error < 0) {
+ log_error (1, "[error]: select (%s)\n", strerror (errno));
+ break;
+ }
+ if (error == 0) {
+ log_debug (1, "[debug]: timeout after %d seconds\n", opts->timeout);
+ break;
+ }
+
+ if (read_message (node, &msg, sizeof (msg)) != 0) {
+ continue;
+ }
+
+ if (msg.magic != FENCE_KDUMP_MAGIC) {
+ log_debug (1, "[debug]: invalid magic number '0x%X'\n", msg.magic);
+ continue;
+ }
+
+ switch (msg.version) {
+ case FENCE_KDUMP_MSGV1:
+ return (0);
+ default:
+ log_debug (1, "[debug]: invalid message version '0x%X'\n", msg.version);
+ continue;
+ }
+ }
+
+ return (1);
+}
+
+static int
+do_action_metadata (const char *self)
+{
+ fprintf (stdout, "<?xml version=\"1.0\" ?>\n");
+ fprintf (stdout, "<resource-agent name=\"%s\"", basename (self));
+ fprintf (stdout, " shortdesc=\"Fence agent for use with kdump\">\n");
+ fprintf (stdout, "<longdesc>");
+ fprintf (stdout, "The fence_kdump agent is intended to be used with with kdump service.");
+ fprintf (stdout, "</longdesc>\n");
+
+ fprintf (stdout, "<parameters>\n");
+
+ fprintf (stdout, "\t<parameter name=\"nodename\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-n, --nodename\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Name or IP address of node to be fenced");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"ipport\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-p, --ipport\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" default=\"7410\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Port number");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"family\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-f, --family\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" default=\"auto\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Network family");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"action\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-o, --action\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" default=\"off\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Fencing action");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"timeout\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-t, --timeout\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" default=\"60\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Timeout in seconds");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"verbose\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-v, --verbose\" />\n");
+ fprintf (stdout, "\t\t<content type=\"boolean\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Print verbose output");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"version\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-V, --version\" />\n");
+ fprintf (stdout, "\t\t<content type=\"boolean\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Print version");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"verbose\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-h, --help\" />\n");
+ fprintf (stdout, "\t\t<content type=\"boolean\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Print usage");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "</parameters>\n");
+
+ fprintf (stdout, "<actions>\n");
+ fprintf (stdout, "\t<action name=\"off\" />\n");
+ fprintf (stdout, "\t<action name=\"metadata\" />\n");
+ fprintf (stdout, "</actions>\n");
+
+ fprintf (stdout, "</resource-agent>\n");
+
+ return (0);
+}
+
+static void
+print_usage (const char *self)
+{
+ fprintf (stdout, "Usage: %s [options]\n", basename (self));
+ fprintf (stdout, "\n");
+ fprintf (stdout, "Options:\n");
+ fprintf (stdout, "\n");
+ fprintf (stdout, "%s\n",
+ " -n, --nodename=NODE Name or IP address of node to be fenced");
+ fprintf (stdout, "%s\n",
+ " -p, --ipport=PORT IP port number (default: 7410)");
+ fprintf (stdout, "%s\n",
+ " -f, --family=FAMILY Network family: ([auto], ipv4, ipv6)");
+ fprintf (stdout, "%s\n",
+ " -o, --action=ACTION Fencing action: ([off], metadata)");
+ fprintf (stdout, "%s\n",
+ " -t, --timeout=TIMEOUT Timeout in seconds (default: 60)");
+ fprintf (stdout, "%s\n",
+ " -v, --verbose Print verbose output");
+ fprintf (stdout, "%s\n",
+ " -V, --version Print version");
+ fprintf (stdout, "%s\n",
+ " -h, --help Print usage");
+ fprintf (stdout, "\n");
+
+ return;
+}
+
+static void
+get_options_node (fence_kdump_opts_t *opts)
+{
+ int error;
+ struct addrinfo hints;
+ fence_kdump_node_t *node;
+
+ node = malloc (sizeof (fence_kdump_node_t));
+ if (!node) {
+ log_error (1, "[error]: malloc (%s)\n", strerror (errno));
+ return;
+ }
+
+ memset (node, 0, sizeof (fence_kdump_node_t));
+ memset (&hints, 0, sizeof (hints));
+
+ hints.ai_family = opts->family;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_flags = AI_NUMERICSERV;
+
+ strncpy (node->name, opts->nodename, sizeof (node->name));
+ snprintf (node->port, sizeof (node->port), "%d", opts->ipport);
+
+ node->info = NULL;
+ error = getaddrinfo (node->name, node->port, &hints, &node->info);
+ if (error != 0) {
+ log_error (1, "[error]: getaddrinfo (%s)\n", gai_strerror (error));
+ free_node (node);
+ return;
+ }
+
+ error = getnameinfo (node->info->ai_addr, node->info->ai_addrlen,
+ node->addr, sizeof (node->addr),
+ node->port, sizeof (node->port),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error != 0) {
+ log_error (1, "[error]: getnameinfo (%s)\n", gai_strerror (error));
+ free_node (node);
+ return;
+ }
+
+ hints.ai_family = node->info->ai_family;
+ hints.ai_flags |= AI_PASSIVE;
+
+ freeaddrinfo (node->info);
+
+ node->info = NULL;
+ error = getaddrinfo (NULL, node->port, &hints, &node->info);
+ if (error != 0) {
+ log_error (1, "[error]: getaddrinfo (%s)\n", gai_strerror (error));
+ free_node (node);
+ return;
+ }
+
+ node->socket = socket (node->info->ai_family,
+ node->info->ai_socktype,
+ node->info->ai_protocol);
+ if (node->socket < 0) {
+ log_error (1, "[error]: socket (%s)\n", strerror (errno));
+ free_node (node);
+ return;
+ }
+
+ error = bind (node->socket, node->info->ai_addr, node->info->ai_addrlen);
+ if (error != 0) {
+ log_error (1, "[error]: bind (%s)\n", strerror (errno));
+ free_node (node);
+ return;
+ }
+
+ list_add_tail (&node->list, &opts->nodes);
+
+ return;
+}
+
+static void
+get_options (int argc, char **argv, fence_kdump_opts_t *opts)
+{
+ int opt;
+
+ struct option options[] = {
+ { "nodename", required_argument, NULL, 'n' },
+ { "ipport", required_argument, NULL, 'p' },
+ { "family", required_argument, NULL, 'f' },
+ { "action", required_argument, NULL, 'o' },
+ { "timeout", required_argument, NULL, 't' },
+ { "verbose", optional_argument, NULL, 'v' },
+ { "version", no_argument, NULL, 'V' },
+ { "help", no_argument, NULL, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ while ((opt = getopt_long (argc, argv, "n:p:f:o:t:v::Vh", options, NULL)) != EOF) {
+ switch (opt) {
+ case 'n':
+ set_option_nodename (opts, optarg);
+ break;
+ case 'p':
+ set_option_ipport (opts, optarg);
+ break;
+ case 'f':
+ set_option_family (opts, optarg);
+ break;
+ case 'o':
+ set_option_action (opts, optarg);
+ break;
+ case 't':
+ set_option_timeout (opts, optarg);
+ break;
+ case 'v':
+ set_option_verbose (opts, optarg);
+ break;
+ case 'V':
+ print_version (argv[0]);
+ exit (0);
+ case 'h':
+ print_usage (argv[0]);
+ exit (0);
+ default:
+ print_usage (argv[0]);
+ exit (1);
+ }
+ }
+
+ verbose = opts->verbose;
+
+ return;
+}
+
+static void
+get_options_stdin (fence_kdump_opts_t *opts)
+{
+ char buf[1024];
+ char *opt;
+ char *arg;
+
+ while (fgets (buf, sizeof (buf), stdin) != 0) {
+ if (trim (buf) == 0) {
+ continue;
+ }
+ if (buf[0] == '#') {
+ continue;
+ }
+
+ opt = buf;
+
+ if ((arg = strchr (opt, '=')) != 0) {
+ *arg = 0;
+ arg += 1;
+ }
+
+ if (!strcasecmp (opt, "nodename")) {
+ set_option_nodename (opts, arg);
+ continue;
+ }
+ if (!strcasecmp (opt, "ipport")) {
+ set_option_ipport (opts, arg);
+ continue;
+ }
+ if (!strcasecmp (opt, "family")) {
+ set_option_family (opts, arg);
+ continue;
+ }
+ if (!strcasecmp (opt, "action")) {
+ set_option_action (opts, arg);
+ continue;
+ }
+ if (!strcasecmp (opt, "timeout")) {
+ set_option_timeout (opts, arg);
+ continue;
+ }
+ if (!strcasecmp (opt, "verbose")) {
+ set_option_verbose (opts, arg);
+ continue;
+ }
+ }
+
+ verbose = opts->verbose;
+
+ return;
+}
+
+int
+main (int argc, char **argv)
+{
+ int error = 1;
+ fence_kdump_opts_t opts;
+
+ init_options (&opts);
+
+ if (argc > 1) {
+ get_options (argc, argv, &opts);
+ } else {
+ get_options_stdin (&opts);
+ }
+
+ if (opts.action == FENCE_KDUMP_ACTION_OFF) {
+ if (opts.nodename == NULL) {
+ log_error (0, "[error]: action 'off' requires nodename\n");
+ exit (1);
+ }
+ get_options_node (&opts);
+ }
+
+ if (verbose != 0) {
+ print_options (&opts);
+ }
+
+ switch (opts.action) {
+ case FENCE_KDUMP_ACTION_OFF:
+ error = do_action_off (&opts);
+ break;
+ case FENCE_KDUMP_ACTION_METADATA:
+ error = do_action_metadata (argv[0]);
+ break;
+ default:
+ break;
+ }
+
+ free_options (&opts);
+
+ return (error);
+}
diff --git a/fence/agents/kdump/fence_kdump_send.8 b/fence/agents/kdump/fence_kdump_send.8
new file mode 100644
index 0000000..4cec124
--- /dev/null
+++ b/fence/agents/kdump/fence_kdump_send.8
@@ -0,0 +1,50 @@
+.TH fence_kdump_send 8
+.SH NAME
+fence_kdump_send - send kdump acknowlegement message to cluster nodes
+.SH SYNOPSIS
+.B
+fence_kdump_send
+[\fIOPTIONS]\fR... [NODE]...
+.SH DESCRIPTION
+\fIfence_kdump_send\fP is a utility used to send messages that
+acknowledge that the node has entered the kdump crash recovery
+service. This utility is intended to be used the the \fIfence_kdump\fP
+agent as a means detect that a failed node has entered the kdump crash
+recovery service.
+The \fIfence_kdump_send\fP utility is typically run from within the
+kdump kernel after a cluster node has encountered a kernel panic. Once
+the cluster node has entered the kdump crash recovery service,
+\fIfence_kdump_send\fP will periodically send messages to all cluster
+nodes. When the \fIfence_kdump\fP agent receives a valid message from
+the failed not, fencing is complete.
+.SH OPTIONS
+.TP
+.B -p, --ipport=\fIPORT\fP
+IP port number that the \fIfence_kdump\fP agent is using to listen for
+messages. (default: 7410)
+.TP
+.B -f, --family=\fIFAMILY\fP
+IP network family. Force the \fIfence_kdump_send\fP utility to use a
+particular network family. Value for \fIFAMILY\fP can be "auto",
+"ipv4", or "ipv6". (default: auto)
+.TP
+.B -c, --count=\fICOUNT\fP
+Number of messages to send. If \fICOUNT\fP is zero,
+\fIfence_kdump_send\fP will send messages indefinitely. (default: 0)
+.TP
+.B -i, --interval=\fIINTERVAL\fP
+Time to wait between sending a message. The value for \fIINTERVAL\fP
+must be greater than zero. (default: 10)
+.TP
+.B -v, --verbose
+Print verbose output.
+.TP
+.B -V, --version
+Print version and exit.
+.TP
+.B -h, --help
+Print usage and exit.
+.SH AUTHOR
+Ryan O'Hara <rohara(a)redhat.com>
+.SH SEE ALSO
+fence_kdump(8), mkdumprd(8), kdump.conf(5)
diff --git a/fence/agents/kdump/fence_kdump_send.c b/fence/agents/kdump/fence_kdump_send.c
new file mode 100644
index 0000000..29018a4
--- /dev/null
+++ b/fence/agents/kdump/fence_kdump_send.c
@@ -0,0 +1,251 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (c) Ryan O'Hara (rohara(a)redhat.com)
+ * Copyright (c) Red Hat, Inc.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "options.h"
+#include "message.h"
+#include "version.h"
+
+static int verbose = 0;
+
+#define log_debug(lvl, fmt, args...) \
+do { \
+ if (lvl <= verbose) \
+ fprintf (stdout, fmt, ##args); \
+} while (0);
+
+#define log_error(lvl, fmt, args...) \
+do { \
+ if (lvl <= verbose) \
+ fprintf (stderr, fmt, ##args); \
+} while (0);
+
+static int
+send_message (const fence_kdump_node_t *node, void *msg, int len)
+{
+ int error;
+
+ error = sendto (node->socket, msg, len, 0, node->info->ai_addr, node->info->ai_addrlen);
+ if (error < 0) {
+ log_error (1, "[error]: sendto (%s)\n", strerror (errno));
+ goto out;
+ }
+
+ log_debug (1, "[debug]: message sent to node '%s'\n", node->addr);
+
+out:
+ return (error);
+}
+
+static void
+print_usage (const char *self)
+{
+ fprintf (stdout, "Usage: %s [options] [nodes]\n", basename (self));
+ fprintf (stdout, "\n");
+ fprintf (stdout, "Options:\n");
+ fprintf (stdout, "\n");
+ fprintf (stdout, "%s\n",
+ " -p, --ipport=PORT Port number (default: 7410)");
+ fprintf (stdout, "%s\n",
+ " -f, --family=FAMILY Network family ([auto], ipv4, ipv6)");
+ fprintf (stdout, "%s\n",
+ " -c, --count=COUNT Number of messages to send (default: 0)");
+ fprintf (stdout, "%s\n",
+ " -i, --interval=INTERVAL Interval in seconds (default: 10)");
+ fprintf (stdout, "%s\n",
+ " -v, --verbose Print verbose output");
+ fprintf (stdout, "%s\n",
+ " -V, --version Print version");
+ fprintf (stdout, "%s\n",
+ " -h, --help Print usage");
+ fprintf (stdout, "\n");
+
+ return;
+}
+
+static void
+get_options_node (fence_kdump_opts_t *opts)
+{
+ int error;
+ struct addrinfo hints;
+ fence_kdump_node_t *node;
+
+ node = malloc (sizeof (fence_kdump_node_t));
+ if (!node) {
+ log_error (1, "[error]: malloc (%s)\n", strerror (errno));
+ return;
+ }
+
+ memset (node, 0, sizeof (fence_kdump_node_t));
+ memset (&hints, 0, sizeof (hints));
+
+ hints.ai_family = opts->family;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_flags = AI_NUMERICSERV;
+
+ strncpy (node->name, opts->nodename, sizeof (node->name));
+ snprintf (node->port, sizeof (node->port), "%d", opts->ipport);
+
+ node->info = NULL;
+ error = getaddrinfo (node->name, node->port, &hints, &node->info);
+ if (error != 0) {
+ log_error (1, "[error]: getaddrinfo (%s)\n", gai_strerror (error));
+ free_node (node);
+ return;
+ }
+
+ error = getnameinfo (node->info->ai_addr, node->info->ai_addrlen,
+ node->addr, sizeof (node->addr),
+ node->port, sizeof (node->port),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error != 0) {
+ log_error (1, "[error]: getnameinfo (%s)\n", gai_strerror (error));
+ free_node (node);
+ return;
+ }
+
+ node->socket = socket (node->info->ai_family,
+ node->info->ai_socktype,
+ node->info->ai_protocol);
+ if (node->socket < 0) {
+ log_error (1, "[error]: socket (%s)\n", strerror (errno));
+ free_node (node);
+ return;
+ }
+
+ list_add_tail (&node->list, &opts->nodes);
+
+ return;
+}
+
+static void
+get_options (int argc, char **argv, fence_kdump_opts_t *opts)
+{
+ int opt;
+
+ struct option options[] = {
+ { "ipport", required_argument, NULL, 'p' },
+ { "family", required_argument, NULL, 'f' },
+ { "count", required_argument, NULL, 'c' },
+ { "interval", required_argument, NULL, 'i' },
+ { "verbose", optional_argument, NULL, 'v' },
+ { "version", no_argument, NULL, 'V' },
+ { "help", no_argument, NULL, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ while ((opt = getopt_long (argc, argv, "p:f:c:i:v::Vh", options, NULL)) != EOF) {
+ switch (opt) {
+ case 'p':
+ set_option_ipport (opts, optarg);
+ break;
+ case 'f':
+ set_option_family (opts, optarg);
+ break;
+ case 'c':
+ set_option_count (opts, optarg);
+ break;
+ case 'i':
+ set_option_interval (opts, optarg);
+ break;
+ case 'v':
+ set_option_verbose (opts, optarg);
+ break;
+ case 'V':
+ print_version (argv[0]);
+ exit (0);
+ case 'h':
+ print_usage (argv[0]);
+ exit (0);
+ default:
+ print_usage (argv[0]);
+ exit (1);
+ }
+ }
+
+ verbose = opts->verbose;
+
+ return;
+}
+
+int
+main (int argc, char **argv)
+{
+ int count = 1;
+ fence_kdump_msg_t msg;
+ fence_kdump_opts_t opts;
+ fence_kdump_node_t *node;
+
+ init_options (&opts);
+
+ if (argc > 1) {
+ get_options (argc, argv, &opts);
+ } else {
+ print_usage (argv[0]);
+ exit (1);
+ }
+
+ for (; optind < argc; optind++) {
+ opts.nodename = argv[optind];
+ get_options_node (&opts);
+ opts.nodename = NULL;
+ }
+
+ if (list_empty (&opts.nodes)) {
+ print_usage (argv[0]);
+ exit (1);
+ }
+
+ if (verbose != 0) {
+ print_options (&opts);
+ }
+
+ init_message (&msg);
+
+ for (;;) {
+ list_for_each_entry (node, &opts.nodes, list) {
+ send_message (node, &msg, sizeof (msg));
+ }
+
+ if ((opts.count != 0) && (++count > opts.count)) {
+ break;
+ }
+
+ sleep (opts.interval);
+ }
+
+ free_options (&opts);
+
+ return (0);
+}
diff --git a/fence/agents/kdump/list.h b/fence/agents/kdump/list.h
new file mode 100644
index 0000000..8945a62
--- /dev/null
+++ b/fence/agents/kdump/list.h
@@ -0,0 +1,573 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new,
+ struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new,
+ struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void __list_del_entry(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del_entry(entry);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del_entry(list);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del_entry(list);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+
+ return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_rotate_left - rotate the list to the left
+ * @head: the head of the list
+ */
+static inline void list_rotate_left(struct list_head *head)
+{
+ struct list_head *first;
+
+ if (!list_empty(head)) {
+ first = head->next;
+ list_move_tail(first, head);
+ }
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+ struct list_head *head,
+ struct list_head *entry)
+{
+ struct list_head *new_first = entry->next;
+
+ list->next = head->next;
+ list->next->prev = list;
+ list->prev = entry;
+ entry->next = list;
+ head->next = new_first;
+ new_first->prev = head;
+}
+
+/**
+ * list_cut_position - cut a list into two
+ * @list: a new list to add all removed entries
+ * @head: a list with entries
+ * @entry: an entry within head, could be the head itself
+ * and if so we won't cut the list
+ *
+ * This helper moves the initial part of @head, up to and
+ * including @entry, from @head to @list. You should
+ * pass on @entry an element you know is on @head. @list
+ * should be an empty list or a list you do not care about
+ * losing its data.
+ */
+static inline void list_cut_position(struct list_head *list,
+ struct list_head *head,
+ struct list_head *entry)
+{
+ if (list_empty(head))
+ return;
+ if (list_is_singular(head) &&
+ (head->next != entry && head != entry))
+ return;
+ if (entry == head)
+ INIT_LIST_HEAD(list);
+ else
+ __list_cut_position(list, head, entry);
+}
+
+static inline void __list_splice(const struct list_head *list,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+
+ first->prev = prev;
+ prev->next = first;
+ last->next = next;
+ next->prev = last;
+}
+
+/**
+ * list_splice - join two lists, this is designed for stacks
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(const struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head->prev, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head, head->next);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head->prev, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+ for (pos = (head)->prev, n = pos->prev; pos != (head); \
+ pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member) \
+ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue - continue list iteration safe against removal
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from - iterate over list from current point safe against removal
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/**
+ * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
+ * @pos: the loop cursor used in the list_for_each_entry_safe loop
+ * @n: temporary storage used in list_for_each_entry_safe
+ * @member: the name of the list_struct within the struct.
+ *
+ * list_safe_reset_next is not safe to use in general if the list may be
+ * modified concurrently (eg. the lock is dropped in the loop body). An
+ * exception to this is if the cursor element (pos) is pinned in the list,
+ * and list_safe_reset_next is called after re-taking the lock and before
+ * completing the current iteration of the loop body.
+ */
+#define list_safe_reset_next(pos, n, member) \
+ n = list_entry(pos->member.next, typeof(*pos), member)
+
+#endif /* _LINUX_LIST_H */
diff --git a/fence/agents/kdump/message.h b/fence/agents/kdump/message.h
new file mode 100644
index 0000000..11e6d0f
--- /dev/null
+++ b/fence/agents/kdump/message.h
@@ -0,0 +1,42 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (c) Ryan O'Hara (rohara(a)redhat.com)
+ * Copyright (c) Red Hat, Inc.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _FENCE_KDUMP_MESSAGE_H
+#define _FENCE_KDUMP_MESSAGE_H
+
+#define FENCE_KDUMP_MAGIC 0x1B302A40
+
+#define FENCE_KDUMP_MSGV1 0x1
+#define FENCE_KDUMP_MSGV2 0x2
+
+typedef struct __attribute__ ((packed)) fence_kdump_msg {
+ uint32_t magic;
+ uint32_t version;
+} fence_kdump_msg_t;
+
+inline void
+init_message (fence_kdump_msg_t *msg)
+{
+ msg->magic = FENCE_KDUMP_MAGIC;
+ msg->version = FENCE_KDUMP_MSGV1;
+}
+
+#endif /* _FENCE_KDUMP_MESSAGE_H */
diff --git a/fence/agents/kdump/options.h b/fence/agents/kdump/options.h
new file mode 100644
index 0000000..6c7d274
--- /dev/null
+++ b/fence/agents/kdump/options.h
@@ -0,0 +1,241 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (c) Ryan O'Hara (rohara(a)redhat.com)
+ * Copyright (c) Red Hat, Inc.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _FENCE_KDUMP_OPTIONS_H
+#define _FENCE_KDUMP_OPTIONS_H
+
+#include "list.h"
+
+#define FENCE_KDUMP_NAME_LEN 256
+#define FENCE_KDUMP_ADDR_LEN 46
+#define FENCE_KDUMP_PORT_LEN 6
+
+enum {
+ FENCE_KDUMP_ACTION_OFF = 0,
+ FENCE_KDUMP_ACTION_ON = 1,
+ FENCE_KDUMP_ACTION_REBOOT = 2,
+ FENCE_KDUMP_ACTION_STATUS = 3,
+ FENCE_KDUMP_ACTION_LIST = 4,
+ FENCE_KDUMP_ACTION_MONITOR = 5,
+ FENCE_KDUMP_ACTION_METADATA = 6,
+};
+
+enum {
+ FENCE_KDUMP_FAMILY_AUTO = AF_UNSPEC,
+ FENCE_KDUMP_FAMILY_IPV6 = AF_INET6,
+ FENCE_KDUMP_FAMILY_IPV4 = AF_INET,
+};
+
+#define FENCE_KDUMP_DEFAULT_IPPORT 7410
+#define FENCE_KDUMP_DEFAULT_FAMILY 0
+#define FENCE_KDUMP_DEFAULT_ACTION 0
+#define FENCE_KDUMP_DEFAULT_COUNT 0
+#define FENCE_KDUMP_DEFAULT_INTERVAL 10
+#define FENCE_KDUMP_DEFAULT_TIMEOUT 60
+#define FENCE_KDUMP_DEFAULT_VERBOSE 0
+
+typedef struct fence_kdump_opts {
+ char *nodename;
+ int ipport;
+ int family;
+ int action;
+ int count;
+ int interval;
+ int timeout;
+ int verbose;
+ struct list_head nodes;
+} fence_kdump_opts_t;
+
+typedef struct fence_kdump_node {
+ char name[FENCE_KDUMP_NAME_LEN];
+ char addr[FENCE_KDUMP_ADDR_LEN];
+ char port[FENCE_KDUMP_PORT_LEN];
+ int socket;
+ struct addrinfo *info;
+ struct list_head list;
+} fence_kdump_node_t;
+
+inline void
+init_node (fence_kdump_node_t *node)
+{
+ node->info = NULL;
+}
+
+inline void
+free_node (fence_kdump_node_t *node)
+{
+ freeaddrinfo (node->info);
+ free (node);
+}
+
+inline void
+print_node (const fence_kdump_node_t *node)
+{
+ fprintf (stdout, "[debug]: node { \n");
+ fprintf (stdout, "[debug]: name = %s\n", node->name);
+ fprintf (stdout, "[debug]: addr = %s\n", node->addr);
+ fprintf (stdout, "[debug]: port = %s\n", node->port);
+ fprintf (stdout, "[debug]: info = %p\n", node->info);
+ fprintf (stdout, "[debug]: } \n");
+}
+
+inline void
+init_options (fence_kdump_opts_t *opts)
+{
+ opts->nodename = NULL;
+ opts->ipport = FENCE_KDUMP_DEFAULT_IPPORT;
+ opts->family = FENCE_KDUMP_DEFAULT_FAMILY;
+ opts->action = FENCE_KDUMP_DEFAULT_ACTION;
+ opts->count = FENCE_KDUMP_DEFAULT_COUNT;
+ opts->interval = FENCE_KDUMP_DEFAULT_INTERVAL;
+ opts->timeout = FENCE_KDUMP_DEFAULT_TIMEOUT;
+ opts->verbose = FENCE_KDUMP_DEFAULT_VERBOSE;
+
+ INIT_LIST_HEAD (&opts->nodes);
+}
+
+inline void
+free_options (fence_kdump_opts_t *opts)
+{
+ fence_kdump_node_t *node;
+ fence_kdump_node_t *safe;
+
+ list_for_each_entry_safe (node, safe, &opts->nodes, list) {
+ list_del (&node->list);
+ free_node (node);
+ }
+
+ free (opts->nodename);
+}
+
+inline void
+print_options (fence_kdump_opts_t *opts)
+{
+ fence_kdump_node_t *node;
+
+ fprintf (stdout, "[debug]: options { \n");
+ fprintf (stdout, "[debug]: nodename = %s\n", opts->nodename);
+ fprintf (stdout, "[debug]: ipport = %d\n", opts->ipport);
+ fprintf (stdout, "[debug]: family = %d\n", opts->family);
+ fprintf (stdout, "[debug]: count = %d\n", opts->count);
+ fprintf (stdout, "[debug]: interval = %d\n", opts->interval);
+ fprintf (stdout, "[debug]: timeout = %d\n", opts->timeout);
+ fprintf (stdout, "[debug]: verbose = %d\n", opts->verbose);
+ fprintf (stdout, "[debug]: } \n");
+
+ list_for_each_entry (node, &opts->nodes, list) {
+ print_node (node);
+ }
+}
+
+inline void
+set_option_nodename (fence_kdump_opts_t *opts, const char *arg)
+{
+ if (opts->nodename != NULL) {
+ free (opts->nodename);
+ }
+
+ opts->nodename = strdup (arg);
+}
+
+inline void
+set_option_ipport (fence_kdump_opts_t *opts, const char *arg)
+{
+ opts->ipport = atoi (arg);
+
+ if ((opts->ipport < 1) || (opts->ipport > 65535)) {
+ fprintf (stderr, "[error]: invalid ipport '%s'\n", arg);
+ exit (1);
+ }
+}
+
+inline void
+set_option_family (fence_kdump_opts_t *opts, const char *arg)
+{
+ if (!strcasecmp (arg, "auto")) {
+ opts->family = FENCE_KDUMP_FAMILY_AUTO;
+ } else if (!strcasecmp (arg, "ipv6")) {
+ opts->family = FENCE_KDUMP_FAMILY_IPV6;
+ } else if (!strcasecmp (arg, "ipv4")) {
+ opts->family = FENCE_KDUMP_FAMILY_IPV4;
+ } else {
+ fprintf (stderr, "[error]: unsupported family '%s'\n", arg);
+ exit (1);
+ }
+}
+
+inline void
+set_option_action (fence_kdump_opts_t *opts, const char *arg)
+{
+ if (!strcasecmp (arg, "off")) {
+ opts->action = FENCE_KDUMP_ACTION_OFF;
+ } else if (!strcasecmp (arg, "metadata")) {
+ opts->action = FENCE_KDUMP_ACTION_METADATA;
+ } else {
+ fprintf (stderr, "[error]: unsupported action '%s'\n", arg);
+ exit (1);
+ }
+}
+
+inline void
+set_option_count (fence_kdump_opts_t *opts, const char *arg)
+{
+ opts->count = atoi (arg);
+
+ if (opts->count < 0) {
+ fprintf (stderr, "[error]: invalid count '%s'\n", arg);
+ exit (1);
+ }
+}
+
+inline void
+set_option_interval (fence_kdump_opts_t *opts, const char *arg)
+{
+ opts->interval = atoi (arg);
+
+ if (opts->interval < 1) {
+ fprintf (stderr, "[error]: invalid interval '%s'\n", arg);
+ exit (1);
+ }
+}
+
+inline void
+set_option_timeout (fence_kdump_opts_t *opts, const char *arg)
+{
+ opts->timeout = atoi (arg);
+
+ if (opts->timeout < 1) {
+ fprintf (stderr, "[error]: invalid timeout '%s'\n", arg);
+ exit (1);
+ }
+}
+
+inline void
+set_option_verbose (fence_kdump_opts_t *opts, const char *arg)
+{
+ if (arg != NULL) {
+ opts->verbose = atoi (arg);
+ } else {
+ opts->verbose += 1;
+ }
+}
+
+#endif /* _FENCE_KDUMP_OPTIONS_H */
diff --git a/fence/agents/kdump/version.h b/fence/agents/kdump/version.h
new file mode 100644
index 0000000..e7959c4
--- /dev/null
+++ b/fence/agents/kdump/version.h
@@ -0,0 +1,33 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (c) Ryan O'Hara (rohara(a)redhat.com)
+ * Copyright (c) Red Hat, Inc.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _FENCE_KDUMP_VERSION_H
+#define _FENCE_KDUMP_VERSION_H
+
+#define FENCE_KDUMP_VERSION "0.1"
+
+inline void
+print_version (const char *self)
+{
+ fprintf (stdout, "%s %s\n", basename (self), FENCE_KDUMP_VERSION);
+}
+
+#endif /* _FENCE_KDUMP_VERSION_H */
12 years, 9 months
fence-agents: master - ipmilan: Allow privilege selection
by Lon Hohberger
Gitweb: http://git.fedorahosted.org/git/fence-agents.git?p=fence-agents.git;a=com...
Commit: f85b92ee67c5367fbcea1f97dde791b64a212662
Parent: 7e570a1773f11afa9982ee1ed72c3482640dc52a
Author: Kristoffer Knigga <kris(a)knigga.com>
AuthorDate: Fri Jul 1 10:16:44 2011 -0400
Committer: Lon Hohberger <lhh(a)redhat.com>
CommitterDate: Mon Jul 25 18:10:34 2011 -0400
ipmilan: Allow privilege selection
In some cases, it's desirable to limit the rights to an iLO
user in order to mitigate the fact that the login information
is stored as plaintext in the cluster configuration.
Unfortunately, ipmitool and fence_ipmilan do not work in this
configuration.
# /usr/bin/ipmitool -I lanplus -H '10.1.9.40' \
-U 'fence' -P 'fencepost' -v chassis power status
RAKP 2 message indicates an error : unauthorized role requested
Error: Unable to establish IPMI v2 / RMCP+ session
Unable to get Chassis Power Status
It turns out that dialing back the permissions on a user in iLO
changes its privilege level, in this case from administrator to
operator. ipmitool defaults to administrator if nothing is
specified, hence the error. If the correct privilege level is
given to ipmitool the command works:
# /usr/bin/ipmitool -I lanplus -H '10.1.9.40' \
-U 'fence' -L 'OPERATOR' -P 'fencepost' -v chassis power status
Chassis Power is on
This patch adds the 'privlvl' option to fence_ipmilan, allowing
administrators to change the privilege level in the cluster
configuration.
Signed-off-by: Kristoffer Knigga <kris(a)knigga.com>
Signed-off-by: Lon Hohberger <lhh(a)redhat.com>
---
fence/agents/ipmilan/ipmilan.c | 43 +++++++++++++++++++++++++++++++++++----
1 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/fence/agents/ipmilan/ipmilan.c b/fence/agents/ipmilan/ipmilan.c
index c4dbd2d..35130ad 100644
--- a/fence/agents/ipmilan/ipmilan.c
+++ b/fence/agents/ipmilan/ipmilan.c
@@ -76,6 +76,7 @@ struct ipmi {
char *i_user;
char *i_authtype;
char *i_password;
+ char *i_privlvl;
int i_rdfd;
int i_wrfd;
pid_t i_pid;
@@ -174,6 +175,7 @@ struct xml_parameter_s xml_parameters[]={
{"method","-M",0,"string",DEFAULT_METHOD,"Method to fence (onoff or cycle)"},
{"power_wait","-T",0,"string","2","Wait X seconds after on/off operation"},
{"delay","-f",0,"string",NULL,"Wait X seconds before fencing is started"},
+ {"privlvl","-L",0,"string",NULL,"Privilege level on IPMI device"},
{"verbose","-v",0,"boolean",NULL,"Verbose mode"}};
/*
@@ -270,6 +272,11 @@ build_cmd(char *command, size_t cmdlen, struct ipmi *ipmi, int op)
strncat(cmd, arg, sizeof(cmd) - strlen(arg));
}
+ if (ipmi->i_privlvl) {
+ snprintf(arg, sizeof(arg), " -L %s", str_prepare_for_sh(tmp,ipmi->i_privlvl,sizeof(tmp)));
+ strncat(cmd, arg, sizeof(cmd) - strlen(arg));
+ }
+
if (ipmi->i_cipher>=0) {
snprintf(arg, sizeof(arg), " -C %d", ipmi->i_cipher);
strncat(cmd, arg, sizeof(cmd) - strlen(arg));
@@ -558,6 +565,10 @@ ipmi_destroy(struct ipmi *i)
free(i->i_host);
i->i_host = NULL;
}
+ if (i->i_privlvl) {
+ free(i->i_privlvl);
+ i->i_privlvl = NULL;
+ }
i->i_config = 0;
i->i_id = NOTIPMI;
}
@@ -571,7 +582,7 @@ static struct ipmi *
ipmi_init(struct ipmi *i, char *host, char *authtype,
char *user, char *password, int lanplus, int verbose,int timeout,
int power_wait,
- int cipher)
+ int cipher, char *privlvl)
{
const char *p;
@@ -621,6 +632,10 @@ ipmi_init(struct ipmi *i, char *host, char *authtype,
} else
i->i_authtype = NULL;
+ if (privlvl && strlen(privlvl)) {
+ i->i_privlvl = strdup(privlvl);
+ } else
+ i->i_privlvl = NULL;
if (user && strlen(user)) {
i->i_user= strdup(user);
@@ -710,7 +725,8 @@ get_options_stdin(char *ip, size_t iplen,
int *lanplus, int *verbose,int *timeout,
int *power_wait,
int *cipher, char *method, int methodlen,
- char *delay, size_t delaylen)
+ char *delay, size_t delaylen,
+ char *privlvl, size_t privlen)
{
char in[256];
int line = 0;
@@ -765,6 +781,11 @@ get_options_stdin(char *ip, size_t iplen,
pwd_script[pwd_script_len - 1] = '\0';
} else
pwd_script[0] = '\0';
+ } else if (!strcasecmp(name, "privlvl")) {
+ if (val) {
+ strncpy(privlvl, val, privlen);
+ } else
+ privlvl[0] = '\0';
} else if (!strcasecmp(name, "user") || !strcasecmp(name, "login")) {
/* username */
if (val)
@@ -829,6 +850,8 @@ printf(" -P Use Lanplus\n");
printf(" -S <path> Script to retrieve password (if required)\n");
printf(" -l <login> Username/Login (if required) to control power\n"
" on IPMI device\n");
+printf(" -L <privlvl> IPMI privilege level. Defaults to ADMINISTRATOR.\n"
+ " See ipmitool(1) for more info.\n");
printf(" -o <op> Operation to perform.\n");
printf(" Valid operations: on, off, reboot, status,\n");
printf(" diag, list or monitor\n");
@@ -855,6 +878,7 @@ printf(" timeout=<timeout> Same as -t\n");
printf(" power_wait=<time> Same as -T\n");
printf(" cipher=<cipher> Same as -C\n");
printf(" method=<method> Same as -M\n");
+printf(" privlvl=<privlvl> Same as -L\n");
printf(" verbose Same as -v\n\n");
exit(1);
}
@@ -917,6 +941,7 @@ main(int argc, char **argv)
char passwd[64];
char user[64];
char op[64];
+ char privlvl[64];
char method[64];
char delay[64];
char pwd_script[PATH_MAX] = { 0, };
@@ -935,6 +960,7 @@ main(int argc, char **argv)
memset(passwd, 0, sizeof(passwd));
memset(user, 0, sizeof(user));
memset(op, 0, sizeof(op));
+ memset(privlvl, 0, sizeof(privlvl));
memset(method, 0, sizeof(method));
memset(delay, 0, sizeof(delay));
@@ -942,12 +968,18 @@ main(int argc, char **argv)
/*
Parse command line options if any were specified
*/
- while ((opt = getopt(argc, argv, "A:a:i:l:p:S:Po:vV?hHt:T:C:M:f:")) != EOF) {
+ while ((opt = getopt(argc, argv, "A:a:i:l:p:S:Po:vV?hHt:T:C:M:f:L:")) != EOF) {
switch(opt) {
case 'A':
/* Auth type */
strncpy(authtype, optarg, sizeof(authtype));
break;
+ case 'L':
+ /* Privilege level - ipmitool defaults
+ * to ADMINISTRATOR if nothing is given
+ */
+ strncpy(privlvl, optarg, sizeof(privlvl));
+ break;
case 'a':
case 'i':
/* IP address */
@@ -1024,7 +1056,8 @@ main(int argc, char **argv)
op, sizeof(op), &lanplus, &verbose,&timeout,
&down_sleep,
&cipher, method, sizeof(method),
- delay, sizeof(delay)) != 0)
+ delay, sizeof(delay),
+ privlvl, sizeof(privlvl)) != 0)
return 1;
}
@@ -1103,7 +1136,7 @@ main(int argc, char **argv)
}
/* Ok, set up the IPMI struct */
- i = ipmi_init(NULL, ip, authtype, user, passwd, lanplus, verbose, timeout, down_sleep, cipher);
+ i = ipmi_init(NULL, ip, authtype, user, passwd, lanplus, verbose, timeout, down_sleep, cipher, privlvl);
if (!i)
fail_exit("Failed to initialize\n");
12 years, 9 months
cluster: RHEL6 - tunegfs2: Fix label/locktable setting code
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: a727ea072c9d108301266828d9d10e68c4ca0100
Parent: a16005a0369c4ce49d70eae47431987a6dd864bc
Author: Steven Whitehouse <swhiteho(a)redhat.com>
AuthorDate: Fri Jul 22 10:42:10 2011 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Mon Jul 25 19:09:55 2011 +0100
tunegfs2: Fix label/locktable setting code
The code here seemed a bit confused. I've added a check for the
format of the locktable/label based on the same code in mkfs.
In addition we set the lock proto first in order that we use the
new value of the lock proto when checking the format of
the lock table.
There is no need to have a separate function for setting the
label to the locktable, since they are both setting the same
data.
The on-disk locktable and lockproto always contain trailing
NULLs and when we read the sb from disk, we now always add NULLs
at the end of the strings so that we can rely on this later on.
The patch also checks the size of the lock table when it is
set to ensure that it is not too large.
Signed-off-by: Steven Whitehouse <swhiteho(a)redhat.com>
Reported-by: Nathan Straz <nstraz(a)redhat.com>
Reviewed-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/tune/main.c | 29 ++++++++-------
gfs2/tune/super.c | 93 ++++++++++++++++++-------------------------------
gfs2/tune/tunegfs2.h | 1 -
3 files changed, 50 insertions(+), 73 deletions(-)
diff --git a/gfs2/tune/main.c b/gfs2/tune/main.c
index 6a0daff..dc9d6a5 100644
--- a/gfs2/tune/main.c
+++ b/gfs2/tune/main.c
@@ -20,13 +20,13 @@ struct tunegfs2 tunegfs2_struct;
struct tunegfs2 *tfs = &tunegfs2_struct;
-void parse_mount_options(char *arg)
+static void parse_mount_options(char *arg)
{
struct opt_map *m;
char *s, *c;
int l;
struct opt_map {
- char *tag;
+ const char *tag;
int *flag;
char **val;
} map[]= {
@@ -101,6 +101,12 @@ int main(int argc, char **argv)
return EX_USAGE;
}
+ if (tfs->opt_label && tfs->opt_table) {
+ fprintf(stderr, _("The -L and -o locktable= options are mutually exclusive\n"));
+ usage(argv[0]);
+ return EX_USAGE;
+ }
+
tfs->devicename = argv[optind];
tfs->fd = open(tfs->devicename, O_RDWR);
@@ -120,29 +126,26 @@ int main(int argc, char **argv)
goto out;
}
- /* Keep label and table together because they are the same field
- * in the superblock */
-
- if (tfs->opt_label) {
- status = change_label(tfs, tfs->label);
+ if (tfs->opt_proto) {
+ status = change_lockproto(tfs, tfs->proto);
if (status)
goto out;
}
- if (tfs->opt_table) {
- status = change_locktable(tfs, tfs->table);
+ if (tfs->opt_label) {
+ status = change_locktable(tfs, tfs->label);
if (status)
goto out;
}
- if (tfs->opt_proto) {
- status = change_lockproto(tfs, tfs->proto);
+ if (tfs->opt_table) {
+ status = change_locktable(tfs, tfs->table);
if (status)
goto out;
}
- if (tfs->opt_label || tfs->opt_uuid ||
- tfs->opt_table || tfs->opt_proto) {
+ if (tfs->opt_label || tfs->opt_uuid || tfs->opt_table ||
+ tfs->opt_proto) {
status = write_super(tfs);
if (status)
goto out;
diff --git a/gfs2/tune/super.c b/gfs2/tune/super.c
index f02edd6..9b1b901 100644
--- a/gfs2/tune/super.c
+++ b/gfs2/tune/super.c
@@ -104,6 +104,9 @@ int read_super(struct tunegfs2 *tfs)
fprintf(stderr, _("Not a GFS/GFS2 device\n"));
return EX_IOERR;
}
+ /* Ensure that table and proto are NULL terminated */
+ tfs->sb->sb_lockproto[GFS2_LOCKNAME_LEN - 1] = '\0';
+ tfs->sb->sb_locktable[GFS2_LOCKNAME_LEN - 1] = '\0';
return 0;
}
@@ -114,17 +117,7 @@ static int is_gfs2_format(const struct tunegfs2 *tfs)
int print_super(const struct tunegfs2 *tfs)
{
- char *fsname = NULL;
- int table_len = 0, fsname_len = 0;
-
- fsname = strchr(tfs->sb->sb_locktable, ':');
- if (fsname) {
- table_len = fsname - tfs->sb->sb_locktable;
- fsname_len = GFS2_LOCKNAME_LEN - table_len - 1;
- fsname++;
- }
-
- printf(_("Filesystem volume name: %.*s\n"), fsname_len, fsname);
+ printf(_("Filesystem volume name: %s\n"), tfs->sb->sb_locktable);
if (is_gfs2_format(tfs))
printf(_("Filesystem UUID: %s\n"), uuid2str(tfs->sb->sb_uuid));
printf( _("Filesystem magic number: 0x%X\n"), be32_to_cpu(tfs->sb->sb_header.mh_magic));
@@ -133,9 +126,8 @@ int print_super(const struct tunegfs2 *tfs)
printf(_("Root inode: %llu\n"), (unsigned long long)be64_to_cpu(tfs->sb->sb_root_dir.no_addr));
if (is_gfs2_format(tfs))
printf(_("Master inode: %llu\n"), (unsigned long long)be64_to_cpu(tfs->sb->sb_master_dir.no_addr));
- printf(_("Lock Protocol: %.*s\n"), GFS2_LOCKNAME_LEN,
- tfs->sb->sb_lockproto);
- printf(_("Lock table: %.*s\n"), table_len, tfs->sb->sb_locktable);
+ printf(_("Lock Protocol: %s\n"), tfs->sb->sb_lockproto);
+ printf(_("Lock table: %s\n"), tfs->sb->sb_locktable);
return 0;
}
@@ -151,26 +143,6 @@ int write_super(const struct tunegfs2 *tfs)
return 0;
}
-int change_label(struct tunegfs2 *tfs, const char *fsname)
-{
- char *sb_fsname = NULL;
- int l = strlen(fsname), table_len = 0, fsname_len = 0;
-
- sb_fsname = strchr(tfs->sb->sb_locktable, ':');
- if (sb_fsname) {
- table_len = sb_fsname - tfs->sb->sb_locktable;
- fsname_len = GFS2_LOCKNAME_LEN - table_len - 1;
- sb_fsname++;
- }
- if (fsname_len < l) {
- fprintf(stderr, _("Label too long\n"));
- return EX_DATAERR;
- }
- memset(sb_fsname, '\0', fsname_len);
- memcpy(sb_fsname, fsname, l);
- return 0;
-}
-
int change_uuid(struct tunegfs2 *tfs, const char *str)
{
char uuid[16];
@@ -186,12 +158,17 @@ int change_uuid(struct tunegfs2 *tfs, const char *str)
return status;
}
-
int change_lockproto(struct tunegfs2 *tfs, const char *lockproto)
{
int l = strlen(lockproto);
- if (strncmp(lockproto, "lock_dlm", 8)
- && strncmp(lockproto, "lock_nolock", 11)) {
+
+ if (l >= GFS2_LOCKNAME_LEN) {
+ fprintf(stderr, _("Lock protocol name too long\n"));
+ return EX_DATAERR;
+ }
+
+ if (strncmp(lockproto, "lock_dlm", 8) &&
+ strncmp(lockproto, "lock_nolock", 11)) {
fprintf(stderr, _("Incorrect lock protocol specified\n"));
return EX_DATAERR;
}
@@ -202,30 +179,28 @@ int change_lockproto(struct tunegfs2 *tfs, const char *lockproto)
int change_locktable(struct tunegfs2 *tfs, const char *locktable)
{
- char *sb_fsname = NULL;
- char t_fsname[GFS2_LOCKNAME_LEN];
- int l = strlen(locktable), table_len = 0, fsname_len = 0;
-
- sb_fsname = strchr(tfs->sb->sb_locktable, ':');
- if (sb_fsname) {
- table_len = sb_fsname - tfs->sb->sb_locktable;
- fsname_len = GFS2_LOCKNAME_LEN - table_len - 1;
- sb_fsname++;
- }
- /* Gotta check if the existing fsname will allow us to fit in
- * the new locktable name */
- fsname_len = strlen(sb_fsname);
- if (fsname_len > GFS2_LOCKNAME_LEN - table_len - 1)
- fsname_len = GFS2_LOCKNAME_LEN - table_len - 1;
-
- if (l > GFS2_LOCKNAME_LEN - fsname_len - 1) {
- fprintf(stderr, _("Lock table name too big\n"));
+ if (strlen(locktable) >= GFS2_LOCKNAME_LEN) {
+ fprintf(stderr, _("Lock table name too long\n"));
return EX_DATAERR;
}
- memset(t_fsname, '\0', GFS2_LOCKNAME_LEN);
- strncpy(t_fsname, sb_fsname, fsname_len);
- memset(tfs->sb->sb_locktable, '\0', GFS2_LOCKNAME_LEN);
- sprintf(tfs->sb->sb_locktable, "%s:%s", locktable, t_fsname);
+
+ if (strcmp(tfs->sb->sb_lockproto, "lock_dlm") == 0) {
+ char *fsname = strchr(locktable, ':');
+ if (fsname == NULL) {
+ fprintf(stderr, _("locktable error: mising colon in the locktable\n"));
+ return EX_DATAERR;
+ }
+ if (strlen(++fsname) > 16) {
+ fprintf(stderr, _("locktable error: fsname too long\n"));
+ return EX_DATAERR;
+ }
+ if (strchr(fsname, ':')) {
+ fprintf(stderr, _("locktable error: more than one colon present\n"));
+ return EX_DATAERR;
+ }
+ }
+
+ strcpy(tfs->sb->sb_locktable, locktable);
return 0;
}
diff --git a/gfs2/tune/tunegfs2.h b/gfs2/tune/tunegfs2.h
index 3e2706d..1acebef 100644
--- a/gfs2/tune/tunegfs2.h
+++ b/gfs2/tune/tunegfs2.h
@@ -22,7 +22,6 @@ extern int print_super(const struct tunegfs2 *);
extern int read_super(struct tunegfs2 *);
extern int write_super(const struct tunegfs2 *);
extern int change_uuid(struct tunegfs2 *, const char *uuid);
-extern int change_label(struct tunegfs2 *, const char *label);
extern int change_lockproto(struct tunegfs2 *, const char *label);
extern int change_locktable(struct tunegfs2 *, const char *label);
12 years, 9 months
cluster: RHEL6 - tunegfs2: Fix usage message
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: a16005a0369c4ce49d70eae47431987a6dd864bc
Parent: 3b3ff552f7538aae0a141a173d0213189234c22b
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Thu Jul 14 13:11:37 2011 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Mon Jul 25 18:25:05 2011 +0100
tunegfs2: Fix usage message
This is based on upstream commit a830c8747cf7dcc899dc92ad13c3a3b1a3738092
The help message is updated to include all supported options.
rhbz#719126
Signed-off-by: Steven Whitehouse <swhiteho(a)redhat.com>
Signed-off-by: Andrew Price <anprice(a)redhat.com>
Reported-by: Nathan Straz <nstraz(a)redhat.com>
Reviewed-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/tune/main.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/gfs2/tune/main.c b/gfs2/tune/main.c
index be542d7..6a0daff 100644
--- a/gfs2/tune/main.c
+++ b/gfs2/tune/main.c
@@ -52,8 +52,8 @@ void parse_mount_options(char *arg)
static void usage(char *name)
{
- printf("Usage: %s -L <volume label> -U <UUID> -l -o "
- "<mount options> <device> \n", basename(name));
+ printf("Usage: %s [-hlV] [-L <volume_label>] [-U <UUID>]\n\t"
+ "[-o <mount_options>] <device> \n", basename(name));
}
static void version(void)
12 years, 9 months
cluster: RHEL6 - tunegfs2: Ensure we don't try to open a null device
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 3b3ff552f7538aae0a141a173d0213189234c22b
Parent: a186f41a23b2bfc374ce7c4383518da469cffdec
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Thu Jul 14 13:11:37 2011 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Mon Jul 25 18:22:55 2011 +0100
tunegfs2: Ensure we don't try to open a null device
This is based on upstream commit a830c8747cf7dcc899dc92ad13c3a3b1a3738092
Return codes are now taken from sysexits.h rather than trying to pass negative
errno values as per kernel code. There is not an exact error code for all
potential events, but they are close enough I think.
The code also checks that there is exactly one non-option argument (i.e. the
device) given before attempting to open it.
rhbz#719124
Signed-off-by: Andrew Price <anprice(a)redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho(a)redhat.com>
Reported-by: Nathan Straz <nstraz(a)redhat.com>
Reviewed-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/tune/main.c | 19 ++++++++++++-------
gfs2/tune/super.c | 28 ++++++++++++++--------------
2 files changed, 26 insertions(+), 21 deletions(-)
diff --git a/gfs2/tune/main.c b/gfs2/tune/main.c
index 48fd59f..be542d7 100644
--- a/gfs2/tune/main.c
+++ b/gfs2/tune/main.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
+#include <sysexits.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -62,14 +63,14 @@ static void version(void)
int main(int argc, char **argv)
{
- int c, status = 0;
+ int c, status;
memset(tfs, 0, sizeof(struct tunegfs2));
while((c = getopt(argc, argv, "hL:U:lo:V")) != -1) {
switch(c) {
case 'h':
usage(argv[0]);
- break;
+ return 0;
case 'L':
tfs->opt_label = 1;
tfs->label = optarg;
@@ -86,23 +87,27 @@ int main(int argc, char **argv)
break;
case 'V':
version();
- break;
+ return 0;
default:
fprintf(stderr, _("Invalid option.\n"));
usage(argv[0]);
- status = -EINVAL;
- goto out;
+ return EX_USAGE;
}
}
+ if ((argc - optind) != 1) {
+ fprintf(stderr, _("Incorrect number of arguments\n"));
+ usage(argv[0]);
+ return EX_USAGE;
+ }
+
tfs->devicename = argv[optind];
tfs->fd = open(tfs->devicename, O_RDWR);
if (tfs->fd < 0) {
fprintf(stderr, _("Unable to open device %s\n"),
tfs->devicename);
- status = -EIO;
- goto out;
+ return EX_IOERR;
}
status = read_super(tfs);
diff --git a/gfs2/tune/super.c b/gfs2/tune/super.c
index e7ae4be..f02edd6 100644
--- a/gfs2/tune/super.c
+++ b/gfs2/tune/super.c
@@ -1,6 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
-
+#include <sysexits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
@@ -63,7 +63,7 @@ static int str2uuid(const char *newval, char *uuid)
if (strlen(newval) != 36) {
fprintf(stderr, _("Invalid UUID specified.\n"));
- return -EINVAL;
+ return EX_DATAERR;
}
cp = uuid;
@@ -74,13 +74,13 @@ static int str2uuid(const char *newval, char *uuid)
continue;
fprintf(stderr, _("uuid %s has an invalid format."),
newval);
- return -EINVAL;
+ return EX_DATAERR;
}
if (!isxdigit(newval[i])) {
fprintf(stderr, _("uuid %s has an invalid hex "
"digit '%c' at offset %d.\n"),
newval, newval[i], i + 1);
- return -EINVAL;
+ return EX_DATAERR;
}
*cp = str_to_hexchar(&newval[i++]);
cp++;
@@ -96,13 +96,13 @@ int read_super(struct tunegfs2 *tfs)
block = malloc(sizeof(char) * GFS2_DEFAULT_BSIZE);
n = pread(tfs->fd, block, GFS2_DEFAULT_BSIZE, tfs->sb_start);
if (n < 0) {
- fprintf(stderr, _("Error reading from device"));
- return errno;
+ perror("read_super: pread");
+ return EX_IOERR;
}
tfs->sb = block;
if (be32_to_cpu(tfs->sb->sb_header.mh_magic) != GFS2_MAGIC) {
fprintf(stderr, _("Not a GFS/GFS2 device\n"));
- return -EINVAL;
+ return EX_IOERR;
}
return 0;
}
@@ -144,9 +144,9 @@ int write_super(const struct tunegfs2 *tfs)
{
int n;
n = pwrite(tfs->fd, tfs->sb, GFS2_DEFAULT_BSIZE, tfs->sb_start);
- if (n<0) {
- fprintf(stderr, _("Unable to write super block\n"));
- return -errno;
+ if (n < 0) {
+ perror("write_super: pwrite");
+ return EX_IOERR;
}
return 0;
}
@@ -164,7 +164,7 @@ int change_label(struct tunegfs2 *tfs, const char *fsname)
}
if (fsname_len < l) {
fprintf(stderr, _("Label too long\n"));
- return -E2BIG;
+ return EX_DATAERR;
}
memset(sb_fsname, '\0', fsname_len);
memcpy(sb_fsname, fsname, l);
@@ -178,7 +178,7 @@ int change_uuid(struct tunegfs2 *tfs, const char *str)
if (be32_to_cpu(tfs->sb->sb_header.mh_magic) != GFS2_MAGIC) {
fprintf(stderr, _("UUID can be changed for a GFS2"));
fprintf(stderr, _(" device only\n"));
- return -EINVAL;
+ return EX_IOERR;
}
status = str2uuid(str, uuid);
if (!status)
@@ -193,7 +193,7 @@ int change_lockproto(struct tunegfs2 *tfs, const char *lockproto)
if (strncmp(lockproto, "lock_dlm", 8)
&& strncmp(lockproto, "lock_nolock", 11)) {
fprintf(stderr, _("Incorrect lock protocol specified\n"));
- return -EINVAL;
+ return EX_DATAERR;
}
memset(tfs->sb->sb_lockproto, '\0', GFS2_LOCKNAME_LEN);
strncpy(tfs->sb->sb_lockproto, lockproto, l);
@@ -220,7 +220,7 @@ int change_locktable(struct tunegfs2 *tfs, const char *locktable)
if (l > GFS2_LOCKNAME_LEN - fsname_len - 1) {
fprintf(stderr, _("Lock table name too big\n"));
- return -E2BIG;
+ return EX_DATAERR;
}
memset(t_fsname, '\0', GFS2_LOCKNAME_LEN);
strncpy(t_fsname, sb_fsname, fsname_len);
12 years, 9 months
fence-agents: master - Add rha:name and rha:description tag to RelaxNG XSL
by Lon Hohberger
Gitweb: http://git.fedorahosted.org/git/fence-agents.git?p=fence-agents.git;a=com...
Commit: 7e570a1773f11afa9982ee1ed72c3482640dc52a
Parent: 5a518f3cb382c2711bd027916164c7ac45ab3e3e
Author: Lon Hohberger <lhh(a)redhat.com>
AuthorDate: Mon Jun 20 09:55:42 2011 -0400
Committer: Lon Hohberger <lhh(a)redhat.com>
CommitterDate: Fri Jul 22 12:53:27 2011 -0400
Add rha:name and rha:description tag to RelaxNG XSL
Resolves: rhbz#698365
Signed-off-by: Lon Hohberger <lhh(a)redhat.com>
Reviewed-by: Fabio M. Di Nitto <fdinitto(a)redhat.com>
---
fence/agents/lib/fence.rng.head | 12 ++++++------
fence/agents/lib/fence2rng.xsl | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/fence/agents/lib/fence.rng.head b/fence/agents/lib/fence.rng.head
index c7df520..632bb53 100644
--- a/fence/agents/lib/fence.rng.head
+++ b/fence/agents/lib/fence.rng.head
@@ -5,7 +5,7 @@
<!-- begin specific fence devices -->
<!-- begin non-generated device definitions -->
<!-- RPS10 -->
- <group rha:fence_agent="fence_rps10" rha:description="RPS10 Serial Switch" >
+ <group rha:name="fence_rps10" rha:description="RPS10 Serial Switch" >
<attribute name="device" rha:description="The device the switch
is connected to on the controlling host."
rha:sample="/dev/ttys2"/>
@@ -16,7 +16,7 @@
the auth and lanplus attributes. Those attributes apply only to
the impilan fence device.-->
<!-- Brocade, McData, SANBox2, Bladecenter,bullpap, ipmilan -->
- <!-- FIXME split apart and add rha:fence_agent hints for
+ <!-- FIXME split apart and add rha:name hints for
configuration utilities -->
<group>
<attribute name="ipaddr" rha:description="IP address or the name
@@ -47,7 +47,7 @@
</optional>
</group>
<!-- Vixel -->
- <group rha:fence_agent="fence_vixel">
+ <group rha:name="fence_vixel">
<optional>
<attribute name="ipaddr" rha:description="IP address or the
name of the device." rha:sample="10.1.0.1"/>
@@ -70,7 +70,7 @@
and pserver parameters. Also, in Conga, the esh parameter is
an optional ESH path. Presumably those should be attributes in
the schema. We need more invormation on this. -->
- <group rha:fence_agent="fence_egenera">
+ <group rha:name="fence_egenera">
<optional>
<attribute name="cserver" rha:description="The hostname (and
optionally the username in the form of username@hostname)
@@ -99,10 +99,10 @@
<!-- FIXME: It appears that xCat is no longer supported. Found no
fence agents for x Cat in RHEL 5.3. -->
<!-- xCAT -->
- <group rha:fence_agent="fence_xcat">
+ <group rha:name="fence_xcat">
<attribute name="rpowerpath" rha:description="" rha:sample=""/>
</group>
- <group rha:fence_agent="fence_na" rha:description="Node Assassin">
+ <group rha:name="fence_na" rha:description="Node Assassin">
<optional>
<attribute name="option"/> <!-- deprecated; for compatibility. use "action" -->
</optional>
diff --git a/fence/agents/lib/fence2rng.xsl b/fence/agents/lib/fence2rng.xsl
index 8d23ed9..a958de1 100644
--- a/fence/agents/lib/fence2rng.xsl
+++ b/fence/agents/lib/fence2rng.xsl
@@ -7,7 +7,7 @@
</xsl:template>
<xsl:template match="/resource-agent">
<!-- <xsl:value-of select="@name"/> -->
- <group>
+ <group rha:name="<xsl:value-of select="@name"/>" rha:description="<xsl:value-of select="@shortdesc"/>">
<optional>
<attribute name="option"/> <!-- deprecated; for compatibility. use "action" -->
</optional><xsl:for-each select="parameters/parameter">
12 years, 9 months
gfs2-utils: master - tunegfs2: Fix label/locktable setting code
by Steven Whitehouse
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 4adcdab609503628601f0c420327bc909a779a85
Parent: d65e9f6f4ccfdbffd6b0c0a21c73139b1c9caea7
Author: Steven Whitehouse <swhiteho(a)redhat.com>
AuthorDate: Fri Jul 22 10:42:10 2011 +0100
Committer: Steven Whitehouse <swhiteho(a)redhat.com>
CommitterDate: Fri Jul 22 10:42:10 2011 +0100
tunegfs2: Fix label/locktable setting code
The code here seemed a bit confused. I've added a check for the
format of the locktable/label based on the same code in mkfs.
In addition we set the lock proto first in order that we use the
new value of the lock proto when checking the format of
the lock table.
There is no need to have a separate function for setting the
label to the locktable, since they are both setting the same
data.
The on-disk locktable and lockproto always contain trailing
NULLs and when we read the sb from disk, we now always add NULLs
at the end of the strings so that we can rely on this later on.
The patch also checks the size of the lock table when it is
set to ensure that it is not too large.
Signed-off-by: Steven Whitehouse <swhiteho(a)redhat.com>
Reported-by: Nathan Straz <nstraz(a)redhat.com>
---
gfs2/tune/main.c | 29 ++++++++-------
gfs2/tune/super.c | 93 ++++++++++++++++++-------------------------------
gfs2/tune/tunegfs2.h | 1 -
3 files changed, 50 insertions(+), 73 deletions(-)
diff --git a/gfs2/tune/main.c b/gfs2/tune/main.c
index 6a0daff..dc9d6a5 100644
--- a/gfs2/tune/main.c
+++ b/gfs2/tune/main.c
@@ -20,13 +20,13 @@ struct tunegfs2 tunegfs2_struct;
struct tunegfs2 *tfs = &tunegfs2_struct;
-void parse_mount_options(char *arg)
+static void parse_mount_options(char *arg)
{
struct opt_map *m;
char *s, *c;
int l;
struct opt_map {
- char *tag;
+ const char *tag;
int *flag;
char **val;
} map[]= {
@@ -101,6 +101,12 @@ int main(int argc, char **argv)
return EX_USAGE;
}
+ if (tfs->opt_label && tfs->opt_table) {
+ fprintf(stderr, _("The -L and -o locktable= options are mutually exclusive\n"));
+ usage(argv[0]);
+ return EX_USAGE;
+ }
+
tfs->devicename = argv[optind];
tfs->fd = open(tfs->devicename, O_RDWR);
@@ -120,29 +126,26 @@ int main(int argc, char **argv)
goto out;
}
- /* Keep label and table together because they are the same field
- * in the superblock */
-
- if (tfs->opt_label) {
- status = change_label(tfs, tfs->label);
+ if (tfs->opt_proto) {
+ status = change_lockproto(tfs, tfs->proto);
if (status)
goto out;
}
- if (tfs->opt_table) {
- status = change_locktable(tfs, tfs->table);
+ if (tfs->opt_label) {
+ status = change_locktable(tfs, tfs->label);
if (status)
goto out;
}
- if (tfs->opt_proto) {
- status = change_lockproto(tfs, tfs->proto);
+ if (tfs->opt_table) {
+ status = change_locktable(tfs, tfs->table);
if (status)
goto out;
}
- if (tfs->opt_label || tfs->opt_uuid ||
- tfs->opt_table || tfs->opt_proto) {
+ if (tfs->opt_label || tfs->opt_uuid || tfs->opt_table ||
+ tfs->opt_proto) {
status = write_super(tfs);
if (status)
goto out;
diff --git a/gfs2/tune/super.c b/gfs2/tune/super.c
index 9d67054..65e8d5b 100644
--- a/gfs2/tune/super.c
+++ b/gfs2/tune/super.c
@@ -104,6 +104,9 @@ int read_super(struct tunegfs2 *tfs)
fprintf(stderr, _("Not a GFS/GFS2 device\n"));
return EX_IOERR;
}
+ /* Ensure that table and proto are NULL terminated */
+ tfs->sb->sb_lockproto[GFS2_LOCKNAME_LEN - 1] = '\0';
+ tfs->sb->sb_locktable[GFS2_LOCKNAME_LEN - 1] = '\0';
return 0;
}
@@ -114,17 +117,7 @@ static int is_gfs2(const struct tunegfs2 *tfs)
int print_super(const struct tunegfs2 *tfs)
{
- char *fsname = NULL;
- int table_len = 0, fsname_len = 0;
-
- fsname = strchr(tfs->sb->sb_locktable, ':');
- if (fsname) {
- table_len = fsname - tfs->sb->sb_locktable;
- fsname_len = GFS2_LOCKNAME_LEN - table_len - 1;
- fsname++;
- }
-
- printf(_("Filesystem volume name: %.*s\n"), fsname_len, fsname);
+ printf(_("Filesystem volume name: %s\n"), tfs->sb->sb_locktable);
if (is_gfs2(tfs))
printf(_("Filesystem UUID: %s\n"), uuid2str(tfs->sb->sb_uuid));
printf( _("Filesystem magic number: 0x%X\n"), be32_to_cpu(tfs->sb->sb_header.mh_magic));
@@ -133,9 +126,8 @@ int print_super(const struct tunegfs2 *tfs)
printf(_("Root inode: %llu\n"), (unsigned long long)be64_to_cpu(tfs->sb->sb_root_dir.no_addr));
if (is_gfs2(tfs))
printf(_("Master inode: %llu\n"), (unsigned long long)be64_to_cpu(tfs->sb->sb_master_dir.no_addr));
- printf(_("Lock Protocol: %.*s\n"), GFS2_LOCKNAME_LEN,
- tfs->sb->sb_lockproto);
- printf(_("Lock table: %.*s\n"), table_len, tfs->sb->sb_locktable);
+ printf(_("Lock Protocol: %s\n"), tfs->sb->sb_lockproto);
+ printf(_("Lock table: %s\n"), tfs->sb->sb_locktable);
return 0;
}
@@ -151,26 +143,6 @@ int write_super(const struct tunegfs2 *tfs)
return 0;
}
-int change_label(struct tunegfs2 *tfs, const char *fsname)
-{
- char *sb_fsname = NULL;
- int l = strlen(fsname), table_len = 0, fsname_len = 0;
-
- sb_fsname = strchr(tfs->sb->sb_locktable, ':');
- if (sb_fsname) {
- table_len = sb_fsname - tfs->sb->sb_locktable;
- fsname_len = GFS2_LOCKNAME_LEN - table_len - 1;
- sb_fsname++;
- }
- if (fsname_len < l) {
- fprintf(stderr, _("Label too long\n"));
- return EX_DATAERR;
- }
- memset(sb_fsname, '\0', fsname_len);
- memcpy(sb_fsname, fsname, l);
- return 0;
-}
-
int change_uuid(struct tunegfs2 *tfs, const char *str)
{
char uuid[16];
@@ -186,12 +158,17 @@ int change_uuid(struct tunegfs2 *tfs, const char *str)
return status;
}
-
int change_lockproto(struct tunegfs2 *tfs, const char *lockproto)
{
int l = strlen(lockproto);
- if (strncmp(lockproto, "lock_dlm", 8)
- && strncmp(lockproto, "lock_nolock", 11)) {
+
+ if (l >= GFS2_LOCKNAME_LEN) {
+ fprintf(stderr, _("Lock protocol name too long\n"));
+ return EX_DATAERR;
+ }
+
+ if (strncmp(lockproto, "lock_dlm", 8) &&
+ strncmp(lockproto, "lock_nolock", 11)) {
fprintf(stderr, _("Incorrect lock protocol specified\n"));
return EX_DATAERR;
}
@@ -202,30 +179,28 @@ int change_lockproto(struct tunegfs2 *tfs, const char *lockproto)
int change_locktable(struct tunegfs2 *tfs, const char *locktable)
{
- char *sb_fsname = NULL;
- char t_fsname[GFS2_LOCKNAME_LEN];
- int l = strlen(locktable), table_len = 0, fsname_len = 0;
-
- sb_fsname = strchr(tfs->sb->sb_locktable, ':');
- if (sb_fsname) {
- table_len = sb_fsname - tfs->sb->sb_locktable;
- fsname_len = GFS2_LOCKNAME_LEN - table_len - 1;
- sb_fsname++;
- }
- /* Gotta check if the existing fsname will allow us to fit in
- * the new locktable name */
- fsname_len = strlen(sb_fsname);
- if (fsname_len > GFS2_LOCKNAME_LEN - table_len - 1)
- fsname_len = GFS2_LOCKNAME_LEN - table_len - 1;
-
- if (l > GFS2_LOCKNAME_LEN - fsname_len - 1) {
- fprintf(stderr, _("Lock table name too big\n"));
+ if (strlen(locktable) >= GFS2_LOCKNAME_LEN) {
+ fprintf(stderr, _("Lock table name too long\n"));
return EX_DATAERR;
}
- memset(t_fsname, '\0', GFS2_LOCKNAME_LEN);
- strncpy(t_fsname, sb_fsname, fsname_len);
- memset(tfs->sb->sb_locktable, '\0', GFS2_LOCKNAME_LEN);
- sprintf(tfs->sb->sb_locktable, "%s:%s", locktable, t_fsname);
+
+ if (strcmp(tfs->sb->sb_lockproto, "lock_dlm") == 0) {
+ char *fsname = strchr(locktable, ':');
+ if (fsname == NULL) {
+ fprintf(stderr, _("locktable error: mising colon in the locktable\n"));
+ return EX_DATAERR;
+ }
+ if (strlen(++fsname) > 16) {
+ fprintf(stderr, _("locktable error: fsname too long\n"));
+ return EX_DATAERR;
+ }
+ if (strchr(fsname, ':')) {
+ fprintf(stderr, _("locktable error: more than one colon present\n"));
+ return EX_DATAERR;
+ }
+ }
+
+ strcpy(tfs->sb->sb_locktable, locktable);
return 0;
}
diff --git a/gfs2/tune/tunegfs2.h b/gfs2/tune/tunegfs2.h
index 8fe7e07..3b28c58 100644
--- a/gfs2/tune/tunegfs2.h
+++ b/gfs2/tune/tunegfs2.h
@@ -24,7 +24,6 @@ extern int print_super(const struct tunegfs2 *);
extern int read_super(struct tunegfs2 *);
extern int write_super(const struct tunegfs2 *);
extern int change_uuid(struct tunegfs2 *, const char *uuid);
-extern int change_label(struct tunegfs2 *, const char *label);
extern int change_lockproto(struct tunegfs2 *, const char *label);
extern int change_locktable(struct tunegfs2 *, const char *label);
12 years, 9 months
cluster: RHEL6 - mount.gfs2 - gfs2 mounts doubled up in mtab
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: a186f41a23b2bfc374ce7c4383518da469cffdec
Parent: 14f7eb307fc37a57519c5bc1e73b34ecadeb6737
Author: Abhijith Das <adas(a)radium.msp.redhat.com>
AuthorDate: Thu Jul 21 14:59:40 2011 -0500
Committer: Abhijith Das <adas(a)radium.msp.redhat.com>
CommitterDate: Thu Jul 21 14:59:40 2011 -0500
mount.gfs2 - gfs2 mounts doubled up in mtab
When the -o remount option is used with mount.gfs2 it fails to
remove the original mtab entry because it can't find it. Instead
it simply adds the mount entry corresponding to the remount,
thereby doubling the entries in mtab. This patch corrects the
logic to find the mtab entry so mount.gfs2 finds and removes
the original entry correctly before adding the remount entry.
Resolves: rhbz#706141
Signed-off-by: Abhi Das <adas(a)redhat.com>
Reviewed-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/mount/mtab.c | 21 ++++++++++++++-------
1 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/gfs2/mount/mtab.c b/gfs2/mount/mtab.c
index a43d04e..ca12851 100644
--- a/gfs2/mount/mtab.c
+++ b/gfs2/mount/mtab.c
@@ -118,6 +118,7 @@ void del_mtab_entry(struct mount_options *mo)
mode_t old_umask;
struct stat sbuf;
int found = 0;
+ char *abs_path, *abs_dev;
if (ignore_mtab())
return;
@@ -137,13 +138,19 @@ void del_mtab_entry(struct mount_options *mo)
while (fgets(line, PATH_MAX, mtab)) {
/* exclude the line matching the fs being unmounted
from the next version of mtab */
-
- if ((sscanf(line, "%s %s %s", device, path, type) == 3) &&
- (strncmp(type, "gfs", 3) == 0) &&
- (strcmp(path, mo->dir) == 0) &&
- (strcmp(device, mo->dev) == 0)) {
- found = 1;
- continue;
+ if (sscanf(line, "%s %s %s", device, path, type) == 3) {
+ abs_path = realpath(path, NULL);
+ abs_dev = realpath(device, NULL);
+ if ((strcmp(type, "gfs2") == 0) &&
+ (strcmp(abs_path, mo->dir) == 0) &&
+ (strcmp(abs_dev, mo->dev) == 0)) {
+ found = 1;
+ free(abs_path);
+ free(abs_dev);
+ continue;
+ }
+ free(abs_path);
+ free(abs_dev);
}
/* all other lines from mtab are included in
12 years, 9 months
gfs2-utils: master - mount.gfs2 - gfs2 mounts doubled up in mtab
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: d65e9f6f4ccfdbffd6b0c0a21c73139b1c9caea7
Parent: 3f3ba519e40ef5a956a9cd3cac2b928c67a91a1b
Author: Abhi Das <adas(a)tux.(none)>
AuthorDate: Thu Jul 21 14:28:01 2011 -0500
Committer: Abhi Das <adas(a)tux.(none)>
CommitterDate: Thu Jul 21 14:28:01 2011 -0500
mount.gfs2 - gfs2 mounts doubled up in mtab
When the -o remount option is used with mount.gfs2 it fails to
remove the original mtab entry because it can't find it. Instead
it simply adds the mount entry corresponding to the remount,
thereby doubling the entries in mtab. This patch corrects the
logic to find the mtab entry so mount.gfs2 finds and removes
the original entry correctly before adding the remount entry.
Resolves: rhbz#706141
Signed-off-by: Abhi Das <adas(a)redhat.com>
Reviewed-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/mount/mtab.c | 21 ++++++++++++++-------
1 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/gfs2/mount/mtab.c b/gfs2/mount/mtab.c
index 148ff14..fbe5f63 100644
--- a/gfs2/mount/mtab.c
+++ b/gfs2/mount/mtab.c
@@ -120,6 +120,7 @@ void del_mtab_entry(struct mount_options *mo)
mode_t old_umask;
struct stat sbuf;
int found = 0;
+ char *abs_path, *abs_dev;
if (ignore_mtab())
return;
@@ -139,13 +140,19 @@ void del_mtab_entry(struct mount_options *mo)
while (fgets(line, PATH_MAX, mtab)) {
/* exclude the line matching the fs being unmounted
from the next version of mtab */
-
- if ((sscanf(line, "%s %s %s", device, path, type) == 3) &&
- (strncmp(type, "gfs", 3) == 0) &&
- (strcmp(path, mo->dir) == 0) &&
- (strcmp(device, mo->dev) == 0)) {
- found = 1;
- continue;
+ if (sscanf(line, "%s %s %s", device, path, type) == 3) {
+ abs_path = realpath(path, NULL);
+ abs_dev = realpath(device, NULL);
+ if ((strcmp(type, "gfs2") == 0) &&
+ (strcmp(abs_path, mo->dir) == 0) &&
+ (strcmp(abs_dev, mo->dev) == 0)) {
+ found = 1;
+ free(abs_path);
+ free(abs_dev);
+ continue;
+ }
+ free(abs_path);
+ free(abs_dev);
}
/* all other lines from mtab are included in
12 years, 9 months