Annotation of acopm/src/acopm.c, Revision 1.1.1.1
1.1 bountyht 1: /*
2: * Copyright (C) 2017 Aaron M. D. Jones <aaronmdjones@gmail.com>
3: *
4: * Redistribution and use in source and binary forms, with or without
5: * modification, are permitted provided that the following
6: * conditions are met:
7: *
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: *
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * 3. Neither the name of the copyright holder nor the names of its
16: * contributors may be used to endorse or promote products derived from
17: * this software without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20: * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22: * PARTICULAR PURPOSE ARE DISCLAIMED.
23: *
24: * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
25: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31: * POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34: #include "acopm-common.h"
35:
36: #include <assert.h> /* assert() */
37: #include <errno.h> /* errno */
38: #include <inttypes.h> /* PRIu16 */
39: #include <string.h> /* strerror() */
40: #include <strings.h> /* strcasecmp() */
41: #include <unistd.h> /* getuid(), geteuid() */
42:
43: #include "acopm.h" /* EVENT_LOG_* */
44: #include "check.h" /* acopm_check_user() */
45: #include "config.h" /* acopm_config_parse() */
46: #include "daemon.h" /* acopm_daemonise() */
47: #include "exec.h" /* acopm_exec_*() */
48: #include "options.h" /* acopm_parse_options(), ACOPM_OPT_* */
49: #include "signal.h" /* acopm_sighandle_*() */
50: #include "vars.h" /* global variable definitions */
51:
52: #include "irc/client.h" /* acopm_irc_*() */
53: #include "dnsbl/client.h" /* acopm_dnsbl_*() */
54: #include "proxy/client.h" /* acopm_proxy_*(), ACOPM_PROXY_TYPE_NONE */
55: #include "utils/log.h" /* acopm_log_*() */
56: #include "utils/misc.h" /* acopm_rng_*() */
57: #include "utils/siphash24.h" /* acopm_siphash24_setkey() */
58:
59: static char **argv_saved = NULL;
60: static int main_result = EXIT_FAILURE;
61:
62: static const char *const defconfig = ACOPM_CONFIG_FILE_DEFAULT;
63:
64: static inline bool acopm_attr_inline
65: acopm_siphash24_init(void)
66: {
67: (void) acopm_log_debug("%s: initialising hash subsystem", __func__);
68:
69: unsigned char sipkey24[SIPHASH24_KEY_LENGTH];
70: if (! acopm_rng_buf(sipkey24, sizeof sipkey24))
71: return false;
72:
73: return acopm_siphash24_setkey(sipkey24);
74: }
75:
76: static void
77: acopm_connect_cb(struct acopm_irc_client *const restrict client, const char *const restrict nickname,
78: const char *const restrict address)
79: {
80: assert(client == acopm_irc_client);
81:
82: (void) client;
83: (void) acopm_check_user(nickname, address);
84: }
85:
86: static void
87: acopm_command_cb(struct acopm_irc_client *const restrict client, const size_t argc, char **const restrict argv)
88: {
89: if ((argc == 1 || argc == 2) && strcasecmp(argv[0], "EXIT") == 0)
90: {
91: main_result = EXIT_SUCCESS;
92:
93: if (argc == 2)
94: {
95: char *endptr = NULL;
96: const unsigned long int code = strtoul(argv[1], &endptr, 10);
97:
98: assert(endptr != NULL);
99:
100: if (code <= INT_MAX && endptr && ! *endptr)
101: main_result = (int) code;
102: else
103: (void) acopm_irc_log(client, "Exit code '%s' invalid, using %d", argv[1], main_result);
104: }
105:
106: (void) event_base_loopbreak(ev_base);
107: return;
108: }
109:
110: if (argc == 1 && strcasecmp(argv[0], "PING") == 0)
111: {
112: (void) acopm_irc_log(client, "PONG");
113: return;
114: }
115: }
116:
117: static void acopm_attr_noreturn
118: acopm_restart_cb(void)
119: {
120: (void) acopm_log_notice("Restarting");
121: (void) execvp(argv_saved[0], argv_saved);
122: (void) acopm_log_critical("%s: execvp: %s", __func__, strerror(errno));
123: exit(1);
124: }
125:
126: static void acopm_attr_noreturn
127: acopm_event_crit_cb(const int err)
128: {
129: (void) acopm_log_critical("%s: libevent has failed with fatal error %d", __func__, err);
130:
131: acopm_restart_cb();
132: }
133:
134: static void
135: acopm_event_vlog_cb(const int ret, const char *const restrict msg)
136: {
137: switch (ret)
138: {
139: case EVENT_LOG_ERR:
140: (void) acopm_log_error("%s: libevent: %s (%d)", __func__, msg, ret);
141: return;
142:
143: case EVENT_LOG_WARN:
144: (void) acopm_log_warning("%s: libevent: %s (%d)", __func__, msg, ret);
145: return;
146:
147: case EVENT_LOG_MSG:
148: (void) acopm_log_info("%s: libevent: %s (%d)", __func__, msg, ret);
149: return;
150:
151: case EVENT_LOG_DEBUG:
152: (void) acopm_log_debug("%s: libevent: %s (%d)", __func__, msg, ret);
153: return;
154: }
155: }
156:
157: static inline bool acopm_attr_inline
158: acopm_evloop_init(void)
159: {
160: (void) acopm_log_debug("%s: initialising event loop", __func__);
161:
162: if (! (ev_base = event_base_new()))
163: {
164: (void) acopm_log_critical("%s: event_base_new: %s", __func__, strerror(errno));
165: return false;
166: }
167:
168: (void) event_set_fatal_callback(acopm_event_crit_cb);
169: (void) event_set_log_callback(acopm_event_vlog_cb);
170:
171: return true;
172: }
173:
174: static inline void acopm_attr_inline
175: acopm_evloop_free(void)
176: {
177: if (! ev_base)
178: return;
179:
180: (void) acopm_log_debug("%s: destroying event loop", __func__);
181: (void) event_base_free(ev_base);
182: ev_base = NULL;
183: }
184:
185: int
186: main(const int argc, char **const restrict argv)
187: {
188: if (! acopm_log_init())
189: goto end;
190:
191: switch (acopm_parse_options(argc, argv))
192: {
193: case ACOPM_OPT_PARSE_CONTINUE:
194: break;
195:
196: case ACOPM_OPT_PARSE_EXIT_SUCCESS:
197: return EXIT_SUCCESS;
198:
199: case ACOPM_OPT_PARSE_EXIT_FAILURE:
200: return EXIT_FAILURE;
201: }
202:
203: if ((getuid() == ((uid_t) 0)) || (geteuid() == ((uid_t) 0)))
204: {
205: (void) fprintf(stderr, "%s: do NOT run me as root!\n", argv[0]);
206: return EXIT_FAILURE;
207: }
208:
209: argv_saved = argv;
210:
211: #if defined(PACKAGE_NAME) && defined(PACKAGE_VERSION)
212: (void) acopm_log_info("This is %s version %s starting up", PACKAGE_NAME, PACKAGE_VERSION);
213: #endif
214:
215: if (! *config_file && ! acopm_strset_buf(config_file, defconfig))
216: (void) acopm_log_warning("%s: config file '%s' too long, truncated (BUG)", __func__, defconfig);
217:
218: if (! acopm_evloop_init())
219: goto end;
220: if (! acopm_sighandle_init())
221: goto end;
222: if (! acopm_rng_init())
223: goto end;
224: if (! acopm_siphash24_init())
225: goto end;
226: if (! acopm_check_init())
227: goto end;
228: if (! (acopm_irc_client = acopm_irc_new(ev_base, acopm_connect_cb, acopm_command_cb, acopm_restart_cb)))
229: goto end;
230: if (! (acopm_dnsbl_client = acopm_dnsbl_new(ev_base)))
231: goto end;
232: if (! (acopm_proxy_client = acopm_proxy_new(ev_base)))
233: goto end;
234: if (! acopm_config_parse())
235: goto end;
236: if (! acopm_exec_init())
237: goto end;
238: if (! acopm_irc_connect(acopm_irc_client))
239: goto end;
240: if (! acopm_daemonise())
241: goto end;
242:
243: (void) acopm_log_info("Entering event loop");
244: (void) event_base_dispatch(ev_base);
245:
246: if (main_result == EXIT_SUCCESS)
247: (void) acopm_log_info("Leaving event loop");
248: else
249: (void) acopm_log_warning("Leaving event loop");
250:
251: end:
252: (void) acopm_exec_free();
253:
254: if (acopm_proxy_client)
255: (void) acopm_proxy_free(acopm_proxy_client);
256:
257: if (acopm_dnsbl_client)
258: (void) acopm_dnsbl_free(acopm_dnsbl_client);
259:
260: if (acopm_irc_client)
261: (void) acopm_irc_free(acopm_irc_client);
262:
263: (void) acopm_check_free();
264: (void) acopm_rng_free();
265: (void) acopm_sighandle_free();
266: (void) acopm_evloop_free();
267: (void) acopm_log_free();
268:
269: return main_result;
270: }
CVSweb