2 Copyright 2016, 2017 IoT.bzh
4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
23 #include <sys/types.h>
30 #include "utils-file.h"
32 #include "wgtpkg-mustach.h"
33 #include "wgtpkg-unit.h"
35 static char *template;
38 * Pack a null terminated 'text' by removing empty lines,
39 * lines made of blanks and terminated with \, lines
40 * starting with the 'purge' character (can be null).
41 * Lines made of the 'purge' character followed with
42 * "nl" exactly (without quotes ") are replaced with
45 * Returns the pointer to the ending null.
47 static char *pack(char *text, char purge)
49 char *read, *write, *begin, *start, c, emit, cont, nextcont;
52 c = *(begin = write = read = text);
57 while (c && c != '\n') {
58 if (c != ' ' && c != '\t') {
59 if (c == '\\' && read[1] == '\n')
74 if (purge && *begin == purge) {
75 if (!strncmp(begin+1, "nl\n",3))
89 * Searchs the first character of the next line
90 * of the 'text' and returns its address
91 * Returns NULL if there is no next line.
93 static inline char *nextline(char *text)
95 char *result = strchr(text, '\n');
96 return result + !!result;
100 * Search in 'text' the offset of a line beginning with the 'pattern'
101 * Returns NULL if not found or the address of the line contning the pattern
102 * If args isn't NULL and the pattern is found, the pointed pattern is
103 * updated with the address of the character following the found pattern.
105 static char *offset(char *text, const char *pattern, char **args)
110 len = strlen(pattern);
112 if (strncmp(text, pattern, len))
113 text = nextline(text);
128 static int process_one_unit(char *spec, struct unitdesc *desc)
131 int isuser, issystem, issock, isserv;
133 /* found the configuration directive of the unit */
134 isuser = !!offset(spec, "%systemd-unit user\n", NULL);
135 issystem = !!offset(spec, "%systemd-unit system\n", NULL);
136 issock = !!offset(spec, "%systemd-unit socket ", &nsoc);
137 isserv = !!offset(spec, "%systemd-unit service ", &nsrv);
139 if (isuser ^ issystem) {
140 desc->scope = isuser ? unitscope_user : unitscope_system;
142 desc->scope = unitscope_unknown;
145 if (issock ^ isserv) {
147 desc->type = unittype_socket;
150 desc->type = unittype_service;
153 desc->name_length = (size_t)(strchrnul(desc->name, '\n') - desc->name);
154 desc->name = strndup(desc->name, desc->name_length);
156 desc->type = unittype_unknown;
158 desc->name_length = 0;
161 desc->content = spec;
162 desc->content_length = (size_t)(pack(spec, '%') - spec);
169 static int process_all_units(char *spec, int (*process)(void *closure, const struct unitdesc descs[], unsigned count), void *closure)
173 char *beg, *end, *after;
174 struct unitdesc *descs, *d;
179 beg = offset(spec, "%begin systemd-unit\n", NULL);
182 end = offset(beg, "%end systemd-unit\n", &after);
184 /* unterminated unit !! */
185 ERROR("unterminated unit description!! %s", beg);
190 d = realloc(descs, (n + 1) * sizeof *descs);
194 memset(&d[n], 0, sizeof *d);
196 rc2 = process_one_unit(beg, &descs[n]);
203 beg = offset(after, "%begin systemd-unit\n", NULL);
206 if (rc == 0 && process)
207 rc = process(closure, descs, n);
209 free((char *)(descs[--n].name));
215 int unit_generator_on(const char *filename)
221 rc = getfile(filename ? : FWK_UNIT_CONF, &template, NULL);
223 size = (size_t)(pack(template, ';') - template);
224 tmp = realloc(template, 1 + size);
231 void unit_generator_off()
237 int unit_generator_process(struct json_object *jdesc, int (*process)(void *closure, const struct unitdesc descs[], unsigned count), void *closure)
243 rc = template ? 0 : unit_generator_on(NULL);
246 rc = apply_mustach(template, jdesc, &instance, &size);
248 rc = process_all_units(instance, process, closure);