#define _POSIX_C_SOURCE 200809L #define _XOPEN_SOURCE 700 #include #include #include #include "libmbpk.h" #include "ini.h" #include #include #include #define MBPK_DB_DIR "/var/lib/mbpk" #define MBPK_REPO_DIR "/var/lib/mbpk-repo" #define MBPK_REPO_CONFIG "/etc/mbpk-repos.ini" #define MAX_REPOS 32 typedef struct { const char *name; const char *desc; const char *url; char **packages; } mbpk_repository; struct curl_memory { char* memory; size_t size; }; mbpk_repository *repos[MAX_REPOS]; int repo_count = 0; static int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { int rv; /* silence, compiler */ (void)sb; (void)typeflag; (void)ftwbuf; rv = remove(fpath); if (rv) { perror(fpath); } return rv; } int rm_rf(const char *path) { return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); } /* static char* strdup(const char *s) { size_t size = strlen(s) + 1; char* p = (char*)malloc(size); if (p) { memcpy(p, s, size); } return p; } */ static char **split_string(const char *str) { char *str_copy; char *token; char **result; int count; int i; count = 0; if (!str || !*str) { return NULL; } str_copy = strdup(str); if (!str_copy) { return NULL; } token = strtok(str_copy, " "); while (token) { count++; token = strtok(NULL, " "); } free(str_copy); if (count == 0) { return NULL; } result = malloc((unsigned long)(count + 1) * sizeof(char*)); if (!result) { return NULL; } str_copy = strdup(str); if (!str_copy) { free(result); return NULL; } token = strtok(str_copy, " "); i = 0; while (token) { result[i] = strdup(token); if (!result[i]) { while (i > 0) { free((void*)result[--i]); } free(result); free(str_copy); return NULL; } i++; token = strtok(NULL, " "); } result[count] = NULL; free(str_copy); return result; } static void free_split_array(char **arr) { int i; if (!arr) { return; } for (i = 0; arr[i] != NULL; i++) { free((void*)arr[i]); } free(arr); } static size_t curl_memory_write_calback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct curl_memory *mem = (struct curl_memory*)userp; char *ptr = realloc(mem->memory, mem->size + realsize + 1); if (!ptr) { return 0; } mem->memory = ptr; memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } int mbpk_init(void) { CURLcode result; struct stat st; if (stat(MBPK_DB_DIR, &st) == -1) { if (mkdir(MBPK_DB_DIR, 0755) == -1) { return MBPK_DB_FAIL; } } if (stat(MBPK_REPO_DIR, &st) == -1) { if (mkdir(MBPK_REPO_DIR, 0755) == -1) { return MBPK_REPO_FAIL; } } result = curl_global_init(CURL_GLOBAL_ALL); if (result != CURLE_OK) { return MBPK_CURL_INIT_FAIL; } return MBPK_OK; } static int repo_conf_handler(void* user, const char* section, const char* name, const char* value) { /* SHUT UP COMPILER AAAAAAAAAAAAA */ (void)user; if (!(strcmp(name, "url") == 0)) { return 0; /* unknown name, error */ } if (repo_count >= MAX_REPOS) { return 0; /* too many repos */ } repos[repo_count] = malloc(sizeof(mbpk_repository)); if (repos[repo_count] == NULL) { return 0; /* out of memory */ } repos[repo_count]->name = strdup(section); repos[repo_count]->desc = NULL; /* mbpk_update_repositories will fill this in later */ repos[repo_count]->url = strdup(value); repos[repo_count]->packages = NULL; /* mbpk_update_repositories will fill this in later */ if (repos[repo_count]->name == NULL || repos[repo_count]->url == NULL) { free((void*)repos[repo_count]->name); free((void*)repos[repo_count]->url); free(repos[repo_count]); repos[repo_count] = NULL; return 0; /* out of memory */ } repo_count++; return 1; } static int repo_ini_handler(void *user, const char *section, const char *name, const char *value) { mbpk_repository *repo; /* SILENCE YOU COMPILER */ (void)section; repo = (mbpk_repository*)user; if (strcmp(name, "name") == 0) { free((void*)repo->name); repo->name = strdup(value); } else if (strcmp(name, "url") == 0) { free((void*)repo->url); repo->url = strdup(value); } else if (strcmp(name, "desc") == 0) { free((void*)repo->desc); repo->desc = strdup(value); } else if (strcmp(name, "packages") == 0) { /* Do stuff here */ if (repo->packages) { free_split_array(repo->packages); } repo->packages = split_string(value); } return 1; } int mbpk_update_repositories(void) { /* Declarations */ struct stat st; int i; mbpk_repository *repo; CURL *curl; CURLcode result; char *repo_ini_url; char *repo_ini_path; char *repo_dir; char *pkg_ini_url; char *pkg_dir; size_t dir_len; size_t repo_ini_path_len; size_t pkg_ini_url_len; size_t pkg_dir_len; FILE *fp; struct curl_memory chunk; repo_count = 0; if (ini_parse(MBPK_REPO_CONFIG, repo_conf_handler, NULL) < 0) { return MBPK_REPO_FAIL; } for (i = 0; i < repo_count; i++) { repo = repos[i]; printf("[libmbpk debug] processing repo %s\n", repo->name); chunk.memory = malloc(1); if (!chunk.memory) { return MBPK_OUT_OF_MEMORY; } chunk.size = 0; curl = curl_easy_init(); if (curl) { repo_ini_url = malloc(strlen(repo->url) + strlen("/repo.ini") + 1); if (!repo_ini_url) { return MBPK_OUT_OF_MEMORY; } strcpy(repo_ini_url, repo->url); strcat(repo_ini_url, "/repo.ini"); printf("[libmbpk debug] URL: %s\n", repo_ini_url); printf("[libmbpk debug] repo url field: %s\n", repo->url); curl_easy_setopt(curl, CURLOPT_URL, repo_ini_url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); /* follow redirects */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_memory_write_calback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunk); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); /* fail on errors like 404 */ curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); /* accept encoding like gzip */ result = curl_easy_perform(curl); curl_easy_cleanup(curl); free(repo_ini_url); if (result != CURLE_OK) { printf("[libmbpk debug] perform cURL failed\n"); free(chunk.memory); return MBPK_CURL_PERFORM_FAIL; } else { printf("[libmbpk debug] %lu bytes received\n", (unsigned long)chunk.size); printf("[libmbpk debug] Response:\n%s\n", chunk.memory); } } else { free(chunk.memory); return MBPK_CURL_INIT_FAIL; } dir_len = strlen(MBPK_REPO_DIR) + 1 + strlen(repo->name) + 1; repo_dir = malloc(dir_len); if (!repo_dir) { free(chunk.memory); return MBPK_OUT_OF_MEMORY; } sprintf(repo_dir, "%s/%s", MBPK_REPO_DIR, repo->name); repo_ini_path_len = strlen(repo_dir) + 1 + strlen("repo.ini") + 1; repo_ini_path = malloc(repo_ini_path_len); if (!repo_ini_path) { free(chunk.memory); free(repo_dir); return MBPK_OUT_OF_MEMORY; } sprintf(repo_ini_path, "%s/repo.ini", repo_dir); if (stat(repo_dir, &st) == -1) { if (mkdir(repo_dir, 0755) == -1) { free(chunk.memory); free(repo_ini_path); free(repo_dir); return MBPK_REPO_FAIL; } } fp = fopen(repo_ini_path, "w"); if (!fp) { free(repo_ini_path); free(repo_dir); free(chunk.memory); return MBPK_REPO_FAIL; } fwrite(chunk.memory, 1, chunk.size, fp); fclose(fp); free(chunk.memory); if (ini_parse(repo_ini_path, repo_ini_handler, (void*)repo) < 0) { free(repo_ini_path); return MBPK_REPO_FAIL; } free(repo_ini_path); printf("[libmbpk debug] repo %s desc: %s\n", repo->name, repo->desc); printf("[libmbpk debug] repo %s packages:\n", repo->name); pkg_dir_len = strlen(repo_dir) + 1 + strlen("pkg") + 1; pkg_dir = malloc(pkg_dir_len); if (!pkg_dir) { return MBPK_OUT_OF_MEMORY; } sprintf(pkg_dir, "%s/pkg", repo_dir); if (stat(pkg_dir, &st) == -1) { printf("[libmbpk debug] removing old pkg directory for %s\n", repo->name); if (rm_rf(pkg_dir) != 0) { free(pkg_dir); free(repo_dir); return MBPK_REPO_FAIL; } } for (i = 0; repo->packages[i] != NULL; i++) { chunk.memory = malloc(1); if (!chunk.memory) { free(pkg_dir); free(repo_dir); return MBPK_OUT_OF_MEMORY; } chunk.size = 0; /* oh fuck, thats why this didnt work - i was overwriting broken shit */ printf(" %s\n", repo->packages[i]); curl = curl_easy_init(); if (curl) { pkg_ini_url_len = strlen(repo->url) + 1 + strlen("pkg") + 1 + strlen(repo->packages[i]) + strlen(".ini") + 1; pkg_ini_url = malloc(pkg_ini_url_len); if (!pkg_ini_url) { free(repo_dir); return MBPK_OUT_OF_MEMORY; } sprintf(pkg_ini_url, "%s/pkg/%s.ini", repo->url, repo->packages[i]); curl_easy_setopt(curl, CURLOPT_URL, pkg_ini_url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); /* follow redirects */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_memory_write_calback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunk); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); /* fail on errors like 404 */ curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); /* accept encoding like gzip */ result = curl_easy_perform(curl); curl_easy_cleanup(curl); free(pkg_ini_url); if (result != CURLE_OK) { printf("[libmbpk debug] perform cURL failed\n"); free(chunk.memory); free(pkg_dir); free(repo_dir); return MBPK_CURL_PERFORM_FAIL; } else { printf("[libmbpk debug] %lu bytes received\n", (unsigned long)chunk.size); printf("[libmbpk debug] Response:\n%s\n", chunk.memory); } } else { free(chunk.memory); free(repo_dir); free(pkg_dir); return MBPK_CURL_INIT_FAIL; } free(chunk.memory); free(pkg_dir); free(repo_dir); } } return MBPK_OK; } void mbpk_cleanup(void) { int i; for (i = 0; i < repo_count; i++) { if (repos[i]) { free((void*)repos[i]->name); free((void*)repos[i]->url); free((void*)repos[i]->desc); free((void*)repos[i]->packages); free((void*)repos[i]); repos[i] = NULL; } } repo_count = 0; curl_global_cleanup(); } const char* mbpk_strerr(int code) { const char* strerr; switch (code) { case MBPK_OK: strerr = "MBPK_OK (0)"; break; case MBPK_DB_FAIL: strerr = "MBPK_DB_FAIL (1)"; break; case MBPK_REPO_FAIL: strerr = "MBPK_REPO_FAIL (2)"; break; case MBPK_DL_FAIL: strerr = "MBPK_DL_FAIL (3)"; break; case MBPK_EXTRACT_FAIL: strerr = "MBPK_EXTRACT_FAIL (4)"; break; case MBPK_CURL_INIT_FAIL: strerr = "MBPK_CURL_INIT_FAIL (5)"; break; case MBPK_CURL_PERFORM_FAIL: strerr = "MBPK_CURL_PERFORM_FAIL (6)"; break; case MBPK_OUT_OF_MEMORY: strerr = "MBPK_OUT_OF_MEMORY (7)"; break; default: strerr = "MBPK_UNKNOWN_ERR"; break; } return strerr; }