Commit e55efaac authored by Hermann Mayer's avatar Hermann Mayer
Browse files

[Utils][Config][Daemon] Added initial utils, a daemon specific configuration...

[Utils][Config][Daemon] Added initial utils, a daemon specific configuration parser and a test case for it. Also added a initial daemon stub.
parent 8ead6625
Loading
Loading
Loading
Loading

Makefile

0 → 100644
+34 −0
Original line number Diff line number Diff line
include Makefile.shared

BINS = $(patsubst src/test/%.c,%,$(wildcard src/test/*.c))
TEST_BINS = $(BINS:%=test-%)
TEST_MEM_BINS = $(BINS:%=test-mem-%)

MAN_PAGES = $(patsubst docs/man/%,%,$(wildcard docs/man/*.[0-9]))
DOCS = $(MAN_PAGES:%=docs-%)

build:
	$(MAKE) build -C src/
	$(MAKE) build -C docs/man/
clean:
	$(MAKE) clean -C src/
	$(MAKE) clean -C docs/man/
test:
	$(MAKE) test -C src/test/
$(TEST_BINS):
	$(MAKE) $@ -C src/test/
$(TEST_MEM_BINS):
	$(MAKE) $@ -C src/test/
$(DOCS):
	$(MAKE) $@ -C docs/man/
install:
	$(MAKE) $@ -C src/
	$(MAKE) $@ -C docs/man/
	$(MAKE) $@ -C dist/
uninstall:
	$(MAKE) $@ -C src/
	$(MAKE) $@ -C docs/man/
	$(MAKE) $@ -C dist/
all: build

.PHONY: all clean test

Makefile.shared

0 → 100644
+25 −0
Original line number Diff line number Diff line
export TEST := test
export PRINTF := printf
export CP := cp
export MV := mv
export RM := rm
export FIND := find
export GCC := gcc
export MAN := man
export INSTALL := install
XML_CONF := xml2-config

export VERSION := $(shell cat VERSION)
export MACHTYPE := $(shell $(CC) -dumpmachine)
export CFLAGS = $(shell $(XML_CONF) --cflags) -Wall -Werror -g -O0 \
    -DVERSION="\"$(VERSION)\"" -DMACHTYPE="\"$(MACHTYPE)\""
export INCLUDES = $(shell $(XML_CONF) --libs) -lconfig -lbcm2835 -lmicrohttpd

DESTDIR ?=
export prefix ?= /usr/local
export datarootdir ?= $(prefix)/share
export exec_prefix ?= $(prefix)
export bindir ?= $(exec_prefix)/bin
export mandir ?= $(datarootdir)/man
export sysconfdir ?= $(prefix)/etc
export libdir ?= $(exec_prefix)/lib

src/Makefile

0 → 100644
+46 −0
Original line number Diff line number Diff line
SUBDIRS ?= utils test bin

BUILD_SUBDIRS := $(SUBDIRS:%=build-%)
INSTALL_SUBDIRS := $(SUBDIRS:%=install-%)
UNINSTALL_SUBDIRS := $(SUBDIRS:%=uninstall-%)
CLEAN_SUBDIRS := $(SUBDIRS:%=clean-%)

OBJS := $(patsubst %.c,%.o,$(wildcard *.c))
CLEAN_OBJS := $(OBJS:%=clean-%)

$(OBJS): INFILE = $(@:%o=%c)
$(OBJS): OUTFILE = $(@)
$(OBJS):
	$(TEST) -f $(OUTFILE) || \
		$(GCC) -c $(INFILE) $(CFLAGS) -std=gnu11 $(INCLUDES)

$(CLEAN_OBJS): FILE = $(@:clean-%=%)
$(CLEAN_OBJS):
	$(TEST) -f $(FILE) && \
		$(RM) $(FILE) 2>/dev/null || true

$(BUILD_SUBDIRS): DIR = $(@:build-%=%)
$(BUILD_SUBDIRS):
	$(MAKE) all -C $(DIR)

$(CLEAN_SUBDIRS): DIR = $(@:clean-%=%)
$(CLEAN_SUBDIRS):
	$(MAKE) clean -C $(DIR)

clean: $(CLEAN_OBJS) $(CLEAN_SUBDIRS)
build: $(OBJS) $(BUILD_SUBDIRS)

$(INSTALL_SUBDIRS): DIR = $(@:install-%=%)
$(INSTALL_SUBDIRS):
	$(MAKE) install -C $(DIR)

$(UNINSTALL_SUBDIRS): DIR = $(@:uninstall-%=%)
$(UNINSTALL_SUBDIRS):
	$(MAKE) uninstall -C $(DIR)

install: build $(INSTALL_SUBDIRS)
uninstall: $(UNINSTALL_SUBDIRS)

all: build

.PHONY: all clean $(BUILD_SUBDIRS) $(CLEAN_SUBDIRS) $(OBJS)

src/bin/Makefile

0 → 100644
+38 −0
Original line number Diff line number Diff line
OBJS = $(shell $(FIND) .. -type f -name *.o)
BINS = $(patsubst %.c,%,$(wildcard *.c))
CLEAN_BINS = $(BINS:%=clean-%)
INSTALL_BINS = $(BINS:%=install-%)
UNINSTALL_BINS = $(BINS:%=uninstall-%)

$(BINS): INFILE = $(@:%=%.c)
$(BINS):
ifeq ($(OBJS),)
	$(MAKE) build -C ..
endif
	$(TEST) -f $@ || \
		$(GCC) -o $@ $(INFILE) $(OBJS) $(CFLAGS) -std=gnu11 $(INCLUDES)

$(CLEAN_BINS): BIN = $(@:clean-%=%)
$(CLEAN_BINS):
	$(TEST) -f $(BIN) && \
		$(RM) $(BIN) 2>/dev/null || true

clean: $(CLEAN_BINS)
build: $(BINS)

$(INSTALL_BINS): BIN = $(@:install-%=%)
$(INSTALL_BINS):
	-$(TEST) -d $(DESTDIR)$(bindir) || \
		$(INSTALL) -dm755 $(DESTDIR)$(bindir)
	$(INSTALL) -m755 $(BIN) $(DESTDIR)$(bindir)

$(UNINSTALL_BINS): BIN = $(@:uninstall-%=%)
$(UNINSTALL_BINS):
	-$(TEST) -f $(DESTDIR)$(bindir)/$(BIN) && \
		$(RM) $(DESTDIR)$(bindir)/$(BIN)

install: $(INSTALL_BINS)
uninstall: $(UNINSTALL_BINS)
all: build

.PHONY: clean build

src/bin/relayd.c

0 → 100644
+230 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015 Hermann Mayer
 *
 * relayd - The daemon
 *
 * This file is part of relayd.
 *
 * relayd is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * relayd is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with relayd.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <getopt.h>
#include <sys/stat.h>
#include "../utils/logger.h"
#include "../utils/pidfile.h"
#include "../utils/config.h"

static const char *pidfile = "/run/relayd.pid";
static struct config conf;

void handle_requests(struct config *conf)
{
    while (1) {
        sleep(1000);
    }
}

void init_relays(struct config *conf)
{
}

void handle_signal(int signo)
{
    if (SIGINT == signo || SIGTERM == signo) {
        utlog(LOG_NOTICE, "Received SIGINT/TERM signal, shuting down..");
        pidfile_remove(pidfile);
        exit(EXIT_SUCCESS);
    }
}

void daemonize()
{
    pid_t pid;

    // Fork off the parent process
    pid = fork();

    // An error occurred
    if (pid < 0) {
        exit(EXIT_FAILURE);
    }

    // Success: Let the parent terminate
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }

    // On success: The child process becomes session leader
    if (setsid() < 0) {
        exit(EXIT_FAILURE);
    }

    // Fork off for the second time
    pid = fork();

    // An error occurred
    if (pid < 0) {
        exit(EXIT_FAILURE);
    }

    // Success: Let the parent terminate
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }

    // Set new file permissions
    umask(0);

    // Change the working directory to the root directory
    chdir("/");

    // Close all open file descriptors
    for (int i = sysconf(_SC_OPEN_MAX); i > 0; i--) {
        close(i);
    }
}

void print_version(int exit_code)
{
    utlog(LOG_NOTICE, "relayd version %s (%s)\n",
            VERSION, MACHTYPE);
    utlog(LOG_NOTICE, "Copyright (C) 2015 Hermann Mayer\n");
    utlog(LOG_NOTICE, "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n");
    utlog(LOG_NOTICE, "\n");
    utlog(LOG_NOTICE, "This is free software; you are free to change and redistribute it.\n");
    utlog(LOG_NOTICE, "There is NO WARRANTY, to the extent permitted by law.\n");
    free_config(&conf);
    exit(exit_code);
}

void print_help(int exit_code)
{
    utlog(LOG_INFO, "relayd [OPTION]\n");
    utlog(LOG_INFO, "\n");
    utlog(LOG_INFO, "Control connected relays.\n");
    utlog(LOG_INFO, "\n");
    utlog(LOG_INFO, "  -h --help         Show the available arguments\n");
    utlog(LOG_INFO, "  -c --config       Set the path to a config file\n");
    utlog(LOG_INFO, "  -f --foreground   Keep the daemon running in foreground\n");
    exit(exit_code);
}

int main(int argc, char **argv)
{
    if (1 == argc) {
        utlog(LOG_ERR, "No configuration file was specified\n\n");
        print_help(EXIT_FAILURE);
    }

    int c;
    int foreground = 0;
    char *config_file = "";

    while (1) {

        static struct option long_options[] = {
            {"help",       no_argument,       0, 'h'},
            {"version",    no_argument,       0, 'v'},
            {"config",     required_argument, 0, 'c'},
            {"foreground", no_argument,       0, 'f'},
            {0, 0, 0, 0}
        };

        // getopt_long stores the option index here.
        int option_index = 0;

        c = getopt_long(argc, argv, "hvfc:",
                long_options, &option_index);

        // Detect the end of the options.
        if (c == -1) {
            break;
        }

        switch (c) {
            case 'h':
                print_help(EXIT_SUCCESS);
                break;

            case 'v':
                print_version(EXIT_SUCCESS);
                break;

            case 'c':
                config_file = optarg;
                break;

            case 'f':
                foreground = 1;
                break;

            case '?':
                // getopt_long already printed an error message.
                utlog(LOG_INFO, "\n");
                print_help(EXIT_FAILURE);
                break;

            default:
                break;
        }
    }

    if (0 == strcmp("", config_file)) {
        utlog(LOG_ERR, "No configuration file was specified.\n");
        exit(EXIT_FAILURE);
    }

    pid_t pid;

    if (0 != (pid = pidfile_check(pidfile))) {
        utlog(LOG_ERR, "A instance of relayd (%d) is already running\n",
                pid);
        exit(EXIT_FAILURE);
    }

    conf = get_config(config_file);
    validate_config(&conf);

    // Run as daemon if we should
    if (0 == foreground) {
        daemonize();
        utlog_mode(LOG_BACKGROUND);
        utlog_pri_mode(LOG_PRI_DISABLE);
    } else {
        utlog_mode(LOG_FOREGROUND);
        utlog_pri_mode(LOG_PRI_ENABLE);
    }

    // Write a pidfile for the current daemon process
    if (0 == pidfile_write(pidfile)) {
        exit(EXIT_FAILURE);
    }

    // Bind the signal handler
    signal(SIGINT, handle_signal);
    signal(SIGTERM, handle_signal);

    // Initialize the relays
    init_relays(&conf);

    // Call the business logic loop
    handle_requests(&conf);

    return EXIT_SUCCESS;
}
Loading