arch/net/charmrun/daemon.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * $Source: /cvsroot/charm/src/arch/net/charmrun/daemon.c,v $
00003  * $Author: gzheng $
00004  * $Date: 2006-01-19 15:24:09 $
00005  * $Revision: 1.8 $
00006  *****************************************************************************/
00007 
00008 #include <stdio.h>
00009 #include <string.h>
00010 #include <stdlib.h>
00011 
00012 #ifdef _WIN32
00013 #include <windows.h>
00014 #include <sys/types.h>
00015 #include <process.h>
00016 #else
00017 #include <errno.h>
00018 #include <sys/wait.h>
00019 typedef unsigned int BYTE;
00020 #endif
00021 #include <time.h>
00022 
00023 #include "sockRoutines.h"
00024 #include "daemon.h"
00025 
00026 /*If FACELESS is defined, the daemon logs runs to a file
00027 (daemon.log) and doesn't show a DOS window.
00028 Otherwise, the daemon logs things to its DOS window.
00029 */
00030 /*#define FACELESS*/  /*<- sent in from the makefile*/
00031 
00032 FILE *logfile;/*Status messages to standard output*/
00033 
00034 int abort_writelog(int code,const char *msg) {
00035         fprintf(logfile,"Socket error %d-- %s!\n",code,msg);
00036         fclose(logfile);
00037         exit(3);
00038         return -1;
00039 }
00040 
00041 char startProgram(const char *exeName, const char *args, 
00042                                 const char *cwd, char *env);
00043 
00044 void goFaceless(void);
00045 
00046 int main()
00047 {
00048   unsigned int myPortNumber = DAEMON_IP_PORT;
00049   int myfd;
00050   int i;
00051   
00052   int remotefd;         /* Remote Process Connecting */
00053   skt_ip_t remoteIP;         /* Remote Process's IP */
00054   unsigned int remotePortNumber; /* Port on which remote port is connecting */
00055   
00056   taskStruct task;      /* Information about the task to be performed */
00057   time_t curTime;
00058 
00059   int doNext = 1;
00060 
00061   logfile=stdout;
00062 #ifdef FACELESS
00063   logfile=fopen("daemon.log","w+");
00064   if (logfile==NULL) /*Couldn't open log file*/
00065     logfile=stdout;
00066   else 
00067         goFaceless();
00068 #endif
00069   
00070   curTime=time(NULL);
00071   fprintf(logfile,"Logfile for Windows Spawner Daemon for Converse programs\n"
00072           "Run starting: %s\n\n",ctime(&curTime));fflush(logfile);
00073   
00074   skt_init();
00075   skt_set_abort(abort_writelog);
00076   
00077   /* Initialise "Listening Socket" */
00078   myfd=skt_server(&myPortNumber);
00079   
00080   while(1) {
00081     char ip_str[200];
00082     char *argLine; /* Argument list for called program */
00083     char statusCode;/*Status byte sent back to requestor*/
00084     fd_set  rfds;
00085     struct timeval tmo;
00086     int sstatus, wstatus;    /* status code for select and waitpid */
00087     
00088     if (doNext) 
00089     fprintf(logfile,"\nListening for requests on port %d\n",myPortNumber);
00090         fflush(logfile);
00091     
00092     tmo.tv_sec = 5;               /* call waitpid every a few seconds */
00093     tmo.tv_usec = 0;
00094     FD_ZERO(&rfds);
00095     FD_SET(myfd,&rfds);
00096     sstatus=select(FD_SETSIZE, &rfds, 0, 0, &tmo);
00097 
00098 #ifndef _WIN32
00099       /* test and get rid of zombie process */
00100     waitpid(-1, &wstatus, WNOHANG);
00101 #endif
00102     if (sstatus == 0) {
00103       doNext = 0;
00104       continue;
00105     }
00106 
00107     /* Accept & log a TCP connection from a client */
00108     remotefd=skt_accept(myfd, &remoteIP, &remotePortNumber); 
00109     
00110     curTime=time(NULL);
00111     fprintf(logfile,"Connection from IP %s, port %d at %s",
00112             skt_print_ip(ip_str,remoteIP),remotePortNumber,
00113             ctime(&curTime));
00114     fflush(logfile);
00115     
00116     /* Recv the task to be done */
00117     skt_recvN(remotefd, (BYTE *)&task, sizeof(task));
00118     task.pgm[DAEMON_MAXPATHLEN-1]=0; /*null terminate everything in sight*/
00119     task.cwd[DAEMON_MAXPATHLEN-1]=0;
00120     task.env[DAEMON_MAXENV-1]=0;
00121 
00122     /* Check magic number */
00123     if (ChMessageInt(task.magic)!=DAEMON_MAGIC) {
00124       fprintf(logfile,"************ SECURITY ALERT! ************\n"
00125               "Received execution request with the wrong magic number 0x%08x!\n"
00126               "This could indicate someone is trying to hack your system.\n\n\n",ChMessageInt(task.magic));
00127       fflush(logfile);
00128       skt_close(remotefd);
00129       continue; /*DON'T execute this command (could be evil!)*/
00130     }
00131     
00132     /* Allocate memory for arguments*/
00133     argLine = (char *)malloc(sizeof(char) * (ChMessageInt(task.argLength)+1));
00134     
00135     /* Recv the command line*/
00136     skt_recvN(remotefd, (BYTE *)argLine, ChMessageInt(task.argLength));
00137     
00138     /*Add null terminator*/
00139     argLine[ChMessageInt(task.argLength)] = 0;
00140     
00141     {
00142     /* converting between windows and unix directory name  */
00143     char c1, c2;
00144 #ifndef _WIN32
00145     c1 = '\\'; c2 = '/';
00146 #else
00147     c1 = '/'; c2 = '\\';
00148 #endif
00149     /* modify \ to / in path */
00150     for (i=0; task.pgm[i]!=0; i++) 
00151       if (task.pgm[i]==c1) task.pgm[i]=c2;
00152     for (i=0; task.cwd[i]!=0; i++) 
00153       if (task.cwd[i]==c1) task.cwd[i]=c2;
00154     }
00155 
00156     fprintf(logfile,"Invoking '%s'\n"
00157             "and argLine '%s'\n"
00158             "and environment '%s'\n"
00159             "in '%s'\n",
00160             task.pgm,argLine,task.env,task.cwd);fflush(logfile);
00161     
00162     /* Finally, create the process*/
00163     statusCode=startProgram(task.pgm,argLine,task.cwd,task.env);
00164 
00165     /*Send status byte back to requestor*/
00166     skt_sendN(remotefd,(BYTE *)&statusCode,sizeof(char));
00167     skt_close(remotefd);
00168 
00169     /*Free recv'd arguments*/
00170     free(argLine);
00171 
00172     doNext = 1;
00173   }
00174   return 0;  
00175 }
00176 
00177 #ifdef _WIN32
00178 /********************** Win32 Spawn ****************/
00179 void goFaceless(void)
00180 {
00181     printf("Switching to background mode...\n");
00182         fflush(stdout);
00183     sleep(2);/*Give user a chance to read message*/
00184     FreeConsole();
00185 }
00186 /*
00187 Paste the environment string oldEnv just after dest.
00188 This is a bit of a pain since windows environment strings
00189 are double-null terminated.
00190   */
00191 void envCat(char *dest,LPTSTR oldEnv)
00192 {
00193   char *src=oldEnv;
00194   dest+=strlen(dest);/*Advance to end of dest*/
00195   dest++;/*Advance past terminating NULL character*/
00196   while ((*src)!='\0') {
00197     int adv=strlen(src)+1;/*Length of newly-copied string plus NULL*/
00198     strcpy(dest,src);/*Copy another environment string*/
00199     dest+=adv;/*Advance past newly-copied string and NULL*/
00200     src+=adv;/*Ditto for src*/
00201   }
00202   *dest='\0';/*Paste on final terminating NULL character*/
00203   FreeEnvironmentStrings(oldEnv);
00204 }
00205 
00206 
00207 char startProgram(const char *exeName, const char *args, 
00208                                 const char *cwd, char *env)
00209 {
00210   int ret;
00211   PROCESS_INFORMATION pi;         /* process Information for the process spawned */
00212   STARTUPINFO si={0};                 /* startup info for the process spawned */
00213 
00214   char environment[10000];/*Doubly-null terminated environment strings*/
00215   char cmdLine[10000];/*Program command line, including executable name*/
00216   if (strlen(exeName)+strlen(args) > 10000) 
00217         return 0; /*Command line too long.*/
00218   strcpy(cmdLine,exeName);
00219   strcat(cmdLine," ");
00220   strcat(cmdLine,args);
00221 
00222   /*Copy over the environment variables*/
00223   strcpy(environment,env);
00224   /*Paste all system environment strings after task.env */
00225   envCat(environment,GetEnvironmentStrings());
00226   
00227   /* Initialise the security attributes for the process 
00228      to be spawned */
00229   si.cb = sizeof(si);   
00230 
00231   ret = CreateProcess(NULL,     /* application name */
00232                             cmdLine,    /* command line */
00233                             NULL,/*&sa,*/                                                       /* process SA */
00234                             NULL,/*&sa,*/                                                       /* thread SA */
00235                             FALSE,                                                      /* inherit flag */
00236 #ifdef FACELESS
00237                                 CREATE_NEW_PROCESS_GROUP|DETACHED_PROCESS, 
00238 #else
00239                                 CREATE_NEW_PROCESS_GROUP|CREATE_NEW_CONSOLE,
00240 #endif
00241                                 /* creation flags */
00242                             environment,                                        /* environment block */
00243                             cwd,                                                        /* working directory */
00244                             &si,                                                        /* startup info */
00245                             &pi);
00246  
00247   if (ret==0)
00248   {
00249       /*Something went wrong!  Look up the Windows error code*/
00250       int error=GetLastError();
00251       char statusCode=daemon_err2status(error);
00252       fprintf(logfile,"******************* ERROR *****************\n"
00253               "Error in creating process!\n"
00254               "Error code = %ld-- %s\n\n\n", error,
00255               daemon_status2msg(statusCode));
00256           fflush(logfile);
00257           return statusCode;
00258   } 
00259   else
00260         return 'G';
00261 }
00262 
00263 #else /*UNIX systems*/
00264 
00265 #include <sys/types.h>
00266 #include <sys/stat.h>
00267 #include <unistd.h>
00268 #include <fcntl.h>
00269 
00270 void goFaceless(void)
00271 {
00272     printf("Switching to background mode...\n");
00273         if (fork()!=0) 
00274                 exit(0); /*Kill off the parent process, freeing terminal*/
00275 }
00276 
00277 char ** args2argv(const char *args,char **argv,char *exe) {
00278         int cur=0,len=strlen(args);
00279         int argc=0;
00280         argv[argc++] = exe;
00281         while (cur<len) {
00282                 int start,end;
00283                 while (cur<len && args[cur]==' ') cur++;
00284                 start=cur;
00285                 while (cur<len && args[cur]!=' ') cur++;
00286                 end=cur;
00287                 if (start<end){
00288                         int i;
00289                         argv[argc]=(char *)malloc(sizeof(char)*(end-start+1));
00290                         for (i=0;i<end-start;i++)
00291                                 argv[argc][i]=args[start+i];
00292                         argv[argc++][end-start]=0;/*Null-terminate*/
00293                 }
00294         }
00295         argv[argc]=0;/* Null-terminate arg list */
00296         return argv;
00297 }
00298 
00299 char startProgram(const char *exeName, const char *args, 
00300                                 const char *cwd, char *env)
00301 {
00302         int ret=0,fd;
00303         if (0!=access(cwd,F_OK)) return 'D';
00304         if (0!=access(cwd,X_OK)) return 'A';
00305         if (0!=access(exeName,F_OK)) return 'F';
00306         if (0!=access(exeName,R_OK|X_OK)) return 'A';
00307         
00308         if (fork()==0)
00309         {
00310                 char **argv=(char **)malloc(sizeof(char *)*1000);
00311                 ret|=chdir(cwd);
00312                 putenv(env);
00313 #if 1
00314                 /*Redirect program's stdin, out, err to /dev/null*/
00315                 fd=open("/dev/null",O_RDWR);
00316                 dup2(fd,0);
00317                 dup2(fd,1);
00318                 dup2(fd,2);
00319 #endif
00320                 for (fd=3;fd<1024;fd++) close(fd);
00321                 ret|=execvp(exeName,args2argv(args,argv,exeName));
00322                 exit(1);
00323         }
00324         /*FIXME: parent needs to check on child's status, e.g., by 
00325           child sending SIGUSR2 back to parent on error.*/
00326         return 'G';
00327 }
00328 
00329 #endif

Generated on Sun Jun 29 13:29:06 2008 for Charm++ by  doxygen 1.5.1