123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- /*
- * 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 <at> inaccess.com
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <math.h>
- 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 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] <command to execute with args>\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;i<argc;i++) {
- j+=strlen(argv[i]);
- if (j+1>sizeof(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<<amt) -1;
- return ((v>>(32-amt)) & msk1) | ((v<<amt) & ~msk1);
- }
-
- unsigned *md5( const char *msg, int mlen)
- {
- static Digest h0 = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476 };
- // static Digest h0 = { 0x01234567, 0x89ABCDEF, 0xFEDCBA98, 0x76543210 };
- static DgstFctn ff[] = { &f0, &f1, &f2, &f3 };
- static short M[] = { 1, 5, 3, 7 };
- static short O[] = { 0, 1, 5, 0 };
- static short rot0[] = { 7,12,17,22};
- static short rot1[] = { 5, 9,14,20};
- static short rot2[] = { 4,11,16,23};
- static short rot3[] = { 6,10,15,21};
- static short *rots[] = {rot0, rot1, rot2, rot3 };
- static unsigned kspace[64];
- static unsigned *k;
-
- static Digest h;
- Digest abcd;
- DgstFctn fctn;
- short m, o, g;
- unsigned f;
- short *rotn;
- union {
- unsigned w[16];
- char b[64];
- }mm;
- int os = 0;
- int grp, grps, q, p;
- unsigned char *msg2;
-
- if (k==NULL) k= calcKs(kspace);
-
- for (q=0; q<4; q++) h[q] = h0[q]; // initialize
-
- {
- grps = 1 + (mlen+8)/64;
- msg2 = malloc( 64*grps);
- memcpy( msg2, msg, mlen);
- msg2[mlen] = (unsigned char)0x80;
- q = mlen + 1;
- while (q < 64*grps){ msg2[q] = 0; q++ ; }
- {
- // unsigned char t;
- WBunion u;
- u.w = 8*mlen;
- // t = u.b[0]; u.b[0] = u.b[3]; u.b[3] = t;
- // t = u.b[1]; u.b[1] = u.b[2]; u.b[2] = t;
- q -= 8;
- memcpy(msg2+q, &u.w, 4 );
- }
- }
-
- for (grp=0; grp<grps; grp++)
- {
- memcpy( mm.b, msg2+os, 64);
- for(q=0;q<4;q++) abcd[q] = h[q];
- for (p = 0; p<4; p++) {
- fctn = ff[p];
- rotn = rots[p];
- m = M[p]; o= O[p];
- for (q=0; q<16; q++) {
- g = (m*q + o) % 16;
- f = abcd[1] + rol( abcd[0]+ fctn(abcd) + k[q+16*p] + mm.w[g], rotn[q%4]);
-
- abcd[0] = abcd[3];
- abcd[3] = abcd[2];
- abcd[2] = abcd[1];
- abcd[1] = f;
- }
- }
- for (p=0; p<4; p++)
- h[p] += abcd[p];
- os += 64;
- }
- return h;
- }
-
- char * str2md5str( char msg[] )
- {
- int j,k;
- unsigned *d = md5(msg, strlen(msg));
- WBunion u;
- char s[16];
- char * md5str;
- md5str=malloc(34);
-
- for (j=0;j<4; j++){
- u.w = d[j];
- for (k=0;k<4;k++) {
- sprintf(s,"%02x",u.b[k]);
- strcat(md5str,s);
- }
- }
-
- return md5str;
- }
|