aboutsummaryrefslogtreecommitdiffstats
path: root/src/build.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/build.c')
-rw-r--r--src/build.c170
1 files changed, 90 insertions, 80 deletions
diff --git a/src/build.c b/src/build.c
index f4def6a..5728155 100644
--- a/src/build.c
+++ b/src/build.c
@@ -36,9 +36,10 @@ typedef struct do_attr {
} do_attr;
typedef struct dep_info {
+ const char *target;
char *path;
+ unsigned char *hash;
unsigned int magic;
- unsigned char hash[20];
int32_t flags;
#define DEP_SOURCE (1 << 1)
} dep_info;
@@ -50,57 +51,40 @@ static char **parsecmd(char *cmd, size_t *i, size_t keep_free);
static char *get_relpath(const char *target);
static char *get_dep_path(const char *target);
static void write_dep_header(dep_info *dep);
-static int handle_c(const char *target);
-static void hash_file(const char *target, unsigned char *hash);
+static int handle_ident(dep_info *dep, int ident);
+static int handle_c(dep_info *dep);
+static unsigned char *hash_file(const char *target);
/* Build given target, using it's .do script. */
-static int build_target(const char *dep) {
+static int build_target(dep_info *dep) {
int retval = 1;
- dep.path = get_dep_path(target);
- dep.magic = atoi(getenv("REDO_MAGIC"));
- dep.flags = 0;
-
/* get the .do script which we are going to execute */
- do_attr *doscripts = get_doscripts(target);
+ do_attr *doscripts = get_doscripts(dep->target);
if (!doscripts->chosen) {
- if (fexists(target)) {
+ if (fexists(dep->target)) {
/* if our target file has no .do script associated but exists,
then we treat it as a source */
- dep.flags |= DEP_SOURCE;
- hash_file(target, dep.hash);
- write_dep_header(&dep);
+ dep->flags |= DEP_SOURCE;
+ dep->hash = hash_file(dep->target);
+ write_dep_header(dep);
goto exit;
}
- die("%s couldn't be built as no suitable .do script exists\n", target);
+ die("%s couldn't be built as no suitable .do script exists\n",
+ dep->target);
}
- char *reltarget = get_relpath(target);
+ char *reltarget = get_relpath(dep->target);
printf("\033[32mredo \033[1m\033[37m%s\033[0m\n", reltarget);
free(reltarget);
- /* get the old hash (if any) */
- FILE *fp = fopen(dep.path, "rb");
- if (!fp) {
- if (errno != ENOENT)
- fatal("redo: failed to open %s\n", dep.path);
-
- memset(dep.hash, 0, 20); /* FIXME */
- } else {
- if (fseek(fp, sizeof(unsigned), SEEK_SET))
- fatal("redo: fseek() failed");
- if (fread(dep.hash, 1, 20, fp) < 20)
- fatal("redo: failed to read stuff");
- fclose(fp);
- }
-
/* remove old dependency record */
- if (remove(dep.path) && errno != ENOENT)
+ if (remove(dep->path) && errno != ENOENT)
fatal("redo: failed to remove %s", dep->path);
- char *temp_output = concat(2, target, ".redoing.tmp");
+ char *temp_output = concat(2, dep->target, ".redoing.tmp");
pid_t pid = fork();
if (pid == -1) {
@@ -117,12 +101,13 @@ static int build_target(const char *dep) {
free(dirc);
- char **argv = parse_shebang(xbasename((char*)target),
+ char **argv = parse_shebang(xbasename(dep->target),
xbasename(doscripts->chosen), xbasename(temp_output));
/* set "REDO_PARENT_TARGET" */
- if (setenv("REDO_PARENT_TARGET", target, 1))
- fatal("redo: failed to setenv() REDO_PARENT_TARGET to %s", target);
+ if (setenv("REDO_PARENT_TARGET", dep->target, 1))
+ fatal("redo: failed to setenv() REDO_PARENT_TARGET to %s",
+ dep->target);
/* excelp() has nearly everything we want: automatic parsing of the
shebang line through execve() and fallback to /bin/sh if no valid
@@ -152,39 +137,50 @@ static int build_target(const char *dep) {
/* check if our output file is > 0 bytes long */
if (fsize(temp_output) > 0) {
- if (rename(temp_output, target))
- fatal("redo: failed to rename %s to %s", temp_output, target);
+ if (rename(temp_output, dep->target))
+ fatal("redo: failed to rename %s to %s", temp_output, dep->target);
- unsigned char new_hash[20];
- hash_file(target, new_hash);
- retval = memcmp(new_hash, dep.hash, 20);
- if (retval)
- memcpy(dep.hash, new_hash, 20);
+ unsigned char *new_hash = hash_file(dep->target);
+ if (dep->hash) {
+ retval = memcmp(new_hash, dep->hash, 20);
+ if (retval)
+ memcpy(dep->hash, new_hash, 20);
- write_dep_header(&dep);
+ free(new_hash);
+ } else {
+ dep->hash = new_hash;
+ }
+
+ write_dep_header(dep);
} else {
if (remove(temp_output) && errno != ENOENT)
fatal("redo: failed to remove %s", temp_output);
}
- free(dep.path);
-
/* depend on the .do script */
- dep.flags = 0;
- dep.path = get_dep_path(doscripts->chosen);
- if (!fexists(dep.path)) {
- hash_file(doscripts->chosen, dep.hash);
- write_dep_header(&dep);
+ dep_info dep2 = {
+ .magic = dep->magic,
+ .target = dep->target,
+ .path = get_dep_path(doscripts->chosen),
+ .hash = NULL,
+ .flags = 0,
+ };
+
+ if (!fexists(dep2.path)) {
+ dep2.hash = hash_file(doscripts->chosen);
+ write_dep_header(&dep2);
+ free(dep2.hash);
}
- add_dep(doscripts->chosen, target, 'c');
+ free(dep2.path);
+
+ add_dep(doscripts->chosen, dep->target, 'c');
/* redo-ifcreate on specific if general was chosen */
if (doscripts->general == doscripts->chosen)
- add_dep(doscripts->specific, target, 'e');
+ add_dep(doscripts->specific, dep->target, 'e');
free(temp_output);
exit:
- free(dep.path);
free_do_attr(doscripts);
return retval;
@@ -374,12 +370,14 @@ void add_dep(const char *target, const char *parent, int ident) {
free(dep_path);
}
-/* Hash target, storing the result in hash. */
-static void hash_file(const char *target, unsigned char *hash) {
+/* Hash the target file, returning a pointer to the heap allocated hash. */
+static unsigned char *hash_file(const char *target) {
FILE *in = fopen(target, "rb");
if (!in)
fatal("redo: failed to open %s", target);
+ unsigned char *hash = xmalloc(20);
+
SHA_CTX context;
unsigned char data[8192];
size_t read;
@@ -392,6 +390,8 @@ static void hash_file(const char *target, unsigned char *hash) {
fatal("redo: failed to read from %s", target);
SHA1_Final(hash, &context);
fclose(in);
+
+ return hash;
}
void sha1_to_hex(const unsigned char *sha1, char *buf) {
@@ -427,68 +427,78 @@ static void write_dep_header(dep_info *dep) {
}
int update_target(const char *target, int ident) {
+ dep_info dep = {
+ .magic = atoi(getenv("REDO_MAGIC")),
+ .target = target,
+ .path = get_dep_path(target),
+ .hash = NULL,
+ .flags = 0,
+ };
+
+ int retval = handle_ident(&dep, ident);
+ free(dep.path);
+ free(dep.hash);
+
+ return retval;
+}
+
+static int handle_ident(dep_info *dep, int ident) {
switch(ident) {
case 'a':
- return build_target(target);
+ return build_target(dep);
case 'e':
- if (fexists(target))
- return build_target(target);
+ if (fexists(dep->target))
+ return build_target(dep);
return 0;
case 'c':
- return handle_c(target);
+ return handle_c(dep);
default:
die("redo: unknown identifier '%c'\n", ident);
}
}
-static int handle_c(const char *target) {
- char *dep_path = get_dep_path(target);
-
- FILE *fp = fopen(dep_path, "rb");
+static int handle_c(dep_info *dep) {
+ FILE *fp = fopen(dep->path, "rb");
if (!fp) {
- if (errno == ENOENT) {
+ if (errno == ENOENT)
/* dependency record does not exist */
- free(dep_path);
- return build_target(target);
- } else {
- fatal("redo: failed to open %s", dep_path);
- }
+ return build_target(dep);
+ else
+ fatal("redo: failed to open %s", dep->path);
}
char buf[FILENAME_MAX];
if (fread(buf, 1, HEADERSIZE, fp) < HEADERSIZE)
- fatal("redo: failed to read %zu bytes from %s", HEADERSIZE, dep_path);
-
- free(dep_path);
+ fatal("redo: failed to read %zu bytes from %s", HEADERSIZE, dep->path);
errno = 0;
buf[10] = '\0';
long magic = strtol(buf, NULL, 10);
if (errno)
- return build_target(target);
+ return build_target(dep);
- if (!fexists(target)) {
+ if (!fexists(dep->target)) {
if (buf[52] == 'S') /* source flag set */
/* target is a source and must not be rebuild */
return 1;
else
- return build_target(target);
+ return build_target(dep);
}
- if (magic == (unsigned) atoi(getenv("REDO_MAGIC")))
+ if (magic == dep->magic)
/* magic number matches */
return 1;
- unsigned char hash[20];
char char_hash[40];
- hash_file(target, hash);
+ unsigned char *hash = hash_file(dep->target);
sha1_to_hex(hash, char_hash);
+ free(hash);
buf[51] = '\0';
if (memcmp(char_hash, buf+11, 40))
- return build_target(target);
+ return build_target(dep);
char *ptr;
char *root = getenv("REDO_ROOT");
@@ -530,7 +540,7 @@ static int handle_c(const char *target) {
fclose(fp);
if (rebuild)
- return build_target(target);
+ return build_target(dep);
return 0;
}