1/*
2 * The new sysinstall program.
3 *
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
6 *
7 * $FreeBSD$
8 *
9 * Copyright (c) 1995
10 *	Jordan Hubbard.  All rights reserved.
11 * Copyright (c) 2001
12 *      Murray Stokely.  All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer,
19 *    verbatim and that no modifications are made prior to this
20 *    point in the file.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 */
38
39#include "sysinstall.h"
40
41/* Routines for dealing with variable lists */
42
43static void
44make_variable(char *var, char *value, int dirty)
45{
46    Variable *vp;
47
48    /* Trim leading and trailing whitespace */
49    var = string_skipwhite(string_prune(var));
50
51    if (!var || !*var)
52	return;
53
54
55    /* Now search to see if it's already in the list */
56    for (vp = VarHead; vp; vp = vp->next) {
57	if (!strcmp(vp->name, var)) {
58	    if (vp->dirty && !dirty)
59		return;
60	    setenv(var, value, 1);
61	    free(vp->value);
62	    vp->value = strdup(value);
63	    if (dirty != -1)
64		vp->dirty = dirty;
65	    return;
66	}
67    }
68
69    setenv(var, value, 1);
70    /* No?  Create a new one */
71    vp = (Variable *)safe_malloc(sizeof(Variable));
72    vp->name = strdup(var);
73    vp->value = strdup(value);
74    if (dirty == -1)
75	dirty = 0;
76    vp->dirty = dirty;
77    vp->next = VarHead;
78    VarHead = vp;
79}
80
81void
82variable_set(char *var, int dirty)
83{
84    char tmp[1024], *cp;
85
86    if (!var)
87	msgFatal("NULL variable name & value passed.");
88    else if (!*var)
89	msgDebug("Warning:  Zero length name & value passed to variable_set()\n");
90    SAFE_STRCPY(tmp, var);
91    if ((cp = index(tmp, '=')) == NULL)
92	msgFatal("Invalid variable format: %s", var);
93    *(cp++) = '\0';
94    make_variable(tmp, string_skipwhite(cp), dirty);
95}
96
97void
98variable_set2(char *var, char *value, int dirty)
99{
100    if (!var || !value)
101	msgFatal("Null name or value passed to set_variable2(%s) = %s!",
102		var ? var : "", value ? value : "");
103    else if (!*var || !*value)
104	msgDebug("Warning:  Zero length name or value passed to variable_set2(%s) = %s\n",
105		var, value);
106    make_variable(var, value, dirty);
107}
108
109char *
110variable_get(char *var)
111{
112    return getenv(var);
113}
114
115int
116variable_cmp(char *var, char *value)
117{
118    char *val;
119
120    if ((val = variable_get(var)))
121	return strcmp(val, value);
122    return -1;
123}
124
125void
126variable_unset(char *var)
127{
128    Variable *vp;
129    char name[512], *cp;
130
131    if ((cp = index(var, '=')) != NULL)
132	sstrncpy(name, var, cp - var);
133    else
134	SAFE_STRCPY(name, var);
135    unsetenv(name);
136    /* Now search to see if it's in our list, if we have one.. */
137    if (!VarHead)
138	return;
139    else if (!VarHead->next && !strcmp(VarHead->name, name)) {
140	safe_free(VarHead->name);
141	safe_free(VarHead->value);
142	free(VarHead);
143	VarHead = NULL;
144    }
145    else {
146	for (vp = VarHead; vp; vp = vp->next) {
147	    if (!strcmp(vp->name, name)) {
148		Variable *save = vp->next;
149
150		safe_free(vp->name);
151		safe_free(vp->value);
152		*vp = *save;
153		safe_free(save);
154		break;
155	    }
156	}
157    }
158}
159
160/* Prompt user for the name of a variable */
161char *
162variable_get_value(char *var, char *prompt, int dirty)
163{
164    char *cp;
165
166    cp = variable_get(var);
167    if (cp && variable_get(VAR_NONINTERACTIVE))
168	return cp;
169    else if ((cp = msgGetInput(cp, "%s", prompt)) != NULL)
170	variable_set2(var, cp, dirty);
171    else
172	cp = NULL;
173    return cp;
174}
175
176/* Check if value passed in data (in the form "variable=value") is
177 * valid, and it's status compared to the value of variable stored in
178 * env
179 *
180 * Possible return values :
181 * -3: Invalid line, the data string is NOT set as an env variable
182 * -2: Invalid line, the data string is set as an env variable
183 * -1: Invalid line
184 *  0: Valid line, is NOT equal to env version
185 *  1: Valid line, is equal to env version
186 *  2: Valid line, value empty - e.g. foo=""
187 *  3: Valid line, does not exist in env
188*/
189int
190variable_check2(char *data)
191{
192    char *cp, *cp2, *cp3, tmp[256];
193
194    if (data == NULL)
195	return -1;
196    SAFE_STRCPY(tmp, data);
197    if ((cp = index(tmp, '=')) != NULL) {
198        *(cp++) = '\0';
199	if (*cp == '"') {	/* smash quotes if present */
200	    ++cp;
201	    if ((cp3 = index(cp, '"')) != NULL)
202		*cp3 = '\0';
203	}
204	else if ((cp3 = index(cp, ',')) != NULL)
205	    *cp3 = '\0';
206        cp2 = variable_get(tmp);
207        if (cp2 != NULL) {
208	    if (*cp == '\0')
209		return 2;
210	    else
211		return strcmp(cp, cp2) == 0 ? 1 : 0;
212	}
213        else
214	    return 3;
215    }
216    else
217	return variable_get(tmp) != NULL ? -2 : -3;
218}
219
220/* Check if the value passed in data (in the form "variable=value") is
221   equal to the value of variable stored in env */
222int
223variable_check(char *data)
224{
225    int ret;
226    ret = variable_check2(data);
227
228    switch(ret) {
229    case -2:
230    case 1:
231    case 2:
232	return TRUE;
233	/* NOT REACHED */
234    default:
235	return FALSE;
236    }
237}
238
239int
240dump_variables(dialogMenuItem *unused)
241{
242    FILE *fp;
243    Variable *vp;
244
245    if (isDebug())
246	msgDebug("Writing %s variables to file..\n", ProgName);
247
248    fp = fopen("/etc/sysinstall.vars", "w");
249    if (!fp) {
250	msgConfirm("Unable to write to /etc/sysinstall.vars: %s",
251		   strerror(errno));
252	return DITEM_FAILURE;
253    }
254
255    for (vp = VarHead; vp; vp = vp->next)
256	fprintf(fp, "%s=\"%s\" (%d)\n", vp->name, vp->value, vp->dirty);
257
258    fclose(fp);
259
260    return DITEM_SUCCESS;
261}
262
263/* Free all of the variables, useful to really start over as when the
264   user selects "restart" from the interrupt menu. */
265void
266free_variables(void)
267{
268    Variable *vp;
269
270    /* Free the variables from our list, if we have one.. */
271    if (!VarHead)
272	return;
273    else if (!VarHead->next) {
274	unsetenv(VarHead->name);
275	safe_free(VarHead->name);
276	safe_free(VarHead->value);
277	free(VarHead);
278	VarHead = NULL;
279    }
280    else {
281	for (vp = VarHead; vp; ) {
282	    Variable *save = vp;
283	    unsetenv(vp->name);
284	    safe_free(vp->name);
285	    safe_free(vp->value);
286	    vp = vp->next;
287	    safe_free(save);
288	}
289	VarHead = NULL;
290    }
291}
292
293/*
294 * Persistent variables.  The variables modified by these functions
295 * are not cleared between invocations of sysinstall.  This is useful
296 * to allow the user to completely restart sysinstall, without having
297 * it load all of the modules again from the installation media which
298 * are still in memory.
299 */
300
301void
302pvariable_set(char *var)
303{
304    char *p;
305    char tmp[1024];
306
307    if (!var)
308	msgFatal("NULL variable name & value passed.");
309    else if (!*var)
310	msgDebug("Warning:  Zero length name & value passed to variable_set()\n");
311    /* Add a trivial namespace to whatever name the caller chooses. */
312    SAFE_STRCPY(tmp, "SYSINSTALL_PVAR");
313    if (index(var, '=') == NULL)
314	msgFatal("Invalid variable format: %s", var);
315    strlcat(tmp, var, 1024);
316    p = strchr(tmp, '=');
317    *p = '\0';
318    setenv(tmp, p + 1, 1);
319}
320
321char *
322pvariable_get(char *var)
323{
324    char tmp[1024];
325
326    SAFE_STRCPY(tmp, "SYSINSTALL_PVAR");
327    strlcat(tmp, var, 1024);
328    return getenv(tmp);
329}
330