#include #include #include #include #include #define PKG_DB "../snaggies" #define PKG_INFO_CMD "./snagpkginfo.sh" typedef struct { char* id; char* name; char* desc; char* script_path; } package_info_t; void subcmd_install(char* pkgs[], size_t count); bool load_package_info(package_info_t* info, char* pkgid); int main(int argc, char* argv[]) { // run install subcommand with each argument as a package subcmd_install(argv+1, argc-1); return 0; } void subcmd_install(char* pkgs[], size_t count) { // install each package listed for (int i = 0; i < count; ++i) { char* pkgid = pkgs[i]; // load package description package_info_t info; if (load_package_info(&info, pkgid)) { printf("Installing '%s'\n", info.name); } } } bool load_package_info(package_info_t* info, char* pkgid) { // construct package description directory path and ensure it exists size_t pkg_dir_len = strlen(PKG_DB) + strlen(pkgid) + 1; char* pkg_dir = malloc(pkg_dir_len + 1); snprintf(pkg_dir, pkg_dir_len + 1, "%s/%s", PKG_DB, pkgid); if (access(pkg_dir, F_OK) != 0) { fprintf(stderr, "Package '%s' not found in database\n", pkgid); free(pkg_dir); return false; } // construct package description script path and ensure it exists size_t script_path_len = pkg_dir_len + strlen(pkgid) + 4; info->script_path = malloc(script_path_len + 1); snprintf(info->script_path, script_path_len + 1, "%s/%s.sh", pkg_dir, pkgid); free(pkg_dir); if (access(info->script_path, F_OK) != 0) { fprintf(stderr, "Package '%s' broken, doesn't have description script\n", pkgid); free(info->script_path); return false; } // run getpkginfo script that outputs package attributes size_t cmd_len = strlen(PKG_INFO_CMD) + script_path_len + 3; char* cmd = malloc(cmd_len + 1); snprintf(cmd, cmd_len + 1, "%s '%s'", PKG_INFO_CMD, info->script_path); FILE* getinfo_fp = popen(cmd, "r"); if (getinfo_fp == NULL) { perror("failed to popen getpkginfo"); exit(1); // fatal error } // go through each NULL delimited section of the output size_t n = 0; char* line = NULL; ssize_t read; while ((read = getdelim(&line, &n, '\0', getinfo_fp)) != -1) { // read in property based on first attribute type character char atype = line[0]; char* avalue = line+1; switch (atype) { case 'i': // id info->id = strdup(avalue); break; case 'n': // name info->name = strdup(avalue); break; case 'd': // description info->desc = strdup(avalue); break; } } free(line); // close the getpkginfo process if (pclose(getinfo_fp) != 0) { perror("failed to pclose getpkginfo"); exit(1); // fatal error } return true; }