kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 39a5f219862d1d6934bc4488fa9d9b9f03f4db09
parent 7ac1ea379d91f9cb5f634706f44bc405b6ef541c
Author: Joris Vink <joris@coders.se>
Date:   Wed,  6 Jul 2016 16:16:15 +0200

Allow "kore build" to produce single binaries.

Producing single binaries can now be done with building with
"kore build". To get started edit your build.conf and add the
following directives:

single_binary = yes
kore_source = /path/to/kore

optionally you can add kore_flavor to instruct how kore should
be built:

kore_flavor = NOTLS=1

When doing this your build.conf must also include the correct
linking options as the linking is now done fully by kore build.

The binary produced will include your configuration and takes
over a few of kore its command line flags (such as -f, -n or -r).

Diffstat:
.gitignore | 1+
Makefile | 15+++++++++++----
includes/kore.h | 9++++++++-
src/cli.c | 329++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
src/config.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/kore.c | 58+++++++++++++++++++++++++++++++++++++++++++++++-----------
src/module.c | 18+++++++++++++++---
src/utils.c | 11++++++-----
src/worker.c | 2++
9 files changed, 430 insertions(+), 79 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -4,3 +4,4 @@ kore *.module *.DSYM cert +obj diff --git a/Makefile b/Makefile @@ -2,6 +2,7 @@ CC?=gcc PREFIX?=/usr/local +OBJDIR?=obj KORE=kore INSTALL_DIR=$(PREFIX)/bin INCLUDE_DIR=$(PREFIX)/include/kore @@ -9,7 +10,6 @@ INCLUDE_DIR=$(PREFIX)/include/kore S_SRC= src/kore.c src/buf.c src/cli.c src/config.c src/connection.c \ src/domain.c src/mem.c src/msg.c src/module.c src/net.c \ src/pool.c src/timer.c src/utils.c src/worker.c src/keymgr.c -S_OBJS= $(S_SRC:.c=.o) CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes CFLAGS+=-Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual @@ -70,11 +70,18 @@ else S_SRC+=src/bsd.c endif -$(KORE): $(S_OBJS) +S_OBJS= $(S_SRC:src/%.c=$(OBJDIR)/%.o) + +$(KORE): $(OBJDIR) $(S_OBJS) $(CC) $(S_OBJS) $(LDFLAGS) -o $(KORE) +objects: $(OBJDIR) $(S_OBJS) + all: $(KORE) +$(OBJDIR): + @mkdir -p $(OBJDIR) + install: mkdir -p $(INCLUDE_DIR) mkdir -p $(INSTALL_DIR) @@ -85,11 +92,11 @@ uninstall: rm -f $(INSTALL_DIR)/$(KORE) rm -rf $(INCLUDE_DIR) -.c.o: +$(OBJDIR)/%.o: src/%.c $(CC) $(CFLAGS) -c $< -o $@ clean: find . -type f -name \*.o -exec rm {} \; - rm -f $(KORE) + rm -rf $(KORE) $(OBJDIR) .PHONY: all clean diff --git a/includes/kore.h b/includes/kore.h @@ -399,6 +399,10 @@ struct kore_keyreq { }; #endif +#if !defined(KORE_SINGLE_BINARY) +extern char *config_file; +#endif + extern pid_t kore_pid; extern int foreground; extern int kore_debug; @@ -407,7 +411,6 @@ extern char *chroot_path; extern int skip_runas; extern char *runas_user; extern char *kore_pidfile; -extern char *config_file; extern char *kore_tls_cipher_list; extern int tls_version; @@ -631,6 +634,10 @@ void kore_buf_replace_string(struct kore_buf *, char *, void *, size_t); void kore_keymgr_run(void); void kore_keymgr_cleanup(void); +#if defined(KORE_SINGLE_BINARY) +void kore_main(void); +#endif + #if defined(__cplusplus) } #endif diff --git a/src/cli.c b/src/cli.c @@ -68,6 +68,9 @@ struct buildopt { char *name; + char *kore_source; + char *kore_flavor; + int single_binary; struct kore_buf *cflags; struct kore_buf *cxxflags; struct kore_buf *ldflags; @@ -99,9 +102,10 @@ TAILQ_HEAD(cfile_list, cfile); static void cli_fatal(const char *, ...) __attribute__((noreturn)); static void cli_file_close(int); -static void cli_run_kore(void *); +static void cli_run_kore(void); static void cli_generate_certs(void); static void cli_link_library(void *); +static void cli_compile_kore(void *); static void cli_compile_source_file(void *); static void cli_mkdir(const char *, int); static int cli_dir_exists(const char *); @@ -118,6 +122,7 @@ static void cli_file_write(int, const void *, size_t); static int cli_vasprintf(char **, const char *, ...); static void cli_spawn_proc(void (*cb)(void *), void *); static void cli_write_asset(const char *, const char *); +static void cli_register_kore_file(char *, struct dirent *); static void cli_register_source_file(char *, struct dirent *); static void cli_file_create(const char *, const char *, size_t); static int cli_file_requires_build(struct stat *, const char *); @@ -126,6 +131,7 @@ static void cli_find_files(const char *, static void cli_add_source_file(char *, char *, char *, struct stat *, int); +static struct buildopt *cli_buildopt_default(void); static struct buildopt *cli_buildopt_new(const char *); static struct buildopt *cli_buildopt_find(const char *); static void cli_buildopt_cleanup(void); @@ -133,6 +139,12 @@ static void cli_buildopt_parse(const char *); static void cli_buildopt_cflags(struct buildopt *, const char *); static void cli_buildopt_cxxflags(struct buildopt *, const char *); static void cli_buildopt_ldflags(struct buildopt *, const char *); +static void cli_buildopt_single_binary(struct buildopt *, + const char *); +static void cli_buildopt_kore_source(struct buildopt *, + const char *); +static void cli_buildopt_kore_flavor(struct buildopt *, + const char *); static void cli_flavor_load(void); static void cli_flavor_change(const char *); @@ -209,6 +221,14 @@ static const char *build_data = "# %s build config\n" "# You can switch flavors using: kore flavor [newflavor]\n" "\n" + "# Set to yes if you wish to produce a single binary instead\n" + "# of a dynamic library. If you set this to yes you must also\n" + "# set kore_source together with kore_flavor and update ldflags\n" + "# to include the appropriate libraries you will be linking with.\n" + "#single_binary=no\n" + "#kore_source=/home/joris/src/kore\n" + "#kore_flavor=\n" + "\n" "# The flags below are shared between flavors\n" "cflags=-Wall -Wmissing-declarations -Wshadow\n" "cflags=-Wstrict-prototypes -Wmissing-prototypes\n" @@ -245,6 +265,7 @@ static const char *gitignore = "*.o\n.flavor\n.objs\n%s.so\nassets.h\ncert\n"; static int s_fd = -1; static char *appl = NULL; +static int run_after = 0; static char *rootdir = NULL; static char *compiler_c = "gcc"; static char *compiler_cpp = "g++"; @@ -393,6 +414,7 @@ cli_flavor(int argc, char **argv) static void cli_build(int argc, char **argv) { + struct dirent dp; struct cfile *cf; struct buildopt *bopt; struct timeval times[2]; @@ -427,7 +449,6 @@ cli_build(int argc, char **argv) if (!cli_dir_exists(src_path) || !cli_file_exists(config)) cli_fatal("%s doesn't appear to be a kore app", appl); - free(config); cli_flavor_load(); bopt = cli_buildopt_new("_default"); @@ -437,38 +458,62 @@ cli_build(int argc, char **argv) free(data); } - cli_buildopt_parse(build_path); - free(build_path); - - /* Build all source files. */ cli_find_files(src_path, cli_register_source_file); free(src_path); - printf("building %s (%s)\n", appl, flavor); - cli_build_cflags(bopt); - cli_build_cxxflags(bopt); - cli_build_ldflags(bopt); + cli_buildopt_parse(build_path); + free(build_path); (void)cli_vasprintf(&obj_path, "%s/.objs", rootdir); if (!cli_dir_exists(obj_path)) cli_mkdir(obj_path, 0755); free(obj_path); + if (bopt->single_binary) { + if (bopt->kore_source == NULL) + cli_fatal("single_binary set but not kore_source"); + + printf("building kore (%s)\n", bopt->kore_source); + cli_spawn_proc(cli_compile_kore, bopt); + + (void)cli_vasprintf(&src_path, "%s/src", bopt->kore_source); + cli_find_files(src_path, cli_register_kore_file); + free(src_path); + } + + printf("building %s (%s)\n", appl, flavor); + + cli_build_cflags(bopt); + cli_build_cxxflags(bopt); + cli_build_ldflags(bopt); + (void)unlink(assets_header); /* Generate the assets. */ - if (cli_dir_exists(assets_path)) { - cli_file_open(assets_header, - O_CREAT | O_TRUNC | O_WRONLY, &s_fd); + cli_file_open(assets_header, O_CREAT | O_TRUNC | O_WRONLY, &s_fd); + cli_file_writef(s_fd, "#ifndef __H_KORE_ASSETS_H\n"); + cli_file_writef(s_fd, "#define __H_KORE_ASSETS_H\n"); - cli_file_writef(s_fd, "#ifndef __H_KORE_ASSETS_H\n"); - cli_file_writef(s_fd, "#define __H_KORE_ASSETS_H\n"); + if (cli_dir_exists(assets_path)) cli_find_files(assets_path, cli_build_asset); - cli_file_writef(s_fd, "\n#endif\n"); - cli_file_close(s_fd); + + if (bopt->single_binary) { + memset(&dp, 0, sizeof(dp)); + dp.d_type = DT_REG; + printf("adding config %s\n", config); + (void)snprintf(dp.d_name, + sizeof(dp.d_name), "builtin_kore.conf"); + cli_build_asset(config, &dp); } + cli_file_writef(s_fd, "\n#endif\n"); + cli_file_close(s_fd); + free(assets_path); + free(config); + + if (cxx_files_count > 0) + compiler_ld = compiler_cpp; requires_relink = 0; TAILQ_FOREACH(cf, &source_files, list) { @@ -485,10 +530,6 @@ cli_build(int argc, char **argv) if (utimes(cf->opath, times) == -1) printf("utime(%s): %s\n", cf->opath, errno_s); - if (cf->build == BUILD_CXX) { - compiler_ld = compiler_cpp; - } - requires_relink++; } @@ -502,18 +543,26 @@ cli_build(int argc, char **argv) } free(cpath); - (void)cli_vasprintf(&sofile, "%s.so", appl); + if (bopt->single_binary) { + requires_relink++; + (void)cli_vasprintf(&sofile, "%s", appl); + } else { + (void)cli_vasprintf(&sofile, "%s.so", appl); + } + if (!cli_file_exists(sofile)) requires_relink++; free(sofile); if (requires_relink) { - cli_spawn_proc(cli_link_library, NULL); + cli_spawn_proc(cli_link_library, bopt); printf("%s built successfully!\n", appl); } else { printf("nothing to be done!\n"); } - cli_buildopt_cleanup(); + + if (run_after == 0) + cli_buildopt_cleanup(); } static void @@ -538,6 +587,7 @@ cli_clean(int argc, char **argv) static void cli_run(int argc, char **argv) { + run_after = 1; cli_build(argc, argv); if (chdir(rootdir) == -1) @@ -547,7 +597,7 @@ cli_run(int argc, char **argv) * We are exec()'ing kore again, while we could technically set * the right cli options manually and just continue running. */ - cli_run_kore(NULL); + cli_run_kore(); } static void @@ -850,12 +900,14 @@ cli_register_source_file(char *fpath, struct dirent *dp) if (stat(fpath, &st) == -1) cli_fatal("stat(%s): %s", fpath, errno_s); + if (!strcmp(ext, ".cpp")) + cxx_files_count++; + (void)cli_vasprintf(&opath, "%s/.objs/%s.o", rootdir, dp->d_name); if (!cli_file_requires_build(&st, opath)) { build = BUILD_NOBUILD; } else if (!strcmp(ext, ".cpp")) { build = BUILD_CXX; - cxx_files_count++; } else { build = BUILD_C; } @@ -864,6 +916,33 @@ cli_register_source_file(char *fpath, struct dirent *dp) } static void +cli_register_kore_file(char *fpath, struct dirent *dp) +{ + struct stat st, ost; + char *opath, *ext, *fname; + + if ((ext = strrchr(fpath, '.')) == NULL || strcmp(ext, ".c")) + return; + + if (stat(fpath, &st) == -1) + cli_fatal("stat(%s): %s", fpath, errno_s); + + *ext = '\0'; + if ((fname = basename(fpath)) == NULL) + cli_fatal("basename failed"); + + (void)cli_vasprintf(&opath, "%s/.objs/%s.o", rootdir, fname); + + /* Silently ignore non existing object files for kore source files. */ + if (stat(opath, &ost) == -1) { + free(opath); + return; + } + + cli_add_source_file(dp->d_name, fpath, opath, &st, BUILD_NOBUILD); +} + +static void cli_file_remove(char *fpath, struct dirent *dp) { if (unlink(fpath) == -1) @@ -1049,17 +1128,24 @@ cli_compile_source_file(void *arg) args[idx] = NULL; execvp(compiler, args); + cli_fatal("failed to start '%s': %s", compiler, errno_s); } static void cli_link_library(void *arg) { struct cfile *cf; + struct buildopt *bopt; int idx, i; - char *libname; + char *output; char *args[source_files_count + 11 + LD_FLAGS_MAX]; - (void)cli_vasprintf(&libname, "%s/%s.so", rootdir, appl); + bopt = arg; + + if (bopt->single_binary) + (void)cli_vasprintf(&output, "%s/%s", rootdir, appl); + else + (void)cli_vasprintf(&output, "%s/%s.so", rootdir, appl); idx = 0; args[idx++] = compiler_ld; @@ -1070,26 +1156,95 @@ cli_link_library(void *arg) for (i = 0; i < ldflags_count; i++) args[idx++] = ldflags[i]; + if (bopt->single_binary) { + args[idx++] = "-rdynamic"; +#if defined(__linux__) + args[idx++] = "-ldl"; +#endif + } + args[idx++] = "-o"; - args[idx++] = libname; + args[idx++] = output; args[idx] = NULL; execvp(compiler_ld, args); + cli_fatal("failed to start '%s': %s", compiler_ld, errno_s); +} + +static void +cli_compile_kore(void *arg) +{ + struct buildopt *bopt = arg; + int idx, i, fcnt; + char *obj, *args[16], pwd[MAXPATHLEN], *flavors[7]; + + if (getcwd(pwd, sizeof(pwd)) == NULL) + cli_fatal("could not get cwd: %s", errno_s); + + (void)cli_vasprintf(&obj, "OBJDIR=%s/.objs", pwd); + + if (putenv(obj) != 0) + cli_fatal("cannot set OBJDIR for building kore"); + + if (putenv("CFLAGS=-DKORE_SINGLE_BINARY") != 0) + cli_fatal("cannot set CFLAGS for building kore"); + + fcnt = kore_split_string(bopt->kore_flavor, " ", flavors, 7); + +#if defined(OpenBSD) || defined(__FreeBSD_version) || \ + defined(NetBSD) || defined(__DragonFly_version) + args[0] = "gmake"; +#else + args[0] = "make"; +#endif + + args[1] = "-s"; + args[2] = "-C"; + args[3] = bopt->kore_source; + args[4] = "objects"; + + idx = 5; + for (i = 0; i < fcnt; i++) { + printf("using flavor %s\n", flavors[i]); + args[idx++] = flavors[i]; + } + + args[idx] = NULL; + + execvp(args[0], args); + cli_fatal("failed to start '%s': %s", args[0], errno_s); } static void -cli_run_kore(void *arg) +cli_run_kore(void) { - char *args[4], *cpath; + struct buildopt *bopt; + char *args[4], *cpath, *cmd, *flags; - (void)cli_vasprintf(&cpath, "conf/%s.conf", appl); + bopt = cli_buildopt_default(); - args[0] = "kore"; - args[1] = "-fnrc"; - args[2] = cpath; - args[3] = NULL; + if (bopt->single_binary) { + cpath = NULL; + flags = "-fnr"; + (void)cli_vasprintf(&cmd, "./%s", appl); + } else { + cmd = "kore"; + flags = "-fnrc"; + (void)cli_vasprintf(&cpath, "conf/%s.conf", appl); + } - execvp("kore", args); + args[0] = cmd; + args[1] = flags; + + if (cpath != NULL) { + args[2] = cpath; + args[3] = NULL; + } else { + args[2] = NULL; + } + + execvp(args[0], args); + cli_fatal("failed to start '%s': %s", args[0], errno_s); } static void @@ -1142,8 +1297,14 @@ parse_option: cli_buildopt_cxxflags(bopt, t); } else if (!strcasecmp(p, "ldflags")) { cli_buildopt_ldflags(bopt, t); + } else if (!strcasecmp(p, "single_binary")) { + cli_buildopt_single_binary(bopt, t); + } else if (!strcasecmp(p, "kore_source")) { + cli_buildopt_kore_source(bopt, t); + } else if (!strcasecmp(p, "kore_flavor")) { + cli_buildopt_kore_flavor(bopt, t); } else { - printf("ignoring unknown option %s\n", p); + printf("ignoring unknown option '%s'\n", p); } } } @@ -1157,6 +1318,9 @@ cli_buildopt_new(const char *name) bopt->cflags = NULL; bopt->cxxflags = NULL; bopt->ldflags = NULL; + bopt->single_binary = 0; + bopt->kore_source = NULL; + bopt->kore_flavor = NULL; bopt->name = kore_strdup(name); TAILQ_INSERT_TAIL(&build_options, bopt, list); @@ -1176,6 +1340,17 @@ cli_buildopt_find(const char *name) return (NULL); } +static struct buildopt * +cli_buildopt_default(void) +{ + struct buildopt *bopt; + + if ((bopt = cli_buildopt_find("_default")) == NULL) + fatal("no _default buildopt options"); + + return (bopt); +} + static void cli_buildopt_cleanup(void) { @@ -1191,6 +1366,10 @@ cli_buildopt_cleanup(void) kore_buf_free(bopt->cxxflags); if (bopt->ldflags != NULL) kore_buf_free(bopt->ldflags); + if (bopt->kore_source != NULL) + kore_mem_free(bopt->kore_source); + if (bopt->kore_flavor != NULL) + kore_mem_free(bopt->kore_flavor); kore_mem_free(bopt); } } @@ -1198,10 +1377,8 @@ cli_buildopt_cleanup(void) static void cli_buildopt_cflags(struct buildopt *bopt, const char *string) { - if (bopt == NULL) { - if ((bopt = cli_buildopt_find("_default")) == NULL) - cli_fatal("no _default build options"); - } + if (bopt == NULL) + bopt = cli_buildopt_default(); if (bopt->cflags == NULL) bopt->cflags = kore_buf_create(128); @@ -1212,10 +1389,8 @@ cli_buildopt_cflags(struct buildopt *bopt, const char *string) static void cli_buildopt_cxxflags(struct buildopt *bopt, const char *string) { - if (bopt == NULL) { - if ((bopt = cli_buildopt_find("_default")) == NULL) - cli_fatal("no _default build options"); - } + if (bopt == NULL) + bopt = cli_buildopt_default(); if (bopt->cxxflags == NULL) bopt->cxxflags = kore_buf_create(128); @@ -1226,10 +1401,8 @@ cli_buildopt_cxxflags(struct buildopt *bopt, const char *string) static void cli_buildopt_ldflags(struct buildopt *bopt, const char *string) { - if (bopt == NULL) { - if ((bopt = cli_buildopt_find("_default")) == NULL) - cli_fatal("no _default build options"); - } + if (bopt == NULL) + bopt = cli_buildopt_default(); if (bopt->ldflags == NULL) bopt->ldflags = kore_buf_create(128); @@ -1238,6 +1411,48 @@ cli_buildopt_ldflags(struct buildopt *bopt, const char *string) } static void +cli_buildopt_single_binary(struct buildopt *bopt, const char *string) +{ + if (bopt == NULL) + bopt = cli_buildopt_default(); + else + cli_fatal("single_binary only supported in global context"); + + if (!strcmp(string, "yes")) + bopt->single_binary = 1; + else + bopt->single_binary = 0; +} + +static void +cli_buildopt_kore_source(struct buildopt *bopt, const char *string) +{ + if (bopt == NULL) + bopt = cli_buildopt_default(); + else + cli_fatal("kore_source only supported in global context"); + + if (bopt->kore_source != NULL) + kore_mem_free(bopt->kore_source); + + bopt->kore_source = kore_strdup(string); +} + +static void +cli_buildopt_kore_flavor(struct buildopt *bopt, const char *string) +{ + if (bopt == NULL) + bopt = cli_buildopt_default(); + else + cli_fatal("kore_flavor only supported in global context"); + + if (bopt->kore_flavor != NULL) + kore_mem_free(bopt->kore_flavor); + + bopt->kore_flavor = kore_strdup(string); +} + +static void cli_build_flags_common(struct kore_buf* buf) { kore_buf_appendf(buf, @@ -1282,6 +1497,9 @@ cli_build_cflags(struct buildopt *bopt) obopt->cflags->offset); } + if (bopt->single_binary) + kore_buf_appendf(bopt->cflags, "-DKORE_SINGLE_BINARY"); + string = kore_buf_stringify(bopt->cflags, NULL); printf("CFLAGS=%s\n", string); cflags_count = kore_split_string(string, " ", cflags, CFLAGS_MAX); @@ -1324,12 +1542,14 @@ cli_build_ldflags(struct buildopt *bopt) if (bopt->ldflags == NULL) bopt->ldflags = kore_buf_create(128); + if (bopt->single_binary == 0) { #if defined(__MACH__) - kore_buf_appendf(bopt->ldflags, - "-dynamiclib -undefined suppress -flat_namespace "); + kore_buf_appendf(bopt->ldflags, + "-dynamiclib -undefined suppress -flat_namespace "); #else - kore_buf_appendf(bopt->ldflags, "-shared "); + kore_buf_appendf(bopt->ldflags, "-shared "); #endif + } if (obopt != NULL && obopt->ldflags != NULL) { kore_buf_append(bopt->ldflags, obopt->ldflags->data, @@ -1351,6 +1571,9 @@ cli_flavor_load(void) cli_fatal("could not get cwd: %s", errno_s); appl = basename(pwd); + if (appl == NULL) + cli_fatal("basename: %s", errno_s); + appl = kore_strdup(appl); (void)cli_vasprintf(&conf, "conf/%s.conf", appl); if (!cli_dir_exists("conf") || !cli_file_exists(conf)) diff --git a/src/config.c b/src/config.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <sys/param.h> #include <sys/stat.h> #include <stdio.h> @@ -36,9 +37,16 @@ /* XXX - This is becoming a clusterfuck. Fix it. */ +#if !defined(KORE_SINGLE_BINARY) +static int configure_load(char *); +#else +static FILE *config_file_write(void); +extern u_int8_t asset_builtin_kore_conf[]; +extern u_int32_t asset_len_builtin_kore_conf; +#endif + static int configure_include(char *); static int configure_bind(char *); -static int configure_load(char *); static int configure_domain(char *); static int configure_chroot(char *); static int configure_runas(char *); @@ -100,7 +108,9 @@ static struct { } config_names[] = { { "include", configure_include }, { "bind", configure_bind }, +#if !defined(KORE_SINGLE_BINARY) { "load", configure_load }, +#endif { "domain", configure_domain }, { "chroot", configure_chroot }, { "runas", configure_runas }, @@ -150,7 +160,9 @@ static struct { { NULL, NULL }, }; +#if !defined(KORE_SINGLE_BINARY) char *config_file = NULL; +#endif #if !defined(KORE_NO_HTTP) static u_int8_t current_method = 0; @@ -158,15 +170,20 @@ static struct kore_auth *current_auth = NULL; static struct kore_module_handle *current_handler = NULL; #endif +extern const char *__progname; static struct kore_domain *current_domain = NULL; void kore_parse_config(void) { +#if !defined(KORE_SINGLE_BINARY) kore_parse_config_file(config_file); +#else + kore_parse_config_file(NULL); +#endif if (!kore_module_loaded()) - fatal("no site module was loaded"); + fatal("no application module was loaded"); if (skip_chroot != 1 && chroot_path == NULL) { fatal("missing a chroot path"); @@ -192,8 +209,12 @@ kore_parse_config_file(const char *fpath) int i, lineno; char buf[BUFSIZ], *p, *t; +#if !defined(KORE_SINGLE_BINARY) if ((fp = fopen(fpath, "r")) == NULL) fatal("configuration given cannot be opened: %s", fpath); +#else + fp = config_file_write(); +#endif kore_debug("parsing configuration file '%s'", fpath); @@ -282,6 +303,7 @@ configure_bind(char *options) return (kore_server_bind(argv[0], argv[1], argv[2])); } +#if !defined(KORE_SINGLE_BINARY) static int configure_load(char *options) { @@ -294,6 +316,46 @@ configure_load(char *options) kore_module_load(argv[0], argv[1]); return (KORE_RESULT_OK); } +#else +static FILE * +config_file_write(void) +{ + FILE *fp; + ssize_t ret; + int fd, len; + char fpath[MAXPATHLEN]; + + len = snprintf(fpath, sizeof(fpath), "/tmp/%s.XXXXXX", __progname); + if (len == -1 || (size_t)len >= sizeof(fpath)) + fatal("failed to create temporary path"); + + if ((fd = mkstemp(fpath)) == -1) + fatal("mkstemp(%s): %s", fpath, errno_s); + + (void)unlink(fpath); + + for (;;) { + ret = write(fd, asset_builtin_kore_conf, + asset_len_builtin_kore_conf); + if (ret == -1) { + if (errno == EINTR) + continue; + fatal("failed to write temporary config: %s", errno_s); + } + + if ((size_t)ret != asset_len_builtin_kore_conf) + fatal("failed to write temporary config"); + break; + } + + if ((fp = fdopen(fd, "w+")) == NULL) + fatal("fdopen(): %s", errno_s); + + rewind(fp); + + return (fp); +} +#endif #if !defined(KORE_NO_TLS) static int diff --git a/src/kore.c b/src/kore.c @@ -47,6 +47,8 @@ u_int32_t kore_socket_backlog = 5000; char *kore_pidfile = KORE_PIDFILE_DEFAULT; char *kore_tls_cipher_list = KORE_DEFAULT_CIPHER_LIST; +extern char *__progname; + static void usage(void); static void version(void); static void kore_server_start(void); @@ -56,24 +58,37 @@ static void kore_server_sslstart(void); static void usage(void) { +#if !defined(KORE_SINGLE_BINARY) fprintf(stderr, "Usage: kore [options | command]\n"); +#else + fprintf(stderr, "Usage: %s [options]\n", __progname); +#endif fprintf(stderr, "\n"); fprintf(stderr, "Available options:\n"); - fprintf(stderr, "\t-c\tspecify the configuration file to use\n"); - fprintf(stderr, "\t-d\trun with debug on (if compiled in)\n"); - fprintf(stderr, "\t-f\tstart kore in foreground mode\n"); +#if !defined(KORE_SINGLE_BINARY) + fprintf(stderr, "\t-c\tconfiguration to use\n"); +#endif +#if defined(KORE_DEBUG) + fprintf(stderr, "\t-d\trun with debug on)\n"); +#endif + fprintf(stderr, "\t-f\tstart in foreground\n"); fprintf(stderr, "\t-h\tthis help text\n"); fprintf(stderr, "\t-n\tdo not chroot\n"); - fprintf(stderr, "\t-r\tdo not drop privs\n"); - fprintf(stderr, "\t-v\tdisplay kore's version information\n"); + fprintf(stderr, "\t-r\tdo not drop privileges\n"); + fprintf(stderr, "\t-v\tdisplay kore build information\n"); +#if !defined(KORE_SINGLE_BINARY) kore_cli_usage(0); +#else + fprintf(stderr, "\nbuilt with https://kore.io\n"); + exit(1); +#endif } static void version(void) { - printf("kore %d.%d.%d-%s ", KORE_VERSION_MAJOR, KORE_VERSION_MINOR, + printf("%d.%d.%d-%s ", KORE_VERSION_MAJOR, KORE_VERSION_MINOR, KORE_VERSION_PATCH, KORE_VERSION_STATE); #if defined(KORE_NO_TLS) printf("no-tls "); @@ -90,6 +105,9 @@ version(void) #if defined(KORE_DEBUG) printf("debug "); #endif +#if defined(KORE_SINGLE_BINARY) + printf("single "); +#endif printf("\n"); exit(0); @@ -99,22 +117,29 @@ int main(int argc, char *argv[]) { int ch, flags; +#if defined(KORE_SINGLE_BINARY) + void (*kmain)(void); +#endif flags = 0; +#if !defined(KORE_SINGLE_BINARY) while ((ch = getopt(argc, argv, "c:dfhnrv")) != -1) { +#else + while ((ch = getopt(argc, argv, "dfhnrv")) != -1) { +#endif flags++; switch (ch) { +#if !defined(KORE_SINGLE_BINARY) case 'c': config_file = optarg; break; - case 'd': +#endif #if defined(KORE_DEBUG) + case 'd': kore_debug = 1; -#else - printf("kore not compiled with debug support\n"); -#endif break; +#endif case 'f': foreground = 1; break; @@ -140,11 +165,13 @@ main(int argc, char *argv[]) kore_mem_init(); +#if !defined(KORE_SINGLE_BINARY) if (argc > 0) { if (flags) fatal("You cannot specify kore flags and a command"); return (kore_cli_main(argc, argv)); } +#endif kore_pid = getpid(); nlisteners = 0; @@ -159,8 +186,15 @@ main(int argc, char *argv[]) kore_module_init(); kore_server_sslstart(); +#if !defined(KORE_SINGLE_BINARY) if (config_file == NULL) usage(); +#else + kore_module_load(NULL, NULL); + *(void **)&(kmain) = kore_module_getsym("kore_main"); + if (kmain != NULL) + kmain(); +#endif kore_parse_config(); kore_platform_init(); @@ -380,7 +414,7 @@ kore_server_start(void) if (!foreground) kore_write_kore_pid(); - kore_log(LOG_NOTICE, "kore is starting up"); + kore_log(LOG_NOTICE, "%s is starting up", __progname); #if defined(KORE_USE_PGSQL) kore_log(LOG_NOTICE, "pgsql built-in enabled"); #endif @@ -407,8 +441,10 @@ kore_server_start(void) if (sig_recv != 0) { switch (sig_recv) { case SIGHUP: +#if !defined(KORE_SINGLE_BINARY) kore_worker_dispatch_signal(sig_recv); kore_module_reload(0); +#endif break; case SIGINT: case SIGQUIT: diff --git a/src/module.c b/src/module.c @@ -46,19 +46,27 @@ kore_module_cleanup(void) void kore_module_load(const char *path, const char *onload) { +#if !defined(KORE_SINGLE_BINARY) struct stat st; +#endif struct kore_module *module; kore_debug("kore_module_load(%s, %s)", path, onload); + module = kore_malloc(sizeof(struct kore_module)); + module->onload = NULL; + module->ocb = NULL; + +#if !defined(KORE_SINGLE_BINARY) if (stat(path, &st) == -1) fatal("stat(%s): %s", path, errno_s); - module = kore_malloc(sizeof(struct kore_module)); module->path = kore_strdup(path); module->mtime = st.st_mtime; - module->onload = NULL; - module->ocb = NULL; +#else + module->path = NULL; + module->mtime = 0; +#endif module->handle = dlopen(module->path, RTLD_NOW | RTLD_GLOBAL); if (module->handle == NULL) @@ -77,6 +85,7 @@ kore_module_load(const char *path, const char *onload) void kore_module_onload(void) { +#if !defined(KORE_SINGLE_BINARY) struct kore_module *module; TAILQ_FOREACH(module, &modules, list) { @@ -85,11 +94,13 @@ kore_module_onload(void) (void)module->ocb(KORE_MODULE_LOAD); } +#endif } void kore_module_reload(int cbs) { +#if !defined(KORE_SINGLE_BINARY) struct stat st; struct kore_domain *dom; struct kore_module_handle *hdlr; @@ -148,6 +159,7 @@ kore_module_reload(int cbs) #if !defined(KORE_NO_HTTP) kore_validator_reload(); #endif +#endif } int diff --git a/src/utils.c b/src/utils.c @@ -521,8 +521,8 @@ kore_text_trim(char *string, size_t len) if (len == 0) return (string); - end = string + len; - while (isspace(*string)) + end = (string + len) - 1; + while (isspace(*string) && string < end) string++; while (isspace(*end) && end > string) @@ -561,8 +561,9 @@ kore_read_line(FILE *fp, char *in, size_t len) void fatal(const char *fmt, ...) { - va_list args; - char buf[2048]; + va_list args; + char buf[2048]; + extern const char *__progname; va_start(args, fmt); (void)vsnprintf(buf, sizeof(buf), fmt, args); @@ -576,6 +577,6 @@ fatal(const char *fmt, ...) kore_keymgr_cleanup(); #endif - printf("kore: %s\n", buf); + printf("%s: %s\n", __progname, buf); exit(1); } diff --git a/src/worker.c b/src/worker.c @@ -333,7 +333,9 @@ kore_worker_entry(struct kore_worker *kw) if (sig_recv != 0) { switch (sig_recv) { case SIGHUP: +#if !defined(KORE_SINGLE_BINARY) kore_module_reload(1); +#endif break; case SIGQUIT: case SIGINT: