diff --git a/CHANGELOG b/CHANGELOG
index c72ab06..dd19ead 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -88,7 +88,12 @@ version 2.77
Add mtu setting facility to --ra-param. Thanks to David
Flamand for the patch.
-
+
+ Capture STDOUT and STDERR output from dhcp-script and log
+ it as part of the dnsmasq log stream. Makes life easier
+ for diagnosing unexpected problems in scripts.
+ Thanks to Petr Mensik for the patch.
+
version 2.76
Include 0.0.0.0/8 in DNS rebind checks. This range
diff --git a/Makefile b/Makefile
index 751fe75..8fbfd5f 100644
--- a/Makefile
+++ b/Makefile
@@ -57,8 +57,8 @@ idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) -
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
-lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
-lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
+lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2`
+lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2`
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index d231e7b..6c9ebaf 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -1577,8 +1577,8 @@ database.
All file descriptors are
-closed except stdin, stdout and stderr which are open to /dev/null
-(except in debug mode).
+closed except stdin, which is open to /dev/null, and stdout and stderr which capture output for logging by dnsmasq.
+(In debug mode, stdio, stdout and stderr file are left as those inherited from the invoker of dnsmasq).
The script is not invoked concurrently: at most one instance
of the script is ever running (dnsmasq waits for an instance of script to exit
diff --git a/src/config.h b/src/config.h
index 5602369..2b5852f 100644
--- a/src/config.h
+++ b/src/config.h
@@ -409,14 +409,14 @@ static char *compile_opts =
"no-"
# endif
"DHCPv6 "
-# if !defined(HAVE_SCRIPT)
+#endif
+#if !defined(HAVE_SCRIPT)
"no-scripts "
-# else
-# if !defined(HAVE_LUASCRIPT)
- "no-"
-# endif
- "Lua "
+#else
+# if !defined(HAVE_LUASCRIPT)
+ "no-"
# endif
+ "Lua "
#endif
#ifndef HAVE_TFTP
"no-"
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 70b84dc..045489f 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -1302,6 +1302,7 @@ static void async_event(int pipe, time_t now)
daemon->tcp_pids[i] = 0;
break;
+#if defined(HAVE_SCRIPT)
case EVENT_KILLED:
my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
break;
@@ -1315,12 +1316,19 @@ static void async_event(int pipe, time_t now)
daemon->lease_change_command, strerror(ev.data));
break;
+ case EVENT_SCRIPT_LOG:
+ my_syslog(MS_SCRIPT | LOG_DEBUG, "%s", msg ? msg : "");
+ free(msg);
+ msg = NULL;
+ break;
+
/* necessary for fatal errors in helper */
case EVENT_USER_ERR:
case EVENT_DIE:
case EVENT_LUA_ERR:
fatal_event(&ev, msg);
break;
+#endif
case EVENT_REOPEN:
/* Note: this may leave TCP-handling processes with the old file still open.
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index c7d9982..c75ff2e 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -145,30 +145,31 @@ struct event_desc {
int event, data, msg_sz;
};
-#define EVENT_RELOAD 1
-#define EVENT_DUMP 2
-#define EVENT_ALARM 3
-#define EVENT_TERM 4
-#define EVENT_CHILD 5
-#define EVENT_REOPEN 6
-#define EVENT_EXITED 7
-#define EVENT_KILLED 8
-#define EVENT_EXEC_ERR 9
-#define EVENT_PIPE_ERR 10
-#define EVENT_USER_ERR 11
-#define EVENT_CAP_ERR 12
-#define EVENT_PIDFILE 13
-#define EVENT_HUSER_ERR 14
-#define EVENT_GROUP_ERR 15
-#define EVENT_DIE 16
-#define EVENT_LOG_ERR 17
-#define EVENT_FORK_ERR 18
-#define EVENT_LUA_ERR 19
-#define EVENT_TFTP_ERR 20
-#define EVENT_INIT 21
-#define EVENT_NEWADDR 22
-#define EVENT_NEWROUTE 23
-#define EVENT_TIME_ERR 24
+#define EVENT_RELOAD 1
+#define EVENT_DUMP 2
+#define EVENT_ALARM 3
+#define EVENT_TERM 4
+#define EVENT_CHILD 5
+#define EVENT_REOPEN 6
+#define EVENT_EXITED 7
+#define EVENT_KILLED 8
+#define EVENT_EXEC_ERR 9
+#define EVENT_PIPE_ERR 10
+#define EVENT_USER_ERR 11
+#define EVENT_CAP_ERR 12
+#define EVENT_PIDFILE 13
+#define EVENT_HUSER_ERR 14
+#define EVENT_GROUP_ERR 15
+#define EVENT_DIE 16
+#define EVENT_LOG_ERR 17
+#define EVENT_FORK_ERR 18
+#define EVENT_LUA_ERR 19
+#define EVENT_TFTP_ERR 20
+#define EVENT_INIT 21
+#define EVENT_NEWADDR 22
+#define EVENT_NEWROUTE 23
+#define EVENT_TIME_ERR 24
+#define EVENT_SCRIPT_LOG 25
/* Exit codes. */
#define EC_GOOD 0
@@ -243,8 +244,9 @@ struct event_desc {
/* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
-#define MS_TFTP LOG_USER
-#define MS_DHCP LOG_DAEMON
+#define MS_TFTP LOG_USER
+#define MS_DHCP LOG_DAEMON
+#define MS_SCRIPT LOG_MAIL
struct all_addr {
union {
diff --git a/src/helper.c b/src/helper.c
index 2b8164b..4fffa27 100644
--- a/src/helper.c
+++ b/src/helper.c
@@ -14,6 +14,7 @@
along with this program. If not, see .
*/
+#include
#include "dnsmasq.h"
#ifdef HAVE_SCRIPT
@@ -135,7 +136,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
max_fd != event_fd && max_fd != err_fd)
close(max_fd);
-
+
#ifdef HAVE_LUASCRIPT
if (daemon->luascript)
{
@@ -189,6 +190,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
unsigned char *buf = (unsigned char *)daemon->namebuff;
unsigned char *end, *extradata, *alloc_buff = NULL;
int is6, err = 0;
+ int pipeout[2];
free(alloc_buff);
@@ -472,16 +474,54 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (!daemon->lease_change_command)
continue;
+ /* Pipe to capture stdout and stderr from script */
+ if (!option_bool(OPT_DEBUG) && pipe(pipeout) == -1)
+ continue;
+
/* possible fork errors are all temporary resource problems */
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
sleep(2);
if (pid == -1)
- continue;
+ {
+ if (!option_bool(OPT_DEBUG))
+ {
+ close(pipeout[0]);
+ close(pipeout[1]);
+ }
+ continue;
+ }
/* wait for child to complete */
if (pid != 0)
{
+ if (!option_bool(OPT_DEBUG))
+ {
+ FILE *fp;
+
+ close(pipeout[1]);
+
+ /* Read lines sent to stdout/err by the script and pass them back to be logged */
+ if (!(fp = fdopen(pipeout[0], "r")))
+ close(pipeout[0]);
+ else
+ {
+ while (fgets(daemon->packet, daemon->packet_buff_sz, fp))
+ {
+ /* do not include new lines, log will append them */
+ size_t len = strlen(daemon->packet);
+ if (len > 0)
+ {
+ --len;
+ if (daemon->packet[len] == '\n')
+ daemon->packet[len] = 0;
+ }
+ send_event(event_fd, EVENT_SCRIPT_LOG, 0, daemon->packet);
+ }
+ fclose(fp);
+ }
+ }
+
/* reap our children's children, if necessary */
while (1)
{
@@ -504,6 +544,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue;
}
+
+ if (!option_bool(OPT_DEBUG))
+ {
+ /* map stdout/stderr of script to pipeout */
+ close(pipeout[0]);
+ dup2(pipeout[1], STDOUT_FILENO);
+ dup2(pipeout[1], STDERR_FILENO);
+ close(pipeout[1]);
+ }
if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
{
@@ -580,7 +629,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
hostname = NULL;
my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
- }
+ }
+
/* we need to have the event_fd around if exec fails */
if ((i = fcntl(event_fd, F_GETFD)) != -1)
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
diff --git a/src/log.c b/src/log.c
index abae78c..5d085a3 100644
--- a/src/log.c
+++ b/src/log.c
@@ -288,7 +288,9 @@ void my_syslog(int priority, const char *format, ...)
func = "-tftp";
else if ((LOG_FACMASK & priority) == MS_DHCP)
func = "-dhcp";
-
+ else if ((LOG_FACMASK & priority) == MS_SCRIPT)
+ func = "-script";
+
#ifdef LOG_PRI
priority = LOG_PRI(priority);
#else