[PATCH] Move *NIX functions into separate file.
by emaste@adaranet.com
This is in advance of changes to bring in FreeBSD support.
Sponsored-by: ADARA Networks
Signed-off-by: Ed Maste <emaste(a)adaranet.com>
---
Build- and sanity-tested on CentOS 6.3, this change mirrors refactoring in
my github repo for the FreeBSD port.
src/Makefile.am | 4 +
src/drv_debian.c | 1 +
src/drv_redhat.c | 1 +
src/drv_suse.c | 1 +
src/dutil_linux.c | 238 -----------------------------------------
src/dutil_linux.h | 22 ----
src/dutil_posix.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/dutil_posix.h | 57 ++++++++++
8 files changed, 370 insertions(+), 260 deletions(-)
create mode 100644 src/dutil_posix.c
create mode 100644 src/dutil_posix.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 008629d..97ccbbe 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,6 +24,7 @@ endif
DRIVER_SOURCES_COMMON = dutil.h dutil.c
DRIVER_SOURCES_LINUX = dutil_linux.h dutil_linux.c
DRIVER_SOURCES_MSWINDOWS = dutil_mswindows.h dutil_mswindows.c drv_mswindows.c
+DRIVER_SOURCES_POSIX = dutil_posix.c
DRIVER_SOURCES_REDHAT = drv_redhat.c
DRIVER_SOURCES_DEBIAN = drv_debian.c
DRIVER_SOURCES_SUSE = drv_suse.c
@@ -42,18 +43,21 @@ EXTRA_DIST = netcf_public.syms \
if NETCF_DRIVER_REDHAT
DRIVER_SOURCES = \
$(DRIVER_SOURCES_COMMON) \
+ $(DRIVER_SOURCES_POSIX) \
$(DRIVER_SOURCES_LINUX) \
$(DRIVER_SOURCES_REDHAT)
endif
if NETCF_DRIVER_DEBIAN
DRIVER_SOURCES = \
$(DRIVER_SOURCES_COMMON) \
+ $(DRIVER_SOURCES_POSIX) \
$(DRIVER_SOURCES_LINUX) \
$(DRIVER_SOURCES_DEBIAN)
endif
if NETCF_DRIVER_SUSE
DRIVER_SOURCES = \
$(DRIVER_SOURCES_COMMON) \
+ $(DRIVER_SOURCES_POSIX) \
$(DRIVER_SOURCES_LINUX) \
$(DRIVER_SOURCES_SUSE)
endif
diff --git a/src/drv_debian.c b/src/drv_debian.c
index d264dce..ceeed94 100644
--- a/src/drv_debian.c
+++ b/src/drv_debian.c
@@ -36,6 +36,7 @@
#include "ref.h"
#include "list.h"
#include "dutil.h"
+#include "dutil_posix.h"
#include "dutil_linux.h"
#include <libxml/parser.h>
diff --git a/src/drv_redhat.c b/src/drv_redhat.c
index 40658dd..4040f5e 100644
--- a/src/drv_redhat.c
+++ b/src/drv_redhat.c
@@ -36,6 +36,7 @@
#include "ref.h"
#include "list.h"
#include "dutil.h"
+#include "dutil_posix.h"
#include "dutil_linux.h"
#include <libxml/parser.h>
diff --git a/src/drv_suse.c b/src/drv_suse.c
index f88764c..0d4a0af 100644
--- a/src/drv_suse.c
+++ b/src/drv_suse.c
@@ -42,6 +42,7 @@
#include "ref.h"
#include "list.h"
#include "dutil.h"
+#include "dutil_posix.h"
#include "dutil_linux.h"
#include <libxml/parser.h>
diff --git a/src/dutil_linux.c b/src/dutil_linux.c
index da7a586..1fe9b26 100644
--- a/src/dutil_linux.c
+++ b/src/dutil_linux.c
@@ -100,224 +100,6 @@ static struct nl_cache *__rtnl_addr_alloc_cache(struct nl_sock *sk)
}
/*
- * Executing external programs
- */
-
-static int
-exec_program(struct netcf *ncf,
- const char *const*argv,
- const char *commandline,
- pid_t *pid,
- int *outfd)
-{
- sigset_t oldmask, newmask;
- struct sigaction sig_action;
- char errbuf[128];
- int pipeout[2] = {-1, -1};
-
- /* commandline is only used for error reporting */
- if (commandline == NULL)
- commandline = argv[0];
-
- /* create a pipe to receive stdout+stderr from child */
- if (outfd) {
- if (pipe(pipeout) < 0) {
- report_error(ncf, NETCF_EEXEC,
- "failed to create pipe while forking for '%s': %s",
- commandline, strerror_r(errno, errbuf, sizeof(errbuf)));
- goto error;
- }
- *outfd = pipeout[0];
- }
-
- /*
- * Need to block signals now, so that child process can safely
- * kill off caller's signal handlers without a race.
- */
- sigfillset(&newmask);
- if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) {
- report_error(ncf, NETCF_EEXEC,
- "failed to set signal mask while forking for '%s': %s",
- commandline, strerror_r(errno, errbuf, sizeof(errbuf)));
- goto error;
- }
-
- *pid = fork();
-
- ERR_THROW(*pid < 0, ncf, EEXEC, "failed to fork for '%s': %s",
- commandline, strerror_r(errno, errbuf, sizeof(errbuf)));
-
- if (*pid) { /* parent */
- /* Restore our original signal mask now that the child is
- safely running */
- ERR_THROW(pthread_sigmask(SIG_SETMASK, &oldmask, NULL) != 0,
- ncf, EEXEC,
- "failed to restore signal mask while forking for '%s': %s",
- commandline, strerror_r(errno, errbuf, sizeof(errbuf)));
-
- /* parent doesn't use write side of the pipe */
- if (pipeout[1] >= 0)
- close(pipeout[1]);
-
- return 0;
- }
-
- /* child */
-
- /* Clear out all signal handlers from parent so nothing unexpected
- can happen in our child once we unblock signals */
-
- sig_action.sa_handler = SIG_DFL;
- sig_action.sa_flags = 0;
- sigemptyset(&sig_action.sa_mask);
-
- int i;
- for (i = 1; i < NSIG; i++) {
- /* Only possible errors are EFAULT or EINVAL
- The former wont happen, the latter we
- expect, so no need to check return value */
-
- sigaction(i, &sig_action, NULL);
- }
-
- /* Unmask all signals in child, since we've no idea what the
- caller's done with their signal mask and don't want to
- propagate that to children */
- sigemptyset(&newmask);
- if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
- /* return a unique code and let the parent log the error */
- _exit(EXIT_SIGMASK);
- }
-
- if (pipeout[1] >= 0) {
- /* direct stdout and stderr to the pipe */
- if (dup2(pipeout[1], fileno(stdout)) < 0
- || dup2(pipeout[1], fileno(stderr)) < 0) {
- /* return a unique code and let the parent log the error */
- _exit(EXIT_DUP2);
- }
- }
- /* child doesn't use the read side of the pipe */
- if (pipeout[0] >= 0)
- close(pipeout[0]);
-
- /* close all open file descriptors */
- int openmax = sysconf (_SC_OPEN_MAX);
- for (i = 3; i < openmax; i++)
- close(i);
-
- execvp(argv[0], (char **) argv);
-
- /* if execvp() returns, it has failed */
- /* return a unique code and let the parent log the error */
- _exit(errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
-
-error:
- /* This is cleanup of parent process only - child
- should never jump here on error */
- if (pipeout[0] >= 0)
- close(pipeout[0]);
- if (pipeout[1] >= 0)
- close(pipeout[1]);
- if (outfd)
- *outfd = -1;
- return -1;
-}
-
-/**
- * Run a command without using the shell.
- *
- * return 0 if the command run and exited with 0 status; Otherwise
- * return -1
- *
- */
-int run_program(struct netcf *ncf, const char *const *argv, char **output)
-{
-
- pid_t childpid = -1;
- int exitstatus, waitret;
- char *argv_str;
- int ret = -1;
- char errbuf[128];
- char *outtext = NULL;
- int outfd = -1;
- FILE *outfile = NULL;
- size_t outlen;
-
- if (!output)
- output = &outtext;
-
- argv_str = argv_to_string(argv);
- ERR_NOMEM(argv_str == NULL, ncf);
-
- exec_program(ncf, argv, argv_str, &childpid, &outfd);
- ERR_BAIL(ncf);
-
- outfile = fdopen(outfd, "r");
- ERR_THROW(outfile == NULL, ncf, EEXEC,
- "Failed to create file stream for output while executing '%s': %s",
- argv_str, strerror_r(errno, errbuf, sizeof(errbuf)));
-
- *output = fread_file(outfile, &outlen);
- ERR_THROW(*output == NULL, ncf, EEXEC,
- "Error while reading output from execution of '%s': %s",
- argv_str, strerror_r(errno, errbuf, sizeof(errbuf)));
-
- /* finished with the stream. Close it so the child can exit. */
- fclose(outfile);
- outfile = NULL;
-
- while ((waitret = waitpid(childpid, &exitstatus, 0) == -1) &&
- errno == EINTR) {
- /* empty loop */
- }
-
- ERR_THROW(waitret == -1, ncf, EEXEC,
- "Failed waiting for completion of '%s': %s",
- argv_str, strerror_r(errno, errbuf, sizeof(errbuf)));
- ERR_THROW(!WIFEXITED(exitstatus) && WIFSIGNALED(exitstatus), ncf, EEXEC,
- "'%s' terminated by signal: %d",
- argv_str, WTERMSIG(exitstatus));
- ERR_THROW(!WIFEXITED(exitstatus), ncf, EEXEC,
- "'%s' terminated improperly", argv_str);
- ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_ENOENT, ncf, EEXEC,
- "Running '%s' program not found", argv_str);
- ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_CANNOT_INVOKE, ncf, EEXEC,
- "Running '%s' program located but not usable", argv_str);
- ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_SIGMASK, ncf, EEXEC,
- "Running '%s' failed to reset child process signal mask",
- argv_str);
- ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_DUP2, ncf, EEXEC,
- "Running '%s' failed to dup2 child process stdout/stderr",
- argv_str);
- ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_INVALID_IN_THIS_STATE, ncf, EINVALIDOP,
- "Running '%s' operation is invalid in this state",
- argv_str);
- ERR_THROW(WEXITSTATUS(exitstatus) != 0, ncf, EEXEC,
- "Running '%s' failed with exit code %d: %s",
- argv_str, WEXITSTATUS(exitstatus), *output);
- ret = 0;
-
-error:
- if (outfile)
- fclose(outfile);
- else if (outfd >= 0)
- close(outfd);
- FREE(outtext);
- FREE(argv_str);
- return ret;
-}
-
-/* Run the program PROG with the single argument ARG */
-void run1(struct netcf *ncf, const char *prog, const char *arg) {
- const char *const argv[] = {
- prog, arg, NULL
- };
-
- run_program(ncf, argv, NULL);
-}
-
-/*
* augeas-related utilities
*/
int add_augeas_xfm_table(struct netcf *ncf,
@@ -671,26 +453,6 @@ void modprobed_unalias_bond(struct netcf *ncf, const char *name) {
* ioctl and netlink-related utilities
*/
-int init_ioctl_fd(struct netcf *ncf) {
- int ioctl_fd;
- int flags;
-
- ioctl_fd = socket(AF_INET, SOCK_STREAM, 0);
- ERR_THROW(ioctl_fd < 0, ncf, EINTERNAL, "failed to open socket for interface ioctl");
-
- flags = fcntl(ioctl_fd, F_GETFD);
- ERR_THROW(flags < 0, ncf, EINTERNAL, "failed to get flags for ioctl socket");
-
- flags = fcntl(ioctl_fd, F_SETFD, flags | FD_CLOEXEC);
- ERR_THROW(flags < 0, ncf, EINTERNAL, "failed to set FD_CLOEXEC flag on ioctl socket");
- return ioctl_fd;
-
-error:
- if (ioctl_fd >= 0)
- close(ioctl_fd);
- return -1;
-}
-
int if_is_active(struct netcf *ncf, const char *intf) {
struct ifreq ifr;
diff --git a/src/dutil_linux.h b/src/dutil_linux.h
index 4b122db..64fe64f 100644
--- a/src/dutil_linux.h
+++ b/src/dutil_linux.h
@@ -58,25 +58,6 @@ struct augeas_xfm_table {
};
-enum
-{
- EXIT_DUP2=124, /* dup2() of stdout/stderr in child failed */
- EXIT_SIGMASK=125, /* failed to reset signal mask of child */
- EXIT_CANNOT_INVOKE=126, /* program located, but not usable. */
- EXIT_ENOENT=127, /* could not find program to execute */
-
- /* any application-specific exit codes returned by the exec'ed
- * binary should be in the range 193-199 to avoid various
- *ambiguities (confusion with signals, truncation...
- */
- /* NB: the following code matches that in the netcf-transact script */
- EXIT_INVALID_IN_THIS_STATE=199, /* wrong state to perform this operation */
-};
-
-/* run an external program */
-int run_program(struct netcf *ncf, const char *const *argv, char **output);
-void run1(struct netcf *ncf, const char *prog, const char *arg);
-
/* Add a table of transformations that the next GET_AUGEAS should run */
int add_augeas_xfm_table(struct netcf *ncf,
const struct augeas_xfm_table *table);
@@ -128,9 +109,6 @@ void modprobed_alias_bond(struct netcf *ncf, const char *name);
/* Remove an 'alias NAME bonding' as created by modprobed_alias_bond */
void modprobed_unalias_bond(struct netcf *ncf, const char *name);
-/* Get a file descriptor to a ioctl socket */
-int init_ioctl_fd(struct netcf *ncf);
-
/* setup the netlink socket */
int netlink_init(struct netcf *ncf);
diff --git a/src/dutil_posix.c b/src/dutil_posix.c
new file mode 100644
index 0000000..609d7bd
--- /dev/null
+++ b/src/dutil_posix.c
@@ -0,0 +1,306 @@
+/*
+ * dutil_posix.c: *NIX utility functions for driver backends.
+ *
+ * Copyright (C) 2009-2012 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include <internal.h>
+
+#include <augeas.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <dirent.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <c-ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "safe-alloc.h"
+#include "read-file.h"
+#include "ref.h"
+#include "list.h"
+#include "netcf.h"
+#include "dutil.h"
+#include "dutil_posix.h"
+
+/*
+ * Executing external programs
+ */
+
+static int
+exec_program(struct netcf *ncf,
+ const char *const*argv,
+ const char *commandline,
+ pid_t *pid,
+ int *outfd)
+{
+ sigset_t oldmask, newmask;
+ struct sigaction sig_action;
+ char errbuf[128];
+ int pipeout[2] = {-1, -1};
+
+ /* commandline is only used for error reporting */
+ if (commandline == NULL)
+ commandline = argv[0];
+
+ /* create a pipe to receive stdout+stderr from child */
+ if (outfd) {
+ if (pipe(pipeout) < 0) {
+ report_error(ncf, NETCF_EEXEC,
+ "failed to create pipe while forking for '%s': %s",
+ commandline, strerror_r(errno, errbuf, sizeof(errbuf)));
+ goto error;
+ }
+ *outfd = pipeout[0];
+ }
+
+ /*
+ * Need to block signals now, so that child process can safely
+ * kill off caller's signal handlers without a race.
+ */
+ sigfillset(&newmask);
+ if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) {
+ report_error(ncf, NETCF_EEXEC,
+ "failed to set signal mask while forking for '%s': %s",
+ commandline, strerror_r(errno, errbuf, sizeof(errbuf)));
+ goto error;
+ }
+
+ *pid = fork();
+
+ ERR_THROW(*pid < 0, ncf, EEXEC, "failed to fork for '%s': %s",
+ commandline, strerror_r(errno, errbuf, sizeof(errbuf)));
+
+ if (*pid) { /* parent */
+ /* Restore our original signal mask now that the child is
+ safely running */
+ ERR_THROW(pthread_sigmask(SIG_SETMASK, &oldmask, NULL) != 0,
+ ncf, EEXEC,
+ "failed to restore signal mask while forking for '%s': %s",
+ commandline, strerror_r(errno, errbuf, sizeof(errbuf)));
+
+ /* parent doesn't use write side of the pipe */
+ if (pipeout[1] >= 0)
+ close(pipeout[1]);
+
+ return 0;
+ }
+
+ /* child */
+
+ /* Clear out all signal handlers from parent so nothing unexpected
+ can happen in our child once we unblock signals */
+
+ sig_action.sa_handler = SIG_DFL;
+ sig_action.sa_flags = 0;
+ sigemptyset(&sig_action.sa_mask);
+
+ int i;
+ for (i = 1; i < NSIG; i++) {
+ /* Only possible errors are EFAULT or EINVAL
+ The former wont happen, the latter we
+ expect, so no need to check return value */
+
+ sigaction(i, &sig_action, NULL);
+ }
+
+ /* Unmask all signals in child, since we've no idea what the
+ caller's done with their signal mask and don't want to
+ propagate that to children */
+ sigemptyset(&newmask);
+ if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
+ /* return a unique code and let the parent log the error */
+ _exit(EXIT_SIGMASK);
+ }
+
+ if (pipeout[1] >= 0) {
+ /* direct stdout and stderr to the pipe */
+ if (dup2(pipeout[1], fileno(stdout)) < 0
+ || dup2(pipeout[1], fileno(stderr)) < 0) {
+ /* return a unique code and let the parent log the error */
+ _exit(EXIT_DUP2);
+ }
+ }
+ /* child doesn't use the read side of the pipe */
+ if (pipeout[0] >= 0)
+ close(pipeout[0]);
+
+ /* close all open file descriptors */
+ int openmax = sysconf (_SC_OPEN_MAX);
+ for (i = 3; i < openmax; i++)
+ close(i);
+
+ execvp(argv[0], (char **) argv);
+
+ /* if execvp() returns, it has failed */
+ /* return a unique code and let the parent log the error */
+ _exit(errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
+
+error:
+ /* This is cleanup of parent process only - child
+ should never jump here on error */
+ if (pipeout[0] >= 0)
+ close(pipeout[0]);
+ if (pipeout[1] >= 0)
+ close(pipeout[1]);
+ if (outfd)
+ *outfd = -1;
+ return -1;
+}
+
+/**
+ * Run a command without using the shell.
+ *
+ * return 0 if the command run and exited with 0 status; Otherwise
+ * return -1
+ *
+ */
+int run_program(struct netcf *ncf, const char *const *argv, char **output)
+{
+
+ pid_t childpid = -1;
+ int exitstatus, waitret;
+ char *argv_str;
+ int ret = -1;
+ char errbuf[128];
+ char *outtext = NULL;
+ int outfd = -1;
+ FILE *outfile = NULL;
+ size_t outlen;
+
+ if (!output)
+ output = &outtext;
+
+ argv_str = argv_to_string(argv);
+ ERR_NOMEM(argv_str == NULL, ncf);
+
+ exec_program(ncf, argv, argv_str, &childpid, &outfd);
+ ERR_BAIL(ncf);
+
+ outfile = fdopen(outfd, "r");
+ ERR_THROW(outfile == NULL, ncf, EEXEC,
+ "Failed to create file stream for output while executing '%s': %s",
+ argv_str, strerror_r(errno, errbuf, sizeof(errbuf)));
+
+ *output = fread_file(outfile, &outlen);
+ ERR_THROW(*output == NULL, ncf, EEXEC,
+ "Error while reading output from execution of '%s': %s",
+ argv_str, strerror_r(errno, errbuf, sizeof(errbuf)));
+
+ /* finished with the stream. Close it so the child can exit. */
+ fclose(outfile);
+ outfile = NULL;
+
+ while ((waitret = waitpid(childpid, &exitstatus, 0) == -1) &&
+ errno == EINTR) {
+ /* empty loop */
+ }
+
+ ERR_THROW(waitret == -1, ncf, EEXEC,
+ "Failed waiting for completion of '%s': %s",
+ argv_str, strerror_r(errno, errbuf, sizeof(errbuf)));
+ ERR_THROW(!WIFEXITED(exitstatus) && WIFSIGNALED(exitstatus), ncf, EEXEC,
+ "'%s' terminated by signal: %d",
+ argv_str, WTERMSIG(exitstatus));
+ ERR_THROW(!WIFEXITED(exitstatus), ncf, EEXEC,
+ "'%s' terminated improperly", argv_str);
+ ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_ENOENT, ncf, EEXEC,
+ "Running '%s' program not found", argv_str);
+ ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_CANNOT_INVOKE, ncf, EEXEC,
+ "Running '%s' program located but not usable", argv_str);
+ ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_SIGMASK, ncf, EEXEC,
+ "Running '%s' failed to reset child process signal mask",
+ argv_str);
+ ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_DUP2, ncf, EEXEC,
+ "Running '%s' failed to dup2 child process stdout/stderr",
+ argv_str);
+ ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_INVALID_IN_THIS_STATE, ncf, EINVALIDOP,
+ "Running '%s' operation is invalid in this state",
+ argv_str);
+ ERR_THROW(WEXITSTATUS(exitstatus) != 0, ncf, EEXEC,
+ "Running '%s' failed with exit code %d: %s",
+ argv_str, WEXITSTATUS(exitstatus), *output);
+ ret = 0;
+
+error:
+ if (outfile)
+ fclose(outfile);
+ else if (outfd >= 0)
+ close(outfd);
+ FREE(outtext);
+ FREE(argv_str);
+ return ret;
+}
+
+/* Run the program PROG with the single argument ARG */
+void run1(struct netcf *ncf, const char *prog, const char *arg) {
+ const char *const argv[] = {
+ prog, arg, NULL
+ };
+
+ run_program(ncf, argv, NULL);
+}
+
+/*
+ * ioctl and netlink-related utilities
+ */
+
+int init_ioctl_fd(struct netcf *ncf) {
+ int ioctl_fd;
+ int flags;
+
+ ioctl_fd = socket(AF_INET, SOCK_STREAM, 0);
+ ERR_THROW(ioctl_fd < 0, ncf, EINTERNAL, "failed to open socket for interface ioctl");
+
+ flags = fcntl(ioctl_fd, F_GETFD);
+ ERR_THROW(flags < 0, ncf, EINTERNAL, "failed to get flags for ioctl socket");
+
+ flags = fcntl(ioctl_fd, F_SETFD, flags | FD_CLOEXEC);
+ ERR_THROW(flags < 0, ncf, EINTERNAL, "failed to set FD_CLOEXEC flag on ioctl socket");
+ return ioctl_fd;
+
+error:
+ if (ioctl_fd >= 0)
+ close(ioctl_fd);
+ return -1;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+/* vim: set ts=4 sw=4 et: */
diff --git a/src/dutil_posix.h b/src/dutil_posix.h
new file mode 100644
index 0000000..097ce32
--- /dev/null
+++ b/src/dutil_posix.h
@@ -0,0 +1,57 @@
+/*
+ * dutil_posix.h: *NIX utility functions for driver backends.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef DUTIL_POSIX_H_
+#define DUTIL_POSIX_H_
+
+enum
+{
+ EXIT_DUP2=124, /* dup2() of stdout/stderr in child failed */
+ EXIT_SIGMASK=125, /* failed to reset signal mask of child */
+ EXIT_CANNOT_INVOKE=126, /* program located, but not usable. */
+ EXIT_ENOENT=127, /* could not find program to execute */
+
+ /* any application-specific exit codes returned by the exec'ed
+ * binary should be in the range 193-199 to avoid various
+ *ambiguities (confusion with signals, truncation...
+ */
+ /* NB: the following code matches that in the netcf-transact script */
+ EXIT_INVALID_IN_THIS_STATE=199, /* wrong state to perform this operation */
+};
+
+/* run an external program */
+int run_program(struct netcf *ncf, const char *const *argv, char **output);
+void run1(struct netcf *ncf, const char *prog, const char *arg);
+
+/* Get a file descriptor to a ioctl socket */
+int init_ioctl_fd(struct netcf *ncf);
+
+#endif
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+/* vim: set ts=4 sw=4 et: */
--
1.7.10.3
11 years, 4 months
NetCF FreeBSD porting
by Ed Maste
I'm taking a look at the FreeBSD NetCF porting that Sean and Hiren
posted to this list last June, and want to help get it into a form
where it can be committed.
> Hmm. If the "Linux" sources are useful on FreeBSD, maybe they need to be
> relabelled :-)
>
> What's the proper term for "Unix-like" that doesn't step on anyone's
> trademark/ego? "STARNIX" ? "UNIXLIKE" ? Or should it be split into
> dutil_augeas.* and dutil_libnl.*?
It looks like the primary code reused from dutil_linux.c is
exec_program / run_program (nl and augeas aren't used). Would calling
it dutil_posix be reasonable?
One item I noticed during review, the char *-returning strerror_r is a
GNU-specific version and the current code addresses this with an
#ifdef __FreeBSD__ for each use. Just calling strerror_r first should
be fine on both platforms - any objection to changing each
report_error(..., strerror_r(errno, errbuf, sizeof(errbuf));
to
strerror_r(errno, errbuf, sizeof(errbuf));
report_error(..., errbuf);
-Ed
11 years, 6 months
[PATCH] Correct typo (missing space).
by Ed Maste
---
README | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README b/README
index ba99a82..8832504 100644
--- a/README
+++ b/README
@@ -7,7 +7,7 @@ It takes the description of a network interface in its own
platform-independent format and adapts the local system's network
configuration to provide that interface.
-As an example, imagine you want to bondeth0 and eth1 together to bond0. On
+As an example, imagine you want to bond eth0 and eth1 together to bond0. On
Fedora, that requires modifying the files ifcfg-eth0, ifcfg-eth1 and
ifcfg-bond0 in /etc/sysconfig/network-scripts; on Debian, it requires
changing several entries in /etc/network/interfaces.
--
1.7.10.3
11 years, 6 months
[PATCH 1/2] Ignore backup files created by dpkg
by Guido Günther
While this isn't strictly necessary for /etc/network/interfaces
(since it's not a conffile) the files in /etc/modprobe.d are
conffiles.
For dpkg's conffile handling see e.g.:
http://raphaelhertzog.com/2010/09/21/debian-conffile-configuration-file-m...
---
.gitignore | 10 +++++-----
src/drv_debian.c | 6 ++++++
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/drv_debian.c b/src/drv_debian.c
index 04953e3..6c2dc79 100644
--- a/src/drv_debian.c
+++ b/src/drv_debian.c
@@ -67,6 +67,9 @@ static const struct augeas_pv augeas_xfm_common_pv[] = {
{ "/augeas/load/Interfaces/excl[6]", "*.rpmsave" },
{ "/augeas/load/Interfaces/excl[7]", "*.augnew" },
{ "/augeas/load/Interfaces/excl[8]", "*.augsave" },
+ { "/augeas/load/Interfaces/excl[9]", "*.dpkg-dist" },
+ { "/augeas/load/Interfaces/excl[10]", "*.dpkg-new" },
+ { "/augeas/load/Interfaces/excl[11]", "*.dpkg-old" },
/* modprobe config */
{ "/augeas/load/Modprobe/lens", "Modprobe.lns" },
{ "/augeas/load/Modprobe/incl[1]", "/etc/modprobe.d/*" },
@@ -76,6 +79,9 @@ static const struct augeas_pv augeas_xfm_common_pv[] = {
{ "/augeas/load/Modprobe/excl[3]", "*.rpmsave" },
{ "/augeas/load/Modprobe/excl[4]", "*.rpmnew" },
{ "/augeas/load/Modprobe/excl[5]", "*~" },
+ { "/augeas/load/Modprobe/excl[6]", "*.dpkg-dist" },
+ { "/augeas/load/Modprobe/excl[7]", "*.dpkg-new" },
+ { "/augeas/load/Modprobe/excl[8]", "*.dpkg-old" },
/* sysfs (choice entries from /class/net) */
{ "/augeas/load/Sysfs/lens", "Netcf.id" },
{ "/augeas/load/Sysfs/incl", "/sys/class/net/*/address" }
--
1.7.10.4
11 years, 6 months
[PATCH] Be sure to bail if get_augeas() fails
by Laine Stump
There were a few places where get_augeas() was called at the beginning
of a function, but the function was allowed to continue as normal even
if get_augeas() failed. This was disastrous if any augeas library
function was subsequently called prior to checking for error status -
get_augeas sets ncf->driver->augeas to NULL if there's an error, but
aug_get/aug_put/aug_rm (and possibly others) dereference the aug
pointer they are sent without checking for NULL.
This patch assures that any caller of get_augeas() returns immediately
if get_augeas() fails.
---
src/drv_debian.c | 4 +++-
src/drv_redhat.c | 4 +++-
src/drv_suse.c | 4 +++-
src/dutil_linux.c | 10 +++++++++-
4 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/src/drv_debian.c b/src/drv_debian.c
index 04953e3..1856d69 100644
--- a/src/drv_debian.c
+++ b/src/drv_debian.c
@@ -1,7 +1,7 @@
/*
* drv_initscripts.c: the initscripts backend for netcf
*
- * Copyright (C) 2009 Red Hat Inc.
+ * Copyright (C) 2009-2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -906,6 +906,8 @@ struct netcf_if *drv_define(struct netcf *ncf, const char *xml_str) {
int r;
struct augeas *aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
ncf_xml = parse_xml(ncf, xml_str);
ERR_BAIL(ncf);
diff --git a/src/drv_redhat.c b/src/drv_redhat.c
index 06ad42a..40658dd 100644
--- a/src/drv_redhat.c
+++ b/src/drv_redhat.c
@@ -1,7 +1,7 @@
/*
* drv_redhat.c: the Red Hat distro family backend for netcf
*
- * Copyright (C) 2009 Red Hat Inc.
+ * Copyright (C) 2009-2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -866,6 +866,8 @@ struct netcf_if *drv_define(struct netcf *ncf, const char *xml_str) {
int r;
struct augeas *aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
ncf_xml = parse_xml(ncf, xml_str);
ERR_BAIL(ncf);
diff --git a/src/drv_suse.c b/src/drv_suse.c
index 7b3aa20..f88764c 100644
--- a/src/drv_suse.c
+++ b/src/drv_suse.c
@@ -2,7 +2,7 @@
* drv_suse.c: the suse backend for suse
*
* Copyright (C) 2010 Novell Inc.
- * Copyright (C) 2009 Red Hat Inc.
+ * Copyright (C) 2009-2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1008,6 +1008,8 @@ struct netcf_if *drv_define(struct netcf *ncf, const char *xml_str) {
int r;
struct augeas *aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
ncf_xml = parse_xml(ncf, xml_str);
ERR_BAIL(ncf);
diff --git a/src/dutil_linux.c b/src/dutil_linux.c
index 3cefb9e..da7a586 100644
--- a/src/dutil_linux.c
+++ b/src/dutil_linux.c
@@ -1,7 +1,7 @@
/*
* dutil_linux.c: Linux utility functions for driver backends.
*
- * Copyright (C) 2009, 2011, 2012 Red Hat Inc.
+ * Copyright (C) 2009-2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -441,6 +441,8 @@ int defnode(struct netcf *ncf, const char *name, const char *value,
char *expr = NULL;
int r, created;
+ ERR_BAIL(ncf);
+
va_start(ap, format);
r = vasprintf (&expr, format, ap);
va_end (ap);
@@ -590,6 +592,8 @@ int aug_get_mac(struct netcf *ncf, const char *intf, const char **mac) {
char *path;
struct augeas *aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
r = xasprintf(&path, "/files/sys/class/net/%s/address/content", intf);
ERR_NOMEM(r < 0, ncf);
@@ -611,6 +615,8 @@ void modprobed_alias_bond(struct netcf *ncf, const char *name) {
struct augeas *aug = get_augeas(ncf);
int r, nmatches;
+ ERR_BAIL(ncf);
+
nmatches = aug_fmt_match(ncf, NULL,
"/files/etc/modprobe.d/*/alias[ . = '%s']",
name);
@@ -648,6 +654,8 @@ void modprobed_unalias_bond(struct netcf *ncf, const char *name) {
struct augeas *aug = get_augeas(ncf);
int r;
+ ERR_BAIL(ncf);
+
r = xasprintf(&path,
"/files/etc/modprobe.d/*/alias[ . = '%s'][modulename = 'bonding']",
name);
--
1.7.11.4
11 years, 6 months
[PATCH] Fix bug that eats config parameters which have identical names.
by Hendrik Schwartke
Two (or more) nodes with identical names that are in the same
element are passed to libaugeas in such a way that only the last
node is actually written to the config file.
If e.g. there are two pre-up commands for a bridge on debian only
one is written to /etc/network/interfaces.
This fix changes this behaviour so that all of them are written.
---
src/drv_debian.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/drv_debian.c b/src/drv_debian.c
index 04953e3..1bf7558 100644
--- a/src/drv_debian.c
+++ b/src/drv_debian.c
@@ -679,7 +679,7 @@ static int aug_put_xml(struct netcf *ncf, xmlDocPtr xml) {
label = xml_prop(node, "label");
value = xml_prop(node, "value");
- r = aug_fmt_set(ncf, value, "%s/%s[%d]/%s",
+ r = aug_fmt_set(ncf, value, "%s/%s[%d]/%s[last()+1]",
network_interfaces_path,
arraylabel, n, label ? label : "1");
ERR_COND_BAIL(r < 0, ncf, EOTHER);
--
1.7.9.5
11 years, 6 months
[PATCH 2/2] Add minimal HACKING document
by Guido Günther
that explains how to run netcf from the just built sources
and how to run the tests.
---
HACKING | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 HACKING
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..04c9dbf
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,7 @@
+To run nctool from the built source dir use:
+
+ NETCF_DATADIR=data/ src/nctool
+
+To run the tests use:
+
+ make check
--
1.7.10.4
11 years, 6 months
Why check for IFF_RUNNING in if_is_active?
by Hendrik Schwartke
Hi,
I'm wondering why the IFF_RUNNING flag is checked in if_is_active.
Shouldn't it be enough to check only for IFF_UP?
My problem is that whenever I set a device up which is intentionally not
running (because the cable is not plugged in or because it's a tap
device) I got an error although everything is perfectly right.
So I have to write a wrapper to distinguish between "real" error
messages and the "cable is not inserted" error.
Is there any reason for checking both flags I didn't notice?
Regards
Hendrik
11 years, 6 months