int folders_init(void) { int ret; const char *resources_dir = config_get(CONFIG_RESOURCES_DIR); const char *list_name; ULOGD("%s", __func__); list_name = "names"; ret = load_words(resources_dir, list_name, &folders_names); if (ret < 0) { ULOGE("load_words %s: %s", list_name, strerror(-ret)); return ret; } list_name = "adjectives"; ret = load_words(resources_dir, list_name, &folders_adjectives); if (ret < 0) { ULOGE("load_words %s: %s", list_name, strerror(-ret)); goto err; } return 0; err: folders_cleanup(); return ret; }
static unsigned read_index(const char *name) { long index; char *bracket; char *endptr; bracket = strchr(name, '['); if (bracket == NULL) { ULOGE("access to an array must be performed with [...]"); return -1; } errno = 0; index = strtol(bracket + 1, &endptr, 0); if (errno != 0) return UINT_MAX; if (bracket + 1 == endptr) return UINT_MAX; if (*endptr != ']') { ULOGE("invalid array access near '%s'", bracket); return UINT_MAX; } if (index >= INT_MAX) { ULOGE("index overflow: %ld", index); return UINT_MAX; } return index; }
int folder_add_property(const char *folder_name, const char *name) { int ret; struct rs_node *node; struct folder_property *property; struct folder *folder; folder = folder_find(folder_name); if (folder == NULL) { ULOGE("folder %s doesn't exist", folder_name); return -ENOENT; } /* refuse repetitions */ node = rs_dll_find_match(&folder->properties, folder_property_match_str_array_name, name); if (node != NULL) return -EEXIST; property = custom_property_new(name); if (property == NULL) { ret = -errno; ULOGE("custom_property: %m"); return ret; } return folder_register_property(folder->name, property); }
static int sha1(struct firmware *firmware, unsigned char hash[SHA_DIGEST_LENGTH]) { int ret; size_t count; SHA_CTX ctx; FILE __attribute__((cleanup(ut_file_close))) *f = NULL; char buf[BUF_SIZE] = {0}; SHA1_Init(&ctx); if (ut_file_is_dir(firmware->path)) { SHA1_Update(&ctx, firmware->path, strlen(firmware->path)); } else { f = fopen(firmware->path, "rbe"); if (f == NULL) { ret = -errno; ULOGE("%s: fopen(%s) : %m", firmware->path, __func__); return ret; } do { count = fread(buf, 1, BUF_SIZE, f); if (count != 0) SHA1_Update(&ctx, buf, count); } while (count == BUF_SIZE); if (ferror(f)) { ULOGE("error reading %s for sha1 computation", firmware->path); return -EIO; } } SHA1_Final(hash, &ctx); return 0; }
char *folder_get_info(const char *folder_name, const char *entity_identifier) { int ret; char *info = NULL; char *old_info = NULL; char *value = NULL; const struct folder *folder; struct folder_entity *entity; struct rs_node *node = NULL; struct folder_property *property; errno = 0; if (ut_string_is_invalid(folder_name) || ut_string_is_invalid(entity_identifier)) { errno = EINVAL; return NULL; } folder = folder_find(folder_name); if (folder == NULL) { errno = ENOENT; return NULL; } entity = find_entity(folder, entity_identifier); if (entity == NULL) return NULL; while ((node = rs_dll_next_from(&folder->properties, node)) != NULL) { property = to_property(node); ret = property_get(property, entity, &value); if (ret < 0) { ut_string_free(&info); ULOGE("property_get: %s", strerror(-ret)); errno = -ret; return NULL; } old_info = info; ret = asprintf(&info, "%s%s: %s\n", info ? info : "", property->name, value); ut_string_free(&value); ut_string_free(&old_info); if (ret < 0) { info = NULL; ULOGE("asprintf error"); errno = -ENOMEM; return NULL; } } return info == NULL ? strdup("") : info; }
int folder_entity_get_property(struct folder_entity *entity, const char *name, char **value) { int ret = 0; struct rs_node *property_node; struct folder_property *property; bool is_array_access; unsigned index; if (entity == NULL || ut_string_is_invalid(name) || value == NULL) return -EINVAL; property_node = rs_dll_find_match(&entity->folder->properties, folder_property_match_str_array_name, name); if (property_node == NULL) { ULOGE("property \"%s\" not found for folder %s", name, entity->folder->name); return -ESRCH; } property = to_property(property_node); is_array_access = name[strlen(name) - 1] == ']'; if (is_array_access && !folder_property_is_array(property)) { ULOGE("non-array property accessed as an array one"); return -EINVAL; } if (is_array_access) { index = read_index(name); if (index == UINT_MAX) return -EINVAL; ret = property->geti(property, entity, index, value); if (ret < 0) { ULOGE("property->geti: %s", strerror(-ret)); return ret; } if (*value == NULL) { *value = strdup("nil"); if (*value == NULL) return -errno; } } else { ret = property_get(property, entity, value); if (ret < 0) { ULOGE("property_get: %s", strerror(-ret)); return ret; } } return *value == NULL ? -errno : 0; }
static struct firmware *firmware_new(const char *path) { int ret; const char *sha1; struct firmware *firmware; const char *firmware_repository_path = config_get(CONFIG_REPOSITORY_PATH); ULOGD("indexing firmware %s", path); firmware = calloc(1, sizeof(*firmware)); if (firmware == NULL) return NULL; firmware->entity.folder = folder_find(FIRMWARES_FOLDER_NAME); if (ut_file_is_dir(path)) { firmware->path = realpath(path, NULL); if (firmware->path == NULL) { ret = -errno; ULOGE("strdup: %m"); goto err; } ULOGI("real path is %s", firmware->path); } else { ret = asprintf(&firmware->path, "%s/%s", firmware_repository_path, path); if (ret == -1) { firmware->path = NULL; ULOGE("asprintf error"); errno = -ENOMEM; goto err; } } /* force sha1 computation while in parallel section */ sha1 = compute_sha1(firmware); if (sha1 == NULL) goto err; ret = mount_firmware(firmware); if (ret < 0) ULOGW("read_firmware_info failed: %s\n", strerror(-ret)); ULOGD("indexing firmware %s done", path); return firmware; err: firmware_delete(&firmware); return NULL; }
const char *folders_list(void) { int ret; struct folder *folder = folders + FOLDERS_MAX; /* the result is cached */ if (list != NULL) return list; while (folder-- > folders) { if (folder->name == NULL) continue; ret = ut_string_append(&list, "%s ", folder->name); if (ret < 0) { ULOGC("ut_string_append"); errno = -ret; return NULL; } } if (list == NULL) { ULOGE("no folder registered, that _is_ weird"); errno = ENOENT; return NULL; } if (list[0] != '\0') list[strlen(list) - 1] = '\0'; return list; }
/* result must be freed with free */ static char *folder_request_friendly_name(struct folder *folder) { int ret; const char *adjective; const char *name; char *friendly_name = NULL; unsigned max_names = rs_dll_get_count(&folders_names) * rs_dll_get_count(&folders_adjectives); errno = 0; if (rs_dll_get_count(&folder->entities) > max_names) { ULOGC("more than %u entities in folder %s, weird...", max_names, folder->name); errno = ENOMEM; return NULL; } do { adjective = pick_random_word(&folders_adjectives); name = pick_random_word(&folders_names); ut_string_free(&friendly_name); /* in case we loop */ ret = asprintf(&friendly_name, "%s_%s", adjective, name); if (ret < 0) { ULOGE("asprintf error"); errno = ENOMEM; return NULL; } } while (find_entity(folder, friendly_name) != NULL); return friendly_name; }
int folder_store(const char *folder_name, struct folder_entity *entity) { struct folder_entity *needle; struct folder *folder; ULOGD("%s(%s, %p)", __func__, folder_name, entity); folder = folder_find(folder_name); if (folder == NULL) return -ENOENT; entity->folder = folder; needle = find_entity(folder, folder_entity_get_sha1(entity)); if (needle != NULL) { ULOGE("entity %s already exists", folder_entity_get_sha1(entity)); return -EEXIST; } rs_dll_push(&folder->entities, &entity->node); /* must be done after stored, because it's _drop which frees it */ ut_string_free(&entity->name); entity->name = folder_request_friendly_name(folder); if (entity->name == NULL) return -errno; return 0; }
static void unmount_firmware(struct firmware *firmware) { int ret; struct io_process process; const char *mount_dir = folder_entity_get_base_workspace(&firmware->entity); ret = io_process_init_prepare_launch_and_wait(&process, &process_default_parameters, NULL, "/bin/umount", mount_dir, NULL); if (ret < 0) ULOGE("umount %s failed: %m", mount_dir); else if (process.status != 0) ULOGE("umount %s exited with status %d", mount_dir, process.status); }
static int client_start(const struct sockaddr *addr, uint32_t addrlen) { int res; res = pomp_ctx_connect(s_app.ctx, addr, addrlen); if (res < 0) ULOGE("pomp_ctx_connect: err=%d(%s)", res, strerror(-res)); return res; }
static int firmware_preparation_start(struct preparation *preparation) { int ret; struct firmware_preparation *firmware_preparation; struct firmware *firmware = NULL; char buf[0x200] = {0}; char *pbuf = &buf[0]; const char *uuid = buf + 5; const char *id = preparation->identification_string; if (ut_file_is_dir(id)) { ret = get_from_path(&firmware, id); if (ret < 0) return ret; if (firmware == NULL) firmware = firmware_new(id); return preparation->completion(preparation, &firmware->entity); } firmware_preparation = ut_container_of(preparation, struct firmware_preparation, preparation); ret = ut_process_read_from_output(&pbuf, 0x200, "\"%s\" \"%s\" " "\"%s\" \"%s\" \"%s\" \"%s\"", config_get(CONFIG_CURL_HOOK), "uuid", id, config_get(CONFIG_REPOSITORY_PATH), "", /* we don't know uuid yet, of course */ config_get(CONFIG_VERBOSE_HOOK_SCRIPTS)); if (ret < 0) { ULOGE("uuid retrieval failed"); return ret; } ut_string_rstrip(pbuf); /* * the uuid corresponds to an already registered firmware, nothing to * do and we consider it a success */ if (uuid_already_registered(uuid)) { firmware = get_from_uuid(uuid); return preparation->completion(preparation, &firmware->entity); } ret = io_process_init_prepare_and_launch(&firmware_preparation->process, &(struct io_process_parameters){ .stdout_sep_cb = preparation_progress_sep_cb, .out_sep1 = '\n', .out_sep2 = IO_SRC_SEP_NO_SEP2, .stderr_sep_cb = log_warn_src_sep_cb, .err_sep1 = '\n', .err_sep2 = IO_SRC_SEP_NO_SEP2, .timeout = PREPARATION_TIMEOUT, .signum = PREPARATION_TIMEOUT_SIGNAL, },
static int store_word(struct rs_dll *list, const char *word) { int ret; struct word *w; w = calloc(1, sizeof(*w)); if (w == NULL) { ret = -errno; ULOGE("calloc: %s", strerror(-ret)); return ret; } w->word = strdup(word); if (w->word == NULL) { ret = -errno; ULOGE("calloc: %s", strerror(-ret)); free(w); return ret; } return rs_dll_enqueue(list, &w->node); }
static int load_words(const char *resources_dir, const char *list_name, struct rs_dll *list) { int ret; char __attribute__((cleanup(ut_string_free))) *path = NULL; FILE __attribute__((cleanup(ut_file_close))) *f = NULL; ret = asprintf(&path, "%s/%s", resources_dir, list_name); if (ret == -1) { path = NULL; ULOGE("asprintf error"); exit(1); } f = fopen(path, "rbe"); if (f == NULL) { ret = -errno; ULOGE("failure opening %s: %s", path, strerror(-ret)); return ret; } return store_word_list(list, f); }
static int property_get(struct folder_property *property, struct folder_entity *entity, char **value) { char *suffix; int i; int ret; if (!folder_property_is_array(property)) return property->get(property, entity, value); for (i = 0;; i++) { ret = property->geti(property, entity, i, &suffix); if (ret < 0) { ut_string_free(value); ULOGE("property->geti: %s", strerror(-ret)); return ret; } if (ut_string_match(suffix, "nil")) { ut_string_free(&suffix); break; } ret = ut_string_append(value, "%s ", suffix); ut_string_free(&suffix); if (ret < 0) { ut_string_free(value); ULOGE("ut_string_append: %s", strerror(-ret)); return ret; } } if (*value == NULL) { *value = strdup(" "); if (*value == NULL) return -errno; } (*value)[strlen(*value) - 1] = '\0'; return 0; }
int folder_register_properties(const char *folder, struct folder_property *properties) { int ret; struct folder_property *property = properties; for (property = properties; property->name != NULL; property++) { ret = folder_register_property(folder, property); if (ret < 0) { ULOGE("folder_register_property: %s", strerror(-ret)); return ret; } } return 0; }
static void preparation_progress_sep_cb(struct io_src_sep *sep, char *chunk, unsigned len) { int ret; struct firmware_preparation *firmware_preparation; struct preparation *preparation; struct io_process *process; if (len == 0) return; process = ut_container_of(sep, struct io_process, stdout_src); firmware_preparation = ut_container_of(process, struct firmware_preparation, process); preparation = &firmware_preparation->preparation; chunk[len] = '\0'; ut_string_rstrip(chunk); ULOGD("%s "FIRMWARES_FOLDER_NAME" preparation %s", preparation->identification_string, chunk); /* * rearm the "watch dog", we don't want to abort a working dl because it * took too long */ ret = io_process_set_timeout(process, PREPARATION_TIMEOUT, PREPARATION_TIMEOUT_SIGNAL); if (ret < 0) ULOGW("resetting firmware preparation timeout failed: %s", strerror(-ret)); if (ut_string_match_prefix(chunk, "destination_file=")) { firmware_preparation->destination_file = strdup(chunk + 17); /* * here the hook is stuck in a sleep, waiting for us to say it * it can nicely die */ io_process_signal(process, SIGUSR1); } else { ret = firmwared_notify(FWD_ANSWER_PREPARE_PROGRESS, FWD_FORMAT_ANSWER_PREPARE_PROGRESS, preparation->seqnum, preparation->folder, preparation->identification_string, chunk); if (ret < 0) ULOGE("firmwared_notify: %s", strerror(-ret)); } }
const char *folder_entity_get_base_workspace(struct folder_entity *entity) { int ret; if (entity->base_workspace == NULL) { ret = asprintf(&entity->base_workspace, "%s/%s/%s", config_get(CONFIG_MOUNT_PATH), entity->folder->name, folder_entity_get_sha1(entity)); if (ret < 0) { entity->base_workspace = NULL; ULOGE("asprintf base_workspace error"); ret = -ENOMEM; return NULL; } } return entity->base_workspace; }
static void firmware_preparation_termination(struct io_process *process, pid_t pid, int status) { int ret; struct firmware_preparation *firmware_preparation; struct preparation *preparation; struct firmware *firmware; firmware_preparation = ut_container_of(process, struct firmware_preparation, process); io_mon_remove_source(firmwared_get_mon(), io_process_get_src(&firmware_preparation->process)); preparation = &firmware_preparation->preparation; if (status != 0) { if (WIFSIGNALED(status)) { ULOGD("curl hook terminated on signal %s", strsignal(WTERMSIG(status))); } else { if (WTERMSIG(status) != SIGUSR1) { ULOGE("curl hook error, use absolute paths"); ret = -EINVAL; goto err; } } } /* TODO the following may block a long time */ firmware = firmware_new(firmware_preparation->destination_file); preparation->completion(preparation, &firmware->entity); return; err: firmwared_notify(FWD_ANSWER_ERROR, FWD_FORMAT_ANSWER_ERROR, preparation->seqnum, -ret, strerror(-ret)); preparation->completion(preparation, NULL); }
static int entity_completion(struct preparation *preparation, struct folder_entity *entity) { struct folder *folder; int ret = 0; if (entity == NULL) { ULOGW("%*s creation failed for identification string %s", (int)strlen(preparation->folder) - 1, preparation->folder, preparation->identification_string); ret = -EINVAL; goto out; } /* if already prepared, nothing to be done */ folder = folder_find(preparation->folder); if (find_entity(folder, folder_entity_get_sha1(entity))) goto out; /* folder_store transfers the ownership of the entity to the folder */ ret = folder_store(preparation->folder, entity); if (ret < 0) { do_drop(entity, false); ULOGE("folder_store: %s", strerror(-ret)); goto out; } ret = 0; out: if (ret >= 0) firmwared_notify(FWD_ANSWER_PREPARED, FWD_FORMAT_ANSWER_PREPARED, preparation->seqnum, preparation->folder, folder_entity_get_sha1(entity), entity->name); preparation->has_ended = true; return ret; }
static int store_word_list(struct rs_dll *list, FILE *f) { int ret; char *cret; char buf[0x100]; char *word; rs_dll_init(list, NULL); while ((cret = fgets(buf, 0xFF, f)) != NULL) { buf[0xFF] = '\0'; word = ut_string_strip(buf); if (strlen(word) != 0) { ret = store_word(list, word); if (ret < 0) { ULOGE("store_word: %s", strerror(-ret)); return ret; } } } return 0; }
static void client_event_cb(struct pomp_ctx *ctx, enum pomp_event event, struct pomp_conn *conn, const struct pomp_msg *msg, void *userdata) { int fd, msgid; unsigned int bufsize; void *video_buffer; GstVideoFormat videoformat; unsigned int width, height; switch (event) { case POMP_EVENT_CONNECTED: ULOGI("connected to pimp user filter"); break; case POMP_EVENT_DISCONNECTED: ULOGI("disconnected from pimp user filter"); break; case POMP_EVENT_MSG: switch (msgid = pomp_msg_get_id(msg)) { case SEND_FD: pomp_msg_read(msg, "%x%u%u%u%u", &fd, &bufsize, &videoformat, &width, &height); ULOGI("received a FD from pimp: %d", fd); video_buffer = mmap(NULL, bufsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); s_app.process(video_buffer, bufsize, videoformat, width, height, s_app.priv); pomp_ctx_send(ctx, BUFFER_PROCESSING_DONE, NULL); break; default: ULOGW("received unknown message id from pimp : %d", msgid); break; } break; default: ULOGE("Unknown event: %d", event); break; } }
int folder_entity_set_property(struct folder_entity *entity, const char *name, const char *value) { int ret; unsigned index; bool is_array_access; struct rs_node *property_node; struct folder_property *property; wordexp_t __attribute__((cleanup(wordfree)))we = {0}; if (entity == NULL || ut_string_is_invalid(name) || ut_string_is_invalid(value)) return -EINVAL; property_node = rs_dll_find_match(&entity->folder->properties, folder_property_match_str_array_name, name); if (property_node == NULL) { ULOGE("property \"%s\" not found for folder %s", name, entity->folder->name); return -ESRCH; } property = to_property(property_node); is_array_access = name[strlen(name) - 1] == ']'; if (is_array_access && !folder_property_is_array(property)) { ULOGE("non-array property accessed as an array one"); return -EINVAL; } if (is_array_access) { if (property->seti == NULL) { ULOGE("property %s.%s[] is read-only", entity->folder->name, name); return -EPERM; } index = read_index(name); if (index == UINT_MAX) return -EINVAL; ret = property->seti(property, entity, index, value); if (ret < 0) { ULOGE("property->seti: %s", strerror(-ret)); return ret; } } else { if (folder_property_is_array(property)) { if (property->seti == NULL) { ULOGE("property %s.%s[] is read-only", entity->folder->name, name); return -EPERM; } ret = wordexp(value, &we, 0); if (ret != 0) { ULOGE("wordexp error %d", ret); return ret == WRDE_NOSPACE ? ENOMEM : EINVAL; } for (index = 0; index < we.we_wordc; index++) { ret = property->seti(property, entity, index, we.we_wordv[index]); if (ret < 0) { ULOGE("property->seti: %s", strerror(-ret)); return ret; } } ret = property->seti(property, entity, index, "nil"); if (ret < 0) { ULOGE("property->seti: %s", strerror(-ret)); return ret; } } else { if (property->set == NULL) { ULOGE("property %s.%s is read-only", entity->folder->name, name); return -EPERM; } ret = property->set(property, entity, value); if (ret < 0) { ULOGE("property->set: %s", strerror(-ret)); return ret; } } } return 0; }