2 * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/param.h>
37 #include <sys/types.h>
40 #include "cfzy_file.h"
41 #include "cfzy_conftree.h"
42 #include "cfzy_confnode.h"
44 #define LOG(level, fmt, args...) \
45 CFZY_LOG("c_hdr", level, fmt, ##args)
47 /* does not clean directories on error, if path exist, assume it's a
48 * directory and ignore error */
49 int cfzy_recursive_mkdir(const char *path)
55 n = snprintf(tmp, sizeof(tmp),"%s", path);
56 if (n <= 0 || n >= PATH_MAX)
59 /* ignore all trailing '/' */
60 while (n > 0 && tmp[--n] == '/')
63 /* create all intermediate directories */
64 for (p = tmp + 1; *p; p++) {
69 if (mkdir(tmp, S_IRWXU) < 0 && errno != EEXIST)
76 ret = mkdir(tmp, S_IRWXU);
77 if (ret < 0 && errno == EEXIST)
84 * Get the file name from a config name. Replace first underscore
86 * CONFIG_A_B -> config/a/b.h
87 * CONFIG_A__B___C -> config/a/_b/__c.h
89 static char *configname_to_filename(const char *name)
94 /* allocate room for dst buffer */
96 filename = malloc(len + 3);
99 strncpy(filename, name, len + 1);
101 for (s = filename; *s != '\0'; s++) {
102 /* '/' is not allowed in variable name */
108 /* convert the first '_' in '/' */
126 static int __cfzy_multi_c_hdr_write(const struct cfzy_confnode *n)
128 const struct cfzy_confnode *c;
130 char *filename = NULL;
131 char *dname_buf = NULL, *dname_ptr = NULL;
136 /* only dump the node if it has a name and a value */
137 if (n->name != NULL && n->effective_value != NULL) {
138 /* get the name of the file (full path) */
139 filename = configname_to_filename(n->name);
140 if (filename == NULL)
143 /* get directory name from file name */
144 dname_buf = strdup(filename);
145 if (dname_buf == NULL)
147 dname_ptr = dirname(dname_buf);
150 if (cfzy_recursive_mkdir(dname_ptr) < 0)
154 memset(oldval, 0, sizeof(oldval));
155 f = fopen(filename, "r");
157 ret = fread(oldval, 1, sizeof(oldval) - 1, f);
159 LOG(ERR, "cannot read <%s>\n", filename);
166 /* if config node is a bool, we have NULL and n will
167 * output the same val (is not st) */
168 if (n->flags & CFZY_F_VAL_IS_BOOL) {
169 val = cfzy_confnode_str2bool(n, n->effective_value);
173 /* bool is false -> not set */
175 if (snprintf(newval, sizeof(newval),
176 "/* %s is not set */",
177 cfzy_confnode_name(n)) < 0)
182 if (snprintf(newval, sizeof(newval),
183 "/* %s = %s */", cfzy_confnode_name(n),
184 n->effective_value) < 0)
189 if (snprintf(newval, sizeof(newval),
190 "/* %s = %s */", cfzy_confnode_name(n),
191 n->effective_value) < 0)
195 /* if the value is different, write the new value */
196 if (strncmp(newval, oldval, sizeof(newval)) != 0) {
197 f = fopen(filename, "w");
199 LOG(ERR, "cannot open file <%s>\n", filename);
203 if (fprintf(f, "%s", newval) < 0) {
204 LOG(ERR, "cannot write in <%s>\n",
216 /* dump all the children of root node */
217 TAILQ_FOREACH(c, &n->children, child_next) {
218 if (__cfzy_multi_c_hdr_write(c) < 0)
227 if (dname_buf != NULL)
229 if (filename != NULL)
235 /* write config/foo/bar.h */
236 int cfzy_multi_c_hdr_write(const struct cfzy_conftree *conftree,
239 char old_cwd_buf[PATH_MAX];
240 char *old_cwd = NULL;
241 const struct cfzy_confnode *c;
244 LOG(INFO, "multi C headers write <%s>\n", basedir);
246 if (cfzy_recursive_mkdir(basedir) < 0)
249 old_cwd = getcwd(old_cwd_buf, sizeof(old_cwd_buf));
250 if (old_cwd == NULL) {
251 LOG(ERR, "getcwd failed: %s\n", strerror(errno));
255 if (chdir(basedir) < 0) {
256 LOG(ERR, "chdir failed: %s\n", strerror(errno));
260 /* dump all the children of root node */
261 TAILQ_FOREACH(c, &conftree->root->children, child_next) {
262 ret = __cfzy_multi_c_hdr_write(c);
267 if (chdir(old_cwd) < 0)
268 LOG(ERR, "chdir back to <%s> failed: %s\n",
269 old_cwd, strerror(errno));
274 /* write config/autoconf.h */
275 int cfzy_c_hdr_write(const struct cfzy_conftree *conftree,
276 const char *filename)
279 const struct cfzy_confnode *c;
282 LOG(INFO, "open old C header <%s>\n", filename);
284 /* open old file in read mode */
286 f = fopen(filename, "r");
287 if (f == NULL && errno != ENOENT) {
288 printf("cannot open file <%s>: %s\n",
289 filename, strerror(errno));
293 /* old file exists */
296 /* write C header in temp file */
299 printf("cannot open temp file\n");
303 /* dump all the children of root node */
304 TAILQ_FOREACH(c, &conftree->root->children, child_next) {
305 ret = cfzy_confnode_c_hdr_write(c, tmp_f);
310 /* files are the same, nothing to do */
311 if (cfzy_file_compare(f, tmp_f) == 0) {
312 LOG(INFO, "already up to date: <%s>\n", filename);
322 /* reopen the file in write mode */
324 LOG(INFO, "write new C header <%s>\n", filename);
326 f = fopen(filename, "w");
328 printf("cannot open file <%s>\n", filename);
332 /* dump all the children of root node */
333 TAILQ_FOREACH(c, &conftree->root->children, child_next) {
334 ret = cfzy_confnode_c_hdr_write(c, f);