From 55c564a02869230ba3ed0f468e9a3d567b045666 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 27 Jun 2016 13:24:43 +1000 Subject: Refactor rc.conf processing to be services based. --- .../include/machine/rtems-bsd-rc-conf-directives.h | 61 -- .../include/machine/rtems-bsd-rc-conf-services.h | 168 ++++++ rtemsbsd/include/machine/rtems-bsd-rc-conf.h | 61 +- rtemsbsd/rtems/rtems-bsd-rc-conf-net.c | 461 +++++++++++---- rtemsbsd/rtems/rtems-bsd-rc-conf.c | 635 +++++++++++++++++---- testsuite/rcconf01/test_main.c | 158 ++++- 6 files changed, 1202 insertions(+), 342 deletions(-) delete mode 100644 rtemsbsd/include/machine/rtems-bsd-rc-conf-directives.h create mode 100644 rtemsbsd/include/machine/rtems-bsd-rc-conf-services.h diff --git a/rtemsbsd/include/machine/rtems-bsd-rc-conf-directives.h b/rtemsbsd/include/machine/rtems-bsd-rc-conf-directives.h deleted file mode 100644 index 5eaa2606..00000000 --- a/rtemsbsd/include/machine/rtems-bsd-rc-conf-directives.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2016 Chris Johns . All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * The directives available with rc.conf. You define the list you wish - * to have available in your application and they will be available. - */ - -#ifndef _RTEMS_BSP_RC_CONF_DIRECTIVES_h -#define _RTEMS_BSP_RC_CONF_DIRECTIVES_h - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include -#include - -/* - * Use the same SYSINT for all directives. - */ -#define RTEMS_BSD_RC_CONF_SYSINT(_n) \ - SYSINIT(_n, SI_SUB_CREATE_INIT, SI_ORDER_ANY, _n ## _init, NULL) - -/* - * Decls for the handlers. - */ -void rc_conf_net_init(void* arg); /* Installed by default. */ - -/* - * The user available directives. - */ -/* add here */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif diff --git a/rtemsbsd/include/machine/rtems-bsd-rc-conf-services.h b/rtemsbsd/include/machine/rtems-bsd-rc-conf-services.h new file mode 100644 index 00000000..bc8ee0d8 --- /dev/null +++ b/rtemsbsd/include/machine/rtems-bsd-rc-conf-services.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2016 Chris Johns . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * The services available to rc.conf. You define the list you wish to have + * available in your application and they will be available. + * + * A service is a functional unit that can be started. + */ + +#ifndef _RTEMS_BSD_RC_CONF_SERVICES_h +#define _RTEMS_BSD_RC_CONF_SERVICES_h + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Structure to pass argc and argv between functions. + */ +typedef struct rtems_bsd_rc_conf_argc_argv { + uint32_t marker; + char* command; + int argc; + const char** argv; +} rtems_bsd_rc_conf_argc_argv; + +/* + * A service controls a peice of functionalty. It loosely follows the things + * found in /etc/rc.d in FreeBSD. A service can query the rc.conf file for + * items of interest. + */ +typedef int (*rtems_bsd_rc_conf_service)(rtems_bsd_rc_conf* rc_conf); + +/* + * Register a service. The name is the name of the service and the control + * string contains the before, after and requires string. + * + * The control string has the format of: + * + * key:item,item,item; + * + * where the keys are: + * + * before + * after + * require + * + * For example "before:telnet;after:net;require:net" + * + * Notes + * + * 1. The parsing of this string is simple and will not handle any + * white-space. The tokens are delmiter to delmiter. + * + * 2. If there are competing positions in the control string the last one + * processed is used. After is processed first then 'before'. + */ +extern int rtems_bsd_rc_conf_service_add(const char* name, + const char* control, + rtems_bsd_rc_conf_service service); + +/* + * Remove a registered a service. + */ +extern int rtems_bsd_rc_conf_service_remove(const char* name); + +/* + * Return the name of the file being processed. + */ +extern const char* rtems_bsd_rc_conf_name(rtems_bsd_rc_conf* rc_conf); + +/* + * Search for the regular expression in the file for the first occurrence. + */ +extern int rtems_bsd_rc_conf_find(rtems_bsd_rc_conf* rc_conf, + const char* expression, + rtems_bsd_rc_conf_argc_argv* argc_argv); + +/* + * Search for the next occurance of the regular expression in the file. + */ +extern int rtems_bsd_rc_conf_find_next(rtems_bsd_rc_conf* rc_conf, + rtems_bsd_rc_conf_argc_argv* argc_argv); + +/* + * Create an argc/argv structure. You can reuse this for repeated calls and the + * rc.conf code manage the resources it uses. Destroy the structure when you + * have finished. + */ +extern rtems_bsd_rc_conf_argc_argv* rtems_bsd_rc_conf_argc_argv_create(void); + +/* + * Destroy the argc/argv structure. + */ +extern void rtems_bsd_rc_conf_argc_argv_destroy(rtems_bsd_rc_conf_argc_argv* argc_argv); + +/* + * Return the name of the rc.conf file. + */ +extern const char* rtems_bsd_rc_conf_name(rtems_bsd_rc_conf* rc_conf); + +/* + * Return the current find line. + */ +extern int rtems_bsd_rc_conf_line(rtems_bsd_rc_conf* rc_conf); + +/* + * Return the verbose state. + */ +extern bool rtems_bsd_rc_conf_verbose(rtems_bsd_rc_conf* rc_conf); + +/* + * Print the argv list. Helper for verbose modes. + */ +extern void rtems_bsd_rc_conf_print_cmd(rtems_bsd_rc_conf* rc_conf, + const char* name, + int arvc, + const char** argv); + +/* + * Use the same SYSINT for all directives. + */ +#define RTEMS_BSD_RC_CONF_SYSINT(_n) \ + SYSINIT(_n, SI_SUB_CREATE_INIT, SI_ORDER_ANY, _n ## _init, NULL) + +/* + * Decls for the handlers. + */ +void rc_conf_net_init(void* arg); /* Installed by default. */ + +/* + * Added services. + */ +/* add here */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/rtemsbsd/include/machine/rtems-bsd-rc-conf.h b/rtemsbsd/include/machine/rtems-bsd-rc-conf.h index 64c008cc..68b334af 100644 --- a/rtemsbsd/include/machine/rtems-bsd-rc-conf.h +++ b/rtemsbsd/include/machine/rtems-bsd-rc-conf.h @@ -24,12 +24,16 @@ */ /* - * Parse a FreeBSD /etc/rc.conf format file and execute the configuration - * options we want to support. + * FreeBSD /etc/rc.conf initialisation. Initialise the software stack using the + * the configuration options held in your rc.conf file. The file conforms to the + * format defined in the FreeBSD man page rc.conf(5). + * + * The services and configuration present in your rc.conf will only work if the + * services have been configured into your application. */ -#ifndef _RTEMS_BSP_RC_CONF_h -#define _RTEMS_BSP_RC_CONF_h +#ifndef _RTEMS_BSD_RC_CONF_h +#define _RTEMS_BSD_RC_CONF_h #include @@ -43,56 +47,33 @@ extern "C" { #define RTEMS_BSD_RC_CONF_MAX_SIZE (8 * 1024) /* - * Directive processing data. This data is opaque externally. + * The rc.conf data. It is externally opaque. */ typedef struct rtems_bsd_rc_conf_ rtems_bsd_rc_conf; -/* - * A directive is a line in rc.conf and is 'name=value'. The handler is invoked - * if the name matches directive's regular expression. - */ -typedef int (*rtems_bsd_rc_conf_directive)(rtems_bsd_rc_conf* rc_conf, - int argc, - const char** argv); - -/* - * Register a directive handler. - */ -extern int rtems_bsd_rc_conf_directive_add(const char* dir_regex, - rtems_bsd_rc_conf_directive handler); - /* * Run an rc.conf script loaded into memory. + * + * The timeout can be -1 for no wait, 0 to wait forever or a timeout in seconds. */ -extern int rtems_bsd_run_rc_conf_script(const char* name, const char* text, bool verbose); +extern int rtems_bsd_run_rc_conf_script(const char* name, + const char* text, + int timeout, + bool verbose); /* * Run the rc.conf file. + * + * The timeout can be -1 for no wait, 0 to wait forever or a timeout in seconds. */ -extern int rtems_bsd_run_rc_conf(const char* name, bool verbose); +extern int rtems_bsd_run_rc_conf(const char* name, int timeout, bool verbose); /* * Run /etc/rc.conf. + * + * The timeout can be -1 for no wait, 0 to wait forever or a timeout in seconds. */ -extern int rtems_bsd_run_etc_rc_conf(bool verbose); - -/* - * Return the name of the file being processed. - */ -extern const char* rtems_bsd_rc_conf_name(rtems_bsd_rc_conf* rc_conf); - -/* - * Return the line number being processed. - */ -extern int rtems_bsd_rc_conf_line(rtems_bsd_rc_conf* rc_conf); - -/* - * Print the argv list. Helper for verbose modes. - */ -extern void rtems_bsd_rc_conf_print_cmd(rtems_bsd_rc_conf* rc_conf, - const char* name, - int argc, - const char** argv); +extern int rtems_bsd_run_etc_rc_conf(int timeout, bool verbose); #ifdef __cplusplus } diff --git a/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c b/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c index ace8ced7..f4dc0d6f 100644 --- a/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c +++ b/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c @@ -38,6 +38,8 @@ #include #include +#include + #include #include #include @@ -48,7 +50,22 @@ #include #include -#include +#include + +/* + * Default defaultroute_delay is 30seconds. + */ +static int defaultroute_delay_secs = 30; + +/* + * Show a result. + */ +static void +show_result(const char* label, int r) +{ + if (r < 0) + fprintf(stderr, "error: %s: %s\n", label, strerror(errno)); +} /* * cloned_interfaces @@ -58,23 +75,26 @@ * See 'man rc.conf(5)' on FreeBSD. */ static int -cloned_interfaces(rtems_bsd_rc_conf* rc_conf, - int argc, - const char** argv) +cloned_interfaces(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa) { int arg; - for (arg = 1; arg < argc; ++arg) { + int r = 0; + + r = rtems_bsd_rc_conf_find(rc_conf, "cloned_interfaces", aa); + if (r < 0) { + if (errno == ENOENT) + r = 0; + return r; + } + + for (arg = 1; arg < aa->argc; ++arg) { const char* ifconfg_args[] = { - "ifconfig", argv[arg], "create", NULL + "ifconfig", aa->argv[arg], "create", NULL }; - int r; rtems_bsd_rc_conf_print_cmd(rc_conf, "cloning_interfaces", 3, ifconfg_args); - r = rtems_bsd_command_ifconfig(3, (char**) ifconfg_args); - if (r != EX_OK) { - errno = ECANCELED; - return -1; - } + rtems_bsd_command_ifconfig(3, (char**) ifconfg_args); } + return 0; } @@ -95,71 +115,62 @@ typedef struct { static RTEMS_CHAIN_DEFINE_EMPTY(create_args_items); static int -create_args_(rtems_bsd_rc_conf* rc_conf, - int argc, - const char** argv) +load_create_args(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa) { - rtems_chain_node* node = rtems_chain_first(&create_args_items); - const rtems_chain_node* tail = rtems_chain_tail(&create_args_items); - const char* label = argv[0] + strlen("create_args_"); - create_args_item* item; - int arg; - - while (node != tail) { - item = (create_args_item*) node; - if (strcasecmp(item->label, label) == 0) { - fprintf(stderr, "error: %s:%d: duplicate create args entry: %s\n", + int r = 0; + + r = rtems_bsd_rc_conf_find(rc_conf, "create_args_.*", aa); + + while (r == 0) { + rtems_chain_node* node; + const char* label; + create_args_item* item; + int arg; + + rtems_bsd_rc_conf_print_cmd(rc_conf, "create_args_", aa->argc, aa->argv); + + label = aa->argv[0] + strlen("create_args_"); + + node = rtems_chain_first(&create_args_items); + + while (!rtems_chain_is_tail(&create_args_items, node)) { + item = (create_args_item*) node; + if (strcasecmp(item->label, label) == 0) { + fprintf(stderr, "error: %s:%d: duplicate create args entry: %s\n", + rtems_bsd_rc_conf_name(rc_conf), + rtems_bsd_rc_conf_line(rc_conf), + aa->argv[0]); + errno = EEXIST; + return -1; + } + node = rtems_chain_next(node); + } + + item = calloc(1, sizeof(*item)); + if (item == NULL) { + errno = ENOMEM; + fprintf(stderr, "error: %s:%d: %s\n", rtems_bsd_rc_conf_name(rc_conf), rtems_bsd_rc_conf_line(rc_conf), - argv[0]); - errno = EEXIST; + strerror(errno)); return -1; } - node = rtems_chain_next(node); - } - item = calloc(1, sizeof(*item)); - if (item == NULL) { - errno = ENOMEM; - fprintf(stderr, "error: %s:%d: %s\n", - rtems_bsd_rc_conf_name(rc_conf), - rtems_bsd_rc_conf_line(rc_conf), - strerror(errno)); - return -1; - } + item->argc = aa->argc; - item->argc = argc; - - item->label = strdup(label); - if (item->label == NULL) { - free(item); - errno = ENOMEM; - fprintf(stderr, "error: %s:%d: %s\n", - rtems_bsd_rc_conf_name(rc_conf), - rtems_bsd_rc_conf_line(rc_conf), - strerror(errno)); - return -1; - } - - item->argv = calloc(argc + 1, sizeof(char*)); - if (item->argv == NULL) { - free((void*) item->label); - free(item); - errno = ENOMEM; - fprintf(stderr, "error: %s:%d: %s\n", - rtems_bsd_rc_conf_name(rc_conf), - rtems_bsd_rc_conf_line(rc_conf), - strerror(errno)); - return -1; - } + item->label = strdup(label); + if (item->label == NULL) { + free(item); + errno = ENOMEM; + fprintf(stderr, "error: %s:%d: %s\n", + rtems_bsd_rc_conf_name(rc_conf), + rtems_bsd_rc_conf_line(rc_conf), + strerror(errno)); + return -1; + } - for (arg = 0; arg < argc; ++arg) { - item->argv[arg] = strdup(argv[0]); - if (item->argv[arg] == NULL) { - int a; - for (a = 0; a < arg; ++a) - free((void*) item->argv[a]); - free(item->argv); + item->argv = calloc(aa->argc + 1, sizeof(char*)); + if (item->argv == NULL) { free((void*) item->label); free(item); errno = ENOMEM; @@ -169,9 +180,35 @@ create_args_(rtems_bsd_rc_conf* rc_conf, strerror(errno)); return -1; } + + for (arg = 0; arg < aa->argc; ++arg) { + item->argv[arg] = strdup(aa->argv[0]); + if (item->argv[arg] == NULL) { + int a; + for (a = 0; a < arg; ++a) + free((void*) item->argv[a]); + free(item->argv); + free((void*) item->label); + free(item); + errno = ENOMEM; + fprintf(stderr, "error: %s:%d: %s\n", + rtems_bsd_rc_conf_name(rc_conf), + rtems_bsd_rc_conf_line(rc_conf), + strerror(errno)); + return -1; + } + } + + rtems_chain_append(&create_args_items, &item->node); + + r = rtems_bsd_rc_conf_find_next(rc_conf, aa); } - rtems_chain_append(&create_args_items, &item->node); + /* + * ignore not found. + */ + if (r < 0 && errno == ENOENT) + r = 0; return 0; } @@ -185,12 +222,14 @@ create_args_(rtems_bsd_rc_conf* rc_conf, */ static int ifconfig_(rtems_bsd_rc_conf* rc_conf, + const char* ifname, int argc, const char** argv) { - const char** args; - int arg; - int r; + const char** args; + int arg; + int r; + const char const* ifconfig_show[] = { "ifconfig", ifname, NULL }; for (arg = 1; arg < argc; ++arg) { if (strcasecmp(argv[arg], "NOAUTO") == 0) @@ -204,7 +243,7 @@ ifconfig_(rtems_bsd_rc_conf* rc_conf, } args[0] = "ifconfig"; - args[1] = argv[0] + strlen("ifconfig_"); + args[1] = ifname; for (arg = 1; arg < argc; ++arg) args[arg + 1] = argv[arg]; @@ -222,7 +261,9 @@ ifconfig_(rtems_bsd_rc_conf* rc_conf, return -1; } - return 0; + r = rtems_bsd_command_ifconfig(2, (char**) ifconfig_show); + + return r; } /* @@ -233,16 +274,24 @@ ifconfig_(rtems_bsd_rc_conf* rc_conf, * See 'man rc.conf(5)' on FreeBSD. */ static int -hostname(rtems_bsd_rc_conf* rc_conf, - int argc, - const char** argv) +hostname(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa) { - if (argc > 2) { - errno = EINVAL; + const char** argv; + int r; + const char const* default_argv[] = { "hostname", "Amnesiac", NULL }; + + r = rtems_bsd_rc_conf_find(rc_conf, "hostname", aa); + if (r < 0 && errno != ENOENT) return -1; + + if (r < 0 || (r == 0 && aa->argc != 2)) { + argv = default_argv; + } + else { + argv = aa->argv; } - rtems_bsd_rc_conf_print_cmd(rc_conf, "hostname", argc, argv); + fprintf(stdout, "Setting hostname: %s.\n", argv[1]); return sethostname(argv[1], strlen(argv[1])); } @@ -255,48 +304,250 @@ hostname(rtems_bsd_rc_conf* rc_conf, * See 'man rc.conf(5)' on FreeBSD. */ static int -defaultrouter(rtems_bsd_rc_conf* rc_conf, - int argc, - const char** argv) +defaultrouter(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa) { - if (argc > 2) { + int r; + + r = rtems_bsd_rc_conf_find(rc_conf, "defaultrouter", aa); + if (r < 0 && errno != ENOENT) + return -1; + + if (r == 0) { + if (aa->argc > 2) { + errno = EINVAL; + return -1; + } + + if (strcasecmp(aa->argv[1], "NO") != 0) { + const char* args[] = { "route", "add", "default", aa->argv[1], NULL }; + int r; + + rtems_bsd_rc_conf_print_cmd(rc_conf, "defaultrouter", 4, args); + + r = rtems_bsd_command_route(4, (char**) args); + if (r != EX_OK) { + errno = ECANCELED; + return -1; + } + } + } + + return 0; +} + +/* + * defaultroute_delay + * + * eg defaultroute=120 + * + * See 'man rc.conf(5)' on FreeBSD. + */ +static int +defaultroute_delay(rtems_bsd_rc_conf* rc_conf, + int argc, + const char** argv) +{ + int value; + char* end = NULL; + + if (argc != 2) { errno = EINVAL; return -1; } - if (strcasecmp(argv[1], "NO") != 0) { - const char* args[] = { - "route", "add", "default", argv[1], NULL + value = strtol(argv[1], &end, 10); + + if (end == NULL) { + const char* args[] = { + "defaultrouter_delay", argv[1], NULL }; - int r; - rtems_bsd_rc_conf_print_cmd(rc_conf, "defaultrouter", 4, args); + rtems_bsd_rc_conf_print_cmd(rc_conf, "defaultrouter", 2, args); - r = rtems_bsd_command_route(4, (char**) args); - if (r != EX_OK) { - errno = ECANCELED; - return -1; + defaultroute_delay_secs = value; + } + else { + errno = EINVAL; + return -1; + } + + return 0; +} + +static int +show_interfaces(const char* msg, struct ifaddrs* ifap) +{ + struct ifaddrs* ifa; + + fprintf(stdout, msg); + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcasecmp("lo0", ifa->ifa_name) == 0) { + fprintf(stdout, "%s ", ifa->ifa_name); + break; } } + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcasecmp("lo0", ifa->ifa_name) != 0) { + fprintf(stdout, "%s ", ifa->ifa_name); + } + } + + fprintf(stdout, "\b.\n"); + return 0; } -static void -add_directive(const char* name, rtems_bsd_rc_conf_directive handler) +static int +setup_lo0(rtems_bsd_rc_conf* rc_conf, struct ifaddrs* ifap) { - int r; - r = rtems_bsd_rc_conf_directive_add(name, handler); - if (r < 0) - fprintf(stderr, "error: cannot register rc.conf handler: %s\n", name); + struct ifaddrs* ifa; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcasecmp("lo0", ifa->ifa_name) == 0) { + const char* lo0_argv[] = { + "ifconfig_lo0", "inet", "127.0.0.1", "netmask", "255.0.0.0", NULL + }; + show_result("lo0", ifconfig_(rc_conf, "lo0", 5, lo0_argv)); + return 0; + } + } + fprintf(stderr, "warning: no loopback interface found\n"); + return -1; +} + +static int +setup_interfaces(rtems_bsd_rc_conf* rc_conf, + rtems_bsd_rc_conf_argc_argv* aa, + struct ifaddrs* ifap) +{ + struct ifaddrs* ifa; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcasecmp("lo0", ifa->ifa_name) != 0) { + char iface[64]; + int r; + snprintf(iface, sizeof(iface), "ifconfig_%s", ifa->ifa_name); + r = rtems_bsd_rc_conf_find(rc_conf, iface, aa); + if (r == 0) { + show_result(iface, ifconfig_(rc_conf, ifa->ifa_name, aa->argc, aa->argv)); + } + } + } + return 0; +} + +static int +setup_vlans(rtems_bsd_rc_conf* rc_conf, + rtems_bsd_rc_conf_argc_argv* aa, + struct ifaddrs* ifap) +{ + rtems_bsd_rc_conf_argc_argv* vaa; + struct ifaddrs* ifa; + + vaa = rtems_bsd_rc_conf_argc_argv_create(); + if (vaa == NULL) + return -1; + + show_result("create_args", load_create_args(rc_conf, aa)); + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcasecmp("lo0", ifa->ifa_name) != 0) { + char expr[128]; + int r; + /* + * Look for vlans_'iface'="101 102 103" + */ + snprintf(expr, sizeof(expr), "vlans_%s", ifa->ifa_name); + r = rtems_bsd_rc_conf_find(rc_conf, expr, aa); + if (r == 0) { + int arg; + for (arg = 1; arg < aa->argc; ++arg) { + char vlan_name[64]; + const char* vlan_create[] = { + "ifconfig", vlan_name, "create", NULL + }; + /* + * Create the VLAN name as 'iface'.'vlan'. + */ + snprintf(vlan_name, sizeof(vlan_name), + "%s.%s", ifa->ifa_name, aa->argv[arg]); + rtems_bsd_rc_conf_print_cmd(rc_conf, "vlan", 3, vlan_create); + r = rtems_bsd_command_ifconfig(3, (char**) vlan_create); + if (r == 0) { + /* + * Look for ifconfig_'iface'_'vlan'="..." + */ + snprintf(expr, sizeof(expr), + "ifconfig_%s_%s", ifa->ifa_name, aa->argv[arg]); + r = rtems_bsd_rc_conf_find(rc_conf, expr, vaa); + if (r == 0) { + show_result(vlan_name, ifconfig_(rc_conf, vlan_name, + vaa->argc, vaa->argv)); + } + } + } + } + } + } + + rtems_bsd_rc_conf_argc_argv_destroy(vaa); + + return 0; +} + +static int +interfaces(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa) +{ + struct ifaddrs* ifap; + + if (getifaddrs(&ifap) != 0) { + fprintf(stderr, "error: interfaces: getifaddrs: %s\n", strerror(errno)); + return -1; + } + + show_interfaces("Starting network: ", ifap); + show_result("cloned_interfaces", cloned_interfaces(rc_conf, aa)); + show_result("lo0", setup_lo0(rc_conf, ifap)); + show_result("ifaces", setup_interfaces(rc_conf, aa, ifap)); + show_result("vlans", setup_vlans(rc_conf, aa, ifap)); + + free(ifap); + + return 0; +} + +static int +network_service(rtems_bsd_rc_conf* rc_conf) +{ + rtems_bsd_rc_conf_argc_argv* aa; + int r; + + aa = rtems_bsd_rc_conf_argc_argv_create(); + if (aa == NULL) + return -1; + + show_result("hostname", hostname(rc_conf, aa)); + + r = interfaces(rc_conf, aa); + if (r < 0) { + rtems_bsd_rc_conf_argc_argv_destroy(aa); + return -1; + } + + show_result("defaultrouter", defaultrouter(rc_conf, aa)); + + rtems_bsd_rc_conf_argc_argv_destroy(aa); + + return 0; } void rc_conf_net_init(void* arg) { - add_directive("cloned_interfaces", cloned_interfaces); - add_directive("create_args_.*", create_args_); - add_directive("ifconfig_.*", ifconfig_); - add_directive("hostname", hostname); - add_directive("defaultrouter", defaultrouter); + int r; + r = rtems_bsd_rc_conf_service_add("network", + "after:first;", + network_service); + if (r < 0) + fprintf(stderr, "error: network service add failed: %s\n", strerror(errno)); } diff --git a/rtemsbsd/rtems/rtems-bsd-rc-conf.c b/rtemsbsd/rtems/rtems-bsd-rc-conf.c index de243111..431e1c44 100644 --- a/rtemsbsd/rtems/rtems-bsd-rc-conf.c +++ b/rtemsbsd/rtems/rtems-bsd-rc-conf.c @@ -41,10 +41,10 @@ #include #include -#include +#include /* - * By default the networking directives are available. + * By default the networking service is always available. */ RTEMS_BSD_RC_CONF_SYSINT(rc_conf_net); @@ -54,47 +54,75 @@ RTEMS_BSD_RC_CONF_SYSINT(rc_conf_net); #define MAX_LINE_SIZE (512) /* - * Directive handler chain. + * Intrenal rc.conf data. This is not visible out side of here. */ struct rtems_bsd_rc_conf_ { - const char* name; /**< Name of the file. */ - const char* data; /**< Pre-processed rc.conf data. */ - size_t line_count; /**< Number of lines with text. */ - const char** lines; /**< The lines in the file's text. */ - size_t line; /**< The line being processed. */ - bool verbose; /**< Verbose processing. */ + const char* name; /**< Name of the file. */ + const char* data; /**< Pre-processed rc.conf data. */ + size_t line_count; /**< Number of lines with text. */ + const char** lines; /**< The lines in the file's text. */ + size_t line; /**< The line being processed. */ + char* find_regex; /**< Find's regular expression. */ + int timeout; /**< The timeout for processing rc.conf. */ + bool verbose; /**< Verbose processing. */ + int error_code; /**< The error code returned to the caller. */ + rtems_id lock; /**< Threading lock for this data. */ + rtems_id waiter; /**< The waiting thread, 0 if no one waiting */ }; /* - * Directive handler chain. + * Services handler chain. */ typedef struct { - rtems_chain_node node; - const char* directive; - rtems_bsd_rc_conf_directive handler; -} directive; + rtems_chain_node node; + const char* name; + const char* control; + const char* before; + const char* after; + const char* require; + rtems_bsd_rc_conf_service entry; +} service; /* - * Control of argc and argv. + * The chain of services. */ -typedef struct { - char* command; - int argc; - const char** argv; -} argc_argv; +static RTEMS_CHAIN_DEFINE_EMPTY(services); -/* - * The chain of directives. - */ -static RTEMS_CHAIN_DEFINE_EMPTY(directives); +#define ARGC_ARGV_MARKER (0x20010928) + +static int +argc_argv_valid(rtems_bsd_rc_conf_argc_argv* aa) +{ + if (aa->marker != ARGC_ARGV_MARKER) { + errno = EACCES; + return -1; + } + return 0; +} + +static void +argc_argv_clean(rtems_bsd_rc_conf_argc_argv* aa) +{ + if (argc_argv_valid(aa) >= 0) { + free(aa->argv); + free(aa->command); + aa->argv = NULL; + aa->command = NULL; + } +} static int -argc_argv_create(const char* line, argc_argv* aa) +argc_argv_update(const char* line, rtems_bsd_rc_conf_argc_argv* aa) { char* c; int arg; char* brk; + if (argc_argv_valid(aa) < 0) + return -1; + + argc_argv_clean(aa); + if (strnlen(line, MAX_LINE_SIZE) >= MAX_LINE_SIZE) { errno = EFBIG; return -1; @@ -145,19 +173,63 @@ argc_argv_create(const char* line, argc_argv* aa) return 0; } -static void -argc_argv_destroy(argc_argv* aa) +static int +lock_create(rtems_bsd_rc_conf* rc_conf) { - free(aa->argv); - free(aa->command); - aa->argv = NULL; - aa->command = NULL; + rtems_status_code sc; + sc = rtems_semaphore_create(rtems_build_name('B', 'S', 'D', 'r'), + 1, + RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | + RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | + RTEMS_LOCAL, + 0, + &rc_conf->lock); + if (sc != RTEMS_SUCCESSFUL) { + fprintf(stderr, "error: rc_conf: cannot create lock: %s", rtems_status_text(sc)); + errno = EIO; + return -1; + } + return 0; +} + +static int +lock_delete(rtems_bsd_rc_conf* rc_conf) +{ + rtems_semaphore_delete(rc_conf->lock); + return 0; +} + +static int +lock(rtems_bsd_rc_conf* rc_conf) +{ + rtems_status_code sc; + sc = rtems_semaphore_obtain(rc_conf->lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) { + fprintf(stderr, "error: rc_conf: locking: %s", rtems_status_text(sc)); + errno = EIO; + return -1; + } + return 0; +} + +static int +unlock(rtems_bsd_rc_conf* rc_conf) +{ + rtems_status_code sc; + sc = rtems_semaphore_release(rc_conf->lock); + if (sc != RTEMS_SUCCESSFUL) { + fprintf(stderr, "error: rc_conf: locking: %s", rtems_status_text(sc)); + errno = EIO; + return -1; + } + return 0; } static int rc_conf_create(rtems_bsd_rc_conf* rc_conf, const char* name, const char* text, + int timeout, bool verbose) { size_t length; @@ -167,6 +239,7 @@ rc_conf_create(rtems_bsd_rc_conf* rc_conf, char* marker; const char** lines; size_t line_count; + int r; memset(rc_conf, 0, sizeof(*rc_conf)); @@ -240,12 +313,26 @@ rc_conf_create(rtems_bsd_rc_conf* rc_conf, } } - rc_conf->name = name; + rc_conf->name = strdup(name); rc_conf->data = copy; rc_conf->line_count = line_count; rc_conf->lines = lines; rc_conf->line = 0; + rc_conf->timeout = timeout; rc_conf->verbose = verbose; + if (timeout >= 0) + rc_conf->waiter = rtems_task_self(); + + /* + * Create the lock. + */ + r = lock_create(rc_conf); + if (r < 0) { + free((void*) rc_conf->name); + free((void*) rc_conf->lines); + free((void*) rc_conf->data); + return -1; + } return 0; } @@ -253,144 +340,480 @@ rc_conf_create(rtems_bsd_rc_conf* rc_conf, static void rc_conf_destroy(rtems_bsd_rc_conf* rc_conf) { - free((void*) rc_conf->lines); - free((void*) rc_conf->data); - rc_conf->data = NULL; - rc_conf->name = NULL; + if (rc_conf->name != NULL) { + free((void*) rc_conf->name); + free((void*) rc_conf->lines); + free((void*) rc_conf->data); + rc_conf->name = NULL; + rc_conf->lines = NULL; + rc_conf->data = NULL; + lock_delete(rc_conf); + } } +rtems_bsd_rc_conf_argc_argv* +rtems_bsd_rc_conf_argc_argv_create(void) +{ + rtems_bsd_rc_conf_argc_argv* aa = calloc(1, sizeof(rtems_bsd_rc_conf_argc_argv)); + if (aa != NULL) + aa->marker = ARGC_ARGV_MARKER; + return aa; +} -static int -parse_line(rtems_bsd_rc_conf* rc_conf) +void +rtems_bsd_rc_conf_argc_argv_destroy(rtems_bsd_rc_conf_argc_argv* aa) { - const char* line; - rtems_chain_node* node = rtems_chain_first(&directives); - const rtems_chain_node* tail = rtems_chain_tail(&directives); - argc_argv aa; - int r; + if (aa->marker == ARGC_ARGV_MARKER) { + argc_argv_clean(aa); + free(aa); + } +} - line = rc_conf->lines[rc_conf->line]; +int rtems_bsd_rc_conf_find_next(rtems_bsd_rc_conf* rc_conf, + rtems_bsd_rc_conf_argc_argv* argc_argv) +{ - if (*line == '\0') - return 0; + if (argc_argv_valid(argc_argv) < 0) + return -1; - r = argc_argv_create(line, &aa); - if (r < 0) { - fprintf(stderr, "error: %s:%lu: creating argc/argv: %s\n", - rc_conf->name, rc_conf->line + 1, strerror(errno)); - return r; - } + while (rc_conf->line < rc_conf->line_count) { + const char* line; + regex_t rege; + #define MAX_MATCHES 1 + regmatch_t matches[MAX_MATCHES]; + int r; - while (node != tail) { - directive* dir = (directive*) node; - regex_t rege; - #define MAX_MATCHES 1 - regmatch_t matches[MAX_MATCHES]; + line = rc_conf->lines[rc_conf->line]; + ++rc_conf->line; - r = regcomp(®e, dir->directive, REG_EXTENDED); + if (*line == '\0') + continue; + + if (argc_argv_update(line, argc_argv) < 0) + return -1; + + r = regcomp(®e, rc_conf->find_regex, REG_EXTENDED); if (r != 0) { char rerror[128]; regerror(r, ®e, rerror, sizeof(rerror)); fprintf(stderr, "error: %s:%lu: %s\n", rc_conf->name, rc_conf->line + 1, rerror); - argc_argv_destroy(&aa); return -1; } - r = regexec(®e, aa.argv[0], MAX_MATCHES, matches, 0); + r = regexec(®e, argc_argv->argv[0], MAX_MATCHES, matches, 0); if (r != 0 && r != REG_NOMATCH) { char rerror[128]; regerror(r, ®e, rerror, sizeof(rerror)); fprintf(stderr, "error: %s:%lu: %s\n", rc_conf->name, rc_conf->line + 1, rerror); regfree(®e); - argc_argv_destroy(&aa); return -1; } - if (r == 0) { - r = dir->handler(rc_conf, aa.argc, aa.argv); - if (r < 0) - fprintf(stderr, "error: %s:%lu: runtime error: %s: %s\n", - rc_conf->name, rc_conf->line + 1, aa.argv[0], strerror(errno)); - regfree(®e); - argc_argv_destroy(&aa); - return r; - } - regfree(®e); - node = rtems_chain_next(node); - } - - errno = ENOSYS; + /* + * Match found. + */ + if (r == 0) + return 0; - fprintf(stderr, "error: %s:%lu: %s: configuration name is not supported\n", - rc_conf->name, rc_conf->line + 1, aa.argv[0]); + regfree(®e); + } - argc_argv_destroy(&aa); + errno = ENOENT; return -1; } +int rtems_bsd_rc_conf_find(rtems_bsd_rc_conf* rc_conf, + const char* expression, + rtems_bsd_rc_conf_argc_argv* argc_argv) +{ + if (argc_argv_valid(argc_argv) < 0) + return -1; + free(rc_conf->find_regex); + rc_conf->find_regex = strdup(expression); + rc_conf->line = 0; + if (rc_conf->find_regex == NULL) { + errno = ENOMEM; + return -1; + } + return rtems_bsd_rc_conf_find_next(rc_conf, argc_argv); +} + int -rtems_bsd_rc_conf_directive_add(const char* dir_regex, - rtems_bsd_rc_conf_directive handler) +rtems_bsd_rc_conf_service_add(const char* name, + const char* control, + rtems_bsd_rc_conf_service entry) { - directive* dir; + service* srv; + char* ctl = NULL; + char* s; + char* c; - dir = malloc(sizeof(*dir)); - if (dir == NULL) { + srv = malloc(sizeof(*srv)); + if (srv == NULL) { errno = ENOMEM; return -1; } - memset(dir, 0, sizeof(*dir)); + memset(srv, 0, sizeof(*srv)); - dir->directive = strdup(dir_regex); - if (dir->directive == NULL) { - free(dir); + srv->name = strdup(name); + if (control != NULL) { + ctl = strdup(control); + srv->control = ctl; + } + srv->entry = entry; + + if (srv->name == NULL || (control != NULL && ctl == NULL)) { + fprintf(stderr, "error: rc.conf: add service: no memory\n"); + free((void*) srv->control); + free((void*) srv->name); + free(srv); errno = ENOMEM; return -1; } - dir->handler = handler; + if (control != NULL) { + s = c = ctl; + + while (*c != '\0') { + if (*c == ';') { + *c = '\0'; + + if (strncasecmp("before:", s, sizeof("before:") - 1) == 0) { + if (srv->before == NULL) { + srv->before = s + sizeof("before:") - 1; + s = NULL; + } + else { + fprintf(stderr, "error: rc.conf: add service: repeated 'before'\n"); + c = NULL; + } + } + else if (strncasecmp("after:", s, sizeof("after:") - 1) == 0) { + if (srv->after == NULL) { + srv->after = s + sizeof("after:") - 1; + s = NULL; + } + else { + fprintf(stderr, "error: rc.conf: add service: repeated 'after'\n"); + c = NULL; + } + } + else if (strncasecmp("require:", s, sizeof("require:") - 1) == 0) { + if (srv->require == NULL) { + srv->require = s + sizeof("require:") - 1; + s = NULL; + } + else { + fprintf(stderr, "error: rc.conf: add service: repeated 'require'\n"); + c = NULL; + } + } + else { + fprintf(stderr, "error: rc.conf: add service: unknown keyword: %s\n", s); + c = NULL; + } + + if (c == NULL) { + free((void*) srv->control); + free((void*) srv->name); + free(srv); + errno = EINVAL; + return -1; + } + } + else if (s == NULL) { + s = c; + } - rtems_chain_append(&directives, &dir->node); + ++c; + } + + if (s != NULL) { + fprintf(stderr, "error: rc.conf: add service: no ';' found\n"); + free((void*) srv->control); + free((void*) srv->name); + free(srv); + errno = EINVAL; + return -1; + } + + /* + * Place on the services list. The node is removed before being inserted. If + * there are competing positions the last position is used. As a result + * handle 'after' before 'before'. + */ + rtems_chain_prepend(&services, &srv->node); + } + else { + /* + * No control string, add the end. + */ + rtems_chain_append(&services, &srv->node); + } + + /* + * After. + */ + if (srv->after != NULL) { + const char* cc = srv->after; + while (*cc != '\0') { + const char* cs = cc; + size_t l; + while (*cc != ',' && *cc != '\0') + ++cc; + l = cc - cs; + if (strncasecmp(cs, "last", l) == 0) { + fprintf(stderr, + "error: rc.conf: add service: 'last' in 'after': %s\n", + control); + rtems_chain_extract(&srv->node); + free((void*) srv->control); + free((void*) srv->name); + free(srv); + errno = EINVAL; + return -1; + } + else if (strncasecmp(cs, "first", l) == 0) { + /* already prepended */ + } + else { + rtems_chain_node* node = rtems_chain_first(&services); + while (!rtems_chain_is_tail(&services, node)) { + service* ss = (service*) node; + if (ss != srv && + strlen(ss->name) == l && strncasecmp(ss->name, cs, l) == 0) { + rtems_chain_extract(&srv->node); + rtems_chain_insert(&ss->node, &srv->node); + break; + } + node = rtems_chain_next(node); + } + } + } + } + + /* + * Before. + */ + if (srv->before != NULL) { + const char* cc = srv->before; + while (*cc != '\0') { + const char* cs = cc; + size_t l; + while (*cc != ',' && *cc != '\0') + ++cc; + l = cc - cs; + if (strncasecmp(cs, "first", l) == 0) { + fprintf(stderr, "error: rc.conf: add service: 'first' in 'before'\n"); + rtems_chain_extract(&srv->node); + free((void*) srv->control); + free((void*) srv->name); + free(srv); + errno = EINVAL; + return -1; + } + else if (strncasecmp(cs, "last", l) == 0) { + rtems_chain_extract(&srv->node); + rtems_chain_append(&services, &srv->node); + } + else { + rtems_chain_node* node = rtems_chain_first(&services); + while (!rtems_chain_is_tail(&services, node)) { + service* ss = (service*) node; + if (strlen(ss->name) == l && strncasecmp(ss->name, cs, l) == 0) { + rtems_chain_extract(&srv->node); + if (rtems_chain_is_first(node)) + rtems_chain_prepend(&services, &srv->node); + else { + service* sp = (service*) rtems_chain_previous(node); + rtems_chain_insert(&sp->node, &srv->node); + } + break; + } + node = rtems_chain_next(node); + } + } + } + } return 0; } int -rtems_bsd_run_rc_conf_script(const char* name, const char* text, bool verbose) +rtems_bsd_rc_conf_service_remove(const char* name) +{ + rtems_chain_node* node = rtems_chain_first(&services); + const rtems_chain_node* tail = rtems_chain_tail(&services); + + while (node != tail) { + service* srv = (service*) node; + + if (strcasecmp(name, srv->name) == 0) { + rtems_chain_extract(&srv->node); + free((void*) srv->control); + free((void*) srv->name); + free(srv); + return 0; + } + + node = rtems_chain_next(node); + } + + errno = ENOENT; + return -1; +} + +static rtems_task rc_conf_worker(rtems_task_argument task_argument) +{ + rtems_bsd_rc_conf* rc_conf = (rtems_bsd_rc_conf*) task_argument; + rtems_chain_node* node = rtems_chain_first(&services); + int r = 0; + int error; + + if (rc_conf->verbose) + printf("rc.conf: running\n"); + + while (!rtems_chain_is_tail(&services, node)) { + service* srv = (service*) node; + int rr; + if (rc_conf->verbose) + printf("BSD service: %s\n", srv->name); + rr = srv->entry(rc_conf); + if (rr < 0) { + fprintf(stderr, "error: bsd service: %s: %s\n", srv->name, strerror(errno)); + if (r == 0) { + r = rr; + error = errno; + } + } + node = rtems_chain_next(node); + } + + if (rc_conf->verbose) + printf("rc.conf: services done\n"); + + lock(rc_conf); + + if (r < 0) + rc_conf->error_code = error; + + /* + * If there is a waiter signal else clean up because the waiter has gone. + */ + if (rc_conf->waiter != 0) { + rtems_event_send(rc_conf->waiter, RTEMS_EVENT_1); + unlock(rc_conf); + } + else { + unlock(rc_conf); + rc_conf_destroy(rc_conf); + } + + if (rc_conf->verbose) + printf("rc.conf: finished\n"); + + rtems_task_delete(RTEMS_SELF); +} + +int +rtems_bsd_run_rc_conf_script(const char* name, + const char* text, + int timeout, + bool verbose) { - rtems_bsd_rc_conf rc_conf; - int r; + rtems_bsd_rc_conf rc_conf; + rtems_task_priority priority; + rtems_id worker; + rtems_status_code sc; + int r = 0; if (verbose) - printf("rc.conf: processing: %s size:%lu\n", name, strlen(text)); + printf("rc.conf: start: %s size:%lu, timeout: %i\n", + name, strlen(text), timeout); - r = rc_conf_create(&rc_conf, name, text, verbose); + r = rc_conf_create(&rc_conf, name, text, timeout, verbose); if (r < 0) { fprintf(stderr, "error: %s: parse error: %s\n", name, strerror(errno)); return -1; } - while (rc_conf.line < rc_conf.line_count) { - r = parse_line(&rc_conf); - if (r < 0) - break; - ++rc_conf.line; + sc = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority); + if (sc != RTEMS_SUCCESSFUL) { + fprintf(stderr, "error: %s: get priority: %s\n", + name, rtems_status_text(sc)); + errno = EIO; + return -1; } - rc_conf_destroy(&rc_conf); + sc = rtems_task_create(rtems_build_name('B', 'S', 'D', 'r' ), + priority, + 8 * 1024, + RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR, + RTEMS_LOCAL | RTEMS_FLOATING_POINT, + &worker); + if (sc != RTEMS_SUCCESSFUL) { + fprintf (stderr, "error: worker create: %s", rtems_status_text(sc)); + errno = EIO; + return -1; + } + + sc = rtems_task_start(worker, + rc_conf_worker, + (rtems_task_argument) &rc_conf); + if (sc != RTEMS_SUCCESSFUL) { + fprintf (stderr, "error: worker start: %s", rtems_status_text(sc)); + errno = EIO; + return - 1; + } + + if (timeout >= 0) { + rtems_event_set out = 0; + rtems_interval ticks; + + if (timeout == 0) + ticks = RTEMS_NO_TIMEOUT; + else + ticks = RTEMS_MICROSECONDS_TO_TICKS(timeout * 1000000UL); + + sc = rtems_event_receive(RTEMS_EVENT_1, + RTEMS_WAIT | RTEMS_EVENT_ANY, + ticks, + &out); + if (sc != RTEMS_SUCCESSFUL) { + if (sc != RTEMS_TIMEOUT) { + fprintf (stderr, "error: worker event in: %s", rtems_status_text(sc)); + errno = EIO; + } + else { + lock(&rc_conf); + rc_conf.waiter = 0; + unlock(&rc_conf); + errno = ETIMEDOUT; + } + r = -1; + } + else { + lock(&rc_conf); + errno = rc_conf.error_code; + if (errno != 0) + r = -1; + unlock(&rc_conf); + rc_conf_destroy(&rc_conf); + } + } return r; } int -rtems_bsd_run_rc_conf(const char* name, bool verbose) +rtems_bsd_run_rc_conf(const char* name, int timeout, bool verbose) { struct stat sb; int r; @@ -424,7 +847,7 @@ rtems_bsd_run_rc_conf(const char* name, bool verbose) fclose(file); - r = rtems_bsd_run_rc_conf_script(name, rc_conf, verbose); + r = rtems_bsd_run_rc_conf_script(name, rc_conf, timeout, verbose); free(rc_conf); @@ -432,9 +855,9 @@ rtems_bsd_run_rc_conf(const char* name, bool verbose) } int -rtems_bsd_run_etc_rc_conf(bool verbose) +rtems_bsd_run_etc_rc_conf(int timeout, bool verbose) { - return rtems_bsd_run_rc_conf("/etc/rc.conf", verbose); + return rtems_bsd_run_rc_conf("/etc/rc.conf", timeout, verbose); } const char* @@ -450,7 +873,7 @@ rtems_bsd_rc_conf_line(rtems_bsd_rc_conf* rc_conf) } bool - rtems_bsd_rc_conf_verbose(rtems_bsd_rc_conf* rc_conf) +rtems_bsd_rc_conf_verbose(rtems_bsd_rc_conf* rc_conf) { return rc_conf->verbose; } @@ -462,7 +885,7 @@ void rtems_bsd_rc_conf_print_cmd(rtems_bsd_rc_conf* rc_conf, { if (rc_conf->verbose) { int arg; - printf("rc.conf: %s:%lu: %s:", rc_conf->name, rc_conf->line + 1, name); + printf("rc.conf: %s: %s:", rc_conf->name, name); for (arg = 0; arg < argc; ++arg) printf(" %s", argv[arg]); printf("\n"); diff --git a/testsuite/rcconf01/test_main.c b/testsuite/rcconf01/test_main.c index 8f1cf2f2..be878a38 100644 --- a/testsuite/rcconf01/test_main.c +++ b/testsuite/rcconf01/test_main.c @@ -26,14 +26,17 @@ #include #include +#include #include #include #include #include #include #include +#include #include +#include #define TEST_NAME "LIBBSD RC.CONF 1" @@ -52,39 +55,97 @@ static const char* rc_conf_regex = \ #define NUM_OF_TEST_REGEX_ 6 static bool test_regex_results[NUM_OF_TEST_REGEX_]; static int test_regex_last_num; +static int test_service_last_num; static const char* rc_conf_not_found = \ "# invalid directive.\n" \ "abc_def_0=\"not found\"\n"; static int -test_regex_(rtems_bsd_rc_conf* rc_conf, int argc, const char** argv) +test_service(rtems_bsd_rc_conf* rc_conf) { - int num; - int arg; - - rtems_bsd_rc_conf_print_cmd(rc_conf, "test_regex_", argc, argv); - - assert(strncasecmp(argv[0], "test_regex_", strlen("test_regex_")) == 0); - num = atoi(argv[0] + strlen("test_regex_")); - assert(num == (test_regex_last_num + 1)); - assert((num - 1) < NUM_OF_TEST_REGEX_); - for (arg = 0; arg < argc; ++arg) { - const char* a = argv[arg]; - size_t l = strlen(a); - if (l > 0) { - assert(!isspace(a[0])); - assert(!isspace(a[l - 1])); - assert(a[0] != '"'); - assert(a[l - 1] != '"'); + rtems_bsd_rc_conf_argc_argv* aa; + int r; + + test_service_last_num = 1; + + assert((aa = rtems_bsd_rc_conf_argc_argv_create()) != NULL); + r = rtems_bsd_rc_conf_find(rc_conf, "test_regex_.*", aa); + assert(r == 0 || (r < 0 && errno == ENOENT)); + if (r < 0 && errno == ENOENT) + return -1; + + while (r == 0) { + int num; + int arg; + rtems_bsd_rc_conf_print_cmd(rc_conf, "test_service", aa->argc, aa->argv); + assert(strncasecmp(aa->argv[0], "test_regex_", strlen("test_regex_")) == 0); + num = atoi(aa->argv[0] + strlen("test_regex_")); + assert(num == (test_regex_last_num + 1)); + assert((num - 1) < NUM_OF_TEST_REGEX_); + for (arg = 0; arg < aa->argc; ++arg) { + const char* a = aa->argv[arg]; + size_t l = strlen(a); + if (l > 0) { + assert(!isspace(a[0])); + assert(!isspace(a[l - 1])); + assert(a[0] != '"'); + assert(a[l - 1] != '"'); + } } + test_regex_results[num - 1] = true; + ++test_regex_last_num; + r = rtems_bsd_rc_conf_find_next(rc_conf, aa); + assert(r == 0 || (r < 0 && errno == ENOENT)); } - test_regex_results[num - 1] = true; - ++test_regex_last_num; + rtems_bsd_rc_conf_argc_argv_destroy(aa); + puts("test_service done"); + return 0; +} + +static int +test_service_2(rtems_bsd_rc_conf* rc_conf) +{ + puts("test_service_2"); + assert(test_service_last_num == 1); + test_service_last_num = 2; + return 0; +} +static int +test_service_3(rtems_bsd_rc_conf* rc_conf) +{ + puts("test_service_3"); + assert(test_service_last_num == 2); + test_service_last_num = 3; return 0; } +static int +test_service_4(rtems_bsd_rc_conf* rc_conf) +{ + puts("test_service_4"); + assert(test_service_last_num == 3); + test_service_last_num = 4; + return 0; +} + +static int +test_service_5(rtems_bsd_rc_conf* rc_conf) +{ + puts("test_service_5"); + assert(test_service_last_num == 4); + test_service_last_num = 5; + return 0; +} + +static int +test_service_bad(rtems_bsd_rc_conf* rc_conf) +{ + puts("test_service_bad"); + return -1; +} + static void make_rc_conf(const char* rc_conf) { @@ -105,38 +166,49 @@ test_regex_check(void) } static void -test_etc_rc_conf(void) +test_regex_reset(void) { memset(&test_regex_results[0], 0, sizeof(test_regex_results)); test_regex_last_num = 0; + test_service_last_num = 0; + } + +static void +test_etc_rc_conf(void) +{ + puts("test_etc_rc_conf"); make_rc_conf("/etc/rc.conf"); - assert(rtems_bsd_run_etc_rc_conf(true) == 0); + test_regex_reset(); + assert(rtems_bsd_run_etc_rc_conf(0, true) == 0); test_regex_check(); } static void test_rc_conf(void) { - memset(&test_regex_results[0], 0, sizeof(test_regex_results)); - test_regex_last_num = 0; + puts("test_rc_conf"); make_rc_conf("/my_rc.conf"); - assert(rtems_bsd_run_rc_conf("/my_rc.conf", true) == 0); + test_regex_reset(); + assert(rtems_bsd_run_rc_conf("/my_rc.conf", 0, true) == 0); test_regex_check(); } static void test_rc_conf_script(void) { - memset(&test_regex_results[0], 0, sizeof(test_regex_results)); - test_regex_last_num = 0; - assert(rtems_bsd_run_rc_conf_script("internal", rc_conf_regex, true) == 0); + puts("test_rc_conf_conf"); + test_regex_reset(); + assert(rtems_bsd_run_rc_conf_script("internal", rc_conf_regex, 0, true) == 0); test_regex_check(); } static void test_rc_conf_script_not_found(void) { - assert(rtems_bsd_run_rc_conf_script("internal", rc_conf_not_found, true) < 0); + puts("test_rc_conf_conf_not_found"); + test_regex_reset(); + assert(rtems_bsd_run_rc_conf_script("internal", rc_conf_not_found, 0, true) < 0); + assert(test_regex_last_num == 0); } static void @@ -146,7 +218,33 @@ setup(void) mkdir("/etc", S_IRWXU | S_IRWXG | S_IRWXO); /* ignore errors, check the dir after. */ assert(stat("/etc", &sb) == 0); assert(S_ISDIR(sb.st_mode)); - assert(rtems_bsd_rc_conf_directive_add("test_regex_.*", test_regex_) == 0); + assert(rtems_bsd_rc_conf_service_add("test_service_2", + "before:last;", + test_service_2) == 0); + assert(rtems_bsd_rc_conf_service_add("test_service_5", + "after:test_service_2;", + test_service_5) == 0); + assert(rtems_bsd_rc_conf_service_add("test_service_4", + "before:test_service_5;", + test_service_4) == 0); + assert(rtems_bsd_rc_conf_service_add("test_service_3", + "before:test_service_4;after:test_service_2;", + test_service_3) == 0); + assert(rtems_bsd_rc_conf_service_add("test_service_bad", + "before:first;", + test_service_bad) < 0); + assert(rtems_bsd_rc_conf_service_add("test_service_bad", + "after:last;", + test_service_bad) < 0); + assert(rtems_bsd_rc_conf_service_add("test_service_bad", + "after:xxxx,xxxx", + test_service_bad) < 0); + assert(rtems_bsd_rc_conf_service_add("test_service_bad", + "yyyy:xxxx;", + test_service_bad) < 0); + assert(rtems_bsd_rc_conf_service_add("test_service", + "after:first;", + test_service) == 0); } static void -- cgit v1.2.3