Fix compile errors in clam.cxx and inoclam.cxx
[inoclam.git] / src / inoclam.cxx
blobf45b293eed3407d01d97e968fd41f46b42547b60
1 /*
2 * inoclam - Inotify+ClamAV virus scanner
3 * Copyright (C) 2007, 2008 Vermont Department of Taxes
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <list>
20 #include <iterator>
21 #include <errno.h>
22 #include <getopt.h>
23 #include <string.h>
24 #include <iostream>
25 #include <libdaemon/dlog.h>
26 #include <libdaemon/dpid.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
34 #include "config.hxx"
35 #include "clam.hxx"
36 #include "inoclam.hxx"
37 #include "inotify.hxx"
38 #include "monitor.hxx"
39 #include "signal.hxx"
40 #include "smtp.hxx"
42 /**
43 * Determines if gatewayavd should run in the background (daemonized) or
44 * not. If daemonize is 1, then gatewayavd should run in the background.
46 int daemonize;
48 /**
49 * Determines if our process killed a running inoclam process successfully.
51 int killed;
53 /**
54 * Displays some version and copyright information upon request (-v or --version).
56 void display_version()
58 daemon_log(LOG_INFO, "inoclam v%s (%s)", VERSION, CODENAME);
59 daemon_log(LOG_INFO, "Copyright (C) 2007 Vermont Department of Taxes");
60 daemon_log(LOG_INFO, "This is free software; see the source for copying conditions. There is NO");
61 daemon_log(LOG_INFO, "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
64 /**
65 * Displays some usage information, command line parameters and whatnot.
66 * @param program the name of the program.
68 void display_help(char *program)
70 daemon_log(LOG_INFO, "Usage: %s [options]", program);
71 daemon_log(LOG_INFO, "Options:");
72 daemon_log(LOG_INFO, " -c --config=[FILE] Specifiy an alternate config location");
73 daemon_log(LOG_INFO, " -f --foreground Run in the foreground");
74 daemon_log(LOG_INFO, " -h --help Show this help message");
75 daemon_log(LOG_INFO, " -k --kill Kill the running instance");
76 daemon_log(LOG_INFO, " -v --version Show version information");
79 /**
80 * A command line parser using getopts.
81 * @param argc The number of command line arguments coming in argv.
82 * @param argv The command line arguments.
83 * @return Returns 0 on success and non-zero when we want the program to terminate.
85 int parse_args(int argc, char **argv)
87 int option_index;
88 int done;
90 static struct option long_options[] = {
91 {"help", no_argument, 0, 'h'},
92 {"version", no_argument, 0, 'v'},
93 {"kill", no_argument, 0, 'k'},
94 {"foreground", no_argument, 0, 'f'},
95 {"config", required_argument, 0, 'c'},
96 {0, 0, 0, 0}
99 option_index = 0;
100 done = 0;
102 while (!done) {
103 int c;
104 int ret;
106 c = getopt_long(argc, argv, "hvkfc:", long_options, &option_index);
107 if (c < 0) {
108 break;
111 switch (c) {
112 case 'c':
113 if (configfile) {
114 free(configfile);
115 configfile = NULL;
117 configfile = strdup(optarg);
118 break;
119 case 'h':
120 display_help(argv[0]);
121 done = 1;
122 break;
123 case 'v':
124 display_version();
125 done = 1;
126 break;
127 case 'k':
128 ret = daemon_pid_file_kill_wait(SIGQUIT, 30);
129 if (ret < 0) {
130 daemon_log(LOG_ERR, "Daemon not killed: (%s)", strerror(errno));
131 } else {
132 killed = 1;
134 done = 1;
135 break;
136 case 'f':
137 daemonize = 0;
138 break;
139 default:
140 daemon_log(LOG_ERR, "Unsupported option");
141 done = 1;
142 break;
146 return done;
149 int main(int argc, char *argv[], char *envp[])
151 int fd;
152 int ret;
153 pid_t pid;
154 pthread_t watch_thread;
155 pthread_attr_t watch_thread_attr;
157 /* Default Values for Global Variables */
158 daemonize = 1;
159 killed = 0;
160 exit_now = 0;
161 configfile = strdup(DEFAULT_CONFIGFILE);
163 /* Sanity Checks */
164 if (argc < 1 || !argv || !argv[0]) {
165 daemon_log(LOG_ERR, "(%u:%s) Cannot determine program name from argv[0]\n");
166 return 1;
169 daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
171 if (geteuid() != 0) {
172 daemon_log(LOG_ERR, "You need root privileges to run this application.");
173 return 1;
176 /* Command Line Arguements */
177 ret = parse_args(argc, argv);
178 if (ret) {
179 return (killed ? 0 : ret);
182 pid = daemon_pid_file_is_running();
183 if (pid > 0) {
184 daemon_log(LOG_ERR, "%s is already running (PID => %u)", argv[0], daemon_log_ident, pid);
185 daemon_log(LOG_INFO, "Use `%s -k` to kill the running instance", daemon_log_ident);
186 return 1;
189 /* Daemonize */
190 if (daemonize) {
191 /* Configure Logging */
192 daemon_log_use = DAEMON_LOG_SYSLOG;
194 umask(0);
196 pid = fork();
197 if (pid < 0) {
198 return 1;
199 } else if (pid > 0) {
200 return 0;
203 setsid();
205 pid = fork();
206 if (pid < 0) {
207 return 1;
208 } else if (pid > 0) {
209 return 0;
212 ret = chdir("/");
213 if (ret < 0) {
214 daemon_log(LOG_ERR, "Could not chdir() to '/': %s", strerror(errno));
215 return 1;
218 /* close open file descriptors */
219 for (fd = 0; fd < getdtablesize(); fd++) {
220 ret = close(fd);
221 if (ret == -1 && errno != EBADF) {
222 daemon_log(LOG_ERR, "Could not close fd #%d: %s", fd, strerror(errno));
223 return 1;
227 /* re-open stdin, stdout, stderr */
228 fd = open("/dev/null", O_RDONLY);
229 fd = open("/dev/null", O_WRONLY);
230 fd = open("/dev/null", O_WRONLY);
233 ret = daemon_pid_file_create();
234 if (ret < 0) {
235 daemon_log(LOG_ERR, "Could not create PID file: %s", strerror(errno));
236 return 1;
239 /* this must run before any threads are created */
240 monitor_init();
242 /* Configure */
243 std::list < config::config * >*conf;
244 conf = config_parse();
245 if (configfile) {
246 free(configfile);
247 configfile = NULL;
250 /* Install Signal Handlers */
251 install_signal_handlers();
253 /* Initialize Virus Detection Engine and Load Virus Definitions */
254 clam *clamav;
255 clamav = new clam();
257 pthread_attr_init(&watch_thread_attr);
258 pthread_attr_setdetachstate(&watch_thread_attr, PTHREAD_CREATE_DETACHED);
260 for (std::list < config::config * >::iterator itr = conf->begin(); itr != conf->end(); ++itr) {
262 inotify_main_args_t *args;
263 args = (inotify_main_args_t *) malloc(sizeof(inotify_main_args_t));
264 if (!args) {
265 daemon_log(LOG_ERR, "MALLOC FAILED!");
266 exit_now = 1;
267 } else {
268 args->conf = *itr;
269 args->clamav = clamav;
271 monitor_inc();
272 ret = pthread_create(&watch_thread, &watch_thread_attr, inotify_main, (void *) args);
273 if (ret) {
274 monitor_dec();
275 daemon_log(LOG_ERR, "Can't create watch thread: %s", strerror(errno));
276 exit_now = 1;
281 while (!exit_now) {
282 sleep(3);
283 sched_yield();
286 monitor_wait(); /* thread cleanup */
288 /* Free resources used by libclamav */
289 delete clamav;
291 for (std::list < config::config * >::iterator itr = conf->begin(); itr != conf->end(); ++itr) {
292 delete *itr;
295 delete conf;
296 daemon_pid_file_remove();
298 daemon_log(LOG_INFO, "Exiting...");
299 return 0;