#include #include #include #include #include #include #include #include #include #include #define nil NULL int main(int argc, char **argv) { char *path, *e, *origexe, *s, exe[4096], *argv0, *in, *out, *dirout, dhh[SHA256_DIGEST_LENGTH*2+1]; uint8_t tmp[65536], dh[SHA256_DIGEST_LENGTH]; int d, f, i, argout; SHA256_CTX shactx; struct stat st; ssize_t n; pid_t pid; if((dirout = getenv("LLCACHE_DIR")) == nil){ fprintf(stderr, "LLCACHE_DIR not set\n"); goto err; } if((argv0 = basename(argv[0])) == nil){ fprintf(stderr, "argv[0] is not a proper path\n"); goto err; } if((n = readlink("/proc/self/exe", exe, sizeof(exe))) >= (ssize_t)sizeof(exe)){ exesmall: fprintf(stderr, "exe buffer too small\n"); goto err; }else if(n < 0){ perror("exe buffer"); goto err; } exe[n] = 0; origexe = realpath(exe, nil); path = strdup(getenv("PATH")); for(s = path; s != nil; s = e ? e + 1 : nil){ if((e = strchr(s, ':')) != nil) *e = 0; if((d = open(s, O_DIRECTORY|O_RDONLY)) < 0) continue; n = readlinkat(d, argv0, exe, sizeof(exe)); if(n >= (ssize_t)sizeof(exe)) goto exesmall; if(n < 0){ if((n = fstatat(d, argv0, &st, 0)) == 0) exe[0] = 0; } close(d); if(n < 0 || strcmp(origexe, exe) == 0) continue; if(snprintf(exe, sizeof(exe), "%s/%s", s, argv0) >= (int)sizeof(exe)) goto exesmall; if((s = realpath(exe, nil)) == nil || strcmp(origexe, s) == 0){ free(s); continue; } break; } if(s == nil){ fprintf(stderr, "%s: not found\n", argv0); goto err; } SHA256_Init(&shactx); SHA256_Update(&shactx, s, strlen(s)+1); in = nil; out = nil; argout = -1; for(i = 1; i < argc; i++){ if(argv[i][0] == '/'){ if(strcmp(argv[i-1], "-o") == 0){ out = argv[i]; argout = i; }else{ in = argv[i]; } }else{ SHA256_Update(&shactx, argv[i], strlen(argv[i])+1); } } if(in == nil || out == nil) goto run; if((f = open(in, O_RDONLY)) < 0){ inerr: perror("input"); goto err; } for(;;){ if((n = read(f, tmp, sizeof(tmp))) == 0) break; if(n < 0) goto inerr; SHA256_Update(&shactx, tmp, n); } close(f); SHA256_Final(dh, &shactx); for(i = 0; i < (int)sizeof(dh); i++) sprintf(&dhh[i*2], "%02x", dh[i]); pid = 0; copy: if((d = open(dirout, O_DIRECTORY)) >= 0 && (f = openat(d, dhh, O_RDONLY)) >= 0 && fstat(f, &st) == 0){ close(d); if((d = creat(out, st.st_mode)) < 0){ perror("creat"); goto err; } for(;;){ if((n = read(f, tmp, sizeof(tmp))) == 0) break; if(n < 0) goto inerr; if(write(d, tmp, n) != n){ perror("output"); goto err; } } close(f); close(d); return 0; } if(pid != 0){ fprintf(stderr, "endless loop?\n"); goto err; } run: if((pid = fork()) < 0){ perror("fork"); goto err; }else if(pid == 0){ if(argout > 0){ snprintf((char*)tmp, sizeof(tmp), "%s/%s", dirout, dhh); argv[argout] = (char*)tmp; } execvp(s, argv); perror("exec"); goto err; } if(waitpid(pid, &i, 0) < 0){ perror("waitpid"); goto err; } if(i == 0) goto copy; err: return 1; }