#include "instance.h" #include "l2su.h" #include "uuid/uuid.h" #include #include #include #include #include #include #include int l2_instance__load_all_from_object(json_t *obj); json_t *l2_instance__save_all_to_object(void); /* da main functionality */ int l2_instance_load_all(void) { /* open + openat because I am too lazy to concatenate the path with the filename */ int instfd = l2_launcher_open_config("instance.json", O_RDONLY, 0); if (instfd < 0) { return errno == ENOENT ? INSTANCE_SUCCESS : INSTANCE_ERRNO; } json_error_t jserr; json_t *js = json_loadfd(instfd, JSON_REJECT_DUPLICATES, &jserr); if (!js) { fprintf(stderr, "error: JSON error in instance.json: %s (%s:%d:%d)\n", jserr.text, jserr.source, jserr.line, jserr.column); return INSTANCE_EJSON; } if (!json_is_object(js)) { fprintf(stderr, "error: instances.json value is not an object (is actually %d)\n", json_typeof(js)); json_decref(js); return INSTANCE_EFORMAT; } int res = l2_instance__load_all_from_object(js); json_decref(js); return res; } int l2_instance_save_all(void) { json_t *js = NULL; int instfd = l2_launcher_open_config("instance.json", O_WRONLY | O_CREAT | O_TRUNC, 0644); if (instfd < 0) return INSTANCE_ERRNO; int retval = INSTANCE_SUCCESS; js = l2_instance__save_all_to_object(); if (!js) { retval = INSTANCE_EJSON; goto save_done; } if (json_dumpfd(js, instfd, JSON_INDENT(4)) < 0) { retval = INSTANCE_EJSON; } save_done: close(instfd); json_decref(js); return retval; } /* public utilities */ int l2_instance_add_instance(const struct l2_instance *inst) { char *path = strdup(inst->path); if (!path) return INSTANCE_ERRNO; char *name = strdup(inst->name); if (!name) { free(path); return INSTANCE_ERRNO; } struct l2_instance *newinst = calloc(1, sizeof(struct l2_instance)); if (!newinst) { free(path); free(name); return INSTANCE_ERRNO; } newinst->uuid = inst->uuid; newinst->path = path; newinst->name = name; if (l2_state.instance_head && l2_state.instance_tail) { l2_state.instance_tail->next = newinst; newinst->prev = l2_state.instance_tail; l2_state.instance_tail = newinst; } else { l2_state.instance_head = l2_state.instance_tail = newinst; } return INSTANCE_SUCCESS; } int l2_instance_del_instance(struct l2_instance *inst) { if (inst->next) { inst->next->prev = inst->prev; } else { l2_state.instance_tail = inst->prev; } if (inst->prev) { inst->prev->next = inst->next; } else { l2_state.instance_head = inst->next; } free((char *)inst->name); /* okay to cast away const because any instance in the list will be allocated with strdup */ free((char *)inst->path); free(inst); return INSTANCE_SUCCESS; } /* internal utilities */ int l2_instance__load_all_from_object(json_t *obj) { const char *key; json_t *val; json_t *tempval; int res; struct l2_instance inst; json_object_foreach(obj, key, val) { if (!json_is_object(val)) { return INSTANCE_EFORMAT; } if (!l2_uuid_from_string(&inst.uuid, key)) { return INSTANCE_EFORMAT; /* invalid UUID */ } tempval = json_object_get(val, "name"); if (!json_is_string(tempval)) { return INSTANCE_EFORMAT; } /* it's okay to discard const here because add_instance duplicates the string */ inst.name = (char *)json_string_value(tempval); tempval = json_object_get(val, "path"); if (!json_is_string(tempval)) { return INSTANCE_EFORMAT; } inst.path = (char *)json_string_value(tempval); if ((res = l2_instance_add_instance(&inst)) != INSTANCE_SUCCESS) { return res; } } return INSTANCE_SUCCESS; } json_t *l2_instance__save_all_to_object(void) { json_t *obj = json_object(); json_t *jinst; if (!obj) return NULL; char uuidbuf[UUID_STRLEN + 1]; for (struct l2_instance *inst = l2_state.instance_head; inst; inst = inst->next) { l2_uuid_to_string(&inst->uuid, uuidbuf); if (json_object_set_new(obj, uuidbuf, jinst = json_object()) < 0) { goto save_err; /* jinst is decref'd anyway (undocumented) */ } if (json_object_set_new(jinst, "name", json_string(inst->name)) < 0) { goto save_err; } if (json_object_set_new(jinst, "path", json_string(inst->path)) < 0) { goto save_err; } } return obj; save_err: json_decref(obj); return NULL; }