diff options
author | Chris Johns <chrisj@rtems.org> | 2016-06-27 13:24:43 +1000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2016-06-27 13:32:24 +1000 |
commit | 55c564a02869230ba3ed0f468e9a3d567b045666 (patch) | |
tree | 1753f3816466adfddcd4f66eb1852efacee5a9af /rtemsbsd/rtems/rtems-bsd-rc-conf.c | |
parent | Add DEFAULT_NETWORK_PAGE_MBUFS_SIZE to allow per BSP allocation domain sizes. (diff) | |
download | rtems-libbsd-55c564a02869230ba3ed0f468e9a3d567b045666.tar.bz2 |
Refactor rc.conf processing to be services based.
Diffstat (limited to 'rtemsbsd/rtems/rtems-bsd-rc-conf.c')
-rw-r--r-- | rtemsbsd/rtems/rtems-bsd-rc-conf.c | 635 |
1 files changed, 529 insertions, 106 deletions
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 <rtems/chain.h> #include <machine/rtems-bsd-rc-conf.h> -#include <machine/rtems-bsd-rc-conf-directives.h> +#include <machine/rtems-bsd-rc-conf-services.h> /* - * 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"); |