hooks.c revision 211884
1/*- 2 * Copyright (c) 2010 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Pawel Jakub Dawidek under sponsorship from 6 * the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sbin/hastd/hooks.c 211884 2010-08-27 14:35:39Z pjd $"); 32 33#include <sys/types.h> 34#include <sys/wait.h> 35 36#include <assert.h> 37#include <fcntl.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <unistd.h> 41#include <string.h> 42#include <syslog.h> 43#include <libgen.h> 44#include <paths.h> 45 46#include <pjdlog.h> 47 48#include "hooks.h" 49 50static void 51descriptors(void) 52{ 53 long maxfd; 54 int fd; 55 56 /* 57 * Close all descriptors. 58 */ 59 maxfd = sysconf(_SC_OPEN_MAX); 60 if (maxfd < 0) { 61 pjdlog_errno(LOG_WARNING, "sysconf(_SC_OPEN_MAX) failed"); 62 maxfd = 1024; 63 } 64 for (fd = 0; fd <= maxfd; fd++) { 65 switch (fd) { 66 case STDIN_FILENO: 67 case STDOUT_FILENO: 68 case STDERR_FILENO: 69 if (pjdlog_mode_get() == PJDLOG_MODE_STD) 70 break; 71 /* FALLTHROUGH */ 72 default: 73 close(fd); 74 break; 75 } 76 } 77 if (pjdlog_mode_get() == PJDLOG_MODE_STD) 78 return; 79 /* 80 * Redirect stdin, stdout and stderr to /dev/null. 81 */ 82 fd = open(_PATH_DEVNULL, O_RDONLY); 83 if (fd < 0) { 84 pjdlog_errno(LOG_WARNING, "Unable to open %s for reading", 85 _PATH_DEVNULL); 86 } else if (fd != STDIN_FILENO) { 87 if (dup2(fd, STDIN_FILENO) < 0) { 88 pjdlog_errno(LOG_WARNING, 89 "Unable to duplicate descriptor for stdin"); 90 } 91 close(fd); 92 } 93 fd = open(_PATH_DEVNULL, O_WRONLY); 94 if (fd < 0) { 95 pjdlog_errno(LOG_WARNING, "Unable to open %s for writing", 96 _PATH_DEVNULL); 97 } else { 98 if (fd != STDOUT_FILENO && dup2(fd, STDOUT_FILENO) < 0) { 99 pjdlog_errno(LOG_WARNING, 100 "Unable to duplicate descriptor for stdout"); 101 } 102 if (fd != STDERR_FILENO && dup2(fd, STDERR_FILENO) < 0) { 103 pjdlog_errno(LOG_WARNING, 104 "Unable to duplicate descriptor for stderr"); 105 } 106 if (fd != STDOUT_FILENO && fd != STDERR_FILENO) 107 close(fd); 108 } 109} 110 111int 112hook_exec(const char *path, ...) 113{ 114 va_list ap; 115 int ret; 116 117 va_start(ap, path); 118 ret = hook_execv(path, ap); 119 va_end(ap); 120 return (ret); 121} 122 123int 124hook_execv(const char *path, va_list ap) 125{ 126 char *args[64]; 127 unsigned int ii; 128 pid_t pid, wpid; 129 int status; 130 131 if (path == NULL || path[0] == '\0') 132 return (0); 133 134 memset(args, 0, sizeof(args)); 135 args[0] = basename(path); 136 for (ii = 1; ii < sizeof(args) / sizeof(args[0]); ii++) { 137 args[ii] = va_arg(ap, char *); 138 if (args[ii] == NULL) 139 break; 140 } 141 assert(ii < sizeof(args) / sizeof(args[0])); 142 143 pid = fork(); 144 switch (pid) { 145 case -1: /* Error. */ 146 pjdlog_errno(LOG_ERR, "Unable to fork %s", path); 147 return (-1); 148 case 0: /* Child. */ 149 descriptors(); 150 execv(path, args); 151 pjdlog_errno(LOG_ERR, "Unable to execute %s", path); 152 exit(EX_SOFTWARE); 153 default: /* Parent. */ 154 break; 155 } 156 157 wpid = waitpid(pid, &status, 0); 158 assert(wpid == pid); 159 160 return (WEXITSTATUS(status)); 161} 162