hooks.c revision 204076
1238384Sjkim/*-
2280304Sjkim * Copyright (c) 2010 The FreeBSD Foundation
3280304Sjkim * All rights reserved.
4238384Sjkim *
5238384Sjkim * This software was developed by Pawel Jakub Dawidek under sponsorship from
6238384Sjkim * the FreeBSD Foundation.
7238384Sjkim *
8238384Sjkim * Redistribution and use in source and binary forms, with or without
9238384Sjkim * modification, are permitted provided that the following conditions
10238384Sjkim * are met:
11238384Sjkim * 1. Redistributions of source code must retain the above copyright
12238384Sjkim *    notice, this list of conditions and the following disclaimer.
13238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer in the
15238384Sjkim *    documentation and/or other materials provided with the distribution.
16238384Sjkim *
17238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18238384Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20238384Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21238384Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22238384Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23238384Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25238384Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26238384Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27238384Sjkim * SUCH DAMAGE.
28238384Sjkim */
29238384Sjkim
30238384Sjkim#include <sys/cdefs.h>
31238384Sjkim__FBSDID("$FreeBSD: head/sbin/hastd/hooks.c 204076 2010-02-18 23:16:19Z pjd $");
32238384Sjkim
33238384Sjkim#include <sys/types.h>
34238384Sjkim#include <sys/wait.h>
35238384Sjkim
36238384Sjkim#include <assert.h>
37238384Sjkim#include <fcntl.h>
38238384Sjkim#include <stdio.h>
39238384Sjkim#include <stdlib.h>
40238384Sjkim#include <unistd.h>
41238384Sjkim#include <string.h>
42238384Sjkim#include <syslog.h>
43238384Sjkim#include <libgen.h>
44238384Sjkim#include <paths.h>
45238384Sjkim
46238384Sjkim#include <pjdlog.h>
47238384Sjkim
48238384Sjkim#include "hooks.h"
49238384Sjkim
50238384Sjkimstatic void
51238384Sjkimdescriptors(void)
52238384Sjkim{
53238384Sjkim	long maxfd;
54238384Sjkim	int fd;
55238384Sjkim
56238384Sjkim	/*
57238384Sjkim	 * Close all descriptors.
58280304Sjkim	 */
59238384Sjkim	maxfd = sysconf(_SC_OPEN_MAX);
60280304Sjkim	if (maxfd < 0) {
61280304Sjkim		pjdlog_errno(LOG_WARNING, "sysconf(_SC_OPEN_MAX) failed");
62280304Sjkim		maxfd = 1024;
63280304Sjkim	}
64238384Sjkim	for (fd = 0; fd <= maxfd; fd++)
65280304Sjkim		close(fd);
66280304Sjkim	/*
67280304Sjkim	 * Redirect stdin, stdout and stderr to /dev/null.
68280304Sjkim	 */
69238384Sjkim	fd = open(_PATH_DEVNULL, O_RDONLY);
70280304Sjkim	if (fd < 0) {
71280304Sjkim		pjdlog_errno(LOG_WARNING, "Unable to open %s for reading",
72280304Sjkim		    _PATH_DEVNULL);
73280304Sjkim	} else if (fd != STDIN_FILENO) {
74238384Sjkim		if (dup2(fd, STDIN_FILENO) < 0) {
75280304Sjkim			pjdlog_errno(LOG_WARNING,
76280304Sjkim			    "Unable to duplicate descriptor for stdin");
77280304Sjkim		}
78280304Sjkim		close(fd);
79280304Sjkim	}
80280304Sjkim	fd = open(_PATH_DEVNULL, O_WRONLY);
81280304Sjkim	if (fd < 0) {
82280304Sjkim		pjdlog_errno(LOG_WARNING, "Unable to open %s for writing",
83280304Sjkim		    _PATH_DEVNULL);
84280304Sjkim	} else {
85280304Sjkim		if (fd != STDOUT_FILENO && dup2(fd, STDOUT_FILENO) < 0) {
86280304Sjkim			pjdlog_errno(LOG_WARNING,
87280304Sjkim			    "Unable to duplicate descriptor for stdout");
88280304Sjkim		}
89280304Sjkim		if (fd != STDERR_FILENO && dup2(fd, STDERR_FILENO) < 0) {
90280304Sjkim			pjdlog_errno(LOG_WARNING,
91280304Sjkim			    "Unable to duplicate descriptor for stderr");
92280304Sjkim		}
93280304Sjkim		if (fd != STDOUT_FILENO && fd != STDERR_FILENO)
94280304Sjkim			close(fd);
95280304Sjkim	}
96280304Sjkim}
97280304Sjkim
98280304Sjkimint
99280304Sjkimhook_exec(const char *path, ...)
100280304Sjkim{
101280304Sjkim	va_list ap;
102280304Sjkim	int ret;
103280304Sjkim
104280304Sjkim	va_start(ap, path);
105280304Sjkim	ret = hook_execv(path, ap);
106280304Sjkim	va_end(ap);
107280304Sjkim	return (ret);
108280304Sjkim}
109280304Sjkim
110280304Sjkimint
111280304Sjkimhook_execv(const char *path, va_list ap)
112280304Sjkim{
113280304Sjkim	char *args[64];
114280304Sjkim	unsigned int ii;
115280304Sjkim	pid_t pid, wpid;
116280304Sjkim	int status;
117280304Sjkim
118280304Sjkim	if (path == NULL || path[0] == '\0')
119280304Sjkim		return (0);
120280304Sjkim
121280304Sjkim	memset(args, 0, sizeof(args));
122280304Sjkim	args[0] = basename(path);
123280304Sjkim	for (ii = 1; ii < sizeof(args) / sizeof(args[0]); ii++) {
124280304Sjkim		args[ii] = va_arg(ap, char *);
125280304Sjkim		if (args[ii] == NULL)
126280304Sjkim			break;
127280304Sjkim	}
128280304Sjkim	assert(ii < sizeof(args) / sizeof(args[0]));
129280304Sjkim
130280304Sjkim	pid = fork();
131280304Sjkim	switch (pid) {
132280304Sjkim	case -1:	/* Error. */
133280304Sjkim		pjdlog_errno(LOG_ERR, "Unable to fork %s", path);
134280304Sjkim		return (-1);
135280304Sjkim	case 0:		/* Child. */
136280304Sjkim		descriptors();
137280304Sjkim		execv(path, args);
138280304Sjkim		pjdlog_errno(LOG_ERR, "Unable to execute %s", path);
139280304Sjkim		exit(EX_SOFTWARE);
140280304Sjkim	default:	/* Parent. */
141280304Sjkim		break;
142280304Sjkim	}
143280304Sjkim
144280304Sjkim	wpid = waitpid(pid, &status, 0);
145280304Sjkim	assert(wpid == pid);
146280304Sjkim
147280304Sjkim	return (WEXITSTATUS(status));
148280304Sjkim}
149280304Sjkim