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 ea5b89d20b73d1d6142f90004576d8e93ce8fbff
parent 818dd84acd5ba00adfbcada2d2eaf20a44c5d44f
Author: Joris Vink <joris@coders.se>
Date:   Fri,  1 Aug 2014 13:59:47 +0200

Move orbit functionality into kore directly.

Makes more sense and reads easier:

kore create myapp
kore build myapp
kore run myapp

Note that kore retains its cli options (if no command was given),
meaning you can still start kore in the traditional way as well.

The command options are simply to make development easier.

Diffstat:
Makefile | 14+++-----------
includes/kore.h | 3+++
src/cli.c | 545+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/kore.c | 29+++++++++++++++++++++++++----
src/orbit.c | 537-------------------------------------------------------------------------------
5 files changed, 576 insertions(+), 552 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,25 +2,20 @@ CC=gcc KORE=kore -ORBIT=orbit INSTALL_DIR=/usr/local/bin INCLUDE_DIR=/usr/local/include/kore -S_SRC= src/kore.c src/accesslog.c src/auth.c src/buf.c src/config.c \ +S_SRC= src/kore.c src/accesslog.c src/auth.c src/buf.c src/cli.c src/config.c \ src/connection.c src/domain.c src/http.c src/mem.c src/module.c \ src/net.c src/pool.c src/spdy.c src/validator.c src/utils.c \ src/worker.c src/zlib_dict.c S_OBJS= $(S_SRC:.c=.o) -O_SRC= src/orbit.c - CFLAGS+=-Wall -Wstrict-prototypes -Wmissing-prototypes CFLAGS+=-Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual CFLAGS+=-Wsign-compare -Iincludes -g LDFLAGS+=-rdynamic -lssl -lcrypto -lz -ORBIT_CFLAGS=$(CFLAGS) - ifneq ("$(DEBUG)", "") CFLAGS+=-DKORE_DEBUG endif @@ -59,19 +54,16 @@ else S_SRC+=src/bsd.c endif -all: $(S_OBJS) $(O_SRC) - $(CC) $(ORBIT_CFLAGS) $(O_SRC) -o $(ORBIT) +all: $(S_OBJS) $(CC) $(LDFLAGS) $(S_OBJS) -o $(KORE) install: mkdir -p $(INCLUDE_DIR) install -m 555 $(KORE) $(INSTALL_DIR)/$(KORE) - install -m 555 $(ORBIT) $(INSTALL_DIR)/$(ORBIT) install -m 644 includes/*.h $(INCLUDE_DIR) uninstall: rm -f $(INSTALL_DIR)/$(KORE) - rm -f $(INSTALL_DIR)/$(ORBIT) rm -rf $(INCLUDE_DIR) .c.o: @@ -79,6 +71,6 @@ uninstall: clean: find . -type f -name \*.o -exec rm {} \; - rm -f $(KORE) $(ORBIT) + rm -f $(KORE) .PHONY: clean diff --git a/includes/kore.h b/includes/kore.h @@ -331,6 +331,9 @@ extern struct kore_domain *primary_dom; extern struct passwd *pw; extern struct kore_pool nb_pool; +void kore_cli_usage(int); +int kore_cli_main(int, char **); + void kore_signal(int); void kore_worker_wait(int); void kore_worker_init(void); diff --git a/src/cli.c b/src/cli.c @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2014 Joris Vink <joris@coders.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/queue.h> +#include <sys/wait.h> + +#include <errno.h> +#include <dirent.h> +#include <libgen.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "kore.h" + +struct cmd { + const char *name; + const char *descr; + void (*cb)(int, char **); +}; + +struct filegen { + void (*cb)(void); +}; + +struct cfile { + char *fpath; + char *opath; + TAILQ_ENTRY(cfile) list; +}; + +TAILQ_HEAD(cfile_list, cfile); + +static void cli_fatal(const char *, ...); + +static void *cli_malloc(size_t); +static void cli_run_kore(void *); +static void cli_link_library(void *); +static void cli_compile_cfile(void *); +static void cli_mkdir(const char *, int); +static int cli_dir_exists(const char *); +static void cli_find_cfiles(const char *); +static void cli_file_open(const char *, int *); +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_file_create(const char *, const char *, size_t); + +static void cli_run(int, char **); +static void cli_help(int, char **); +static void cli_build(int, char **); +static void cli_create(int, char **); + +static void file_create_src(void); +static void file_create_config(void); +static void file_create_gitignore(void); + +static struct cmd cmds[] = { + { "help", "This help text", cli_help }, + { "run", "Run an application", cli_run }, + { "build", "Build an application", cli_build }, + { "create", "Create a new application skeleton", cli_create }, + { NULL, NULL, NULL } +}; + +static struct filegen gen_files[] = { + { file_create_src }, + { file_create_config }, + { file_create_gitignore }, + { NULL } +}; + +static const char *gen_dirs[] = { + "src", + "conf", + "static", + NULL +}; + +static const char *src_data = + "#include <kore/kore.h>\n" + "#include <kore/http.h>\n" + "\n" + "int\t\tpage(struct http_request *);\n" + "\n" + "int\n" + "page(struct http_request *req)\n" + "{\n" + "\thttp_response(req, 200, NULL, 0);\n" + "\treturn (KORE_RESULT_OK);\n" + "}\n"; + +static const char *config_data = + "# Placeholder configuration\n" + "\n" + "bind\t\t127.0.0.1 8888\n" + "pidfile\t\tkore.pid\n" + "load\t\t./%s.so\n" + "\n" + "domain 127.0.0.1 {\n" + "\tstatic\t/\tpage\n" + "}\n"; + +static const char *gitignore_data = "*.o\n.objs\n%s.so\n"; + +static char *appl = NULL; +static char *rootdir = NULL; +static struct cfile_list source_files; +static int cfiles_count; +static struct cmd *command = NULL; + +void +kore_cli_usage(int local) +{ + int i; + + if (local) + fprintf(stderr, "Usage: kore [command]\n"); + + fprintf(stderr, "\nAvailable commands:\n"); + for (i = 0; cmds[i].name != NULL; i++) + printf("\t%s\t%s\n", cmds[i].name, cmds[i].descr); + + fprintf(stderr, "\nFind more information on https://kore.io\n"); + exit(1); +} + +int +kore_cli_main(int argc, char **argv) +{ + int i; + + if (argc < 1) + kore_cli_usage(1); + + for (i = 0; cmds[i].name != NULL; i++) { + if (!strcmp(argv[0], cmds[i].name)) { + argc--; + argv++; + command = &cmds[i]; + cmds[i].cb(argc, argv); + break; + } + } + + if (cmds[i].name == NULL) { + fprintf(stderr, "No such command: %s\n", argv[0]); + kore_cli_usage(1); + } + + return (0); +} + +static void +cli_help(int argc, char **argv) +{ + kore_cli_usage(1); +} + +static void +cli_create(int argc, char **argv) +{ + int i; + char *fpath; + + if (argc != 1) + cli_fatal("missing application name"); + + appl = argv[0]; + cli_mkdir(appl, 0755); + for (i = 0; gen_dirs[i] != NULL; i++) { + cli_vasprintf(&fpath, "%s/%s", appl, gen_dirs[i]); + cli_mkdir(fpath, 0755); + free(fpath); + } + + for (i = 0; gen_files[i].cb != NULL; i++) + gen_files[i].cb(); +} + +static void +cli_build(int argc, char **argv) +{ + struct cfile *cf; + char pwd[PATH_MAX], *spath; + + if (argc == 0) { + if (getcwd(pwd, sizeof(pwd)) == NULL) + cli_fatal("could not get cwd: %s", errno_s); + + rootdir = "."; + appl = basename(pwd); + cli_vasprintf(&spath, "./src"); + } else { + appl = argv[0]; + rootdir = appl; + cli_vasprintf(&spath, "%s/src", appl); + + if (!cli_dir_exists(spath)) + cli_fatal("%s doesn't appear to be an app", appl); + } + + cfiles_count = 0; + TAILQ_INIT(&source_files); + + /* cli_build_statics("static"); */ + cli_find_cfiles(spath); + free(spath); + + cli_vasprintf(&spath, "%s/.objs", rootdir); + if (!cli_dir_exists(spath)) + cli_mkdir(spath, 0755); + + TAILQ_FOREACH(cf, &source_files, list) { + printf("compiling %s\n", cf->fpath); + cli_spawn_proc(cli_compile_cfile, cf); + } + + cli_spawn_proc(cli_link_library, NULL); + + TAILQ_FOREACH(cf, &source_files, list) { + if (unlink(cf->opath) == -1) + printf("couldnt unlink %s\n", cf->opath); + } + + if (rmdir(spath) == -1) + printf("couldn't rmdir %s\n", spath); + + free(spath); +} + +static void +cli_run(int argc, char **argv) +{ + cli_build(argc, argv); + + if (chdir(rootdir) == -1) + cli_fatal("couldn't change directory to %s", rootdir); + + cli_run_kore(NULL); +} + +static void +file_create_src(void) +{ + char *name; + + (void)cli_vasprintf(&name, "src/%s.c", appl); + cli_file_create(name, src_data, strlen(src_data)); + free(name); +} + +static void +file_create_config(void) +{ + int l; + char *name, *data; + + (void)cli_vasprintf(&name, "conf/%s.conf", appl); + l = cli_vasprintf(&data, config_data, appl); + cli_file_create(name, data, l); + + free(name); + free(data); +} + +static void +file_create_gitignore(void) +{ + int l; + char *data; + + l = cli_vasprintf(&data, gitignore_data, appl); + cli_file_create(".gitignore", data, l); + free(data); +} + +static void +cli_mkdir(const char *fpath, int mode) +{ + if (mkdir(fpath, mode) == -1) + cli_fatal("cli_mkdir(%s): %s", fpath, errno_s); +} + +static int +cli_dir_exists(const char *fpath) +{ + struct stat st; + + if (stat(fpath, &st) == -1) + return (0); + + if (!S_ISDIR(st.st_mode)) + return (0); + + return (1); +} + +static void +cli_file_open(const char *fpath, int *fd) +{ + if ((*fd = open(fpath, O_CREAT | O_TRUNC | O_WRONLY, 0755)) == -1) + cli_fatal("cli_file_open(%s): %s", fpath, errno_s); +} + +static void +cli_file_close(int fd) +{ + if (close(fd) == -1) + printf("warning: close() %s\n", errno_s); +} + +static void +cli_file_write(int fd, const void *buf, size_t len) +{ + ssize_t r; + const u_int8_t *d; + size_t written; + + d = buf; + written = 0; + while (written != len) { + r = write(fd, d + written, len - written); + if (r == -1) { + if (errno == EINTR) + continue; + cli_fatal("cli_file_write: %s", errno_s); + } + + written += r; + } +} + +static void +cli_file_create(const char *name, const char *data, size_t len) +{ + int fd; + char *fpath; + + cli_vasprintf(&fpath, "%s/%s", appl, name); + + cli_file_open(fpath, &fd); + cli_file_write(fd, data, len); + cli_file_close(fd); + + printf("created %s\n", fpath); + free(fpath); +} + +static void +cli_find_cfiles(const char *path) +{ + DIR *d; + struct cfile *cf; + struct dirent *dp; + char *fpath; + + if ((d = opendir(path)) == NULL) + cli_fatal("cli_find_cfiles: opendir(%s): %s", path, errno_s); + + while ((dp = readdir(d)) != NULL) { + if (!strcmp(dp->d_name, ".") || + !strcmp(dp->d_name, "..")) + continue; + + cli_vasprintf(&fpath, "%s/%s", path, dp->d_name); + + if (dp->d_type == DT_DIR) { + cli_find_cfiles(fpath); + free(fpath); + } else { + cfiles_count++; + cf = cli_malloc(sizeof(*cf)); + cf->fpath = fpath; + cli_vasprintf(&(cf->opath), + "%s/.objs/%s.o", rootdir, dp->d_name); + TAILQ_INSERT_TAIL(&source_files, cf, list); + } + } +} + +static void +cli_compile_cfile(void *arg) +{ + struct cfile *cf = arg; + char *args[18], *ipath; + + cli_vasprintf(&ipath, "-I%s/src", appl); + + args[0] = "gcc"; + args[1] = ipath; + args[2] = "-I/usr/local/include"; + args[3] = "-Wall"; + args[4] = "-Wstrict-prototypes"; + args[5] = "-Wmissing-prototypes"; + args[6] = "-Wmissing-declarations"; + args[7] = "-Wshadow"; + args[8] = "-Wpointer-arith"; + args[9] = "-Wcast-qual"; + args[10] = "-Wsign-compare"; + args[11] = "-fPIC"; + args[12] = "-g"; + + args[13] = "-c"; + args[14] = cf->fpath; + args[15] = "-o"; + args[16] = cf->opath; + args[17] = NULL; + + execvp("gcc", args); +} + +static void +cli_link_library(void *arg) +{ + int idx; + struct cfile *cf; + char *args[cfiles_count + 10], *libname; + + cli_vasprintf(&libname, "%s/%s.so", rootdir, appl); + + idx = 0; + args[idx++] = "gcc"; + +#if defined(__MACH__) + args[idx++] = "-dynamiclib"; + args[idx++] = "-undefined"; + args[idx++] = "suppress"; + args[idx++] = "-flat_namespace"; +#else + args[idx++] = "-shared"; +#endif + + TAILQ_FOREACH(cf, &source_files, list) + args[idx++] = cf->opath; + + args[idx++] = "-o"; + args[idx++] = libname; + args[idx] = NULL; + + execvp("gcc", args); +} + +static void +cli_run_kore(void *arg) +{ + char *args[4], *cpath; + + cli_vasprintf(&cpath, "conf/%s.conf", appl); + + args[0] = "kore"; + args[1] = "-fnc"; + args[2] = cpath; + args[3] = NULL; + + execvp("kore", args); +} + +static void +cli_spawn_proc(void (*cb)(void *), void *arg) +{ + pid_t pid; + int status; + + pid = fork(); + switch (pid) { + case -1: + cli_fatal("cli_compile_cfile: fork() %s", errno_s); + /* NOTREACHED */ + case 0: + cb(arg); + cli_fatal("cli_spawn_proc: %s", errno_s); + /* NOTREACHED */ + default: + break; + } + + if (waitpid(pid, &status, 0) == -1) + cli_fatal("couldn't wait for child %d", pid); + + if (WEXITSTATUS(status) || WTERMSIG(status) || WCOREDUMP(status)) + cli_fatal("subprocess trouble, check output"); +} + +static void * +cli_malloc(size_t len) +{ + void *ptr; + + if ((ptr = malloc(len)) == NULL) + cli_fatal("cli_malloc: %s", errno_s); + + return (ptr); +} + +static int +cli_vasprintf(char **out, const char *fmt, ...) +{ + int l; + va_list args; + + va_start(args, fmt); + l = vasprintf(out, fmt, args); + va_end(args); + + if (l == -1) + cli_fatal("cli_vasprintf"); + + return (l); +} + +static void +cli_fatal(const char *fmt, ...) +{ + va_list args; + char buf[2048]; + + va_start(args, fmt); + (void)vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (command != NULL) + printf("kore %s: %s\n", command->name, buf); + else + printf("kore: %s\n", buf); + exit(1); +} diff --git a/src/kore.c b/src/kore.c @@ -49,8 +49,17 @@ static void kore_server_sslstart(void); static void usage(void) { - fprintf(stderr, "Usage: kore [-c config] [-dfnv]\n"); - exit(1); + fprintf(stderr, "Usage: kore [options | command]\n"); + 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"); + fprintf(stderr, "\t-h\tThis help text\n"); + fprintf(stderr, "\t-n\tDo not chroot (if not starting kore as root)\n"); + fprintf(stderr, "\t-v\tDisplay kore's version information\n"); + + kore_cli_usage(0); } static void @@ -72,10 +81,13 @@ version(void) int main(int argc, char *argv[]) { - int ch; struct listener *l; + int ch, flags; - while ((ch = getopt(argc, argv, "c:dfnv")) != -1) { + flags = 0; + + while ((ch = getopt(argc, argv, "c:dfhnv")) != -1) { + flags++; switch (ch) { case 'c': config_file = optarg; @@ -90,6 +102,9 @@ main(int argc, char *argv[]) case 'f': foreground = 1; break; + case 'h': + usage(); + break; case 'n': skip_chroot = 1; break; @@ -104,6 +119,12 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; + if (argc > 0) { + if (flags) + fatal("You cannot specify kore flags and a command"); + return (kore_cli_main(argc, argv)); + } + kore_pid = getpid(); nlisteners = 0; LIST_INIT(&listeners); diff --git a/src/orbit.c b/src/orbit.c @@ -1,537 +0,0 @@ -/* - * Copyright (c) 2014 Joris Vink <joris@coders.se> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/queue.h> -#include <sys/wait.h> - -#include <errno.h> -#include <dirent.h> -#include <libgen.h> -#include <fcntl.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#define errno_s strerror(errno) - -struct cmd { - const char *name; - const char *descr; - void (*cb)(int, char **); -}; - -struct filegen { - void (*cb)(void); -}; - -struct cfile { - char *fpath; - char *opath; - TAILQ_ENTRY(cfile) list; -}; - -TAILQ_HEAD(cfile_list, cfile); - -static void usage(void); -static void fatal(const char *, ...); - -static void *orbit_malloc(size_t); -static void orbit_run_kore(void *); -static void orbit_link_library(void *); -static void orbit_compile_cfile(void *); -static void orbit_mkdir(const char *, int); -static int orbit_dir_exists(const char *); -static void orbit_find_cfiles(const char *); -static void orbit_file_open(const char *, int *); -static void orbit_file_write(int, const void *, size_t); -static int orbit_vasprintf(char **, const char *, ...); -static void orbit_spawn_proc(void (*cb)(void *), void *); -static void orbit_file_create(const char *, const char *, size_t); - -static void orbit_run(int, char **); -static void orbit_build(int, char **); -static void orbit_create(int, char **); - -static void file_create_src(void); -static void file_create_config(void); -static void file_create_gitignore(void); - -static struct cmd cmds[] = { - { "create", "Create a new application", orbit_create }, - { "run", "Run an application", orbit_run }, - { "build", "Builds an application", orbit_build }, - { NULL, NULL, NULL } -}; - -static struct filegen gen_files[] = { - { file_create_src }, - { file_create_config }, - { file_create_gitignore }, - { NULL } -}; - -static const char *gen_dirs[] = { - "src", - "conf", - "static", - NULL -}; - -static const char *src_data = - "#include <kore/kore.h>\n" - "#include <kore/http.h>\n" - "\n" - "int\t\tpage(struct http_request *);\n" - "\n" - "int\n" - "page(struct http_request *req)\n" - "{\n" - "\thttp_response(req, 200, NULL, 0);\n" - "\treturn (KORE_RESULT_OK);\n" - "}\n"; - -static const char *config_data = - "# Placeholder configuration\n" - "\n" - "bind\t\t127.0.0.1 8888\n" - "pidfile\t\tkore.pid\n" - "load\t\t./%s.so\n" - "\n" - "domain 127.0.0.1 {\n" - "\tstatic\t/\tpage\n" - "}\n"; - -static const char *gitignore_data = "*.o\n.objs\n%s.so\n"; - -static char *appl = NULL; -static char *rootdir = NULL; -static struct cfile_list source_files; -static int cfiles_count; -static struct cmd *command = NULL; - -static void -usage(void) -{ - int i; - - fprintf(stderr, "Usage: orbit [command]\n"); - for (i = 0; cmds[i].name != NULL; i++) - printf("\t%s - %s\n", cmds[i].name, cmds[i].descr); - - exit(1); -} - -int -main(int argc, char *argv[]) -{ - int i; - - if (argc < 2) - usage(); - - argc--; - argv++; - - for (i = 0; cmds[i].name != NULL; i++) { - if (!strcmp(argv[0], cmds[i].name)) { - argc--; - argv++; - command = &cmds[i]; - cmds[i].cb(argc, argv); - break; - } - } - - if (cmds[i].name == NULL) { - fprintf(stderr, "No such command: %s\n", argv[0]); - usage(); - } - - return (0); -} - -static void -orbit_create(int argc, char **argv) -{ - int i; - char *fpath; - - if (argc != 1) - fatal("missing application name"); - - appl = argv[0]; - orbit_mkdir(appl, 0755); - for (i = 0; gen_dirs[i] != NULL; i++) { - orbit_vasprintf(&fpath, "%s/%s", appl, gen_dirs[i]); - orbit_mkdir(fpath, 0755); - free(fpath); - } - - for (i = 0; gen_files[i].cb != NULL; i++) - gen_files[i].cb(); -} - -static void -orbit_build(int argc, char **argv) -{ - struct cfile *cf; - char pwd[PATH_MAX], *spath; - - if (argc == 0) { - if (getcwd(pwd, sizeof(pwd)) == NULL) - fatal("could not get cwd: %s", errno_s); - - rootdir = "."; - appl = basename(pwd); - orbit_vasprintf(&spath, "./src"); - } else { - appl = argv[0]; - rootdir = appl; - orbit_vasprintf(&spath, "%s/src", appl); - - if (!orbit_dir_exists(spath)) - fatal("%s doesn't appear to be an app", appl); - } - - cfiles_count = 0; - TAILQ_INIT(&source_files); - - /* orbit_build_statics("static"); */ - orbit_find_cfiles(spath); - free(spath); - - orbit_vasprintf(&spath, "%s/.objs", rootdir); - if (!orbit_dir_exists(spath)) - orbit_mkdir(spath, 0755); - - TAILQ_FOREACH(cf, &source_files, list) { - printf("compiling %s\n", cf->fpath); - orbit_spawn_proc(orbit_compile_cfile, cf); - } - - orbit_spawn_proc(orbit_link_library, NULL); - - TAILQ_FOREACH(cf, &source_files, list) { - if (unlink(cf->opath) == -1) - printf("couldnt unlink %s\n", cf->opath); - } - - if (rmdir(spath) == -1) - printf("couldn't rmdir %s\n", spath); - - free(spath); -} - -static void -orbit_run(int argc, char **argv) -{ - orbit_build(argc, argv); - - if (chdir(rootdir) == -1) - fatal("couldn't change directory to %s", rootdir); - - orbit_run_kore(NULL); -} - -static void -file_create_src(void) -{ - char *name; - - (void)orbit_vasprintf(&name, "src/%s.c", appl); - orbit_file_create(name, src_data, strlen(src_data)); - free(name); -} - -static void -file_create_config(void) -{ - int l; - char *name, *data; - - (void)orbit_vasprintf(&name, "conf/%s.conf", appl); - l = orbit_vasprintf(&data, config_data, appl); - orbit_file_create(name, data, l); - - free(name); - free(data); -} - -static void -file_create_gitignore(void) -{ - int l; - char *data; - - l = orbit_vasprintf(&data, gitignore_data, appl); - orbit_file_create(".gitignore", data, l); - free(data); -} - -static void -orbit_mkdir(const char *fpath, int mode) -{ - if (mkdir(fpath, mode) == -1) - fatal("orbit_mkdir(%s): %s", fpath, errno_s); -} - -static int -orbit_dir_exists(const char *fpath) -{ - struct stat st; - - if (stat(fpath, &st) == -1) - return (0); - - if (!S_ISDIR(st.st_mode)) - return (0); - - return (1); -} - -static void -orbit_file_open(const char *fpath, int *fd) -{ - if ((*fd = open(fpath, O_CREAT | O_TRUNC | O_WRONLY, 0755)) == -1) - fatal("orbit_file_open(%s): %s", fpath, errno_s); -} - -static void -orbit_file_close(int fd) -{ - if (close(fd) == -1) - printf("warning: close() %s\n", errno_s); -} - -static void -orbit_file_write(int fd, const void *buf, size_t len) -{ - ssize_t r; - const u_int8_t *d; - size_t written; - - d = buf; - written = 0; - while (written != len) { - r = write(fd, d + written, len - written); - if (r == -1) { - if (errno == EINTR) - continue; - fatal("orbit_file_write: %s", errno_s); - } - - written += r; - } -} - -static void -orbit_file_create(const char *name, const char *data, size_t len) -{ - int fd; - char *fpath; - - orbit_vasprintf(&fpath, "%s/%s", appl, name); - - orbit_file_open(fpath, &fd); - orbit_file_write(fd, data, len); - orbit_file_close(fd); - - printf("created %s\n", fpath); - free(fpath); -} - -static void -orbit_find_cfiles(const char *path) -{ - DIR *d; - struct cfile *cf; - struct dirent *dp; - char *fpath; - - if ((d = opendir(path)) == NULL) - fatal("orbit_find_cfiles: opendir(%s): %s", path, errno_s); - - while ((dp = readdir(d)) != NULL) { - if (!strcmp(dp->d_name, ".") || - !strcmp(dp->d_name, "..")) - continue; - - orbit_vasprintf(&fpath, "%s/%s", path, dp->d_name); - - if (dp->d_type == DT_DIR) { - orbit_find_cfiles(fpath); - free(fpath); - } else { - cfiles_count++; - cf = orbit_malloc(sizeof(*cf)); - cf->fpath = fpath; - orbit_vasprintf(&(cf->opath), - "%s/.objs/%s.o", rootdir, dp->d_name); - TAILQ_INSERT_TAIL(&source_files, cf, list); - } - } -} - -static void -orbit_compile_cfile(void *arg) -{ - struct cfile *cf = arg; - char *args[18], *ipath; - - orbit_vasprintf(&ipath, "-I%s/src", appl); - - args[0] = "gcc"; - args[1] = ipath; - args[2] = "-I/usr/local/include"; - args[3] = "-Wall"; - args[4] = "-Wstrict-prototypes"; - args[5] = "-Wmissing-prototypes"; - args[6] = "-Wmissing-declarations"; - args[7] = "-Wshadow"; - args[8] = "-Wpointer-arith"; - args[9] = "-Wcast-qual"; - args[10] = "-Wsign-compare"; - args[11] = "-fPIC"; - args[12] = "-g"; - - args[13] = "-c"; - args[14] = cf->fpath; - args[15] = "-o"; - args[16] = cf->opath; - args[17] = NULL; - - execvp("gcc", args); -} - -static void -orbit_link_library(void *arg) -{ - int idx; - struct cfile *cf; - char *args[cfiles_count + 10], *libname; - - orbit_vasprintf(&libname, "%s/%s.so", rootdir, appl); - - idx = 0; - args[idx++] = "gcc"; - -#if defined(__MACH__) - args[idx++] = "-dynamiclib"; - args[idx++] = "-undefined"; - args[idx++] = "suppress"; - args[idx++] = "-flat_namespace"; -#else - args[idx++] = "-shared"; -#endif - - TAILQ_FOREACH(cf, &source_files, list) - args[idx++] = cf->opath; - - args[idx++] = "-o"; - args[idx++] = libname; - args[idx] = NULL; - - execvp("gcc", args); -} - -static void -orbit_run_kore(void *arg) -{ - char *args[4], *cpath; - - orbit_vasprintf(&cpath, "conf/%s.conf", appl); - - args[0] = "kore"; - args[1] = "-fnc"; - args[2] = cpath; - args[3] = NULL; - - execvp("kore", args); -} - -static void -orbit_spawn_proc(void (*cb)(void *), void *arg) -{ - pid_t pid; - int status; - - pid = fork(); - switch (pid) { - case -1: - fatal("orbit_compile_cfile: fork() %s", errno_s); - /* NOTREACHED */ - case 0: - cb(arg); - fatal("orbit_spawn_proc: %s", errno_s); - /* NOTREACHED */ - default: - break; - } - - if (waitpid(pid, &status, 0) == -1) - fatal("couldn't wait for child %d", pid); - - if (WEXITSTATUS(status) || WTERMSIG(status) || WCOREDUMP(status)) - fatal("subprocess trouble, check output"); -} - -static void * -orbit_malloc(size_t len) -{ - void *ptr; - - if ((ptr = malloc(len)) == NULL) - fatal("orbit_malloc: %s", errno_s); - - return (ptr); -} - -static int -orbit_vasprintf(char **out, const char *fmt, ...) -{ - int l; - va_list args; - - va_start(args, fmt); - l = vasprintf(out, fmt, args); - va_end(args); - - if (l == -1) - fatal("orbit_vasprintf"); - - return (l); -} - -static void -fatal(const char *fmt, ...) -{ - va_list args; - char buf[2048]; - - va_start(args, fmt); - (void)vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - - if (command != NULL) - printf("orbit %s: %s\n", command->name, buf); - else - printf("orbit: %s\n", buf); - exit(1); -}