Back to index

nordugrid-arc-nox  1.1.0~rc6
daemon.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <math.h>
00006 #include <sys/resource.h>
00007 #include <pwd.h>
00008 #include <grp.h>
00009 #include <sys/types.h>
00010 #include <sys/stat.h>
00011 #include <unistd.h>
00012 #include <fcntl.h>
00013 
00014 #include <arc/Utils.h>
00015 
00016 #include "../conf/conf.h"
00017 #include "../conf/environment.h"
00018 
00019 #include "daemon.h"
00020 
00021 #define DEFAULT_SERVICE_KEY   "/etc/grid-security/hostkey.pem"
00022 #define DEFAULT_SERVICE_CERT  "/etc/grid-security/hostcert.pem"
00023 #define DEFAULT_SERVICE_CADIR "/etc/grid-security/certificates"
00024 
00025 Daemon::Daemon(void):logfile_(""),logsize_(0),lognum_(5),uid_((uid_t)(-1)),gid_((gid_t)(-1)),daemon_(true),pidfile_(""),debug_(-1),logger_(Arc::Logger::getRootLogger()) {
00026   key_path_=Arc::GetEnv("X509_USER_KEY");
00027   cert_path_=Arc::GetEnv("X509_USER_CERT");
00028   cadir_path_=Arc::GetEnv("X509_CERT_DIR");
00029   if(key_path_.empty()) key_path_=DEFAULT_SERVICE_KEY;
00030   if(cert_path_.empty()) cert_path_=DEFAULT_SERVICE_CERT;
00031   if(cadir_path_.empty()) cadir_path_=DEFAULT_SERVICE_CADIR;
00032 }
00033 
00034 Daemon::~Daemon(void) {
00035 }
00036 
00037 int Daemon::arg(char c) {
00038   switch(c) {
00039     case 'F': {
00040       daemon_=false;
00041     }; break;
00042     case 'L': {
00043       logfile_=optarg;
00044     }; break;
00045     case 'U': {
00046       std::string username(optarg);
00047       std::string groupname("");
00048       std::string::size_type n = username.find(':');
00049       if(n != std::string::npos) { groupname=optarg+n+1; username.resize(n); };
00050       if(username.length() == 0) { uid_=0; gid_=0; } else {
00051         struct passwd pw_;
00052         struct passwd *pw;
00053         char buf[BUFSIZ];
00054         getpwnam_r(username.c_str(),&pw_,buf,BUFSIZ,&pw);
00055         if(pw == NULL) {
00056           logger_.msg(Arc::ERROR,"No such user: %s",username);
00057           uid_=0; gid_=0; return -1;
00058         };
00059         uid_=pw->pw_uid;
00060         gid_=pw->pw_gid;
00061       };
00062       if(groupname.length() != 0) { 
00063         struct group gr_;
00064         struct group *gr;
00065         char buf[BUFSIZ];
00066         getgrnam_r(groupname.c_str(),&gr_,buf,BUFSIZ,&gr);
00067         if(gr == NULL) {
00068           logger_.msg(Arc::ERROR,"No such group: %s",groupname);
00069           gid_=0; return -1;
00070         };
00071         gid_=gr->gr_gid;
00072       };
00073     }; break;
00074     case 'P': {
00075       pidfile_=optarg;
00076     }; break;
00077     case 'd': {
00078       char* p;
00079       debug_ = strtol(optarg,&p,10);
00080       if(((*p) != 0) || (debug_<0)) {
00081         logger_.msg(Arc::ERROR,"Improper debug level '%s'",optarg);
00082         return 1;
00083       };
00084     }; break;
00085     default:
00086       return 1;
00087   };
00088   return 0;
00089 }
00090 
00091 int Daemon::config(const std::string& cmd,std::string& rest) {
00092   if(cmd == "gridmap") {
00093     Arc::SetEnv("GRIDMAP",rest); return 0;
00094   } else if(cmd == "hostname") {
00095     Arc::SetEnv("GLOBUS_HOSTNAME",rest); return 0;
00096   } else if(cmd == "globus_tcp_port_range") {
00097     Arc::SetEnv("GLOBUS_TCP_PORT_RANGE",rest); return 0;
00098   } else if(cmd == "globus_udp_port_range") {
00099     Arc::SetEnv("GLOBUS_UDP_PORT_RANGE",rest); return 0;
00100   } else if(cmd == "x509_user_key") {
00101     Arc::SetEnv("X509_USER_KEY",rest); return 0;
00102     key_path_=rest;
00103   } else if(cmd == "x509_user_cert") {
00104     Arc::SetEnv("X509_USER_CERT",rest); return 0;
00105     cert_path_=rest;
00106   } else if(cmd == "x509_cert_dir") {
00107     Arc::SetEnv("X509_CERT_DIR",rest); return 0;
00108     cadir_path_=rest;
00109   } else if(cmd == "http_proxy") {
00110     Arc::SetEnv("ARC_HTTP_PROXY",rest); return 0;
00111   };
00112   if(cmd == "daemon") {
00113     if(daemon_) {
00114       std::string arg = config_next_arg(rest);
00115       if(arg=="") {
00116         logger_.msg(Arc::ERROR,"Missing option for command daemon");
00117         return -1;
00118       };
00119       if(strcasecmp("yes",arg.c_str()) == 0) { daemon_=true; }
00120       else if(strcasecmp("no",arg.c_str()) == 0) { daemon_=false; }
00121       else { logger_.msg(Arc::ERROR,"Wrong option in daemon"); return -1; };
00122     };
00123   } else if(cmd == "logfile") {
00124     if(logfile_.length() == 0) logfile_=config_next_arg(rest);
00125   } else if(cmd == "logsize") {
00126     if(logsize_ == 0) {
00127       char* p;
00128       logsize_ = strtol(rest.c_str(),&p,10);
00129       if(logsize_ < 0) {
00130         logsize_=0;
00131         logger_.msg(Arc::ERROR,"Improper size of log '%s'",rest);
00132         return -1;
00133       };
00134       if((*p) == ' ') {
00135         for(;*p;++p) if((*p) != ' ') break;
00136         if(*p) {
00137           lognum_ = strtol(p,&p,10);
00138           if(lognum_ < 0) {
00139             logsize_=0; lognum_=0;
00140             logger_.msg(Arc::ERROR,"Improper number of logs '%s'",rest);
00141             return -1;
00142           };
00143         };
00144       } else if((*p) != 0) {
00145         logsize_=0; lognum_=0;
00146         logger_.msg(Arc::ERROR,"Improper argument for logsize '%s'",rest);
00147         return -1;
00148       };
00149     };
00150   } else if(cmd == "user") {
00151     if(uid_ == (uid_t)(-1)) {
00152       std::string username = config_next_arg(rest);
00153       std::string groupname("");
00154       std::string::size_type n = username.find(':');
00155       if(n != std::string::npos) { groupname=username.c_str()+n+1; username.resize(n); };
00156       if(username.length() == 0) { uid_=0; gid_=0; } else {
00157         struct passwd pw_;
00158         struct passwd *pw;
00159         char buf[BUFSIZ];
00160         getpwnam_r(username.c_str(),&pw_,buf,BUFSIZ,&pw);
00161 
00162         if(pw == NULL) {
00163           logger_.msg(Arc::ERROR,"No such user: %s",username);
00164           uid_=0; gid_=0; return -1;
00165         };
00166         uid_=pw->pw_uid;
00167         gid_=pw->pw_gid;
00168        };
00169       if(groupname.length() != 0) { 
00170         struct group gr_;
00171         struct group *gr;
00172         char buf[BUFSIZ];
00173         getgrnam_r(groupname.c_str(),&gr_,buf,BUFSIZ,&gr);
00174         if(gr == NULL) {
00175           logger_.msg(Arc::ERROR,"No such group: %s",groupname);
00176           gid_=0; return -1;
00177         };
00178         gid_=gr->gr_gid;
00179       };
00180     };
00181   } else if(cmd == "pidfile") {
00182     if(pidfile_.length() == 0) pidfile_=config_next_arg(rest);
00183   } else if(cmd == "debug") {
00184     if(debug_ == -1) {
00185       char* p;
00186       debug_ = strtol(rest.c_str(),&p,10);
00187       if(((*p) != 0) || (debug_<0)) {
00188         logger_.msg(Arc::ERROR,"Improper debug level '%s'",rest);
00189         return -1;
00190       };
00191     };
00192   } else {
00193     return 1;
00194   };
00195   return 0;
00196 }
00197 
00198 int Daemon::skip_config(const std::string& cmd) {
00199   if(cmd == "debug") return 0;
00200   if(cmd == "daemon") return 0;
00201   if(cmd == "logfile") return 0;
00202   if(cmd == "logsize") return 0;
00203   if(cmd == "user") return 0;
00204   if(cmd == "pidfile") return 0;
00205   return 1;
00206 }
00207 
00208 int Daemon::getopt(int argc, char * const argv[],const char *optstring) {
00209   int n;
00210   std::string opts(optstring);
00211   opts+=DAEMON_OPTS;
00212   while((n=::getopt(argc,argv,opts.c_str())) != -1) {
00213     switch(n) {
00214       case 'F':
00215       case 'L':
00216       case 'U':
00217       case 'P':
00218       case 'd': {
00219         if(arg(n) != 0) return '.';
00220       }; break;
00221       default: return n;
00222     };
00223   };
00224   return -1;
00225 }
00226 
00227 int Daemon::daemon(bool close_fds) {
00228   if(close_fds) {
00229     struct rlimit lim;
00230     int max_files;
00231     if(getrlimit(RLIMIT_NOFILE,&lim) == 0) { max_files=lim.rlim_cur; }
00232     else { max_files=4096; };
00233     if(max_files == RLIM_INFINITY) max_files=4096;
00234     for(int i=3;i<max_files;i++) { close(i); };
00235   };
00236   {
00237     close(0);
00238     int h=::open("/dev/null",O_RDONLY);
00239     if(h != 0) {
00240       if(h != -1) {
00241         int hh = dup2(h,0); if(hh != 0) { if(hh != -1) close(hh); };
00242         close(h);
00243       };
00244     };
00245   };
00246   const char* log = logfile_.c_str();
00247   if(daemon_) { if(log[0] == 0) log="/dev/null"; };
00248   if(log[0] != 0) {
00249     close(1); close(2);
00250     int h=::open(log,O_WRONLY | O_CREAT | O_APPEND,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
00251     if(h != 1) {
00252       if(h != -1) {
00253         int hh = dup2(h,1); if(hh != 1) { if(hh != -1) close(hh); };
00254         hh=dup2(h,2); if(hh != 2) { if(hh != -1) close(hh); };
00255         close(h);
00256       };
00257     } else {
00258       int hh = dup2(h,2); if(hh != 2) { if(hh != -1) close(hh); };
00259     };
00260   } else {  // old stderr
00261     close(1);
00262     int hh = dup2(2,1); if(hh != 1) { if(hh != -1) close(hh); };
00263   };
00264   int hp = -1;
00265   if(pidfile_.length() != 0) hp=::open(pidfile_.c_str(),O_WRONLY | O_CREAT | O_TRUNC,S_IRUSR | S_IWUSR);
00266   if((uid_ != (uid_t)(-1)) && (uid_ != 0)) setuid(uid_);
00267   if((gid_ != (gid_t)(-1)) && (gid_ != 0)) setgid(gid_);
00268   if(debug_ != -1) {
00269     int d=debug_; 
00270     int l=Arc::FATAL;
00271     for(;d>0;--d) l>>=1;
00272     logger_.setThreshold((Arc::LogLevel)l);
00273   };
00274   if(!logfile_.empty()) {
00275     logger_.removeDestinations();
00276     logger_.addDestination(*(new Arc::LogStream(*(new std::ofstream(logfile_.c_str())))));
00277     // TODO: logsize_, lognum_
00278   };
00279   int r = 0;
00280   if(daemon_) {
00281 #ifdef HAVE_DAEMON
00282     r=::daemon(1,1);
00283 #else
00284     r=::fork();
00285     if(r == 0) {
00286       // child
00287       r=setsid();
00288       if(r != -1) r=0;
00289     } else if(r != -1) {
00290       // parent
00291       _exit(0);
00292     };
00293 #endif
00294   };
00295   if(r != 0) return r;
00296   if(hp != -1) {
00297     char buf[30]; int l = snprintf(buf,29,"%u",getpid()); buf[l]=0;
00298     (::write(hp,buf,l) != -1);
00299     ::close(hp);
00300   };
00301   return 0;
00302 }
00303 
00304 const char* Daemon::short_help(void) {
00305   return "[-F] [-U user[:group]] [-L logfile] [-P pidfile] [-d level]";
00306 }
00307 
00308 void Daemon::logfile(const char* path) {
00309   if(logfile_.length() == 0) logfile_=path;
00310 }
00311 
00312 void Daemon::pidfile(const char* path) {
00313   if(pidfile_.length() == 0) pidfile_=path;
00314 }
00315