diff options
| -rw-r--r-- | snag/main.c | 4 | ||||
| -rw-r--r-- | snag/pkg_db.c | 97 | ||||
| -rw-r--r-- | snag/pkg_db.h | 10 |
3 files changed, 82 insertions, 29 deletions
diff --git a/snag/main.c b/snag/main.c index 9804f99..ff7ac64 100644 --- a/snag/main.c +++ b/snag/main.c @@ -18,12 +18,12 @@ void subcmd_install(char* pkgs[], size_t count) { for (int i = 0; i < count; ++i) { char* pkgid = pkgs[i]; - fprintf(stderr, "package: %s\n", pkgid); // load package description package_info_t info; - if (load_package_info(&info, pkgid)) { + if (load_package_info(pkgid, &info)) { printf("Installing %s - %s\n", info.attrs.name, info.attrs.desc); + run_package_install(&info); } } } diff --git a/snag/pkg_db.c b/snag/pkg_db.c index ad9eff3..032c089 100644 --- a/snag/pkg_db.c +++ b/snag/pkg_db.c @@ -8,23 +8,26 @@ #include <errno.h> #include <sys/wait.h> -#define PKG_DB "../packages" -#define PKG_DB_LEN (sizeof(PKG_DB) - 1) #define PKG_INFO_CMD "./get_pkg_attrs.sh" +#define PKG_INST_CMD "./run_pkg_install.sh" -bool load_package_info(package_info_t* info, char* pkgid) { +// 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; + // 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); + 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) { eprintf("Package '%s' not found\n", pkgid); @@ -41,7 +44,8 @@ bool load_package_info(package_info_t* info, char* pkgid) { 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", 4); + 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) { eprintf("Package '%s' broken, doesn't have description script\n", pkgid); @@ -50,15 +54,15 @@ bool load_package_info(package_info_t* info, char* pkgid) { } } - // PIPE and FORK to run get pkg attrs script + // PIPE and FORK to run pkg attrs script int pipefds[2] = {0}; if (pipe(pipefds) < 0) error_out("failed to pipe: %s", strerror(errno)); pid_t pid = fork(); if (pid < 0) error_out("failed to fork: %s", strerror(errno)); - // child proc if (pid == 0) { - // write my stdout the the pipe + // child proc + // write my stdout to the pipe close(pipefds[0]); dup2(pipefds[1], STDOUT_FILENO); close(pipefds[1]); @@ -66,36 +70,85 @@ bool load_package_info(package_info_t* info, char* pkgid) { char* argv[] = { PKG_INFO_CMD, info->script_path, NULL }; char* envp[] = { NULL }; execve(PKG_INFO_CMD, argv, envp); + // what are you still doing here? error_out("execve failed"); - } + } else { + // parent proc, close write end of pipe + close(pipefds[1]); + } // wait for child to finish int wstatus; if (waitpid(pid, &wstatus, 0) < 0) error_out("waitpid failed: %s", strerror(errno)); if (WEXITSTATUS(wstatus) != 0) error_out("failed to execute get pkg attr script"); - // read all bytes from pipe - ssize_t bytes_read = read(pipefds[0], info->package_attrs, sizeof(info->package_attrs)); - if (bytes_read < 0) error_out("Failed to read from pipe"); + // 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) error_out("failed to read from pipe: %s", strerror(errno)); + close(pipefds[0]); - // read attributes from pipe data + // 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->package_attrs[i]; + char atype = info->attrs.buffer[i]; i++; switch (atype) { case 'i': - info->attrs.id = &info->package_attrs[i]; + info->attrs.id = &info->attrs.buffer[i]; break; case 'n': - info->attrs.name = &info->package_attrs[i]; + info->attrs.name = &info->attrs.buffer[i]; break; case 'd': - info->attrs.desc = &info->package_attrs[i]; + info->attrs.desc = &info->attrs.buffer[i]; break; } - for(;info->package_attrs[i] && i < bytes_read; i++); + 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) error_out("failed to pipe: %s", strerror(errno)); + pid_t pid = fork(); + if (pid < 0) error_out("failed to fork: %s", strerror(errno)); + + if (pid == 0) { + // child proc + // write 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? + error_out("execve failed"); + } 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) error_out("failed to read from pipe: %s", strerror(errno)); + close(pipefds[0]); + + // reap the child to finish + int wstatus; + if (waitpid(pid, &wstatus, 0) < 0) error_out("waitpid failed: %s", strerror(errno)); + if (WEXITSTATUS(wstatus) != 0) error_out("failed to execute install script"); +} diff --git a/snag/pkg_db.h b/snag/pkg_db.h index 464380b..0a67043 100644 --- a/snag/pkg_db.h +++ b/snag/pkg_db.h @@ -4,21 +4,21 @@ #include <stdbool.h> // loads and allocates package attributes for the info struct. does not do -// excessive validation, so this should be fine when loading package data in -// bulk. - +// excessive validation, so this should be fine when loading lots of package +// data typedef struct { char* id; char* name; char* desc; + char buffer[4069]; } package_attrs_t; typedef struct { char* script_path; - char package_attrs[4069]; package_attrs_t attrs; } package_info_t; -bool load_package_info(package_info_t* info, char* pkgid); +bool load_package_info(char* pkgid, package_info_t* info); +void run_package_install(const package_info_t* info); #endif |
