00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <mainapp/main_thread.h>
00025 #include <utils/system/signal.h>
00026 #include <utils/system/argparser.h>
00027 #include <core/threading/mutex.h>
00028 #include <core/threading/mutex_locker.h>
00029
00030 #include <iostream>
00031 #include <cstdlib>
00032 #include <cstdio>
00033 #include <unistd.h>
00034 #include <pwd.h>
00035 #include <grp.h>
00036 #include <sys/types.h>
00037 #ifdef HAVE_LIBDAEMON
00038 # include <cerrno>
00039 # include <cstring>
00040 # include <libdaemon/dfork.h>
00041 # include <libdaemon/dlog.h>
00042 # include <libdaemon/dpid.h>
00043 # include <sys/stat.h>
00044 # include <sys/wait.h>
00045 #endif
00046
00047 using namespace std;
00048 using namespace fawkes;
00049
00050
00051
00052
00053
00054 class FawkesMainApp : public SignalHandler
00055 {
00056 public:
00057
00058
00059 FawkesMainApp()
00060 {
00061 __init_running = true;
00062 __init_quit = false;
00063 __sigint_running = false;
00064 }
00065
00066
00067
00068
00069 void run(ArgumentParser *argp)
00070 {
00071 try {
00072 fmt = new FawkesMainThread(argp);
00073 } catch (Exception &e) {
00074 throw;
00075 }
00076
00077 __init_mutex.lock();
00078 __init_running = false;
00079 if ( ! __init_quit ) {
00080 fmt->start();
00081 __init_mutex.unlock();
00082 fmt->join();
00083 } else {
00084 __init_mutex.unlock();
00085 }
00086
00087 delete fmt;
00088 }
00089
00090
00091
00092
00093 void handle_signal(int signum)
00094 {
00095 if ((signum == SIGINT) && ! __sigint_running) {
00096 printf("\nFawkes: SIGINT received, shutting down.\n"
00097 "Hit Ctrl-C again to force immediate exit.\n\n");
00098 MutexLocker lock(&__init_mutex);
00099 if (__init_running) {
00100 __init_quit = true;
00101 } else {
00102 fmt->cancel();
00103 }
00104 __sigint_running = true;
00105 } else if ((signum == SIGTERM) || __sigint_running) {
00106
00107 exit(-2);
00108 }
00109 }
00110
00111 private:
00112 FawkesMainThread *fmt;
00113 Mutex __init_mutex;
00114 bool __init_running;
00115 bool __init_quit;
00116 bool __sigint_running;
00117 };
00118
00119
00120 void
00121 usage(const char *progname)
00122 {
00123 cout << "Fawkes Main Application - Usage Instructions" << endl
00124 << "===============================================================================" << endl
00125 << "Call with: " << progname << " [options]" << endl
00126 << "where [options] is one or more of:" << endl
00127 << " -h These help instructions" << endl
00128 << " -C Cleanup old BB segments" << endl
00129 << " -c db-file Mutable configuration file, created if it does not exist" << endl
00130 << " if it does however it must contain valid SQLite database" << endl
00131 << " -d sql-file Default configuration SQL dump file." << endl
00132 << " -q[qqq] Quiet mode, -q omits debug, -qq debug and info," << endl
00133 << " -qqq omit debug, info and warn, -qqqq no output of logger" << endl
00134 << " -l level Set log level directly mutually exclusive with -q" << endl
00135 << " level is one of debug, info, warn, error and none" << endl
00136 << " -L loggers Define loggers. By default this setting is read from " << endl
00137 << " config file (or console logger if unset in config)." << endl
00138 << " format for loggers is: logger:args[;logger2:args2[!...]]" << endl
00139 << " the loggeroptions depend on the logger. Currently supported:" << endl
00140 << " console (default), file:file.log, network logger always starts" << endl
00141 << " -p plugins Comma-separated list of plugins, for example " << endl
00142 << " fvbase,fvfountain,fvretriever. These plugins will be loaded" << endl
00143 << " in the given order after startup." << endl
00144 << " -u user Drop privileges as soon as possible and run as given user." << endl
00145 << " -g group Drop privileges as soon as possible and run as given group." << endl
00146 #ifdef HAVE_LIBDAEMON
00147 << " -D[pid file] Run daemonized in the background, pid file is optional, " << endl
00148 << " defaults to /var/run/fawkes.pid, must be absolute path." << endl
00149 << " -D[pid file] -k Kill a daemonized process running in the background," << endl
00150 << " pid file is optional as above." << endl
00151 << " -D[pid file] -s Check status of daemon." << endl
00152 #endif
00153 << endl;
00154 }
00155
00156
00157 #ifdef HAVE_LIBDAEMON
00158 void
00159 daemonize_cleanup()
00160 {
00161 daemon_retval_send(-1);
00162 daemon_retval_done();
00163 daemon_pid_file_remove();
00164 }
00165
00166 pid_t
00167 daemonize(int argc, char **argv)
00168 {
00169 pid_t pid;
00170 mode_t old_umask = umask(0);
00171
00172
00173 daemon_retval_init();
00174
00175
00176 if ((pid = daemon_fork()) < 0) {
00177 return -1;
00178
00179 } else if (pid) {
00180 int ret;
00181
00182
00183 if ((ret = daemon_retval_wait(20)) < 0) {
00184 daemon_log(LOG_ERR, "Could not recieve return value from daemon process.");
00185 return -1;
00186 }
00187
00188 if ( ret != 0 ) {
00189 daemon_log(LOG_ERR, "*** Daemon startup failed, see syslog for details. ***");
00190 switch (ret) {
00191 case 1:
00192 daemon_log(LOG_ERR, "Daemon failed to close file descriptors");
00193 break;
00194 case 2:
00195 daemon_log(LOG_ERR, "Daemon failed to create PID file");
00196 break;
00197 }
00198 return -1;
00199 } else {
00200 return pid;
00201 }
00202
00203 } else {
00204 #ifdef DAEMON_CLOSE_ALL_AVAILABLE
00205 if (daemon_close_all(-1) < 0) {
00206 daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
00207
00208 daemon_retval_send(1);
00209 return -1;
00210 }
00211 #endif
00212
00213
00214 if (daemon_pid_file_create() < 0) {
00215 printf("Could not create PID file (%s).", strerror(errno));
00216 daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
00217
00218
00219 daemon_retval_send(2);
00220 return -1;
00221 }
00222
00223
00224 daemon_retval_send(0);
00225
00226 daemon_log(LOG_INFO, "Sucessfully started");
00227
00228 umask(old_umask);
00229 return 0;
00230 }
00231 }
00232
00233
00234
00235 const char *fawkes_pid_file;
00236
00237
00238
00239
00240 const char *
00241 fawkes_daemon_pid_file_proc()
00242 {
00243 return fawkes_pid_file;
00244 }
00245 #endif // HAVE_LIBDAEMON
00246
00247
00248
00249
00250
00251 int
00252 main(int argc, char **argv)
00253 {
00254 ArgumentParser *argp = NULL;
00255 try {
00256 argp = new ArgumentParser(argc, argv, "hCc:d:q::l:L:p:D::ksu:g:");
00257 }
00258 catch (UnknownArgumentException &e) {
00259 cout << endl;
00260 usage(argv[0]);
00261 delete argp;
00262 return -1;
00263 }
00264
00265
00266 const char *user = NULL;
00267 const char *group = NULL;
00268 if (argp->has_arg("u")) {
00269 user = argp->arg("u");
00270 }
00271 if (argp->has_arg("g")) {
00272 group = argp->arg("g");
00273 }
00274
00275 #ifdef HAVE_LIBDAEMON
00276 pid_t pid;
00277 int ret;
00278
00279 if ( argp->has_arg("D") ) {
00280
00281 daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
00282 if ( argp->arg("D") != NULL ) {
00283 fawkes_pid_file = argp->arg("D");
00284 daemon_pid_file_proc = fawkes_daemon_pid_file_proc;
00285 }
00286
00287
00288 if ( argp->has_arg("k") ) {
00289
00290 if ((pid = daemon_pid_file_is_running()) < 0) {
00291 daemon_log(LOG_ERR, "Fawkes daemon not running.");
00292 return 1;
00293 }
00294
00295
00296 if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) {
00297 daemon_log(LOG_WARNING, "Failed to kill daemon");
00298 }
00299 return (ret < 0) ? 1 : 0;
00300 }
00301
00302 if ( argp->has_arg("s") ) {
00303
00304 return (daemon_pid_file_is_running() < 0);
00305 }
00306
00307
00308 if ((pid = daemon_pid_file_is_running()) >= 0) {
00309 daemon_log(LOG_ERR, "Daemon already running on (PID %u)", pid);
00310 return 201;
00311 }
00312
00313 pid = daemonize(argc, argv);
00314 if ( pid < 0 ) {
00315 daemonize_cleanup();
00316 return 201;
00317 } else if (pid) {
00318
00319 return 0;
00320 }
00321 }
00322 #else
00323 if ( argp->has_arg("D") ) {
00324 printf("Daemonizing support is not available.\n"
00325 "(libdaemon[-devel] was not available at compile time)\n");
00326 return 202;
00327 }
00328 #endif
00329
00330 if (user != NULL) {
00331 struct passwd *pw;
00332 if (! (pw = getpwnam(user))) {
00333 printf("Failed to find user %s, check -u argument.\n", user);
00334 return 203;
00335 }
00336 int r = 0;
00337 r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid);
00338 if (r < 0) {
00339 perror("Failed to drop privileges (user)");
00340 }
00341 }
00342
00343 if (group != NULL) {
00344 struct group *gr;
00345 if (! (gr = getgrnam(group))) {
00346 printf("Failed to find group %s, check -g argument.\n", user);
00347 return 204;
00348 }
00349 int r = 0;
00350 r = setresgid(gr->gr_gid, gr->gr_gid, gr->gr_gid);
00351 if (r < 0) {
00352 perror("Failed to drop privileges (group)");
00353 }
00354 }
00355
00356 Thread::init_main();
00357
00358 if ( argp->has_arg("h") ) {
00359 usage(argv[0]);
00360 delete argp;
00361 return 0;
00362 }
00363
00364 FawkesMainApp fawkes;
00365 SignalManager::register_handler(SIGINT, &fawkes);
00366 SignalManager::register_handler(SIGTERM, &fawkes);
00367
00368 try {
00369 fawkes.run(argp);
00370 } catch (Exception &e) {
00371 printf("Running Fawkes failed\n");
00372 e.print_trace();
00373 }
00374
00375 Thread::destroy_main();
00376
00377 #ifdef HAVE_LIBDAEMON
00378 if ( argp->has_arg("D") ) {
00379 daemonize_cleanup();
00380 }
00381 #endif
00382
00383 delete argp;
00384 return 0;
00385 }