/* * runcached * Execute commands while caching their output for subsequent calls. * Command output will be cached for $cacheperiod and replayed for subsequent calls * * Author Spiros Ioannou sivann inaccess.com * */ #include #include #include #include #include #include #include #include #include #include int cacheperiod=27; //seconds char cachedir[512]; int maxwaitprev=5; //seconds to wait for previous same command to finish before quiting int minrand=0; //random seconds to wait before running cmd int maxrand=0; int argskip=1; char pidfile[128]; char * str2md5str( char[]); void cleanup(void); int runit(char **,char *,char *,char *,char *); int isfile(char *path) ; int main(int argc, char **argv) { int i,j,count; char cmd[1024]; char buf[512]; char * cmdmd5; FILE *fp; struct stat st; time_t diffsec; char cmddatafile[128]; char cmdexitcode[128]; char cmdfile[128]; if (argc<2 || (argc==2 && !strcmp(argv[1],"-c"))) { fprintf(stderr,"Usage: %s [-c cacheperiod] \n",argv[0]); exit(1); } if (!strcmp(argv[1],"-c")) { cacheperiod=atoi(argv[2]); argskip=3; } strcpy(cachedir,"/tmp"); for (j=0,cmd[0]=0,i=0+argskip;isizeof(cachedir)) { fprintf(stderr,"argument list too long\n"); exit(2); } strcat(cmd,argv[i]); strcat(cmd," "); } cmd[strlen(cmd)-1]=0; cmdmd5=str2md5str(cmd); if (maxrand-minrand) { srand(time(NULL)); sleep(rand()%(maxrand+1)+minrand); } snprintf(pidfile,127,"%s/%s-runcached.pid",cachedir,cmdmd5); snprintf(cmddatafile,127,"%s/%s.data",cachedir,cmdmd5); snprintf(cmdexitcode,127,"%s/%s.exitcode",cachedir,cmdmd5); snprintf(cmdfile,127,"%s/%s.cmd",cachedir,cmdmd5); atexit(cleanup); // don't run the same command in parallel, wait the previous one to finish count=maxwaitprev; while (isfile(pidfile)) { sleep(1); count-=1; if (count == 0) { fprintf(stderr,"timeout waiting for previous %s to finish\n" , cmd); exit (1); } } //write pid file fp = fopen(pidfile,"w"); if (!fp) { perror(pidfile); exit(2); } fprintf(fp,"%ld",(long)getpid()); fclose(fp); //if not cached before, run it if (!isfile(cmddatafile)) { runit(argv,cmd,cmddatafile,cmdexitcode,cmdfile) ; } //if too old, re-run it if (stat(cmddatafile, &st) == -1) { perror("stat"); exit(EXIT_FAILURE); } diffsec=time(0)-(time_t)st.st_mtim.tv_sec; if (diffsec > cacheperiod) { runit(argv,cmd,cmddatafile,cmdexitcode,cmdfile) ; } fp = fopen(cmddatafile,"r"); if (!fp) { perror(cmddatafile); exit(1); } while (fgets(buf, sizeof(buf), fp) != NULL) printf("%s", buf); fclose(fp); exit(0); } //main int isfile(char *path) { return (access( path, F_OK ) != -1 ) ; } void cleanup(void) { //if ( access( pidfile, F_OK ) != -1 ) { printf("Cleanup\n"); if (isfile(pidfile)) { unlink(pidfile); } } int runit(char **argv,char * cmd,char * cmddatafile,char * cmdexitcode,char * cmdfile) { int out_old, out_new; int err_old, err_new; int exitcode; char buf[1024]; FILE *pfp, *fp; fflush(stdout); fflush(stderr); //redirect stdout and stderr to file out_old = dup(1); out_new = open(cmddatafile,O_WRONLY|O_CREAT|O_TRUNC,S_IROTH|S_IRUSR|S_IRGRP|S_IWUSR); dup2(out_new, 1); close(out_new); err_old = dup(2); err_new = open(cmddatafile,O_WRONLY|O_CREAT|O_APPEND,S_IROTH|S_IRUSR|S_IRGRP|S_IWUSR); dup2(err_new, 2); close(err_new); /* run command with arguments: */ /* argv+=argskip; if (execvp(*argv, argv)<0) { perror("execvp"); exit (errno); } */ pfp = popen(cmd, "r"); if (pfp == NULL) { perror("popen"); exit(errno); } while (fgets(buf, sizeof(buf), pfp) != NULL) printf("%s", buf); exitcode=pclose(pfp); fp = fopen(cmdexitcode,"w"); if (!fp) { perror(cmdexitcode); } else { fprintf(fp,"%d",exitcode); fclose(fp); } fp = fopen(cmdfile,"w"); if (!fp) { perror(cmdfile); } else { fprintf(fp,"%s",cmd); fclose(fp); } //redirect stdout and stderr back to where it was fflush(stdout); dup2(out_old, 1); close(out_old); fflush(stderr); dup2(err_old, 2); close(err_old); } typedef union uwb { unsigned w; unsigned char b[4]; } WBunion; typedef unsigned Digest[4]; unsigned f0( unsigned abcd[] ){ return ( abcd[1] & abcd[2]) | (~abcd[1] & abcd[3]);} unsigned f1( unsigned abcd[] ){ return ( abcd[3] & abcd[1]) | (~abcd[3] & abcd[2]);} unsigned f2( unsigned abcd[] ){ return abcd[1] ^ abcd[2] ^ abcd[3];} unsigned f3( unsigned abcd[] ){ return abcd[2] ^ (abcd[1] |~ abcd[3]);} typedef unsigned (*DgstFctn)(unsigned a[]); unsigned *calcKs( unsigned *k) { double s, pwr; int i; pwr = pow( 2, 32); for (i=0; i<64; i++) { s = fabs(sin(1+i)); k[i] = (unsigned)( s * pwr ); } return k; } // ROtate v Left by amt bits unsigned rol( unsigned v, short amt ) { unsigned msk1 = (1<>(32-amt)) & msk1) | ((v<