aboutsummaryrefslogtreecommitdiffstats
path: root/src/instance.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/instance.c')
-rw-r--r--src/instance.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/src/instance.c b/src/instance.c
new file mode 100644
index 0000000..20c0f59
--- /dev/null
+++ b/src/instance.c
@@ -0,0 +1,193 @@
+#include "instance.h"
+#include "l2su.h"
+#include "uuid/uuid.h"
+
+#include <stdlib.h>
+#include <jansson.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <errno.h>
+
+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, 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;
+ }
+
+ 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;
+}