1 #include "burp.h"
2 #include "alloc.h"
3 #include "asfd.h"
4 #include "conf.h"
5 #include "fzp.h"
6 #include "forkchild.h"
7 #include "handy.h"
8 #include "log.h"
9 #include "strlist.h"
10 #include "run_script.h"
11 
12 #ifndef HAVE_WIN32
13 
log_script_output(struct asfd * asfd,struct fzp ** fzp,struct conf ** confs,int do_logp,int log_remote,int is_stderr,char ** logbuf)14 static int log_script_output(struct asfd *asfd, struct fzp **fzp,
15 	struct conf **confs,
16 	int do_logp, int log_remote, int is_stderr, char **logbuf)
17 {
18 	char buf[256]="";
19 	if(!fzp || !*fzp) return 0;
20 	if(fzp_gets(*fzp, buf, sizeof(buf)))
21 	{
22 		if(logbuf && astrcat(logbuf, buf, __func__)) return -1;
23 		if(log_remote)
24 		{
25 			// logm and low will also log to stdout.
26 			if(is_stderr) logw(asfd, confs?get_cntr(confs):NULL,
27 				"%s", buf);
28 			else
29 				logm(asfd, confs, "%s", buf);
30 		}
31 		else
32 		{
33 			if(do_logp)
34 			{
35 				if(is_stderr)
36 					logp("WARNING: %s", buf);
37 				else
38 					logp("MESSAGE: %s", buf);
39 			}
40 			else
41 			{
42 				// logc does not print a prefix
43 				logc("%s", buf);
44 			}
45 		}
46 	}
47 	if(fzp_eof(*fzp)) fzp_close(fzp);
48 	return 0;
49 }
50 
51 static int got_sigchld=0;
52 static int run_script_status=-1;
53 
run_script_sigchld_handler(int sig)54 static void run_script_sigchld_handler(__attribute__ ((unused)) int sig)
55 {
56 	//printf("in run_script_sigchld_handler\n");
57 	got_sigchld=1;
58 	run_script_status=-1;
59 	waitpid(-1, &run_script_status, 0);
60 }
61 
run_script_select(struct asfd * asfd,struct fzp ** sout,struct fzp ** serr,struct conf ** confs,int do_logp,int log_remote,char ** logbuf)62 static int run_script_select(struct asfd *asfd,
63 	struct fzp **sout, struct fzp **serr,
64 	struct conf **confs, int do_logp, int log_remote, char **logbuf)
65 {
66 	int mfd=-1;
67 	fd_set fsr;
68 	struct timeval tval;
69 	int soutfd=fzp_fileno(*sout);
70 	int serrfd=fzp_fileno(*serr);
71 	// FIX THIS: convert to asfd?
72 	fzp_setlinebuf(*sout);
73 	fzp_setlinebuf(*serr);
74 	set_non_blocking(soutfd);
75 	set_non_blocking(serrfd);
76 
77 	while(1)
78 	{
79 		mfd=-1;
80 		FD_ZERO(&fsr);
81 		if(*sout) add_fd_to_sets(soutfd, &fsr, NULL, NULL, &mfd);
82 		if(*serr) add_fd_to_sets(serrfd, &fsr, NULL, NULL, &mfd);
83 		tval.tv_sec=1;
84 		tval.tv_usec=0;
85 		if(select(mfd+1, &fsr, NULL, NULL, &tval)<0)
86 		{
87 			if(errno!=EAGAIN && errno!=EINTR)
88 			{
89 				logp("%s error: %s\n", __func__,
90 					strerror(errno));
91 				return -1;
92 			}
93 		}
94 		if(FD_ISSET(soutfd, &fsr))
95 		{
96 			if(log_script_output(asfd, sout, confs,
97 				do_logp, log_remote, 0, logbuf)) return -1;
98 		}
99 		if(FD_ISSET(serrfd, &fsr))
100 		{
101 			if(log_script_output(asfd, serr, confs,
102 				do_logp, log_remote, 1, logbuf)) return -1;
103 		}
104 
105 		if(!*sout && !*serr && got_sigchld)
106 		{
107 			//fclose(*sout); *sout=NULL;
108 			//fclose(*serr); *serr=NULL;
109 			got_sigchld=0;
110 			return 0;
111 		}
112 	}
113 
114 	// Never get here.
115 	return -1;
116 }
117 
118 #endif
119 
run_script_to_buf(struct asfd * asfd,const char ** args,struct strlist * userargs,struct conf ** confs,int do_wait,int do_logp,int log_remote,char ** logbuf)120 int run_script_to_buf(struct asfd *asfd,
121 	const char **args, struct strlist *userargs, struct conf **confs,
122 	int do_wait, int do_logp, int log_remote, char **logbuf)
123 {
124 	int a=0;
125 	int l=0;
126 	pid_t p;
127 	struct fzp *serr=NULL;
128 	struct fzp *sout=NULL;
129 	char *cmd[64]={ NULL };
130 	const int maxcmd = sizeof(cmd) / sizeof(cmd[0]);
131 	struct strlist *sl;
132 #ifndef HAVE_WIN32
133 	struct cntr *cntr=NULL;
134 	int s=0;
135 #endif
136 	if(!args || !args[0]) return 0;
137 
138 	for(a=0; args[a] && l < (maxcmd - 1); a++) cmd[l++]=(char *)args[a];
139 	for(sl=userargs; sl && l < (maxcmd - 1); sl=sl->next) cmd[l++]=sl->path;
140 	cmd[l++]=NULL;
141 
142 #ifndef HAVE_WIN32
143 	setup_signal(SIGCHLD, run_script_sigchld_handler);
144 #endif
145 
146 	fflush(stdout); fflush(stderr);
147 	if(do_wait)
148 	{
149 		if((p=forkchild(NULL,
150 			&sout, &serr, cmd[0], cmd))==-1) return -1;
151 	}
152 	else
153 	{
154 		if((p=forkchild_no_wait(NULL,
155 			&sout, &serr, cmd[0], cmd))==-1) return -1;
156 		return 0;
157 	}
158 #ifdef HAVE_WIN32
159 	// My windows forkchild currently just executes, then returns.
160 	return 0;
161 #else
162 	s=run_script_select(asfd, &sout, &serr,
163 		confs, do_logp, log_remote, logbuf);
164 
165 	// Set SIGCHLD back to default.
166 	setup_signal(SIGCHLD, SIG_DFL);
167 
168 	if(s) return -1;
169 
170 	if(confs) cntr=get_cntr(confs);
171 
172 	if(WIFEXITED(run_script_status))
173 	{
174 		int ret=WEXITSTATUS(run_script_status);
175 		logp("%s returned: %d\n", cmd[0], ret);
176 		if(log_remote && confs && ret)
177 			logw(asfd, cntr, "%s returned: %d\n", cmd[0], ret);
178 		return ret;
179 	}
180 	else if(WIFSIGNALED(run_script_status))
181 	{
182 		logp("%s terminated on signal %d\n",
183 			cmd[0], WTERMSIG(run_script_status));
184 		if(log_remote && confs)
185 			logw(asfd, cntr, "%s terminated on signal %d\n",
186 				cmd[0], WTERMSIG(run_script_status));
187 	}
188 	else
189 	{
190 		logp("Strange return when trying to run %s\n", cmd[0]);
191 		if(log_remote && confs) logw(asfd, cntr,
192 			"Strange return when trying to run %s\n", cmd[0]);
193 	}
194 	return -1;
195 #endif
196 }
197 
run_script(struct asfd * asfd,const char ** args,struct strlist * userargs,struct conf ** confs,int do_wait,int do_logp,int log_remote)198 int run_script(struct asfd *asfd, const char **args, struct strlist *userargs,
199 	struct conf **confs, int do_wait, int do_logp, int log_remote)
200 {
201 	return run_script_to_buf(asfd, args, userargs, confs, do_wait,
202 		do_logp, log_remote, NULL /* do not save output to buffer */);
203 }
204