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 conffile Mutable configuration file, created if it does not exist" << endl
00130 << " if it does however it must contain valid SQLite database" << endl
00131 << " -d conffile Default configuration file, created if it does not exist" << endl
00132 << " if it does however it must contain valid SQLite database" << endl
00133 << " -q[qqq] Quiet mode, -q omits debug, -qq debug and info," << endl
00134 << " -qqq omit debug, info and warn, -qqqq no output of logger" << endl
00135 << " -l level Set log level directly mutually exclusive with -q" << endl
00136 << " level is one of debug, info, warn, error and none" << endl
00137 << " -L loggers Define loggers. By default this setting is read from " << endl
00138 << " config file (or console logger if unset in config)." << endl
00139 << " format for loggers is: logger:args[;logger2:args2[!...]]" << endl
00140 << " the loggeroptions depend on the logger. Currently supported:" << endl
00141 << " console (default), file:file.log, network logger always starts" << endl
00142 << " -p plugins Comma-separated list of plugins, for example " << endl
00143 << " fvbase,fvfountain,fvretriever. These plugins will be loaded" << endl
00144 << " in the given order after startup." << endl
00145 << " -u user Drop privileges as soon as possible and run as given user." << endl
00146 << " -g group Drop privileges as soon as possible and run as given group." << endl
00147 #ifdef HAVE_LIBDAEMON
00148 << " -D[pid file] Run daemonized in the background, pid file is optional, " << endl
00149 << " defaults to /var/run/fawkes.pid, must be absolute path." << endl
00150 << " -D[pid file] -k Kill a daemonized process running in the background," << endl
00151 << " pid file is optional as above." << endl
00152 << " -D[pid file] -s Check status of daemon." << endl
00153 #endif
00154 << endl;
00155 }
00156
00157
00158 #ifdef HAVE_LIBDAEMON
00159 void
00160 daemonize_cleanup()
00161 {
00162 daemon_retval_send(-1);
00163 daemon_retval_done();
00164 daemon_pid_file_remove();
00165 }
00166
00167 pid_t
00168 daemonize(int argc, char **argv)
00169 {
00170 pid_t pid;
00171 mode_t old_umask = umask(0);
00172
00173
00174 daemon_retval_init();
00175
00176
00177 if ((pid = daemon_fork()) < 0) {
00178 return -1;
00179
00180 } else if (pid) {
00181 int ret;
00182
00183
00184 if ((ret = daemon_retval_wait(20)) < 0) {
00185 daemon_log(LOG_ERR, "Could not recieve return value from daemon process.");
00186 return -1;
00187 }
00188
00189 if ( ret != 0 ) {
00190 daemon_log(LOG_ERR, "*** Daemon startup failed, see syslog for details. ***");
00191 switch (ret) {
00192 case 1:
00193 daemon_log(LOG_ERR, "Daemon failed to close file descriptors");
00194 break;
00195 case 2:
00196 daemon_log(LOG_ERR, "Daemon failed to create PID file");
00197 break;
00198 }
00199 return -1;
00200 } else {
00201 return pid;
00202 }
00203
00204 } else {
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
00212
00213 if (daemon_pid_file_create() < 0) {
00214 printf("Could not create PID file (%s).", strerror(errno));
00215 daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
00216
00217
00218 daemon_retval_send(2);
00219 return -1;
00220 }
00221
00222
00223 daemon_retval_send(0);
00224
00225 daemon_log(LOG_INFO, "Sucessfully started");
00226
00227 umask(old_umask);
00228 return 0;
00229 }
00230 }
00231
00232
00233
00234 const char *fawkes_pid_file;
00235
00236
00237
00238
00239 const char *
00240 fawkes_daemon_pid_file_proc()
00241 {
00242 return fawkes_pid_file;
00243 }
00244 #endif // HAVE_LIBDAEMON
00245
00246
00247
00248
00249
00250 int
00251 main(int argc, char **argv)
00252 {
00253 ArgumentParser *argp = new ArgumentParser(argc, argv, "hCc:d:q::l:L:p:D::ksu:g:");
00254
00255
00256 const char *user = NULL;
00257 const char *group = NULL;
00258 if (argp->has_arg("u")) {
00259 user = argp->arg("u");
00260 }
00261 if (argp->has_arg("g")) {
00262 group = argp->arg("g");
00263 }
00264
00265 #ifdef HAVE_LIBDAEMON
00266 pid_t pid;
00267 int ret;
00268
00269 if ( argp->has_arg("D") ) {
00270
00271 daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
00272 if ( argp->arg("D") != NULL ) {
00273 fawkes_pid_file = argp->arg("D");
00274 daemon_pid_file_proc = fawkes_daemon_pid_file_proc;
00275 }
00276
00277
00278 if ( argp->has_arg("k") ) {
00279
00280 if ((pid = daemon_pid_file_is_running()) < 0) {
00281 daemon_log(LOG_ERR, "Fawkes daemon not running.");
00282 return 1;
00283 }
00284
00285
00286 if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) {
00287 daemon_log(LOG_WARNING, "Failed to kill daemon");
00288 }
00289 return (ret < 0) ? 1 : 0;
00290 }
00291
00292 if ( argp->has_arg("s") ) {
00293
00294 return (daemon_pid_file_is_running() < 0);
00295 }
00296
00297
00298 if ((pid = daemon_pid_file_is_running()) >= 0) {
00299 daemon_log(LOG_ERR, "Daemon already running on (PID %u)", pid);
00300 return 201;
00301 }
00302
00303 pid = daemonize(argc, argv);
00304 if ( pid < 0 ) {
00305 daemonize_cleanup();
00306 return 201;
00307 } else if (pid) {
00308
00309 return 0;
00310 }
00311 }
00312 #else
00313 if ( argp->has_arg("D") ) {
00314 printf("Daemonizing support is not available.\n"
00315 "(libdaemon[-devel] was not available at compile time)\n");
00316 return 202;
00317 }
00318 #endif
00319
00320 if (user != NULL) {
00321 struct passwd *pw;
00322 if (! (pw = getpwnam(user))) {
00323 printf("Failed to find user %s, check -u argument.\n", user);
00324 return 203;
00325 }
00326 int r = 0;
00327 r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid);
00328 if (r < 0) {
00329 perror("Failed to drop privileges (user)");
00330 }
00331 }
00332
00333 if (group != NULL) {
00334 struct group *gr;
00335 if (! (gr = getgrnam(group))) {
00336 printf("Failed to find group %s, check -g argument.\n", user);
00337 return 204;
00338 }
00339 int r = 0;
00340 r = setresgid(gr->gr_gid, gr->gr_gid, gr->gr_gid);
00341 if (r < 0) {
00342 perror("Failed to drop privileges (group)");
00343 }
00344 }
00345
00346 Thread::init_main();
00347
00348 if ( argp->has_arg("h") ) {
00349 usage(argv[0]);
00350 delete argp;
00351 return 0;
00352 }
00353
00354 FawkesMainApp fawkes;
00355 SignalManager::register_handler(SIGINT, &fawkes);
00356 SignalManager::register_handler(SIGTERM, &fawkes);
00357
00358 try {
00359 fawkes.run(argp);
00360 } catch (Exception &e) {
00361 printf("Running Fawkes failed\n");
00362 e.print_trace();
00363 }
00364
00365 Thread::destroy_main();
00366
00367 #ifdef HAVE_LIBDAEMON
00368 if ( argp->has_arg("D") ) {
00369 daemonize_cleanup();
00370 }
00371 #endif
00372
00373 delete argp;
00374 return 0;
00375 }