29
static void client_connected(struct master_service_connection *conn)
31
const unsigned char *end;
35
exec_child(struct master_service_connection *conn, const char *const *args)
37
unsigned int i, socket_count;
39
if (dup2(conn->fd, STDIN_FILENO) < 0)
40
i_fatal("dup2() failed: %m");
41
if (dup2(conn->fd, STDOUT_FILENO) < 0)
42
i_fatal("dup2() failed: %m");
45
socket_count = master_service_get_socket_count(master_service);
46
for (i = 0; i < socket_count; i++) {
47
if (close(MASTER_LISTEN_FD_FIRST + i) < 0)
48
i_error("close(listener) failed: %m");
50
if (close(MASTER_STATUS_FD) < 0)
51
i_error("close(status) failed: %m");
52
if (close(conn->fd) < 0)
53
i_error("close(conn->fd) failed: %m");
55
for (; *args != NULL; args++)
56
array_append(&exec_args, args, 1);
57
(void)array_append_space(&exec_args);
60
args = array_idx(&exec_args, 0);
61
execvp_const(args[0], args);
64
static bool client_exec_script(struct master_service_connection *conn)
32
66
const char *const *args;
35
unsigned int i, socket_count;
69
size_t prev_size, scanpos;
70
bool header_complete = FALSE;
39
75
net_set_nonblock(conn->fd, FALSE);
40
76
input = buffer_create_dynamic(pool_datastack_create(), IO_BLOCK_SIZE);
49
90
alarm(SCRIPT_READ_TIMEOUT_SECS);
92
while (!header_complete) {
93
const unsigned char *pos, *end;
51
95
prev_size = input->used;
52
96
buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE);
53
ret = read(conn->fd, buf, IO_BLOCK_SIZE);
98
/* peek in socket input buffer */
99
ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK);
55
101
buffer_set_used_size(input, prev_size);
56
102
if (strchr(str_c(input), '\n') != NULL)
57
script_verify_version(t_strcut(str_c(input), '\t'));
60
i_fatal("read() failed: %m");
62
i_fatal("read() failed: disconnected");
64
buffer_set_used_size(input, prev_size + ret);
65
end = CONST_PTR_OFFSET(input->data, input->used);
66
} while (!(end[-1] == '\n' && (input->used == 1 || end[-2] == '\n')));
103
script_verify_version(t_strcut(str_c(input), '\n'));
106
i_fatal("recv(MSG_PEEK) failed: %m");
108
i_fatal("recv(MSG_PEEK) failed: disconnected");
111
/* scan for final \n\n */
112
pos = CONST_PTR_OFFSET(input->data, scanpos);
113
end = CONST_PTR_OFFSET(input->data, prev_size + ret);
114
for (; pos < end; pos++) {
115
if (pos[-1] == '\n' && pos[0] == '\n') {
116
header_complete = TRUE;
121
scanpos = pos - (const unsigned char *)input->data;
123
/* read data for real (up to and including \n\n) */
124
ret = recv(conn->fd, buf, scanpos-prev_size, 0);
125
if (prev_size+ret != scanpos) {
127
i_fatal("recv() failed: %m");
129
i_fatal("recv() failed: disconnected");
130
i_fatal("recv() failed: size of definitive recv() differs from peek");
132
buffer_set_used_size(input, scanpos);
68
136
/* drop the last LF */
69
buffer_set_used_size(input, input->used - 1);
137
buffer_set_used_size(input, scanpos-1);
71
139
args = t_strsplit(str_c(input), "\n");
72
script_verify_version(*args);
74
for (args++; *args != NULL; args++)
75
array_append(&exec_args, args, 1);
76
(void)array_append_space(&exec_args);
79
socket_count = master_service_get_socket_count(master_service);
80
for (i = 0; i < socket_count; i++) {
81
if (close(MASTER_LISTEN_FD_FIRST + i) < 0)
82
i_error("close(listener) failed: %m");
84
if (close(MASTER_STATUS_FD) < 0)
85
i_error("close(status) failed: %m");
86
if (close(conn->fd) < 0)
87
i_error("close() failed: %m");
90
args = array_idx(&exec_args, 0);
91
execvp_const(args[0], args);
140
script_verify_version(*args); args++;
142
if (strncmp(*args, "alarm=", 6) == 0) {
143
alarm(atoi(*args + 6));
146
if (strcmp(*args, "noreply") == 0) {
147
/* no need to fork and check exit status */
148
exec_child(conn, args + 1);
152
i_fatal("empty options");
156
if ((pid = fork()) == (pid_t)-1) {
157
i_error("fork() failed: %m");
163
exec_child(conn, args);
169
/* check script exit status */
170
if (waitpid(pid, &status, 0) < 0) {
171
i_error("waitpid() failed: %m");
173
} else if (WIFEXITED(status)) {
174
ret = WEXITSTATUS(status);
176
i_error("Script terminated abnormally, exit status %d", (int)ret);
179
} else if (WIFSIGNALED(status)) {
180
i_error("Script terminated abnormally, signal %d", WTERMSIG(status));
182
} else if (WIFSTOPPED(status)) {
183
i_fatal("Script stopped, signal %d", WSTOPSIG(status));
186
i_fatal("Script terminated abnormally, return status %d", status);
192
static void client_connected(struct master_service_connection *conn)
196
response[0] = client_exec_script(conn) ? '+' : '-';
198
if (write_full(conn->fd, &response, 2) < 0)
199
i_error("write(response) failed: %m");
94
202
int main(int argc, char *argv[])