From 1d4de11a907e41c06063a2cd5028dc4101690f50 Mon Sep 17 00:00:00 2001 From: José Bollo Date: Tue, 11 Oct 2016 17:07:16 +0200 Subject: Prepare the Integration with systemd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an intermediate commit providing basic functionnalities for setting up integration of the framework with systemd. - file afm-unit.conf is a mustache template - translation of config.xml to json object - mustache (extended) application of the json to the template - post processing of the result for extracting unit files This processing is currently available as a test (and a tool) and will be integrated after more developement, test and validation. Signed-off-by: José Bollo --- src/wgtpkg-unit.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 src/wgtpkg-unit.c (limited to 'src/wgtpkg-unit.c') diff --git a/src/wgtpkg-unit.c b/src/wgtpkg-unit.c new file mode 100644 index 0000000..8569c5a --- /dev/null +++ b/src/wgtpkg-unit.c @@ -0,0 +1,254 @@ +/* + Copyright 2016, 2017 IoT.bzh + + author: José Bollo + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include "verbose.h" +#include "utils-file.h" + +#include "wgtpkg-mustach.h" +#include "wgtpkg-unit.h" + +static char *template; + +/* + * Pack a null terminated 'text' by removing empty lines, + * lines made of blanks and terminated with \, lines + * starting with the 'purge' character (can be null). + * Lines made of the 'purge' character followed with + * "nl" exactly (without quotes ") are replaced with + * an empty line. + * + * Returns the pointer to the ending null. + */ +static char *pack(char *text, char purge) +{ + char *read, *write, *begin, *start, c, emit, cont, nextcont; + + cont = 0; + c = *(begin = write = read = text); + while (c) { + emit = nextcont = 0; + start = NULL; + begin = read; + while (c && c != '\n') { + if (c != ' ' && c != '\t') { + if (c == '\\' && read[1] == '\n') + nextcont = 1; + else { + emit = 1; + if (!start) + start = read; + } + } + c = *++read; + } + if (c) + c = *++read; + if (emit) { + if (!cont && start) + begin = start; + if (purge && *begin == purge) { + if (!strncmp(begin+1, "nl\n",3)) + *write++ = '\n'; + } else { + while (begin != read) + *write++ = *begin++; + } + } + cont = nextcont; + } + *write = 0; + return write; +} + +/* + * Searchs the first character of the next line + * of the 'text' and returns its address + * Returns NULL if there is no next line. + */ +static inline char *nextline(char *text) +{ + char *result = strchr(text, '\n'); + return result + !!result; +} + +/* + * Search in 'text' the offset of a line beginning with the 'pattern' + * Returns NULL if not found or the address of the line contning the pattern + * If args isn't NULL and the pattern is found, the pointed pattern is + * updated with the address of the character following the found pattern. + */ +static char *offset(char *text, const char *pattern, char **args) +{ + size_t len; + + if (text) { + len = strlen(pattern); + do { + if (strncmp(text, pattern, len)) + text = nextline(text); + else { + if (args) + *args = &text[len]; + break; + } + } while (text); + } + return text; +} + +/* + * process one unit + */ + +static int process_one_unit(char *spec, struct unitdesc *desc) +{ + char *nsoc, *nsrv; + int isuser, issystem, issock, isserv; + + /* found the configuration directive of the unit */ + isuser = !!offset(spec, "%systemd-unit user\n", NULL); + issystem = !!offset(spec, "%systemd-unit system\n", NULL); + issock = !!offset(spec, "%systemd-unit socket ", &nsoc); + isserv = !!offset(spec, "%systemd-unit service ", &nsrv); + + if (isuser ^ issystem) { + desc->scope = isuser ? unitscope_user : unitscope_system; + } else { + desc->scope = unitscope_unknown; + } + + if (issock ^ isserv) { + if (issock) { + desc->type = unittype_socket; + desc->name = nsoc; + } else { + desc->type = unittype_service; + desc->name = nsrv; + } + desc->name_length = (size_t)(strchrnul(desc->name, '\n') - desc->name); + desc->name = strndup(desc->name, desc->name_length); + } else { + desc->type = unittype_unknown; + desc->name = NULL; + desc->name_length = 0; + } + + desc->content = spec; + desc->content_length = (size_t)(pack(spec, '%') - spec); + + return 0; +} + +/* + */ +static int process_all_units(char *spec, int (*process)(void *closure, const struct unitdesc descs[], unsigned count), void *closure) +{ + int rc, rc2; + unsigned n; + char *beg, *end, *after; + struct unitdesc *descs, *d; + + descs = NULL; + n = 0; + rc = 0; + beg = offset(spec, "%begin systemd-unit\n", NULL); + while(beg) { + beg = nextline(beg); + end = offset(beg, "%end systemd-unit\n", &after); + if (!end) { + /* unterminated unit !! */ + ERROR("unterminated unit description!! %s", beg); + break; + } + *end = 0; + + d = realloc(descs, (n + 1) * sizeof *descs); + if (d == NULL) + rc2 = -ENOMEM; + else { + memset(&d[n], 0, sizeof *d); + descs = d; + rc2 = process_one_unit(beg, &descs[n]); + } + + if (rc2 >= 0) + n++; + else if (rc == 0) + rc = rc2; + beg = offset(after, "%begin systemd-unit\n", NULL); + } + + if (rc == 0 && process) + rc = process(closure, descs, n); + while(n) + free((char *)(descs[--n].name)); + free(descs); + + return rc; +} + +int unit_generator_on(const char *filename) +{ + size_t size; + char *tmp; + int rc; + + rc = getfile(filename ? : FWK_UNIT_CONF, &template, NULL); + if (!rc) { + size = (size_t)(pack(template, ';') - template); + tmp = realloc(template, 1 + size); + if (tmp) + template = tmp; + } + return rc; +} + +void unit_generator_off() +{ + free(template); + template = NULL; +} + +int unit_generator_process(struct json_object *jdesc, int (*process)(void *closure, const struct unitdesc descs[], unsigned count), void *closure) +{ + int rc; + size_t size; + char *instance; + + rc = template ? 0 : unit_generator_on(NULL); + if (!rc) { + instance = NULL; + rc = apply_mustach(template, jdesc, &instance, &size); + if (!rc) { + rc = process_all_units(instance, process, closure); + } + free(instance); + } + return rc; +} + -- cgit 1.2.3-korg