[netcf-devel] [PATCH] Move *NIX functions into separate file.

Ed Maste emaste at adaranet.com
Wed Sep 19 18:25:13 UTC 2012


This is in advance of changes to bring in FreeBSD support.

Sponsored-by: ADARA Networks
Signed-off-by: Ed Maste <emaste at 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


More information about the netcf-devel mailing list