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 * functions.c
36 * Generic functions for installer.
37 * $Id: functions.c,v 1.22 2005/02/06 21:05:18 cpressey Exp $
38 */
39
40 #include <ctype.h>
41 #include <stdio.h>
42 #include <stdarg.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <libutil.h>
47
48 #include "libaura/mem.h"
49 #include "libaura/dict.h"
50
51 #include "libdfui/dfui.h"
52
53 #include "functions.h"
54 #include "diskutil.h"
55 #include "uiutil.h"
56
57 /*** INSTALLER CONTEXT CONSTRUCTOR ***/
58
59 struct i_fn_args *
i_fn_args_new(const char * os_root,const char * def_tmp_dir,const char * def_cmds_file,int transport,const char * rendezvous)60 i_fn_args_new(const char *os_root, const char *def_tmp_dir,
61 const char *def_cmds_file, int transport, const char *rendezvous)
62 {
63 struct i_fn_args *a;
64 char *filename;
65
66 AURA_MALLOC(a, i_fn_args);
67
68 a->c = NULL;
69 a->os_root = aura_strdup(os_root);
70 a->cfg_root = "";
71 a->name = "";
72 a->short_desc = "";
73 a->long_desc = "";
74 a->result = 0;
75 a->log = NULL;
76 a->s = NULL;
77 a->tmp = NULL;
78 a->temp_files = NULL;
79 a->cmd_names = NULL;
80
81 asprintf(&filename, "%sinstall.log", def_tmp_dir);
82 a->log = fopen(filename, "w");
83 free(filename);
84 if (a->log == NULL) {
85 i_fn_args_free(a);
86 return(NULL);
87 }
88
89 i_log(a, "Installer started");
90 i_log(a, "-----------------");
91
92 i_log(a, "+ Creating DFUI connection on ``%s''\n", rendezvous);
93
94 if ((a->c = dfui_connection_new(transport, rendezvous)) == NULL) {
95 i_log(a, "! ERROR: Couldn't create connection on ``%s''\n", rendezvous);
96 i_fn_args_free(a);
97 return(NULL);
98 }
99
100 i_log(a, "+ Connecting on ``%s''\n", rendezvous);
101
102 if (!dfui_be_start(a->c)) {
103 i_log(a, "! ERROR: Couldn't connect to frontend on ``%s''\n", rendezvous);
104 i_fn_args_free(a);
105 return(NULL);
106 }
107
108 if ((a->s = storage_new()) == NULL) {
109 i_log(a, "! ERROR: Couldn't create storage descriptor");
110 i_fn_args_free(a);
111 return(NULL);
112 }
113
114 a->tmp = def_tmp_dir; /* XXX temporarily set to this */
115 a->temp_files = aura_dict_new(23, AURA_DICT_HASH);
116 a->cmd_names = config_vars_new();
117 if (!config_vars_read(a, a->cmd_names, CONFIG_TYPE_SH, "%s",
118 def_cmds_file)) {
119 i_log(a, "! ERROR: Couldn't read cmdnames config file");
120 i_fn_args_free(a);
121 return(NULL);
122 }
123
124 a->tmp = cmd_name(a, "INSTALLER_TEMP");
125
126 i_log(a, "+ Starting installer state machine");
127
128 return(a);
129 }
130
131 void
i_fn_args_free(struct i_fn_args * a)132 i_fn_args_free(struct i_fn_args *a)
133 {
134 if (a != NULL) {
135 if (a->temp_files != NULL) {
136 temp_files_clean(a);
137 aura_dict_free(a->temp_files);
138 }
139 if (a->cmd_names != NULL) {
140 config_vars_free(a->cmd_names);
141 }
142 if (a->s != NULL) {
143 storage_free(a->s);
144 }
145 if (a->c != NULL) {
146 dfui_be_stop(a->c);
147 }
148 if (a->log != NULL) {
149 fclose(a->log);
150 }
151 AURA_FREE(a, i_fn_args);
152 }
153 }
154
155 /*** INSTALLER CONTEXT FUNCTIONS ***/
156
157 void
i_log(struct i_fn_args * a,const char * fmt,...)158 i_log(struct i_fn_args *a, const char *fmt, ...)
159 {
160 va_list args;
161
162 va_start(args, fmt);
163 vfprintf(stderr, fmt, args);
164 fprintf(stderr, "\n");
165 va_end(args);
166 if (a->log != NULL) {
167 va_start(args, fmt);
168 vfprintf(a->log, fmt, args);
169 fprintf(a->log, "\n");
170 fflush(a->log);
171 va_end(args);
172 }
173 va_end(args);
174 }
175
176 /*** UTILITY ***/
177
178 void
abort_backend(void)179 abort_backend(void)
180 {
181 exit(1);
182 }
183
184 int
assert_clean(struct dfui_connection * c,const char * name,const char * field,const char * not_allowed)185 assert_clean(struct dfui_connection *c, const char *name, const char *field,
186 const char *not_allowed)
187 {
188 if (strpbrk(field, not_allowed) != NULL) {
189 inform(c, "The %s field may not contain any of the "
190 "following characters:\n\n%s",
191 name, not_allowed);
192 return(0);
193 } else {
194 return(1);
195 }
196 }
197
198 /*
199 * Expects a leading 0x.
200 */
201 int
hex_to_int(const char * hex,int * result)202 hex_to_int(const char *hex, int *result)
203 {
204 int i, a = 0;
205 char d;
206
207 if (strncmp(hex, "0x", 2) != 0)
208 return(0);
209
210 for (i = 2; hex[i] != '\0'; i++) {
211 d = toupper(hex[i]);
212 if (isspace(d))
213 continue;
214 if (isdigit(d))
215 a = a * 16 + (d - '0');
216 else if (d >= 'A' && d <= 'F')
217 a = a * 16 + (d + 10 - 'A');
218 else
219 return(0);
220 }
221
222 *result = a;
223 return(1);
224 }
225
226 int
first_non_space_char_is(const char * line,char x)227 first_non_space_char_is(const char *line, char x)
228 {
229 int i;
230
231 for (i = 0; line[i] != '\0'; i++) {
232 if (isspace(line[i]))
233 continue;
234 if (line[i] == x)
235 return(1);
236 return(0);
237 }
238
239 return(0);
240 }
241
242 const char *
capacity_to_string(long capacity)243 capacity_to_string(long capacity)
244 {
245 static char string[6];
246
247 if (capacity < 0)
248 strlcpy(string, "*", 2);
249 else
250 humanize_number(string, sizeof(string),
251 (int64_t)capacity * 1024 * 1024, "",
252 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
253
254 return(string);
255 }
256
257 int
string_to_capacity(const char * string,long * capacity)258 string_to_capacity(const char *string, long *capacity)
259 {
260 int error;
261 int64_t result;
262
263 if (!strcmp(string, "*")) {
264 *capacity = -1;
265 return(1);
266 }
267 error = dehumanize_number(string, &result);
268 if (error != 0)
269 return(0);
270 result /= 1024 * 1024;
271 if (result == 0)
272 return(0);
273 *capacity = result;
274 return(1);
275 }
276
277 /*
278 * Round a number up to the nearest power of two.
279 */
280 unsigned long
next_power_of_two(unsigned long n)281 next_power_of_two(unsigned long n)
282 {
283 unsigned long p, op;
284
285 p = 1;
286 op = 0;
287 while (p < n && p > op) {
288 op = p;
289 p <<= 1;
290 }
291
292 return(p > op ? p : n);
293 }
294
295 /*
296 * Returns file name without extension.
297 * e.g.
298 * ru.koi8-r.kbd -> ru.koi8-r
299 * README -> README
300 *
301 * Caller is responsible for freeing the string returned.
302 */
303 char *
filename_noext(const char * filename)304 filename_noext(const char *filename)
305 {
306 int i;
307 char *buffer, *p;
308
309 buffer = aura_strdup(filename);
310
311 if (strlen(filename) == 0) {
312 buffer[0] = '\0';
313 return(buffer);
314 }
315
316 p = strrchr(filename, '.');
317
318 if (p != NULL) {
319 i = strlen(filename) - strlen(p);
320 buffer[i] = 0;
321 }
322
323 return(buffer);
324 }
325
326 /*
327 * Temp files
328 */
329
330 int
temp_file_add(struct i_fn_args * a,const char * filename)331 temp_file_add(struct i_fn_args *a, const char *filename)
332 {
333 aura_dict_store(a->temp_files, filename, strlen(filename) + 1, "", 1);
334 return(1);
335 }
336
337 int
temp_files_clean(struct i_fn_args * a)338 temp_files_clean(struct i_fn_args *a)
339 {
340 void *rk;
341 size_t rk_len;
342 char *filename;
343
344 aura_dict_rewind(a->temp_files);
345 while (!aura_dict_eof(a->temp_files)) {
346 aura_dict_get_current_key(a->temp_files, &rk, &rk_len);
347 asprintf(&filename, "%s%s", a->tmp, (char *)rk);
348 (void)unlink(filename); /* not much we can do if it fails */
349 free(filename);
350 aura_dict_next(a->temp_files);
351 }
352 return(1);
353 }
354
355 /*
356 * Command names
357 */
358 const char *
cmd_name(const struct i_fn_args * a,const char * cmd_key)359 cmd_name(const struct i_fn_args *a, const char *cmd_key)
360 {
361 const char *name;
362
363 name = config_var_get(a->cmd_names, cmd_key);
364 if (strcmp(name, "") == 0)
365 return("bin/echo"); /* XXX usr/local/sbin/error? */
366 else
367 return(name);
368 }
369