diff options
Diffstat (limited to 'sbin/hastd/hooks.c')
-rw-r--r-- | sbin/hastd/hooks.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/sbin/hastd/hooks.c b/sbin/hastd/hooks.c new file mode 100644 index 0000000..1fdeb75 --- /dev/null +++ b/sbin/hastd/hooks.c @@ -0,0 +1,148 @@ +/*- + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Pawel Jakub Dawidek under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/wait.h> + +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <syslog.h> +#include <libgen.h> +#include <paths.h> + +#include <pjdlog.h> + +#include "hooks.h" + +static void +descriptors(void) +{ + long maxfd; + int fd; + + /* + * Close all descriptors. + */ + maxfd = sysconf(_SC_OPEN_MAX); + if (maxfd < 0) { + pjdlog_errno(LOG_WARNING, "sysconf(_SC_OPEN_MAX) failed"); + maxfd = 1024; + } + for (fd = 0; fd <= maxfd; fd++) + close(fd); + /* + * Redirect stdin, stdout and stderr to /dev/null. + */ + fd = open(_PATH_DEVNULL, O_RDONLY); + if (fd < 0) { + pjdlog_errno(LOG_WARNING, "Unable to open %s for reading", + _PATH_DEVNULL); + } else if (fd != STDIN_FILENO) { + if (dup2(fd, STDIN_FILENO) < 0) { + pjdlog_errno(LOG_WARNING, + "Unable to duplicate descriptor for stdin"); + } + close(fd); + } + fd = open(_PATH_DEVNULL, O_WRONLY); + if (fd < 0) { + pjdlog_errno(LOG_WARNING, "Unable to open %s for writing", + _PATH_DEVNULL); + } else { + if (fd != STDOUT_FILENO && dup2(fd, STDOUT_FILENO) < 0) { + pjdlog_errno(LOG_WARNING, + "Unable to duplicate descriptor for stdout"); + } + if (fd != STDERR_FILENO && dup2(fd, STDERR_FILENO) < 0) { + pjdlog_errno(LOG_WARNING, + "Unable to duplicate descriptor for stderr"); + } + if (fd != STDOUT_FILENO && fd != STDERR_FILENO) + close(fd); + } +} + +int +hook_exec(const char *path, ...) +{ + va_list ap; + int ret; + + va_start(ap, path); + ret = hook_execv(path, ap); + va_end(ap); + return (ret); +} + +int +hook_execv(const char *path, va_list ap) +{ + char *args[64]; + unsigned int ii; + pid_t pid, wpid; + int status; + + if (path == NULL || path[0] == '\0') + return (0); + + memset(args, 0, sizeof(args)); + args[0] = basename(path); + for (ii = 1; ii < sizeof(args) / sizeof(args[0]); ii++) { + args[ii] = va_arg(ap, char *); + if (args[ii] == NULL) + break; + } + assert(ii < sizeof(args) / sizeof(args[0])); + + pid = fork(); + switch (pid) { + case -1: /* Error. */ + pjdlog_errno(LOG_ERR, "Unable to fork %s", path); + return (-1); + case 0: /* Child. */ + descriptors(); + execv(path, args); + pjdlog_errno(LOG_ERR, "Unable to execute %s", path); + exit(EX_SOFTWARE); + default: /* Parent. */ + break; + } + + wpid = waitpid(pid, &status, 0); + assert(wpid == pid); + + return (WEXITSTATUS(status)); +} |