#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ninacerr.h" using namespace std; static const char *logfile = "/var/log/ninac/ninac.log"; static const char *master = NULL; static const char *target = NULL; static const char *task = NULL; static const char *script = NULL; static bool force = false; static void handle_sig(int sig){ fprintf(stderr, "ninacexec: Received signal %d\n", sig) ; } static FILE *ninacexec_open (const SSTRING &fname) { FILE *ret = fopen (fname.c_str(),"a"); if (ret == NULL){ tlmp_error ("Can't open output file %s (%s)",fname.c_str() ,strerror(errno)); }else{ setlinebuf (ret); } return ret; } static void ninacexec_setvar ( const char *dir, const char *unixpath, const char *name, const char *task, const char *target, const char *fmt, ...) { char buf[10000]; { va_list list; va_start (list,fmt); vsnprintf (buf,sizeof(buf)-1,fmt,list); va_end (list); } SSTRING tmp; tmp.setfromf ("%s/ninaccmd -p %s setvar ninac.%s.%s.%s %s" ,dir,unixpath,name,task,target,buf) ; int ret = system (tmp.c_str()); if (ret!=0){ tlmp_error ("ninacexec can't execute %s : return %d" ,tmp.c_str(),ret); } } static void ninacexec_log (pid_t _pid, const char *line, ...) { char buf[10000]; { va_list list; va_start (list,line); vsnprintf (buf,sizeof(buf)-1,line,list); va_end (list); } glocal const char *line = buf; glocal pid_t pid = _pid ; (logfile,"a"); time_t ti = time(NULL); struct tm *t = localtime(&ti); fprintf (fout,"%04d/%02d/%02d %02d:%02d:%02d %5d Exec %s %s:%s/%s %s" ,t->tm_year+1900,t->tm_mon+1,t->tm_mday ,t->tm_hour,t->tm_min,t->tm_sec ,glocal.pid,(force ? "manual" : "auto") ,master,target,task,glocal.line); fprintf (fout,"\n"); return 0; } int main (int argc, char *argv[]) { signal (SIGCHLD,SIG_DFL); signal (SIGTERM, handle_sig) ; glocal int ret = -1; glocal const char *ninacdir = "/usr/bin"; glocal const char *taskdir = "/var/lib/ninac/tasks"; glocal const char *outputdir = "/var/log/ninac"; glocal const char *unixpath = "/var/run/ninac.sock"; glocal.ret = (argc,argv); setproginfo ("ninacexec",VERSION,"Controle l'execution d'une commande"); setarg ('d',"taskdir","Repertoire de taches",glocal.taskdir ,false); setarg ('l',"logfile","Journal",logfile,false); setarg ('m',"master","Serveur maitre",master,true); setarg ('n',"ninacdir","Repertoire des utilitaires ninac" ,glocal.ninacdir,false); setarg ('o',"outputdir","Resultat des commandes",glocal.outputdir,false); setarg ('t',"task","Tache pour informer ninac",task,true); setarg ('s',"script","Script a utiliser",script,true); setarg ('u',"unixpath","Unix domain socket",glocal.unixpath,false); setarg ('v',"target","Target or vserver",target,true); setarg ('f',"force","Indicates that the task was run manually (runtask)",force,false); fprintf (stderr,"task=%s target=%s: %s\n",task,target,msg); syslog (LOG_ERR,"task=%s target=%s: %s",task,target,msg); int ret = -1; // We locate ninac task string path = string(glocal.taskdir) + '/' + target + '/' + script; struct stat st; if (stat(path.c_str(),&st)==-1){ // No task for this target, try default path = string(glocal.taskdir) + "/default/" + script; } if (stat(path.c_str(),&st)==-1){ tlmp_error ("No task %s found in %s/%s or %s/default" ,task,glocal.taskdir,target,glocal.taskdir); ninacexec_log (getpid(), "No task found"); ret = NINACERR_TEMPFAIL; }else{ int fdout[2]; if (pipe(fdout)==-1){ tlmp_error ("Can't setup stdout pipe (%s)",strerror(errno)); ret = NINACERR_TEMPFAIL; ninacexec_log (getpid(), "TEMPFAIL"); }else{ int fderr[2]; if (pipe(fderr)==-1){ tlmp_error ("Can't setup stderr pipe (%s)",strerror(errno)); ret = NINACERR_TEMPFAIL; ninacexec_log (getpid(), "TEMPFAIL"); }else{ pid_t pid = fork(); if (pid == 0){ // Pour creer un process group setsid() ; close (fdout[0]); close (fderr[0]); dup2 (fdout[1],1); dup2 (fderr[1],2); close (fdout[1]); close (fderr[1]); SSTRING env_target,env_master, env_mode, env_task; env_target.setfromf ("TARGET=%s",target); env_master.setfromf ("MASTER=%s",master); env_mode.setfromf ("EXEC_MODE=%s",(force ? "manual" : "auto")); env_task.setfromf ("TASK=%s",task) ; putenv ((char*)env_target.c_str()); putenv ((char*)env_master.c_str()); putenv ((char*)env_mode.c_str()); putenv ((char*)env_task.c_str()); ret = system (path.c_str()); if (WIFSIGNALED(ret)){ signal (SIGTERM, SIG_DFL) ; kill(getpid(), WTERMSIG(ret)) ; ret = -1 ; // au cas ou ca retoure, au moins ca ne retourne pas 0... } else { ret = WEXITSTATUS(ret) ; } _exit(ret); }else if (pid == (pid_t)-1){ tlmp_error ("Can't fork (%s)",strerror(errno)); ret = NINACERR_TEMPFAIL; ninacexec_log (getpid(), "TEMPFAIL"); }else{ glocal int nbout = 0; glocal int nberr = 0; time_t start = time(NULL) ; SSTRING logdir; logdir.setfromf ("%s/%s/%s/%d",glocal.outputdir ,target,task,pid); ninacexec_setvar(glocal.ninacdir, glocal.unixpath, "logbase", task, target, "%s/%s", logdir.c_str(),task) ; ninacexec_setvar(glocal.ninacdir, glocal.unixpath, "pid", task, target, "%d", pid) ; char ctime[64] ; ctime_r(&start, ctime) ; ctime[strlen(ctime) - 1] = '\0' ; ninacexec_setvar(glocal.ninacdir, glocal.unixpath, "started", task, target, "'%s'", ctime) ; ninacexec_setvar(glocal.ninacdir, glocal.unixpath, "mode", task, target, "'%s'", (force ? "manual" : "auto")) ; ninacexec_log (pid, "Start log=%s",logdir.c_str()); glocal FILE *fout = NULL; glocal FILE *ferr = NULL; glocal FILE *finfo = NULL; glocal int fdout = fdout[0]; if (file_mkdirp(logdir.c_str(),getuid(),getgid(),0750)==-1){ tlmp_error ("Can't create directory %s (%s)" ,logdir.c_str(),strerror(errno)); ret = NINACERR_TEMPFAIL; ninacexec_log (pid, "TEMPFAIL"); }else{ SSTRING log_out,log_err,log_info; log_out.setfromf ("%s/%s.out",logdir.c_str(),task); log_err.setfromf ("%s/%s.err",logdir.c_str(),task); log_info.setfromf ("%s/%s.info",logdir.c_str(),task); glocal.fout = ninacexec_open (log_out); glocal.ferr = ninacexec_open (log_err); glocal.finfo = ninacexec_open (log_info); if (glocal.finfo != NULL){ fprintf (glocal.finfo,"pid=%d\n",pid); fprintf (glocal.finfo,"mode=%s\n",(force ? "manual" : "auto")); fprintf (glocal.finfo,"started=%lu\n",start); fflush (glocal.finfo) ; } } close (fdout[1]); close (fderr[1]); (); debug_printf ("Endclient %d\n",getnbclients()); endserver = getnbclients()==1; if (glocal.fdout == no){ glocal.nbout++; if (glocal.fout != NULL){ fprintf (glocal.fout,"%s\n",line); } }else{ glocal.nberr++; if (glocal.ferr != NULL){ fprintf (glocal.ferr,"%s\n",line); } } //printf ("no=%d %s\n",no,line); o.inject(fdout[0]); o.inject(fderr[0]); o.loop(); if (glocal.fout != NULL) fclose (glocal.fout); if (glocal.ferr != NULL) fclose (glocal.ferr); int status; if (wait(&status)!=-1){ time_t end = time(NULL) ; if (WIFSIGNALED(status)){ ret = -WTERMSIG(status) ; } else { ret = WEXITSTATUS(status) ; } ninacexec_log (pid, "End ret=%d nbout=%d nberr=%d" ,ret,glocal.nbout,glocal.nberr); ctime_r(&end, ctime) ; ctime[strlen(ctime) - 1] = '\0' ; ninacexec_setvar(glocal.ninacdir, glocal.unixpath, "ended", task, target, "'%s'", ctime) ; ninacexec_setvar(glocal.ninacdir, glocal.unixpath, "nbout", task, target, "%d", glocal.nbout) ; ninacexec_setvar(glocal.ninacdir, glocal.unixpath, "nberr", task, target, "%d", glocal.nberr) ; if (glocal.finfo != NULL){ fprintf (glocal.finfo,"retstatus=%d\n",ret); fprintf (glocal.finfo,"ended=%lu\n",time(NULL)); fprintf (glocal.finfo,"nbout=%i\n",glocal.nbout); fprintf (glocal.finfo,"nberr=%i\n",glocal.nberr); } }else{ tlmp_error ("wait failed (%s)",strerror(errno)); ninacexec_log (pid, "wait failed (%s)",strerror(errno)); } if (glocal.finfo != NULL) fclose (glocal.finfo); } close (fderr[0]); close (fderr[1]); } close (fdout[0]); close (fdout[1]); } } SSTRING tmp; tmp.setfromf ("%s/ninaccmd -p %s done %s %s %d" ,glocal.ninacdir,glocal.unixpath,task,target,ret); system (tmp.c_str()); return ret; return glocal.ret; }