/* gcc mrk.c -o mrk `pkg-config --cflags --libs eina ecore-file eet` */ // note that this code is far from clean or nice at all. it's not very robust // but it works for the purposes of a proof of concept and getting things off // the ground - so please judge it by that for now #include #include #include #include #include #include #include #include #include #include #include "mrk-proto.h" typedef enum { TMODE_EOL, TMODE_PATH, TMODE_TEXT, TMODE_PATH_CP, TMODE_PATH_CP_LIST, TMODE_PATH_LIST, } Tag_Mode; typedef struct { const char *tag; Tag_Mode mode; } Tag_Type; typedef struct { char *bin; Eina_List *srcs; Eina_List *deps; Eina_List *incs; } Build_Bin; typedef struct { char *src; char *dest; } Build_Data; typedef struct { char *name; char *icon; char *brief; char *version; char *license; char *domain; char *repo; char *devrepo; char *contact; Eina_List *tags; Eina_List *categories; Eina_List *copying; char *needs; Eina_List *bins; Eina_List *data; Eina_List *desktops; Eina_List *icons; Eina_List *po; } Build; static const Tag_Type tags[] = { {"PROJ:", TMODE_EOL}, {"PROJICON:", TMODE_PATH}, {"BRIEF:", TMODE_TEXT}, {"VERSION:", TMODE_EOL}, {"LICENSE:", TMODE_EOL}, {"COPYING:", TMODE_PATH_LIST}, {"NEEDS:", TMODE_EOL}, {"DOMAIN:", TMODE_PATH}, {"REPO:", TMODE_EOL}, {"DEVREPO:", TMODE_EOL}, {"CONTACT:", TMODE_TEXT}, {"CATEGORY:", TMODE_PATH_LIST}, {"TAGS:", TMODE_PATH_LIST}, {"BIN:", TMODE_PATH}, {"SRC:", TMODE_PATH_LIST}, {"DEPS:", TMODE_PATH_LIST}, {"INC:", TMODE_PATH_LIST}, {"DATA:", TMODE_PATH_CP_LIST}, {"DESKTOP:", TMODE_PATH_LIST}, {"ICON:", TMODE_PATH_LIST}, {"PODOMAIN:", TMODE_PATH}, {"PO:", TMODE_PATH_LIST}, {NULL, 0} // END OF LIST }; static Build build = { 0 }; static char *tmpd = "Marrakesh"; static const char *sane_name_veto[] = {"../", "./", "/", NULL}; static const char *sane_name_ok = "01234567890-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. "; static const char *sane_path_veto[] = {"../", "./", NULL}; static const char *sane_path_ok = "01234567890-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. "; static char *server = "devs.enlightenment.org"; static int server_port = 10077; static char *arch = ARCH; static char *os = OS; static void err(char *msg) { fprintf(stderr, "ERROR: %s\n", msg); exit(1); } static int sane_forbidden_path(const char *file, const char **forbidden) { int i; for (i = 0; forbidden[i]; i++) { if (strstr(forbidden[i], file)) return 0; } return 1; } static int sane_allowed_path(const char *file, const char *allowed) { int i, j; for (i = 0; file[i]; i++) { int ok; ok = 0; for (j = 0; allowed[j]; j++) { if (file[i] == allowed[j]) { ok = 1; break; } } if (!ok) return 0; } return 1; } static char * parse_token(char **p, char *end) { char *tok, *seg; while ((*p < end) && (isspace(**p))) (*p)++; if (*p >= end) return NULL; tok = *p; while (*p < end) { if (isspace(**p)) goto token; (*p)++; } token: seg = malloc(*p - tok + 1); if (!seg) return NULL; memcpy(seg, tok, *p - tok); seg[*p - tok] = 0; return seg; } static char * parse_eol(char **p, char *end) { char *tok, *seg; while ((*p < end) && (isspace(**p))) (*p)++; if (*p >= end) return NULL; tok = *p; while (*p < end) { if (**p == '\n') goto token; (*p)++; } token: seg = malloc(*p - tok + 1); if (!seg) return NULL; memcpy(seg, tok, *p - tok); seg[*p - tok] = 0; return seg; } static char * path_check(char *tok) { // XXX: check me return strdup(tok); } static int parse_content(char *mem, size_t size) { char prevc = '\n'; char *end = mem + size; char *p = mem; int skipline = 0; int startline = 0; char *seg = NULL, *s; char *data1 = NULL, *data2 = NULL; int i; Tag_Mode mode = TMODE_TEXT; while (p < end) { if (prevc == '\n') { if (*p == '#') skipline = 1; else skipline = 0; startline = 1; } if (!skipline) { char *tok; char *prevp; prevp = p; tok = parse_token(&p, end); if (!tok) return 1; if (startline) { for (i = 0; tags[i].tag; i++) { if (!strcmp(tok, tags[i].tag)) { // printf("#: %s\n", tok); free(seg); seg = strdup(tok); mode = tags[i].mode; break; } } if (!tags[i].tag) goto not_tag; } else { not_tag: switch (mode) { case TMODE_EOL: case TMODE_TEXT: // prse eol of prevp p = prevp; data1 = parse_eol(&p, end); if (!data1) err("no content"); break; case TMODE_PATH: case TMODE_PATH_LIST: // sanitize (check) path tok put into data1 data1 = path_check(tok); if (!data1) err("path invalid"); break; case TMODE_PATH_CP: case TMODE_PATH_CP_LIST: // sanitize path, then next token > then path 2 -> data1, data2 data1 = path_check(tok); if (!data1) err("path invalid"); s = parse_token(&p, end); if (!s) err("missing > in path copy"); if (!(!strcmp(s, ">"))) err("copy token is not >"); free(s); s = parse_token(&p, end); if (!s) err("missing destination path in path copy"); data2 = path_check(s); if (!data2) err("destination path not valid"); free(s); break; default: break; } // if (data2) // printf(" %i> %s '%s' '%s'\n", // mode, seg, data1, data2); // else // printf(" %i> %s '%s'\n", // mode, seg, data1); if (seg) { if (!strcmp(seg, "PROJ:")) { if (!(sane_forbidden_path(data1, sane_name_veto) && sane_allowed_path(data1, sane_name_ok))) err("name failed sanity check"); free(build.name); build.name = strdup(data1); } else if (!strcmp(seg, "PROJICON:")) { free(build.icon); build.icon = strdup(data1); } else if (!strcmp(seg, "BRIEF:")) { if (!build.brief) build.brief = strdup(data1); else { s = malloc(strlen(build.brief) + 1 + strlen(data1) + 1); if (s) { strcpy(s, build.brief); strcat(s, " "); strcat(s, data1); free(build.brief); build.brief = s; } } } else if (!strcmp(seg, "VERSION:")) { free(build.version); build.version = strdup(data1); } else if (!strcmp(seg, "LICENSE:")) { free(build.license); build.license = strdup(data1); } else if (!strcmp(seg, "COPYING:")) { build.copying = eina_list_append(build.copying, strdup(data1)); } else if (!strcmp(seg, "NEEDS:")) { free(build.needs); build.license = strdup(data1); } else if (!strcmp(seg, "DOMAIN:")) { free(build.domain); build.domain = strdup(data1); } else if (!strcmp(seg, "REPO:")) { free(build.repo); build.repo = strdup(data1); } else if (!strcmp(seg, "DEVREPO:")) { free(build.devrepo); build.devrepo = strdup(data1); } else if (!strcmp(seg, "CATEGORY:")) { build.categories = eina_list_append(build.categories, strdup(data1)); } else if (!strcmp(seg, "TAGS:")) { build.tags = eina_list_append(build.tags, strdup(data1)); } else if (!strcmp(seg, "CONTACT:")) { if (!build.contact) build.contact = strdup(data1); else { s = malloc(strlen(build.contact) + 1 + strlen(data1) + 1); if (s) { strcpy(s, build.contact); strcat(s, " "); strcat(s, data1); free(build.contact); build.contact = s; } } } else if (!strcmp(seg, "BIN:")) { Build_Bin *build_bin = calloc(1, sizeof(Build_Bin)); if (build_bin) { build_bin->bin = strdup(data1); build.bins = eina_list_append(build.bins, build_bin); } } else if (!strcmp(seg, "SRC:")) { Build_Bin *build_bin = eina_list_data_get(eina_list_last(build.bins)); if (build_bin) { build_bin->srcs = eina_list_append(build_bin->srcs, strdup(data1)); } } else if (!strcmp(seg, "DEPS:")) { Build_Bin *build_bin = eina_list_data_get(eina_list_last(build.bins)); if (build_bin) { build_bin->deps = eina_list_append(build_bin->deps, strdup(data1)); } } else if (!strcmp(seg, "INC:")) { Build_Bin *build_bin = eina_list_data_get(eina_list_last(build.bins)); if (build_bin) { build_bin->incs = eina_list_append(build_bin->incs, strdup(data1)); } } else if (!strcmp(seg, "DATA:")) { Build_Data *build_data = calloc(1, sizeof(Build_Data)); if (build_data) { build_data->src = strdup(data1); build_data->dest = strdup(data2); build.data = eina_list_append(build.data, build_data); } } else if (!strcmp(seg, "DESKTOP:")) { build.desktops = eina_list_append(build.desktops, strdup(data1)); } else if (!strcmp(seg, "ICON:")) { build.icons = eina_list_append(build.icons, strdup(data1)); } else if (!strcmp(seg, "PO:")) { build.po = eina_list_append(build.po, strdup(data1)); } } free(data1); free(data2); data1 = NULL; data2 = NULL; } free(tok); prevc = *p; } else { prevc = *p; p++; } startline = 0; } return 1; } static int parse_bld(const char *file) { Eina_File *ef; char *mem; size_t size; int ret; ef = eina_file_open(file, EINA_FALSE); if (!ef) return 0; size = eina_file_size_get(ef); mem = eina_file_map_all(ef, EINA_FILE_SEQUENTIAL); if ((size == 0) || (!mem)) return 0; ret = parse_content(mem, size); eina_file_close(ef); return ret; } static int build_proj(void) { Eina_List *l, *ll; Build_Bin *bin; Build_Data *data; Eina_Strbuf *buf; char *s, *extn, *s2; char tmp[4096]; char tmp2[4096]; const char *ss, *cc; EINA_LIST_FOREACH(build.po, l, s) { snprintf(tmp, sizeof(tmp), "%s/share/locale/%s/LC_MESSAGES/", tmpd, s); ecore_file_mkpath(tmp); snprintf(tmp2, sizeof(tmp2), "po/%s.gmo", s); snprintf(tmp, sizeof(tmp), "%s/share/locale/%s/LC_MESSAGES/%s.mo", tmpd, s, build.domain); ecore_file_cp(tmp2, tmp); } EINA_LIST_FOREACH(build.data, l, data) { s = ecore_file_dir_get(data->dest); if (s) { snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, s); ecore_file_mkpath(tmp); free(s); } snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, data->dest); ecore_file_cp(data->src, tmp); } snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, "share/applications"); ecore_file_mkpath(tmp); EINA_LIST_FOREACH(build.desktops, l, s) { ss = ecore_file_file_get(s); if (!(!strncmp(ss, build.domain, strlen(build.domain)))) err("destkop file wrong domain"); snprintf(tmp, sizeof(tmp), "%s/share/applications/%s", tmpd, ss); ecore_file_cp(s, tmp); } snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, "share/icons"); ecore_file_mkpath(tmp); EINA_LIST_FOREACH(build.icons, l, s) { ss = ecore_file_file_get(s); if (!(!strncmp(ss, build.domain, strlen(build.domain)))) err("icon file wrong domain"); snprintf(tmp, sizeof(tmp), "%s/share/icons/%s", tmpd, ss); ecore_file_cp(s, tmp); } EINA_LIST_FOREACH(build.copying, l, s) { if (strchr(s, '/')) { s2 = ecore_file_dir_get(s); snprintf(tmp, sizeof(tmp), "%s/share/licenses/%s", tmpd, s2); free(s2); } else snprintf(tmp, sizeof(tmp), "%s/share/licenses", tmpd); ecore_file_mkpath(tmp); snprintf(tmp, sizeof(tmp), "%s/share/licenses/%s", tmpd, s); ecore_file_cp(s, tmp); } EINA_LIST_FOREACH(build.bins, l, bin) { if ((buf = eina_strbuf_new())) { s = ecore_file_dir_get(bin->bin); if (s) { snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, s); ecore_file_mkpath(tmp); free(s); } cc = getenv("CC"); if (!cc) cc = "gcc"; eina_strbuf_append(buf, cc); eina_strbuf_append(buf, " -I. -lm -o "); eina_strbuf_append(buf, tmpd); eina_strbuf_append(buf, "/"); eina_strbuf_append(buf, bin->bin); eina_strbuf_append(buf, " -DLOCALEDIR=\\\"/tmp/X/share/locale\\\""); eina_strbuf_append(buf, " -DPACKAGE_BIN_DIR=\\\"/tmp/X/bin\\\""); eina_strbuf_append(buf, " -DPACKAGE_LIB_DIR=\\\"/tmp/X/lib\\\""); eina_strbuf_append(buf, " -DPACKAGE_DATA_DIR=\\\"/tmp/X/share/"); eina_strbuf_append(buf, build.domain); eina_strbuf_append(buf, "\\\""); eina_strbuf_append(buf, " -DPACKAGE_NAME=\\\""); eina_strbuf_append(buf, build.domain); eina_strbuf_append(buf, "\\\""); eina_strbuf_append(buf, " -DPACKAGE_VERSION=\\\""); eina_strbuf_append(buf, build.version); eina_strbuf_append(buf, "\\\""); eina_strbuf_append(buf, " -D_REENTRANT -DHAVE_CONFIG_H -pthread "); eina_strbuf_append(buf, " $CFLAGS "); EINA_LIST_FOREACH(bin->srcs, ll, s) { extn = strrchr(s, '.'); if ((extn) && (!strcasecmp(extn, ".c"))) { eina_strbuf_append(buf, s); eina_strbuf_append(buf, " "); } } EINA_LIST_FOREACH(bin->deps, ll, s) { eina_strbuf_append(buf, " `pkg-config --cflags --libs "); eina_strbuf_append(buf, s); eina_strbuf_append(buf, "` "); } EINA_LIST_FOREACH(bin->incs, ll, s) { eina_strbuf_append(buf, " -I"); eina_strbuf_append(buf, s); eina_strbuf_append(buf, " "); } s = (char *)eina_strbuf_string_get(buf); if (s) system(s); eina_strbuf_free(buf); } } return 1; } static void package_file(Eet_File *ef, const char *file, const char *key) { Eina_File *enf = eina_file_open(file, EINA_FALSE); if (enf) { void *mem = eina_file_map_all(enf, EINA_FILE_SEQUENTIAL); if (mem) { size_t size = eina_file_size_get(enf); eet_write(ef, key, mem, size, EET_COMPRESSION_VERYFAST); } eina_file_close(enf); } } static void package_bin_iter(Eet_File *ef, const char *dir, const char *key) { Eina_List *files; Eina_File *enf; char *s; char tmp[4096]; char tmp2[4096]; files = ecore_file_ls(dir); EINA_LIST_FREE(files, s) { if (!strcmp(s, ".")) continue; else if (!strcmp(s, "..")) continue; snprintf(tmp, sizeof(tmp), "%s/%s", dir, s); snprintf(tmp2, sizeof(tmp2), "%s/%s", key, s); if (ecore_file_is_dir(tmp)) { if (ecore_file_can_exec(tmp)) tmp2[4] = 'D'; package_bin_iter(ef, tmp, tmp2); } else { if (ecore_file_can_exec(tmp)) tmp2[4] = 'X'; else tmp2[4] = 'f'; package_file(ef, tmp, tmp2); } free(s); } } static int pakage_bin(void) { Eet_File *ef; char tmp[4096]; Eina_List *l; char *s; int i; snprintf(tmp, sizeof(tmp), "%s-%s.mkb", build.name, build.version); ef = eet_open(tmp, EET_FILE_MODE_WRITE); if (ef) { #define WRTS(key, var) \ if (var) eet_write(ef, key, var, strlen(var), EET_COMPRESSION_VERYFAST) WRTS("name", build.name); if (build.icon) package_file(ef, build.icon, "icon"); WRTS("brief", build.brief); WRTS("version", build.version); WRTS("license", build.license); WRTS("repo", build.repo); WRTS("devrepo", build.devrepo); WRTS("contact", build.contact); WRTS("needs", build.needs); snprintf(tmp, sizeof(tmp), "%s-%s", os, arch); WRTS("arch", tmp); i = 0; EINA_LIST_FOREACH(build.tags, l, s) { snprintf(tmp, sizeof(tmp), "tag/%i", i++); WRTS(tmp, s); } i = 0; EINA_LIST_FOREACH(build.categories, l, s) { snprintf(tmp, sizeof(tmp), "category/%i", i++); WRTS(tmp, s); } package_bin_iter(ef, tmpd, "bin/f"); eet_close(ef); return 1; } return 0; } static int pakage_src(const char *file) { Eet_File *ef; char tmp[4096]; char tmp2[4096]; snprintf(tmp, sizeof(tmp), "%s-%s.mks", build.name, build.version); ef = eet_open(tmp, EET_FILE_MODE_WRITE); if (ef) { Eina_File *enf; Eina_List *l, *ll; void *mem; size_t size; char *s; Build_Bin *bin; Build_Data *data; enf = eina_file_open(file, EINA_FALSE); if (!enf) err("can't open build file"); mem = eina_file_map_all(enf, EINA_FILE_SEQUENTIAL); if (!mem) err("can't map build file"); size = eina_file_size_get(enf); eet_write(ef, "buildinfo", mem, size, EET_COMPRESSION_VERYFAST); eina_file_close(enf); EINA_LIST_FOREACH(build.copying, l, s) { snprintf(tmp, sizeof(tmp), "src/%s", s); package_file(ef, s, tmp); } EINA_LIST_FOREACH(build.desktops, l, s) { snprintf(tmp, sizeof(tmp), "src/%s", s); package_file(ef, s, tmp); } EINA_LIST_FOREACH(build.icons, l, s) { snprintf(tmp, sizeof(tmp), "src/%s", s); package_file(ef, s, tmp); } EINA_LIST_FOREACH(build.po, l, s) { snprintf(tmp2, sizeof(tmp2), "po/%s.gmo", s); snprintf(tmp, sizeof(tmp), "src/po/%s.gmo", s); package_file(ef, tmp2, tmp); } EINA_LIST_FOREACH(build.bins, l, bin) { EINA_LIST_FOREACH(bin->srcs, ll, s) { snprintf(tmp, sizeof(tmp), "src/%s", s); package_file(ef, s, tmp); } } EINA_LIST_FOREACH(build.data, l, data) { snprintf(tmp, sizeof(tmp), "src/%s", data->src); package_file(ef, data->src, tmp); } eet_close(ef); return 1; } return 0; } static int write_file(Eet_File *ef, const char *key, const char *file) { FILE *f; void *mem; int size; char *s; mem = eet_read(ef, key, &size); if (mem) { s = ecore_file_dir_get(file); if (s) { ecore_file_mkpath(s); free(s); } f = fopen(file, "wb"); if (f) { fwrite(mem, size, 1, f); fclose(f); return 1; } } err("file write failed"); return 0; } static int package_extract(const char *file) { Eet_File *ef; ef = eet_open(file, EET_FILE_MODE_READ); if (ef) { int i, num = 0; char **keys = eet_list(ef, "src/*", &num); if (keys) { for (i = 0; i < num; i++) { if (!strncmp(keys[i], "src/", 4)) { if (!sane_forbidden_path(keys[i], sane_path_veto)) continue; write_file(ef, keys[i], &(keys[i][4])); } } } write_file(ef, "buildinfo", "Marrakesh.mrk"); eet_close(ef); return 1; } err("file does not open"); return 0; } static char * read_string(Eet_File *ef, const char *key) { int size = 0; char *str; char *s = eet_read(ef, key, &size); if (!s) return NULL; str = malloc(size + 1); if (!str) { free(s); return NULL; } memcpy(str, s, size); str[size] = 0; free(s); return str; } static void clean_symlinks(const char *dir) { Eina_List *files; char *s, *ss; char tmp[4096]; files = ecore_file_ls(dir); EINA_LIST_FREE(files, s) { snprintf(tmp, sizeof(tmp), "%s/%s", dir, s); ss = ecore_file_readlink(tmp); if (ss) { free(ss); if (!ecore_file_exists(tmp)) { printf("clean '%s'\n", tmp); ecore_file_unlink(tmp); } } free(s); } } static int field_copy(Eet_File *ef, Eet_File *ef2, const char *key) { int size = 0; char *s = eet_read(ef, key, &size); if (s) { eet_write(ef2, key, s, size, EET_COMPRESSION_VERYFAST); free(s); return 1; } return 0; } static const char * get_home(void) { static char buf[4096] = ""; const char *tmps, *home; if (buf[0]) return buf; tmps = getenv("XDG_DATA_HOME"); home = getenv("HOME"); if (!home) home = "/tmp"; if (tmps) snprintf(buf, sizeof(buf), "%s", tmps); else snprintf(buf, sizeof(buf), "%s", home); return buf; } static int package_clean(void) { char tmp[4096]; snprintf(tmp, sizeof(tmp), "%s/.local/share/icons", get_home()); clean_symlinks(tmp); snprintf(tmp, sizeof(tmp), "%s/.local/share/applications", get_home()); clean_symlinks(tmp); snprintf(tmp, sizeof(tmp), "%s/Applications/.bin", get_home()); clean_symlinks(tmp); return 1; } static int package_install(const char *file) { Eet_File *ef, *ef2; ef = eet_open(file, EET_FILE_MODE_READ); if (ef) { int i, num = 0; char **keys = eet_list(ef, "bin/*", &num); char inst[4096]; char dir[4096]; char tmp[4096]; char tmp2[4096]; char *s; Eina_List *files; char *name; name = read_string(ef, "name"); if (!name) err("no name"); if (!(sane_forbidden_path(name, sane_name_veto) && sane_allowed_path(name, sane_name_ok))) err("name failed sanity check"); snprintf(tmp, sizeof(tmp), "%s/Applications/.bin", get_home()); ecore_file_mkpath(tmp); snprintf(inst, sizeof(inst), "%s/Applications/%s", get_home(), name); if (ecore_file_exists(inst)) err("destination already exists"); ecore_file_mkpath(inst); if (keys) { for (i = 0; i < num; i++) { if (!strncmp(keys[i], "bin/", 4)) { if (!sane_forbidden_path(keys[i], sane_path_veto)) continue; snprintf(tmp, sizeof(tmp), "%s/%s", inst, &(keys[i][6])); write_file(ef, keys[i], tmp); if (keys[i][4] == 'X') { printf("+x '%s'\n", &(keys[i][6])); chmod(tmp, 00500); } } } } snprintf(dir, sizeof(dir), "%s/share/icons", inst); files = ecore_file_ls(dir); EINA_LIST_FREE(files, s) { if (!strcmp(s, ".")) continue; else if (!strcmp(s, "..")) continue; snprintf(tmp, sizeof(tmp), "../../../Applications/%s/share/icons/%s", name, s); snprintf(tmp2, sizeof(tmp2), "%s/.local/share/icons/%s", get_home(), s); if (ecore_file_exists(tmp2)) err("icon file symlink already exists"); ecore_file_symlink(tmp, tmp2); free(s); } snprintf(dir, sizeof(dir), "%s/share/applications", inst); files = ecore_file_ls(dir); EINA_LIST_FREE(files, s) { if (!strcmp(s, ".")) continue; else if (!strcmp(s, "..")) continue; snprintf(tmp, sizeof(tmp), "../../../Applications/%s/share/applications/%s", name, s); snprintf(tmp2, sizeof(tmp2), "%s/.local/share/applications/%s", get_home(), s); if (ecore_file_exists(tmp2)) err("desktop file symlink already exists"); ecore_file_symlink(tmp, tmp2); free(s); } snprintf(dir, sizeof(dir), "%s/bin", inst); files = ecore_file_ls(dir); EINA_LIST_FREE(files, s) { if (!strcmp(s, ".")) continue; else if (!strcmp(s, "..")) continue; snprintf(tmp, sizeof(tmp), "../%s/bin/%s", name, s); snprintf(tmp2, sizeof(tmp2), "%s/Applications/.bin/%s", get_home(), s); if (ecore_file_exists(tmp2)) err("bin file symlink already exists"); ecore_file_symlink(tmp, tmp2); free(s); } snprintf(tmp, sizeof(tmp), "%s/Applications/%s/.icon.png", get_home(), name); write_file(ef, "icon", tmp); snprintf(tmp, sizeof(tmp), "%s/Applications/%s/.info.mki", get_home(), name); ef2 = eet_open(tmp, EET_FILE_MODE_WRITE); free(name); if (ef2) { field_copy(ef, ef2, "name"); field_copy(ef, ef2, "brief"); field_copy(ef, ef2, "version"); field_copy(ef, ef2, "license"); field_copy(ef, ef2, "repo"); field_copy(ef, ef2, "devrepo"); field_copy(ef, ef2, "contact"); field_copy(ef, ef2, "needs"); for (i = 0; i < 9999; i++) { snprintf(tmp, sizeof(tmp), "tag/%i", i); if (!field_copy(ef, ef2, tmp)) break; } for (i = 0; i < 9999; i++) { snprintf(tmp, sizeof(tmp), "category/%i", i); if (!field_copy(ef, ef2, tmp)) break; } eet_close(ef2); } eet_close(ef); return 1; } err("file does not open"); return 0; } static int package_remove(const char *name) { char tmp[4096]; snprintf(tmp, sizeof(tmp), "%s/Applications/%s", get_home(), name); if (!ecore_file_recursive_rm(tmp)) return 0; return 1; } static Ecore_Ipc_Server *ipc = NULL; static char *up_file = NULL; static char *up_path = NULL; static Eina_Bool _ipc_cb_add(void *data, int type, void *event) { Ecore_Ipc_Event_Server_Add *e = event; FILE *f; char tmp[4096]; snprintf(tmp, sizeof(tmp), "%s-%s", os, arch); ecore_ipc_server_send(ipc, 10, M_ID_ARCH, 0, 0, 0, tmp, strlen(tmp)); snprintf(tmp, sizeof(tmp), "%i.%i.%i", eina_version->major, eina_version->minor, eina_version->micro); ecore_ipc_server_send(ipc, 10, M_ID_VERSION, 0, 0, 0, tmp, strlen(tmp)); f = fopen(up_path, "rb"); if (f) { char buf[10000]; size_t size; ecore_ipc_server_send(ipc, 10, M_UP_START, 0, 0, 0, up_file, strlen(up_file)); for (;;) { size = fread(buf, 1, 10000, f); if (size > 0) ecore_ipc_server_send(ipc, 10, M_UP_DATA, 0, 0, 0, buf, size); else break; } ecore_ipc_server_send(ipc, 10, M_UP_END, 0, 0, 0, NULL, 0); fclose(f); } return EINA_TRUE; } static Eina_Bool _ipc_cb_del(void *data, int type, void *event) { Ecore_Ipc_Event_Server_Del *e = event; err("disconnect..."); ecore_main_loop_quit(); return EINA_TRUE; } static Eina_Bool _ipc_cb_dat(void *data, int type, void *event) { Ecore_Ipc_Event_Server_Data *e = event; if (e->major == 10) { if (e->minor == M_UP_OK) { printf("OK\n"); ecore_main_loop_quit(); } else if (e->minor == M_UP_FAIL) { printf("FAIL\n"); err("upload rejected"); } } return EINA_TRUE; } static int package_up(const char *file) { ipc = ecore_ipc_server_connect(ECORE_IPC_REMOTE_SYSTEM, server, server_port, NULL); if (!ipc) return 0; ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, _ipc_cb_add, NULL); ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, _ipc_cb_del, NULL); ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, _ipc_cb_dat, NULL); up_path = strdup(file); up_file = strdup(ecore_file_file_get(file)); ecore_main_loop_begin(); return 1; } static char *down_name = NULL; static char *down_file = NULL; static FILE *down_f = NULL; static Eina_Bool _ipc2_cb_add(void *data, int type, void *event) { Ecore_Ipc_Event_Server_Add *e = event; char tmp[4096]; snprintf(tmp, sizeof(tmp), "%s-%s", os, arch); ecore_ipc_server_send(ipc, 10, M_ID_ARCH, 0, 0, 0, tmp, strlen(tmp)); snprintf(tmp, sizeof(tmp), "%i.%i.%i", eina_version->major, eina_version->minor, eina_version->micro); ecore_ipc_server_send(ipc, 10, M_ID_VERSION, 0, 0, 0, tmp, strlen(tmp)); ecore_ipc_server_send(ipc, 10, M_QRY_GET, 0, 0, 0, down_name, strlen(down_name)); return EINA_TRUE; } static Eina_Bool _ipc2_cb_del(void *data, int type, void *event) { Ecore_Ipc_Event_Server_Del *e = event; err("disconnect..."); ecore_main_loop_quit(); return EINA_TRUE; } static Eina_Bool _ipc2_cb_dat(void *data, int type, void *event) { Ecore_Ipc_Event_Server_Data *e = event; if (e->major == 10) { switch (e->minor) { case M_DOWN_START: if ((e->size > 0) && (e->size <= 1000) && (e->data)) { char *file = malloc(e->size + 1); if (file) { memcpy(file, e->data, e->size); file[e->size] = 0; if ((sane_forbidden_path(file, sane_name_veto) && sane_allowed_path(file, sane_name_ok))) { if (!down_f) { char tmp[4096]; down_file = file; snprintf(tmp, sizeof(tmp), "%s/Applications/.tmp", getenv("HOME")); ecore_file_mkpath(tmp); snprintf(tmp, sizeof(tmp), "%s/Applications/.tmp/%s", getenv("HOME"), down_file); if (ecore_file_exists(tmp)) err("file already exists"); down_f = fopen(file, "wb"); printf("%s\n", file); } else err("already have download"); } else err("mangled filename"); } else err("download file not sane"); } else err("no such package"); break; case M_DOWN_DATA: if ((down_f) && (e->data) && (e->size > 0) && (e->size <= 10000)) { fwrite(e->data, e->size, 1, down_f); } break; case M_DOWN_END: if (down_f) { fclose(down_f); down_f = NULL; ecore_main_loop_quit(); } break; default: break; } } return EINA_TRUE; } static int package_down(const char *name) { ipc = ecore_ipc_server_connect(ECORE_IPC_REMOTE_SYSTEM, server, server_port, NULL); if (!ipc) return 0; ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, _ipc2_cb_add, NULL); ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, _ipc2_cb_del, NULL); ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, _ipc2_cb_dat, NULL); down_name = strdup(name); ecore_main_loop_begin(); return 1; } static char *downsrc_name = NULL; static char *downsrc_file = NULL; static FILE *downsrc_f = NULL; static Eina_Bool _ipc3_cb_add(void *data, int type, void *event) { Ecore_Ipc_Event_Server_Add *e = event; char tmp[4096]; snprintf(tmp, sizeof(tmp), "%s-%s", os, arch); ecore_ipc_server_send(ipc, 10, M_ID_ARCH, 0, 0, 0, tmp, strlen(tmp)); snprintf(tmp, sizeof(tmp), "%i.%i.%i", eina_version->major, eina_version->minor, eina_version->micro); ecore_ipc_server_send(ipc, 10, M_ID_VERSION, 0, 0, 0, tmp, strlen(tmp)); ecore_ipc_server_send(ipc, 10, M_QRY_GET, 0, 0, 0, downsrc_name, strlen(downsrc_name)); return EINA_TRUE; } static Eina_Bool _ipc3_cb_del(void *data, int type, void *event) { Ecore_Ipc_Event_Server_Del *e = event; err("disconnect..."); ecore_main_loop_quit(); return EINA_TRUE; } static Eina_Bool _ipc3_cb_dat(void *data, int type, void *event) { Ecore_Ipc_Event_Server_Data *e = event; if (e->major == 10) { switch (e->minor) { case M_SRC_START: if ((e->size > 0) && (e->size <= 1000) && (e->data)) { char *file = malloc(e->size + 1); if (file) { memcpy(file, e->data, e->size); file[e->size] = 0; if ((sane_forbidden_path(file, sane_name_veto) && sane_allowed_path(file, sane_name_ok))) { if (!downsrc_f) { char tmp[4096]; downsrc_file = file; snprintf(tmp, sizeof(tmp), "%s/Applications/.tmp", getenv("HOME")); ecore_file_mkpath(tmp); snprintf(tmp, sizeof(tmp), "%s/Applications/.tmp/%s", getenv("HOME"), downsrc_file); if (ecore_file_exists(tmp)) err("file already exists"); downsrc_f = fopen(file, "wb"); printf("%s\n", file); } else err("already have download"); } else err("mangled filename"); } else err("download file not sane"); } else err("no such package"); break; case M_SRC_DATA: if ((downsrc_f) && (e->data) && (e->size > 0) && (e->size <= 10000)) { fwrite(e->data, e->size, 1, downsrc_f); } break; case M_SRC_END: if (downsrc_f) { fclose(downsrc_f); downsrc_f = NULL; ecore_main_loop_quit(); } break; default: break; } } return EINA_TRUE; } static int package_downsrc(const char *name) { ipc = ecore_ipc_server_connect(ECORE_IPC_REMOTE_SYSTEM, server, server_port, NULL); if (!ipc) return 0; ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, _ipc3_cb_add, NULL); ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, _ipc3_cb_del, NULL); ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, _ipc3_cb_dat, NULL); downsrc_name = strdup(name); ecore_main_loop_begin(); return 1; } int main(int argc, char **argv) { char *s; eina_init(); eet_init(); ecore_ipc_init(); ecore_file_init(); if (argc < 2) { printf("sub commands:\n" " build\n" " src\n" " bin\n" " extract FILE\n" " inst FILE\n" " clean\n" " rm PKGNAME\n" " rel [FILE]\n" " down PKGNAME\n" " get PKGNAME\n" // " list [CATEGORY]\n" // " search KEY1 [KEY2] [KEY3] [...]\n" // " new\n" // " getsrc\n" " check\n" "\n"); return -1; } s = getenv("DESTDIR"); if (s) tmpd = s; if (getenv("MRKHOST")) server = getenv("MRKHOST"); if (getenv("MRKPORT")) server_port = atoi(getenv("MRKPORT")); if (getenv("MRKARCH")) arch = getenv("MRKARCH"); if (getenv("MRKOS")) os = getenv("MRKOS"); if (!strcmp(argv[1], "build")) { if (!parse_bld("Marrakesh.mrk")) return 1; if (!build_proj()) return 1; } else if (!strcmp(argv[1], "src")) { if (!parse_bld("Marrakesh.mrk")) return 1; if (!pakage_src("Marrakesh.mrk")) return 1; } else if (!strcmp(argv[1], "bin")) { if (!parse_bld("Marrakesh.mrk")) return 1; if (!pakage_bin()) return 1; } else if (!strcmp(argv[1], "extract")) { if (argc < 3) err("need file to extract"); if (!package_extract(argv[2])) return 1; } else if (!strcmp(argv[1], "inst")) { if (argc < 3) err("need file to install"); package_clean(); if (!package_install(argv[2])) return 1; } else if (!strcmp(argv[1], "clean")) { package_clean(); } else if (!strcmp(argv[1], "rm")) { if (argc < 3) err("need package to remove"); if (!package_remove(argv[2])) return 1; package_clean(); } else if (!strcmp(argv[1], "rel")) { char tmp[4096]; char *pk; if (argc < 3) { printf("making src...\n"); if (!parse_bld("Marrakesh.mrk")) return 1; if (!pakage_src("Marrakesh.mrk")) return 1; snprintf(tmp, sizeof(tmp), "%s-%s.mks", build.name, build.version); pk = tmp; } else pk = argv[2]; printf("upload + build...\n"); if (!package_up(pk)) return 1; } else if (!strcmp(argv[1], "down")) { if (argc < 3) err("need package to download"); if (!package_down(argv[2])) return 1; } else if (!strcmp(argv[1], "get")) { if (argc < 3) err("need package to get"); if (!package_down(argv[2])) return 1; if (!down_file) err("no download"); package_remove(argv[2]); package_clean(); if (!package_install(down_file)) return 1; ecore_file_unlink(down_file); } else if (!strcmp(argv[1], "list")) { } else if (!strcmp(argv[1], "search")) { } else if (!strcmp(argv[1], "new")) { } else if (!strcmp(argv[1], "getsrc")) { if (argc < 3) err("need package to download"); if (!package_downsrc(argv[2])) return 1; } else if (!strcmp(argv[1], "check")) { char tmp[4096]; ecore_file_recursive_rm("Marrakesh-Check"); ecore_file_mkdir("Marrakesh-Check"); if (!parse_bld("Marrakesh.mrk")) err("Parse build failed"); if (!pakage_src("Marrakesh.mrk")) err("Source packaging failed"); chdir("Marrakesh-Check"); snprintf(tmp, sizeof(tmp), "../%s-%s.mks", build.name, build.version); if (!package_extract(tmp)) err("Source extract failed"); memset(&build, 0, sizeof(Build)); if (!parse_bld("Marrakesh.mrk")) err("Parse build 2 from source failed"); if (!build_proj()) err("Build project failed"); memset(&build, 0, sizeof(Build)); if (!parse_bld("Marrakesh.mrk")) err("Parse build 3 failed"); if (!pakage_bin()) err("Package binary failed"); printf("OK\n"); } else { err("unknown subcommand!"); return 1; } ecore_file_shutdown(); ecore_ipc_shutdown(); eet_shutdown(); eina_shutdown(); return 0; }