Merge branch 'vendor/LESS'
[dragonfly.git] / usr.sbin / installer / libinstaller / confed.c
1 /*
2  * Copyright (c)2004 The DragonFly Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  *   Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in
13  *   the documentation and/or other materials provided with the
14  *   distribution.
15  *
16  *   Neither the name of the DragonFly Project nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 /*
35  * confed.c
36  * Functions for working with configuration files.
37  * Inspired by (but not derived from) sysinstall's variable.c
38  * $Id: confed.c,v 1.16 2005/02/06 21:05:18 cpressey Exp $
39  */
40
41 #include <sys/stat.h>
42
43 #include <ctype.h>
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <time.h>
49 #include <unistd.h>
50
51 #include "libaura/mem.h"
52 #include "libaura/dict.h"
53 #include "libdfui/system.h"
54
55 #include "confed.h"
56 #include "commands.h"
57 #include "functions.h"
58
59 /*
60  * Create a new, empty set of in-memory config variable settings.
61  */
62 struct config_vars *
63 config_vars_new(void)
64 {
65         struct config_vars *cvs;
66
67         AURA_MALLOC(cvs, config_vars);
68
69         cvs->d = aura_dict_new(1, AURA_DICT_SORTED_LIST);
70
71         return(cvs);
72 }
73
74 /*
75  * Deallocate the memory used by a set of config variable settings.
76  */
77 void
78 config_vars_free(struct config_vars *cvs)
79 {
80         if (cvs == NULL)
81                 return;
82
83         aura_dict_free(cvs->d);
84
85         AURA_FREE(cvs, config_vars);
86 }
87
88 /*
89  * Get the value of a configuration variable in a set of settings
90  * and return it, or a (constant) 0-length string if not found.
91  */
92 const char *
93 config_var_get(const struct config_vars *cvs, const char *name)
94 {
95         void *rv;
96         size_t rv_len;
97
98         aura_dict_fetch(cvs->d, name, strlen(name) + 1, &rv, &rv_len);
99         if (rv == NULL)
100                 return("");
101         else
102                 return(rv);
103 }
104
105 /*
106  * Set the value of a configuration variable.  If the named variable
107  * does not exist within the given set, a new one is created.
108  */
109 int
110 config_var_set(struct config_vars *cvs, const char *name, const char *value)
111 {
112         aura_dict_store(cvs->d,
113             name, strlen(name) + 1,
114             value, strlen(value) + 1);
115         return(1);
116 }
117
118 /*
119  * Write a set of configuration variable settings to a file.
120  */
121 int
122 config_vars_write(const struct config_vars *cvs, int config_type, const char *fmt, ...)
123 {
124         FILE *f;
125         va_list args;
126         char *filename;
127         char tstr[256];
128         int conf_written = 0;
129         time_t t;
130         void *rk, *rv;
131         size_t rk_len, rv_len;
132
133         va_start(args, fmt);
134         vasprintf(&filename, fmt, args);
135         va_end(args);
136
137         if ((f = fopen(filename, "a")) == NULL)
138                 return(0);
139
140         time(&t);
141         strlcpy(tstr, ctime(&t), 256);
142         if (strlen(tstr) > 0)
143                 tstr[strlen(tstr) - 1] = '\0';
144
145         switch (config_type) {
146         case CONFIG_TYPE_SH:
147
148                 aura_dict_rewind(cvs->d);
149                 while (!aura_dict_eof(cvs->d)) {
150                         if (! conf_written) {
151                                 conf_written = 1;
152                                 fprintf(f, "\n");
153                                 fprintf(f, "# -- BEGIN %s "
154                                     "Installer automatically generated "
155                                     "configuration  -- #\n",
156                                     OPERATING_SYSTEM_NAME);
157                                 fprintf(f, "# -- Written on %s -- #\n", tstr);
158                         }
159                         aura_dict_get_current_key(cvs->d, &rk, &rk_len),
160                         aura_dict_fetch(cvs->d, rk, rk_len, &rv, &rv_len);
161                         fprintf(f, "%s=\"%s\"\n", (char *)rk, (char *)rv);
162                         aura_dict_next(cvs->d);
163                 }
164                 if (conf_written) {
165                         fprintf(f, "# -- END of %s Installer "
166                             "automatically generated configuration -- #\n",
167                             OPERATING_SYSTEM_NAME);
168                 }
169                 break;
170         case CONFIG_TYPE_RESOLV:
171                 aura_dict_rewind(cvs->d);
172                 while (!aura_dict_eof(cvs->d)) {
173                         aura_dict_get_current_key(cvs->d, &rk, &rk_len),
174                         aura_dict_fetch(cvs->d, rk, rk_len, &rv, &rv_len);
175                         fprintf(f, "%s\t\t%s\n", (char *)rk, (char *)rv);
176                         aura_dict_next(cvs->d);
177                 }
178                 break;
179         default:
180                 fclose(f);
181                 return(0);
182         }
183
184         fclose(f);
185         return(1);
186 }
187
188 /*
189  * Read variables from a file.
190  * Returns 1 if the variables could be read successfully, 0 if not.
191  */
192 int
193 config_vars_read(struct i_fn_args *a, struct config_vars *cvs,
194                  int config_type __unused, const char *fmt, ...)
195 {
196         struct commands *cmds;
197         char *filename, *tmp_filename, line[1024], *value;
198         FILE *f, *script;
199         va_list args;
200
201         va_start(args, fmt);
202         vasprintf(&filename, fmt, args);
203         va_end(args);
204
205         asprintf(&tmp_filename, "%sextract_vars", a->tmp);
206         script = fopen(tmp_filename, "w");
207         free(tmp_filename);
208         if (script == NULL)
209                 return(0);
210
211         fprintf(script, "set | %susr/bin/sort >%senv.before\n", a->os_root, a->tmp);
212         fprintf(script, ". %s%s\n", a->os_root, filename);
213         fprintf(script, "set | %susr/bin/sort >%senv.after\n", a->os_root, a->tmp);
214         fprintf(script, "%susr/bin/comm -1 -3 %senv.before %senv.after | \\\n",
215             a->os_root, a->tmp, a->tmp);
216         fprintf(script, "    %susr/bin/awk -F= '{ print $1 }' | \\\n", a->os_root);
217         fprintf(script, "    while read __VARNAME; do\n");
218         fprintf(script, "        echo -n ${__VARNAME}=\n");
219         fprintf(script, "        eval echo ' $'${__VARNAME}\n");
220         fprintf(script, "    done\n");
221         fprintf(script, "%sbin/rm -f %senv.before %senv.after\n",
222             a->os_root, a->tmp, a->tmp);
223         fclose(script);
224
225         cmds = commands_new();
226         command_add(cmds, "%sbin/sh %sextract_vars >%sextracted_vars.txt",
227             a->os_root, a->tmp, a->tmp);
228         temp_file_add(a, "extracted_vars.txt");
229         if (!commands_execute(a, cmds)) {
230                 commands_free(cmds);
231                 return(0);
232         }
233         commands_free(cmds);
234
235         /*
236          * Delete the script immediately.
237          */
238         asprintf(&tmp_filename, "%sextract_vars", a->tmp);
239         (void)unlink(tmp_filename);     /* not much we can do if it fails */
240         free(tmp_filename);
241
242         asprintf(&tmp_filename, "%sextracted_vars.txt", a->tmp);
243         f = fopen(tmp_filename, "r");
244         free(tmp_filename);
245         if (f == NULL)
246                 return(0);
247         while (fgets(line, 1024, f) != NULL) {
248                 if (strlen(line) > 0)
249                         line[strlen(line) - 1] = '\0';
250                 /* split line at first = */
251                 for (value = line; *value != '=' && *value != '\0'; value++)
252                         ;
253                 if (*value == '\0')
254                         break;
255                 *value = '\0';
256                 value++;
257                 config_var_set(cvs, line, value);
258         }
259         fclose(f);
260
261         return(1);
262 }