diff options
| author | Jack Jamison <jackqjamison@gmail.com> | 2026-07-22 09:09:18 -0400 |
|---|---|---|
| committer | Jack Jamison <jackqjamison@gmail.com> | 2026-07-22 09:09:18 -0400 |
| commit | 5365f8fa8d6ebfbf3ba92816abe55a99feff6f25 (patch) | |
| tree | 563605dabaf611ebb0c1ee1b65aa56690b01b4fd /snag/src/pkg_db.c | |
| parent | 165816f7854340c3ca09287aee66968777af61ad (diff) | |
clean up
Diffstat (limited to 'snag/src/pkg_db.c')
| -rw-r--r-- | snag/src/pkg_db.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/snag/src/pkg_db.c b/snag/src/pkg_db.c new file mode 100644 index 0000000..c35e47b --- /dev/null +++ b/snag/src/pkg_db.c @@ -0,0 +1,157 @@ +#include "pkg_db.h" +#include "util.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/wait.h> + +#define PKG_INFO_CMD "./scripts/get_pkg_attrs.sh" +#define PKG_INST_CMD "./scripts/run_pkg_install.sh" + +// note: fixed location of package database for now +const char pkg_db[] = "../packages"; +const size_t pkg_db_len = sizeof(pkg_db) - 1; + +bool load_package_info(char* pkgid, package_info_t* info) { + + memset(info, 0, sizeof(*info)); + size_t pkgid_len = strlen(pkgid); + + // construct package description directory path and ensure it exists + // pkg_dir = "pkg_db/pkgid" + size_t pkg_dir_len = pkg_db_len + pkgid_len + 1; + char* pkg_dir = emalloc(pkg_dir_len + 1, "pkg_dir"); + { + memcpy(pkg_dir, pkg_db, pkg_db_len); + pkg_dir[pkg_db_len] = '/'; + memcpy(pkg_dir + pkg_db_len + 1, pkgid, pkgid_len); + pkg_dir[pkg_dir_len] = '\0'; + if (access(pkg_dir, F_OK) != 0) { + print("Package '%s' not found\n", pkgid); + free(pkg_dir); + return false; + } + } + + // construct package description script path and ensure it exists + // script_path = "pkg_dir/pkgid.sh" + size_t script_path_len = pkg_dir_len + pkgid_len + 4; + info->script_path = emalloc(script_path_len + 1, "info->script_path"); + { + memcpy(info->script_path, pkg_dir, pkg_dir_len); + info->script_path[pkg_dir_len] = '/'; + memcpy(&info->script_path[pkg_dir_len + 1], pkgid, pkgid_len); + memcpy(&info->script_path[script_path_len - 3], ".sh", 3); + info->script_path[script_path_len] = '\0'; + free(pkg_dir); + if (access(info->script_path, F_OK) != 0) { + print("Package '%s' broken, doesn't have description script\n", pkgid); + free(info->script_path); + return false; + } + } + + // PIPE and FORK to run pkg attrs script + int pipefds[2] = {0}; + if (pipe(pipefds) < 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 to the pipe + close(pipefds[0]); + dup2(pipefds[1], STDOUT_FILENO); + close(pipefds[1]); + // exec into get attr script + char* argv[] = { PKG_INFO_CMD, info->script_path, NULL }; + char* envp[] = { NULL }; + execve(PKG_INFO_CMD, argv, envp); + // what are you still doing here? + die("CHILD - execve to %s failed: %s", PKG_INFO_CMD, strerror(errno)); + } else { + // parent proc, close write end of pipe + close(pipefds[1]); + } + + // wait for 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 get_pkg_attr script"); + + // read all bytes from pipe into attr buffer + ssize_t bytes_read = read(pipefds[0], info->attrs.buffer, sizeof(info->attrs.buffer)); + if (bytes_read < 0) die("failed to read from pipe: %s", strerror(errno)); + close(pipefds[0]); + + // read attributes from attr buffer + // attribute format: type (char), data value (null terminated str) + // todo(jqj): switch over to dynamically allocated buffer + for (int i = 0; i < bytes_read;) { + char atype = info->attrs.buffer[i]; + i++; + switch (atype) { + case 'i': + info->attrs.id = &info->attrs.buffer[i]; break; + case 'n': + info->attrs.name = &info->attrs.buffer[i]; break; + case 'd': + info->attrs.desc = &info->attrs.buffer[i]; break; + case 'w': + info->attrs.webpage = &info->attrs.buffer[i]; break; + case 'l': + info->attrs.license = &info->attrs.buffer[i]; break; + case 'v': + info->attrs.version = &info->attrs.buffer[i]; break; + } + for(;info->attrs.buffer[i] && i < bytes_read; i++); + i++; + } + + return true; +} + +void run_package_install(const package_info_t* info) { + + // PIPE and FORK to run install script + int pipefds[2] = {0}; + if (pipe(pipefds) < 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(pipefds[0]); + dup2(pipefds[1], STDOUT_FILENO); + dup2(pipefds[1], STDERR_FILENO); + close(pipefds[1]); + // exec into install script + char* argv[] = { PKG_INST_CMD, info->script_path, NULL }; + char* envp[] = { NULL }; + execve(PKG_INST_CMD, argv, envp); + // what are you still doing here? + die("CHILD - execve to %s failed: %s", PKG_INST_CMD, strerror(errno)); + } else { + // parent proc, close write end of pipe + close(pipefds[1]); + } + + // read from the pipe until EOF + char buf[4096]; + ssize_t bytes_read = 0; + while ((bytes_read = read(pipefds[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(pipefds[0]); + + // 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"); +} |
