forked from atheme/atheme-contrib-modules
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathon_db_save.c
144 lines (120 loc) · 3.24 KB
/
on_db_save.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "atheme-compat.h"
#include "conf.h"
#include "datastream.h"
#ifndef _WIN32
DECLARE_MODULE_V1
(
"contrib/on_db_save", false, _modinit, _moddeinit,
"",
"Atheme Development Group <http://www.atheme.org>"
);
static char *command = NULL;
static void on_db_save(void *unused);
static struct update_command_state {
connection_t *out, *err;
pid_t pid;
int running;
} update_command_proc;
void _modinit(module_t *m)
{
hook_add_event("db_saved");
hook_add_db_saved(on_db_save);
add_dupstr_conf_item("db_update_command", &conf_gi_table, 0, &command, NULL);
}
void _moddeinit(module_unload_intent_t intent)
{
hook_del_db_saved(on_db_save);
del_conf_item("db_update_command", &conf_gi_table);
}
static void update_command_finished(pid_t pid, int status, void *data)
{
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
slog(LG_ERROR, "ERROR: Database update command failed with error %d", WEXITSTATUS(status));
update_command_proc.running = 0;
}
static void update_command_recvq_handler(connection_t *cptr, int err)
{
char buf[BUFSIZE];
int count;
count = recvq_getline(cptr, buf, sizeof(buf) - 1);
if (count <= 0)
return;
if (buf[count-1] == '\n')
count--;
if (count == 0)
buf[count++] = ' ';
buf[count] = '\0';
if (err)
{
slog(LG_ERROR, "ERROR: database update command said: %s", buf);
}
else
slog(LG_DEBUG, "db update command stdout: %s", buf);
}
static void update_command_stdout_handler(connection_t *cptr)
{
update_command_recvq_handler(cptr, 0);
}
static void update_command_stderr_handler(connection_t *cptr)
{
update_command_recvq_handler(cptr, 1);
}
static void on_db_save(void *unused)
{
int stdout_pipes[2], stderr_pipes[2];
pid_t pid;
int errno1;
if (!command)
return;
if (update_command_proc.running)
{
slog(LG_ERROR, "ERROR: database update command is still running");
return;
}
if (pipe(stdout_pipes) == -1)
{
int err = errno;
slog(LG_ERROR, "ERROR: Couldn't create pipe for database update command: %s", strerror(err));
return;
}
if (pipe(stderr_pipes) == -1)
{
int err = errno;
slog(LG_ERROR, "ERROR: Couldn't create pipe for database update command: %s", strerror(err));
close(stdout_pipes[0]);
close(stdout_pipes[1]);
return;
}
pid = fork();
switch (pid)
{
case -1:
errno1 = errno;
slog(LG_ERROR, "Failed to fork for database update command: %s", strerror(errno1));
return;
case 0:
connection_close_all_fds();
close(stdout_pipes[0]);
close(stderr_pipes[0]);
dup2(stdout_pipes[1], 1);
dup2(stderr_pipes[1], 2);
close(stdout_pipes[1]);
close(stderr_pipes[1]);
execl("/bin/sh", "sh", "-c", command, NULL);
write(2, "Failed to exec /bin/sh\n", 23);
_exit(255);
return;
default:
close(stdout_pipes[1]);
close(stderr_pipes[1]);
update_command_proc.out = connection_add("update_command_stdout", stdout_pipes[0], 0, recvq_put, NULL);
update_command_proc.err = connection_add("update_command_stderr", stderr_pipes[0], 0, recvq_put, NULL);
update_command_proc.out->recvq_handler = update_command_stdout_handler;
update_command_proc.err->recvq_handler = update_command_stderr_handler;
update_command_proc.pid = pid;
update_command_proc.running = 1;
childproc_add(pid, "db_update", update_command_finished, NULL);
break;
}
}
#endif