aboutsummaryrefslogtreecommitdiff
path: root/gnu/bootloader
ModeNameSize
-rw-r--r--depthcharge.scm4540logplainabout
-rw-r--r--extlinux.scm4284logplainabout
-rw-r--r--grub.scm31837logplainabout
-rw-r--r--u-boot.scm9261logplainabout
n77' href='#n77'>77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
/**
 * part of Hydrilla
 * Program entry point.
 *
 * Copyright (C) 2021 Wojtek Kosior
 * Redistribution terms are gathered in the `copyright' file.
 */

#define _POSIX_C_SOURCE 200809L /* S_IFMT, S_IFDIR */

#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>

#include <cjson/cJSON.h>

#include "string_buf.h"
#include "hashtable.h"

#include "scriptbase.h"

#define PRESERVE_ERRNO(call)						\
	do {								\
		int VERY_UNLIKELY_TO_COLLIDE_NAME_$$$$$$$$##__LINE__ = errno; \
		call;							\
		errno = VERY_UNLIKELY_TO_COLLIDE_NAME_$$$$$$$$##__LINE__; \
	} while (0)

static const char default_search_path[] = CONTENTDIR;

static int process_scriptbase_subdir(struct scriptbase *base,
				     struct dirent *subdir,
				     struct stringbuf *path_buf,
				     struct stringbuf *json_buf)
{
	struct stat statbuf;
	cJSON *index_json;
	int retval = -1;
	size_t initial_len = path_buf->buf_filled, len_dirname;

	if (sb_string(path_buf, subdir->d_name))
		return -1;

	len_dirname = path_buf->buf_filled;

	if (stat(path_buf->buf, &statbuf))
		return -1;

	if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
		return 0;

	if (sb_string(path_buf, "/index.json"))
		return -1;

	printf("Reading %s\n", path_buf->buf);

	stringbuf_truncate(json_buf, 0);
	if (sb_filepath(json_buf, path_buf->buf))
		return -1;

	index_json = cJSON_Parse(json_buf->buf);
	if (!index_json) {
		fprintf(stderr, "Failed to parse json.\n");
		return -1;
	}

	stringbuf_truncate(path_buf, len_dirname);

	retval = catalogue_component(path_buf->buf + initial_len,
				     index_json, base);

	PRESERVE_ERRNO(cJSON_Delete(index_json));

	return retval;
}

static int prepare_scriptbase_from_dir(const char *dir_path,
				       struct scriptbase *base)
{
	DIR *maindir = NULL;
	struct dirent *subdir;
	struct stringbuf path_buf;
	struct stringbuf json_buf;
	size_t base_path_len;
	int retval = -1;

	printf("Searching %s\n", dir_path);
	stringbuf_init(&path_buf);
	stringbuf_init(&json_buf);

	if (scriptbase_init(base, "https://hydrilla.koszko.org/resources"))
		goto end;

	maindir = opendir(dir_path);
	if (!maindir)
		goto end;

	if (sb_sprintf(&path_buf, "%s/", dir_path))
		goto end;

	base_path_len = path_buf.buf_filled;

	while (true) {
		errno = 0;
		subdir = readdir(maindir);
		if (!subdir) {
			if (!errno)
				retval = 0;
			break;
		}

		if (!strcmp(subdir->d_name, "..") ||
		    !strcmp(subdir->d_name, "."))
			continue;

		stringbuf_truncate(&path_buf, base_path_len);

		errno = 0;
		if (process_scriptbase_subdir(base, subdir,
					       &path_buf, &json_buf)) {
			fprintf(stderr, "Error processing subdirectory %s%s",
				subdir->d_name, errno ? ": " : ".\n");
			if (errno)
				perror(NULL);
		}
	}

end:
	if (errno)
		perror(NULL);
	stringbuf_destroy(&path_buf);
	stringbuf_destroy(&json_buf);
	if (maindir)
		closedir(maindir);
	if (retval)
		scriptbase_destroy(base);

	printf("Search in %s %s.\n", dir_path, retval ? "failed" : "finished");

	return retval;
}

static void print_component_name(const void *key, void *val, void *arg)
{
	char type = (char) (size_t) arg;
	bool unfilled;

	unfilled =
		(type == 's' && !((struct script*) val)->filled) ||
		(type == 'b' && !((struct bag*) val)->filled);

	printf("%s%s\n", (const char*) key,
	       unfilled ? " (referenced only)" : "");
}

int serve_scriptbase(struct scriptbase *base, bool);

int main(int argc, char *argv[])
{
	struct scriptbase base;
	const char *search_path = default_search_path;

	if (argc > 1)
		search_path = argv[1];

	if (prepare_scriptbase_from_dir(search_path, &base))
		return -1;
	puts("## LOADED SCRIPTS:");
	ht_map(&base.scripts, (void*) 's', print_component_name);
	puts("## LOADED BAGS:");
	ht_map(&base.bags, (void*) 'b', print_component_name);
	puts("## LOADED PAGES:");
	ht_map(&base.pages, (void*) 'p', print_component_name);

	if (serve_scriptbase(&base, !!getenv("HYDRILLA_WAIT_SIGTERM")))
		fprintf(stderr, "Error serving scriptbase.\n");

	scriptbase_destroy(&base);
	return 0;
}