#include "build_db.h" #include "source_db.h" #include "util.h" #include #include #include #include #include #include #include #include #include #include const char build_db_path[] = "./var/snag/builds"; const size_t build_db_path_len = strlen(build_db_path); #define PKG_BUILD_CMD "./scripts/run_pkg_build.sh" #define API_MESSAGE_NONE 0 #define API_MESSAGE_FINISHED 1 #define API_MESSAGE_TEST 2 bool package_setup_build(const package_info_t* info, package_build_t* build) { // get timestamp string char timestamp_str[32]; { // get time in ms struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) != 0) die("failed to get time: %s", strerror(errno)); unsigned long long total_ms = ((unsigned long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); snprintf(timestamp_str, sizeof(timestamp_str), "%llu", total_ms); } // create build info memset(build, 0, sizeof(*build)); build->package = info; build->directory = vastrcat(build_db_path, "/", info->attrs.id, "-", timestamp_str); // create build directory if (mkdir(build->directory, 0777) == -1) die("failed to create build directory: %s", strerror(errno)); // (re)create symlink to build directory char* symlink_name = vastrcat(build_db_path, "/", info->attrs.id); if (unlink(symlink_name) == -1 && errno != ENOENT) die("failed to remove build symlink '%s': %s", symlink_name, strerror(errno)); if (symlink(build->directory + build_db_path_len + 1, symlink_name) == -1) die("failed to create build symlink '%s': %s", symlink_name, strerror(errno)); free(symlink_name); // unpack package source (eventually this will be done by swenu api) build->source_directory = join_path(build->directory, "source"); unpack_source(&info->attrs.source, build->source_directory); // todo - create paths for log files // todo - create rebuild script return true; } void build_run(const package_build_t* build) { int api_from_sh[2] = {0}; if (pipe(api_from_sh) < 0) die("failed to open api endpoint pipe: %s", strerror(errno)); int api_to_sh[2] = {0}; if (pipe(api_to_sh) < 0) die("failed to open api response pipe: %s", strerror(errno)); // PIPE and FORK to run install script int child_output[2] = {0}; if (pipe(child_output) < 0) die("failed to pipe: %s", strerror(errno)); pid_t pid = fork(); if (pid < 0) die("failed to fork: %s", strerror(errno)); if (pid == 0) { // child proc // connect my stdout and stderr to the pipe close(child_output[0]); dup2(child_output[1], STDOUT_FILENO); dup2(child_output[1], STDERR_FILENO); close(child_output[1]); // close unused api pipes close(api_from_sh[0]); close(api_to_sh[1]); char buf1[1024]; snprintf(buf1, sizeof(buf1), "%d", api_from_sh[1]); char buf2[1024]; snprintf(buf2, sizeof(buf2), "%d", api_to_sh[0]); // exec into install script char* argv[] = { PKG_BUILD_CMD, buf1, buf2, build->package->script_path, NULL }; char* envp[] = { NULL }; execve(PKG_BUILD_CMD, argv, envp); // what are you still doing here? die("CHILD - execve to %s failed: %s", PKG_BUILD_CMD, strerror(errno)); } else { // parent proc, close write end of pipe close(child_output[1]); // close unused api pipes close(api_from_sh[1]); close(api_to_sh[0]); } // all of this should be rewritten char buf[4096]; ssize_t bytes_read = 0; struct pollfd pollfds[] = { { .fd = api_from_sh[0], .events = POLLIN, .revents = 0 }, { .fd = child_output[0], .events = POLLIN, .revents = 0 } }; bool finished = false; while (!finished) { if (poll(pollfds, sizeof(pollfds) / sizeof(*pollfds), 0) < 0) { die("polling child process fds failed %s", strerror(errno)); } if (pollfds[1].revents == POLLIN) { bytes_read = read(child_output[0], buf, sizeof(buf)); if (bytes_read < 0) die("failed to read from child output: %s", strerror(errno)); // print build out, can log and stuff in future printf("%.*s", (int)bytes_read, buf); } if (pollfds[0].revents == POLLIN) { int api_call = 0; bytes_read = read(api_from_sh[0], &api_call, sizeof(api_call)); if (bytes_read < 0) { print("reading from api pipe failed: %s\n", strerror(errno)); } switch (api_call) { case API_MESSAGE_FINISHED: finished = true; break; case API_MESSAGE_TEST: printf("api test\n"); write(api_to_sh[1], "api test\n", strlen("api test\n")); break; case API_MESSAGE_NONE: break; } } } while ((bytes_read = read(child_output[0], buf, sizeof(buf))) > 0) { // print build out, can log and stuff in future printf("%.*s", (int)bytes_read, buf); } if (bytes_read < 0) die("failed to read from pipe: %s", strerror(errno)); close(child_output[0]); // close api pipes close(api_from_sh[0]); close(api_to_sh[1]); // reap the child to finish int wstatus; if (waitpid(pid, &wstatus, 0) < 0) die("waitpid failed: %s", strerror(errno)); if (WEXITSTATUS(wstatus) != 0) die("the child failed to execute install script"); }