121c1c48aSSascha Wildner /*
221c1c48aSSascha Wildner  * Copyright (c)2004 The DragonFly Project.  All rights reserved.
321c1c48aSSascha Wildner  *
421c1c48aSSascha Wildner  * Redistribution and use in source and binary forms, with or without
521c1c48aSSascha Wildner  * modification, are permitted provided that the following conditions
621c1c48aSSascha Wildner  * are met:
721c1c48aSSascha Wildner  *
821c1c48aSSascha Wildner  *   Redistributions of source code must retain the above copyright
921c1c48aSSascha Wildner  *   notice, this list of conditions and the following disclaimer.
1021c1c48aSSascha Wildner  *
1121c1c48aSSascha Wildner  *   Redistributions in binary form must reproduce the above copyright
1221c1c48aSSascha Wildner  *   notice, this list of conditions and the following disclaimer in
1321c1c48aSSascha Wildner  *   the documentation and/or other materials provided with the
1421c1c48aSSascha Wildner  *   distribution.
1521c1c48aSSascha Wildner  *
1621c1c48aSSascha Wildner  *   Neither the name of the DragonFly Project nor the names of its
1721c1c48aSSascha Wildner  *   contributors may be used to endorse or promote products derived
1821c1c48aSSascha Wildner  *   from this software without specific prior written permission.
1921c1c48aSSascha Wildner  *
2021c1c48aSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2121c1c48aSSascha Wildner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2221c1c48aSSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2321c1c48aSSascha Wildner  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2421c1c48aSSascha Wildner  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2521c1c48aSSascha Wildner  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2621c1c48aSSascha Wildner  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2721c1c48aSSascha Wildner  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2821c1c48aSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2921c1c48aSSascha Wildner  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3021c1c48aSSascha Wildner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
3121c1c48aSSascha Wildner  * OF THE POSSIBILITY OF SUCH DAMAGE.
3221c1c48aSSascha Wildner  */
3321c1c48aSSascha Wildner 
3421c1c48aSSascha Wildner /*
3521c1c48aSSascha Wildner  * functions.c
3621c1c48aSSascha Wildner  * Generic functions for installer.
3721c1c48aSSascha Wildner  * $Id: functions.c,v 1.22 2005/02/06 21:05:18 cpressey Exp $
3821c1c48aSSascha Wildner  */
3921c1c48aSSascha Wildner 
4021c1c48aSSascha Wildner #include <ctype.h>
4121c1c48aSSascha Wildner #include <stdio.h>
4221c1c48aSSascha Wildner #include <stdarg.h>
4321c1c48aSSascha Wildner #include <stdlib.h>
4421c1c48aSSascha Wildner #include <string.h>
4521c1c48aSSascha Wildner #include <unistd.h>
461f2824e8SSascha Wildner #include <libutil.h>
4721c1c48aSSascha Wildner 
4821c1c48aSSascha Wildner #include "libaura/mem.h"
4921c1c48aSSascha Wildner #include "libaura/dict.h"
5021c1c48aSSascha Wildner 
5121c1c48aSSascha Wildner #include "libdfui/dfui.h"
5221c1c48aSSascha Wildner 
5321c1c48aSSascha Wildner #include "functions.h"
5421c1c48aSSascha Wildner #include "diskutil.h"
5521c1c48aSSascha Wildner #include "uiutil.h"
5621c1c48aSSascha Wildner 
5721c1c48aSSascha Wildner /*** INSTALLER CONTEXT CONSTRUCTOR ***/
5821c1c48aSSascha Wildner 
5921c1c48aSSascha Wildner 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*4d4ae2faSAntonio Huete Jimenez i_fn_args_new(const char *os_root, const char *def_tmp_dir,
61*4d4ae2faSAntonio Huete Jimenez 	      const char *def_cmds_file, int transport, const char *rendezvous)
6221c1c48aSSascha Wildner {
6321c1c48aSSascha Wildner 	struct i_fn_args *a;
6421c1c48aSSascha Wildner 	char *filename;
6521c1c48aSSascha Wildner 
6621c1c48aSSascha Wildner 	AURA_MALLOC(a, i_fn_args);
6721c1c48aSSascha Wildner 
6821c1c48aSSascha Wildner 	a->c = NULL;
6921c1c48aSSascha Wildner 	a->os_root = aura_strdup(os_root);
7021c1c48aSSascha Wildner 	a->cfg_root = "";
7121c1c48aSSascha Wildner 	a->name = "";
7221c1c48aSSascha Wildner 	a->short_desc = "";
7321c1c48aSSascha Wildner 	a->long_desc = "";
7421c1c48aSSascha Wildner 	a->result = 0;
7521c1c48aSSascha Wildner 	a->log = NULL;
7621c1c48aSSascha Wildner 	a->s = NULL;
7721c1c48aSSascha Wildner 	a->tmp = NULL;
7821c1c48aSSascha Wildner 	a->temp_files = NULL;
7921c1c48aSSascha Wildner 	a->cmd_names = NULL;
8021c1c48aSSascha Wildner 
8121c1c48aSSascha Wildner 	asprintf(&filename, "%sinstall.log", def_tmp_dir);
8221c1c48aSSascha Wildner 	a->log = fopen(filename, "w");
8321c1c48aSSascha Wildner 	free(filename);
8421c1c48aSSascha Wildner 	if (a->log == NULL) {
8521c1c48aSSascha Wildner 		i_fn_args_free(a);
8621c1c48aSSascha Wildner 		return(NULL);
8721c1c48aSSascha Wildner 	}
8821c1c48aSSascha Wildner 
8921c1c48aSSascha Wildner 	i_log(a, "Installer started");
9021c1c48aSSascha Wildner 	i_log(a, "-----------------");
9121c1c48aSSascha Wildner 
9221c1c48aSSascha Wildner 	i_log(a, "+ Creating DFUI connection on ``%s''\n", rendezvous);
9321c1c48aSSascha Wildner 
9421c1c48aSSascha Wildner 	if ((a->c = dfui_connection_new(transport, rendezvous)) == NULL) {
9521c1c48aSSascha Wildner 		i_log(a, "! ERROR: Couldn't create connection on ``%s''\n", rendezvous);
9621c1c48aSSascha Wildner 		i_fn_args_free(a);
9721c1c48aSSascha Wildner 		return(NULL);
9821c1c48aSSascha Wildner 	}
9921c1c48aSSascha Wildner 
10021c1c48aSSascha Wildner 	i_log(a, "+ Connecting on ``%s''\n", rendezvous);
10121c1c48aSSascha Wildner 
10221c1c48aSSascha Wildner 	if (!dfui_be_start(a->c)) {
10321c1c48aSSascha Wildner 		i_log(a, "! ERROR: Couldn't connect to frontend on ``%s''\n", rendezvous);
10421c1c48aSSascha Wildner 		i_fn_args_free(a);
10521c1c48aSSascha Wildner 		return(NULL);
10621c1c48aSSascha Wildner 	}
10721c1c48aSSascha Wildner 
10821c1c48aSSascha Wildner 	if ((a->s = storage_new()) == NULL) {
10921c1c48aSSascha Wildner 		i_log(a, "! ERROR: Couldn't create storage descriptor");
11021c1c48aSSascha Wildner 		i_fn_args_free(a);
11121c1c48aSSascha Wildner 		return(NULL);
11221c1c48aSSascha Wildner 	}
11321c1c48aSSascha Wildner 
11421c1c48aSSascha Wildner 	a->tmp = def_tmp_dir;	/* XXX temporarily set to this */
11521c1c48aSSascha Wildner 	a->temp_files = aura_dict_new(23, AURA_DICT_HASH);
11621c1c48aSSascha Wildner 	a->cmd_names = config_vars_new();
117*4d4ae2faSAntonio Huete Jimenez 	if (!config_vars_read(a, a->cmd_names, CONFIG_TYPE_SH, "%s",
118*4d4ae2faSAntonio Huete Jimenez 		def_cmds_file)) {
11921c1c48aSSascha Wildner 		i_log(a, "! ERROR: Couldn't read cmdnames config file");
12021c1c48aSSascha Wildner 		i_fn_args_free(a);
12121c1c48aSSascha Wildner 		return(NULL);
12221c1c48aSSascha Wildner 	}
12321c1c48aSSascha Wildner 
12421c1c48aSSascha Wildner 	a->tmp = cmd_name(a, "INSTALLER_TEMP");
12521c1c48aSSascha Wildner 
12621c1c48aSSascha Wildner 	i_log(a, "+ Starting installer state machine");
12721c1c48aSSascha Wildner 
12821c1c48aSSascha Wildner 	return(a);
12921c1c48aSSascha Wildner }
13021c1c48aSSascha Wildner 
13121c1c48aSSascha Wildner void
i_fn_args_free(struct i_fn_args * a)13221c1c48aSSascha Wildner i_fn_args_free(struct i_fn_args *a)
13321c1c48aSSascha Wildner {
13421c1c48aSSascha Wildner 	if (a != NULL) {
13521c1c48aSSascha Wildner 		if (a->temp_files != NULL) {
13621c1c48aSSascha Wildner 			temp_files_clean(a);
13721c1c48aSSascha Wildner 			aura_dict_free(a->temp_files);
13821c1c48aSSascha Wildner 		}
13921c1c48aSSascha Wildner 		if (a->cmd_names != NULL) {
14021c1c48aSSascha Wildner 			config_vars_free(a->cmd_names);
14121c1c48aSSascha Wildner 		}
14221c1c48aSSascha Wildner 		if (a->s != NULL) {
14321c1c48aSSascha Wildner 			storage_free(a->s);
14421c1c48aSSascha Wildner 		}
14521c1c48aSSascha Wildner 		if (a->c != NULL) {
14621c1c48aSSascha Wildner 			dfui_be_stop(a->c);
14721c1c48aSSascha Wildner 		}
14821c1c48aSSascha Wildner 		if (a->log != NULL) {
14921c1c48aSSascha Wildner 			fclose(a->log);
15021c1c48aSSascha Wildner 		}
15121c1c48aSSascha Wildner 		AURA_FREE(a, i_fn_args);
15221c1c48aSSascha Wildner 	}
15321c1c48aSSascha Wildner }
15421c1c48aSSascha Wildner 
15521c1c48aSSascha Wildner /*** INSTALLER CONTEXT FUNCTIONS ***/
15621c1c48aSSascha Wildner 
15721c1c48aSSascha Wildner void
i_log(struct i_fn_args * a,const char * fmt,...)15821c1c48aSSascha Wildner i_log(struct i_fn_args *a, const char *fmt, ...)
15921c1c48aSSascha Wildner {
16021c1c48aSSascha Wildner 	va_list args;
16121c1c48aSSascha Wildner 
16221c1c48aSSascha Wildner 	va_start(args, fmt);
16321c1c48aSSascha Wildner 	vfprintf(stderr, fmt, args);
16421c1c48aSSascha Wildner 	fprintf(stderr, "\n");
165c9ae658bSAntonio Huete 	va_end(args);
16621c1c48aSSascha Wildner 	if (a->log != NULL) {
167c9ae658bSAntonio Huete 		va_start(args, fmt);
16821c1c48aSSascha Wildner 		vfprintf(a->log, fmt, args);
16921c1c48aSSascha Wildner 		fprintf(a->log, "\n");
17021c1c48aSSascha Wildner 		fflush(a->log);
171c9ae658bSAntonio Huete 		va_end(args);
17221c1c48aSSascha Wildner 	}
17321c1c48aSSascha Wildner 	va_end(args);
17421c1c48aSSascha Wildner }
17521c1c48aSSascha Wildner 
17621c1c48aSSascha Wildner /*** UTILITY ***/
17721c1c48aSSascha Wildner 
17821c1c48aSSascha Wildner void
abort_backend(void)17921c1c48aSSascha Wildner abort_backend(void)
18021c1c48aSSascha Wildner {
18121c1c48aSSascha Wildner 	exit(1);
18221c1c48aSSascha Wildner }
18321c1c48aSSascha Wildner 
18421c1c48aSSascha Wildner int
assert_clean(struct dfui_connection * c,const char * name,const char * field,const char * not_allowed)18521c1c48aSSascha Wildner assert_clean(struct dfui_connection *c, const char *name, const char *field,
18621c1c48aSSascha Wildner 	     const char *not_allowed)
18721c1c48aSSascha Wildner {
18821c1c48aSSascha Wildner 	if (strpbrk(field, not_allowed) != NULL) {
18921c1c48aSSascha Wildner 		inform(c, "The %s field may not contain any of the "
19021c1c48aSSascha Wildner 		    "following characters:\n\n%s",
19121c1c48aSSascha Wildner 		    name, not_allowed);
19221c1c48aSSascha Wildner 		return(0);
19321c1c48aSSascha Wildner 	} else {
19421c1c48aSSascha Wildner 		return(1);
19521c1c48aSSascha Wildner 	}
19621c1c48aSSascha Wildner }
19721c1c48aSSascha Wildner 
19821c1c48aSSascha Wildner /*
19921c1c48aSSascha Wildner  * Expects a leading 0x.
20021c1c48aSSascha Wildner  */
20121c1c48aSSascha Wildner int
hex_to_int(const char * hex,int * result)20221c1c48aSSascha Wildner hex_to_int(const char *hex, int *result)
20321c1c48aSSascha Wildner {
20421c1c48aSSascha Wildner 	int i, a = 0;
20521c1c48aSSascha Wildner 	char d;
20621c1c48aSSascha Wildner 
20721c1c48aSSascha Wildner 	if (strncmp(hex, "0x", 2) != 0)
20821c1c48aSSascha Wildner 		return(0);
20921c1c48aSSascha Wildner 
21021c1c48aSSascha Wildner 	for (i = 2; hex[i] != '\0'; i++) {
21121c1c48aSSascha Wildner 		d = toupper(hex[i]);
21221c1c48aSSascha Wildner 		if (isspace(d))
21321c1c48aSSascha Wildner 			continue;
21421c1c48aSSascha Wildner 		if (isdigit(d))
21521c1c48aSSascha Wildner 			a = a * 16 + (d - '0');
21621c1c48aSSascha Wildner 		else if (d >= 'A' && d <= 'F')
21721c1c48aSSascha Wildner 			a = a * 16 + (d + 10 - 'A');
21821c1c48aSSascha Wildner 		else
21921c1c48aSSascha Wildner 			return(0);
22021c1c48aSSascha Wildner 	}
22121c1c48aSSascha Wildner 
22221c1c48aSSascha Wildner 	*result = a;
22321c1c48aSSascha Wildner 	return(1);
22421c1c48aSSascha Wildner }
22521c1c48aSSascha Wildner 
22621c1c48aSSascha Wildner int
first_non_space_char_is(const char * line,char x)22721c1c48aSSascha Wildner first_non_space_char_is(const char *line, char x)
22821c1c48aSSascha Wildner {
22921c1c48aSSascha Wildner 	int i;
23021c1c48aSSascha Wildner 
23121c1c48aSSascha Wildner 	for (i = 0; line[i] != '\0'; i++) {
23221c1c48aSSascha Wildner 		if (isspace(line[i]))
23321c1c48aSSascha Wildner 			continue;
23421c1c48aSSascha Wildner 		if (line[i] == x)
23521c1c48aSSascha Wildner 			return(1);
23621c1c48aSSascha Wildner 		return(0);
23721c1c48aSSascha Wildner 	}
23821c1c48aSSascha Wildner 
23921c1c48aSSascha Wildner 	return(0);
24021c1c48aSSascha Wildner }
24121c1c48aSSascha Wildner 
24221c1c48aSSascha Wildner const char *
capacity_to_string(long capacity)24321c1c48aSSascha Wildner capacity_to_string(long capacity)
24421c1c48aSSascha Wildner {
2451f2824e8SSascha Wildner 	static char string[6];
24621c1c48aSSascha Wildner 
24721c1c48aSSascha Wildner 	if (capacity < 0)
24821c1c48aSSascha Wildner 		strlcpy(string, "*", 2);
24921c1c48aSSascha Wildner 	else
2504abb0328SSascha Wildner 		humanize_number(string, sizeof(string),
251f6f9a1e8SSascha Wildner 		    (int64_t)capacity * 1024 * 1024, "",
2521f2824e8SSascha Wildner 		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
25321c1c48aSSascha Wildner 
25421c1c48aSSascha Wildner 	return(string);
25521c1c48aSSascha Wildner }
25621c1c48aSSascha Wildner 
25721c1c48aSSascha Wildner int
string_to_capacity(const char * string,long * capacity)25821c1c48aSSascha Wildner string_to_capacity(const char *string, long *capacity)
25921c1c48aSSascha Wildner {
2601f2824e8SSascha Wildner 	int error;
2611f2824e8SSascha Wildner 	int64_t result;
26221c1c48aSSascha Wildner 
26321c1c48aSSascha Wildner 	if (!strcmp(string, "*")) {
26421c1c48aSSascha Wildner 		*capacity = -1;
26521c1c48aSSascha Wildner 		return(1);
26621c1c48aSSascha Wildner 	}
2671f2824e8SSascha Wildner 	error = dehumanize_number(string, &result);
2681f2824e8SSascha Wildner 	if (error != 0)
2691f2824e8SSascha Wildner 		return(0);
2704abb0328SSascha Wildner 	result /= 1024 * 1024;
2711f2824e8SSascha Wildner 	if (result == 0)
2721f2824e8SSascha Wildner 		return(0);
2731f2824e8SSascha Wildner 	*capacity = result;
2741f2824e8SSascha Wildner 	return(1);
27521c1c48aSSascha Wildner }
27621c1c48aSSascha Wildner 
27721c1c48aSSascha Wildner /*
27821c1c48aSSascha Wildner  * Round a number up to the nearest power of two.
27921c1c48aSSascha Wildner  */
28021c1c48aSSascha Wildner unsigned long
next_power_of_two(unsigned long n)28121c1c48aSSascha Wildner next_power_of_two(unsigned long n)
28221c1c48aSSascha Wildner {
28321c1c48aSSascha Wildner 	unsigned long p, op;
28421c1c48aSSascha Wildner 
28521c1c48aSSascha Wildner 	p = 1;
28621c1c48aSSascha Wildner 	op = 0;
28721c1c48aSSascha Wildner 	while (p < n && p > op) {
28821c1c48aSSascha Wildner 		op = p;
28921c1c48aSSascha Wildner 		p <<= 1;
29021c1c48aSSascha Wildner 	}
29121c1c48aSSascha Wildner 
29221c1c48aSSascha Wildner 	return(p > op ? p : n);
29321c1c48aSSascha Wildner }
29421c1c48aSSascha Wildner 
29521c1c48aSSascha Wildner /*
29621c1c48aSSascha Wildner  * Returns file name without extension.
29721c1c48aSSascha Wildner  * e.g.
29821c1c48aSSascha Wildner  *	ru.koi8-r.kbd -> ru.koi8-r
29921c1c48aSSascha Wildner  *	README -> README
30021c1c48aSSascha Wildner  *
30121c1c48aSSascha Wildner  * Caller is responsible for freeing the string returned.
30221c1c48aSSascha Wildner  */
30321c1c48aSSascha Wildner char *
filename_noext(const char * filename)30421c1c48aSSascha Wildner filename_noext(const char *filename)
30521c1c48aSSascha Wildner {
30621c1c48aSSascha Wildner 	int i;
30721c1c48aSSascha Wildner 	char *buffer, *p;
30821c1c48aSSascha Wildner 
30921c1c48aSSascha Wildner 	buffer = aura_strdup(filename);
31021c1c48aSSascha Wildner 
31121c1c48aSSascha Wildner 	if (strlen(filename) == 0) {
31221c1c48aSSascha Wildner 		buffer[0] = '\0';
31321c1c48aSSascha Wildner 		return(buffer);
31421c1c48aSSascha Wildner 	}
31521c1c48aSSascha Wildner 
31621c1c48aSSascha Wildner 	p = strrchr(filename, '.');
31721c1c48aSSascha Wildner 
31821c1c48aSSascha Wildner 	if (p != NULL) {
31921c1c48aSSascha Wildner 		i = strlen(filename) - strlen(p);
32021c1c48aSSascha Wildner 		buffer[i] = 0;
32121c1c48aSSascha Wildner 	}
32221c1c48aSSascha Wildner 
32321c1c48aSSascha Wildner 	return(buffer);
32421c1c48aSSascha Wildner }
32521c1c48aSSascha Wildner 
32621c1c48aSSascha Wildner /*
32721c1c48aSSascha Wildner  * Temp files
32821c1c48aSSascha Wildner  */
32921c1c48aSSascha Wildner 
33021c1c48aSSascha Wildner int
temp_file_add(struct i_fn_args * a,const char * filename)33121c1c48aSSascha Wildner temp_file_add(struct i_fn_args *a, const char *filename)
33221c1c48aSSascha Wildner {
33321c1c48aSSascha Wildner 	aura_dict_store(a->temp_files, filename, strlen(filename) + 1, "", 1);
33421c1c48aSSascha Wildner 	return(1);
33521c1c48aSSascha Wildner }
33621c1c48aSSascha Wildner 
33721c1c48aSSascha Wildner int
temp_files_clean(struct i_fn_args * a)33821c1c48aSSascha Wildner temp_files_clean(struct i_fn_args *a)
33921c1c48aSSascha Wildner {
34021c1c48aSSascha Wildner 	void *rk;
34121c1c48aSSascha Wildner 	size_t rk_len;
34221c1c48aSSascha Wildner 	char *filename;
34321c1c48aSSascha Wildner 
34421c1c48aSSascha Wildner 	aura_dict_rewind(a->temp_files);
34521c1c48aSSascha Wildner 	while (!aura_dict_eof(a->temp_files)) {
34621c1c48aSSascha Wildner 		aura_dict_get_current_key(a->temp_files, &rk, &rk_len);
34721c1c48aSSascha Wildner 		asprintf(&filename, "%s%s", a->tmp, (char *)rk);
34821c1c48aSSascha Wildner 		(void)unlink(filename);	/* not much we can do if it fails */
34921c1c48aSSascha Wildner 		free(filename);
35021c1c48aSSascha Wildner 		aura_dict_next(a->temp_files);
35121c1c48aSSascha Wildner 	}
35221c1c48aSSascha Wildner 	return(1);
35321c1c48aSSascha Wildner }
35421c1c48aSSascha Wildner 
35521c1c48aSSascha Wildner /*
35621c1c48aSSascha Wildner  * Command names
35721c1c48aSSascha Wildner  */
35821c1c48aSSascha Wildner const char *
cmd_name(const struct i_fn_args * a,const char * cmd_key)35921c1c48aSSascha Wildner cmd_name(const struct i_fn_args *a, const char *cmd_key)
36021c1c48aSSascha Wildner {
36121c1c48aSSascha Wildner 	const char *name;
36221c1c48aSSascha Wildner 
36321c1c48aSSascha Wildner 	name = config_var_get(a->cmd_names, cmd_key);
36421c1c48aSSascha Wildner 	if (strcmp(name, "") == 0)
36521c1c48aSSascha Wildner 		return("bin/echo");	/* XXX usr/local/sbin/error? */
36621c1c48aSSascha Wildner 	else
36721c1c48aSSascha Wildner 		return(name);
36821c1c48aSSascha Wildner }
369