[BusyBox] fixes for dpkg in stable busybox

Ian Campbell icampbell at arcom.com
Thu Jun 12 10:44:57 UTC 2003


Hi all,

Attached is a patch against the stable version of busybox which makes
dpkg work for me rather than segfaulting lots.

Many memory allocation problems and leaks were found by dmalloc, I've
also cleaned up some cases where the code was allocating sizeof(string)
rather than strlen(string) for copying (causing all hell to break
loose). It also fixes the execution of maintainer scripts (by not
freeing the script name before it runs it). Finally it adds an option to
the archiving code ('extract_list_absolute') that causes it to strip the
leading "." from a filename which starts "./", dpkg then uses this
option to cause files to be installed in their correct location rather
than beneath the current directory.

When I started this work several months ago the stable and unstable
versions of dpkg.c were (almost) identical, but they seem to have
diverged a fair bit since then (judging from this monrings snapshot).
Still, perhaps this patch will be useful to someone.

Cheers,
Ian.

PS http://www.busybox.net/mailman/listinfo/busybox/ gives an access
forbidden error. But the link from the archives page to
http://busybox.net/mailman/listinfo/busybox works fine.


-- 
Ian Campbell
Design Engineer

Arcom                                   Direct: +44 (0)1223 403 465
Clifton Road                            Phone:  +44 (0)1223 411 200
Cambridge CB1 7EA                       E-Mail: icampbell at arcom.com
United Kingdom                          Web:    http://www.arcom.com



________________________________________________________________________
This email has been scanned for all viruses by the MessageLabs Email
Security System. For more information on a proactive email security
service working around the clock, around the globe, visit
http://www.messagelabs.com
________________________________________________________________________
-------------- next part --------------
--- busybox-0.60.5.orig/dpkg.c
+++ busybox-0.60.5/dpkg.c
@@ -987,6 +987,11 @@
 			const unsigned int package_num = search_package_hashtable(package_edge->name,
 				package_edge->version, package_edge->operator);
 
+			if ( package_hashtable[package_num] == NULL )
+				error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed",
+						  name_hashtable[package_node->name],
+						  name_hashtable[package_edge->name]);
+
 			status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]);
 			state_status = get_status(status_num, 3);
 			state_want = get_status(status_num, 1);
@@ -995,7 +1000,7 @@
 				case(EDGE_OR_PRE_DEPENDS):
 					/* It must be already installed */
 					/* NOTE: This is untested, nothing apropriate in my status file */
-					if ((package_hashtable[package_num] == NULL) || (state_status != search_name_hashtable("installed"))) {
+					if (state_status != search_name_hashtable("installed")) {
 						error_msg_and_die("Package %s pre-depends on %s, but it is not installed",
 							name_hashtable[package_node->name],
 							name_hashtable[package_edge->name]);
@@ -1004,9 +1009,8 @@
 				case(EDGE_DEPENDS):
 				case(EDGE_OR_DEPENDS):
 					/* It must be already installed, or to be installed */
-					if ((package_hashtable[package_num] == NULL) ||
-						((state_status != search_name_hashtable("installed")) &&
-						(state_want != search_name_hashtable("want_install")))) {
+					if ((state_status != search_name_hashtable("installed")) &&
+						(state_want != search_name_hashtable("want_install"))) {
 						error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed",
 							name_hashtable[package_node->name],
 							name_hashtable[package_edge->name]);
@@ -1056,6 +1060,18 @@
 	}
 }
 
+void free_list(char **list)
+{
+	int count;
+	if (list == NULL)
+		return;
+
+	for(count = 0; list[count]; count++) {
+		free(list[count]);
+	}
+	free(list);
+}
+
 /* maybe i should try and hook this into remove_file.c somehow */
 int remove_file_array(char **remove_names, char **exclude_names)
 {
@@ -1069,7 +1085,7 @@
 	}
 	for (i = 0; remove_names[i] != NULL; i++) {
 		match_flag = FALSE;
-		if (exclude_names != NULL) {
+		if (exclude_names != NULL && exclude_names[0] != 0) {
 			for (j = 0; exclude_names[j] != 0; j++) {
 				if (strcmp(remove_names[i], exclude_names[j]) == 0) {
 					match_flag = TRUE;
@@ -1099,18 +1115,17 @@
 {
 	struct stat path_stat;
 	char *script_path;
+	int retval = EXIT_SUCCESS;
 
 	script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21);
 	sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type);
 
 	/* If the file doesnt exist is isnt a fatal */
-	if (lstat(script_path, &path_stat) < 0) {
-		free(script_path);
-		return(EXIT_SUCCESS);
-	} else {
-		free(script_path);
-		return(system(script_path));
+	if (lstat(script_path, &path_stat) >= 0) {
+		retval = system(script_path);
 	}
+	free(script_path);
+	return(EXIT_SUCCESS);
 }
 
 void all_control_list(char **remove_files, const char *package_name)
@@ -1156,8 +1171,11 @@
 	/* Some directories cant be removed straight away, so do multiple passes */
 	while (remove_file_array(remove_files, exclude_files) == TRUE);
 
+	free_list(remove_files);
+	free_list(exclude_files);
+
 	/* Create a list of all /var/lib/dpkg/info/<package> files */
-	remove_files = xmalloc(11);
+	remove_files = xcalloc(sizeof(remove_files[0]), 11);
 	all_control_list(remove_files, package_name);
 
 	/* Create a list of files in /var/lib/dpkg/info/<package>.* to keep  */
@@ -1175,6 +1193,10 @@
 	/* Change package status */
 	set_status(status_num, "deinstall", 1);
 	set_status(status_num, "config-files", 3);
+
+	/* Free lists */
+	free_list(remove_files);
+	free_list(exclude_files);
 }
 
 void purge_package(const unsigned int package_num)
@@ -1194,14 +1216,16 @@
 	sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
 	remove_files = create_list(list_name);
 
-	exclude_files = xmalloc(1);
+	exclude_files = xcalloc(sizeof(exclude_files[0]), 1);
 	exclude_files[0] = NULL;
 
 	/* Some directories cant be removed straight away, so do multiple passes */
 	while (remove_file_array(remove_files, exclude_files) == TRUE);
 
+	free_list(remove_files);
+
 	/* Create a list of all /var/lib/dpkg/info/<package> files */
-	remove_files = xmalloc(11);
+	remove_files = xcalloc(sizeof(remove_files[0]), 11);
 	all_control_list(remove_files, package_name);
 	remove_file_array(remove_files, exclude_files);
 
@@ -1213,6 +1237,10 @@
 	/* Change package status */
 	set_status(status_num, "purge", 1);
 	set_status(status_num, "not-installed", 3);
+
+	/* Free list */
+	free_list(remove_files);
+	free(exclude_files);
 }
 
 void unpack_package(deb_file_t *deb_file)
@@ -1236,7 +1264,7 @@
 	}
 
 	/* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */
-	info_prefix = (char *) xmalloc(sizeof(package_name) + 20 + 4 + 1);
+	info_prefix = (char *) xmalloc(strlen(package_name) + 20 + 4 + 1);
 	sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name);
 	deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs), info_prefix, NULL);
 
@@ -1246,7 +1274,8 @@
 	/* Create the list file */
 	strcat(info_prefix, "list");
 	out_stream = xfopen(info_prefix, "w");			
-	deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), NULL, NULL);
+	deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list | extract_list_absolute ), 
+		    NULL, NULL);
 	fclose(out_stream);
 
 	/* change status */
--- busybox-0.60.5.orig/libbb/libbb.h
+++ busybox-0.60.5/libbb/libbb.h
@@ -239,7 +239,8 @@
 	extract_unconditional = 512,
 	extract_create_leading_dirs = 1024,
 	extract_quiet = 2048,
-	extract_exclude_list = 4096
+	extract_exclude_list = 4096,
+	extract_list_absolute = 8192
 };
 char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_header)(FILE *),
 	const int extract_function, const char *prefix, char **extract_names);
--- busybox-0.60.5.orig/libbb/unarchive.c
+++ busybox-0.60.5/libbb/unarchive.c
@@ -218,7 +218,14 @@
 	}
 	if ((function & extract_list) || (function & extract_verbose_list)){
 		/* fputs doesnt add a trailing \n, so use fprintf */
-		fprintf(out_stream, "%s\n", file_entry->name);
+		/* If we want absolute paths then strip any leading ./ */
+		if ( function & extract_list_absolute && 
+		     file_entry->name[0] == '.' && 
+		     file_entry->name[1] == '/') {
+			fprintf(out_stream, "%s\n", &file_entry->name[1]);
+		} else {
+			fprintf(out_stream, "%s\n", file_entry->name);
+		}
 	}
 
 	free(full_name);
@@ -266,8 +273,14 @@
 			/* seek past the data entry */
 			seek_sub_file(src_stream, file_entry->size);
 		}
-		free(file_entry->name); /* may be null, but doesn't matter */
-		free(file_entry->link_name);
+		/*
+		 * These should work, but cause a segfault later on. Weird.
+		 * michael 5 sept 2002
+		 */
+		/* dmalloc flags this as a double free */
+		//free(file_entry->name); /* may be null, but doesn't matter */
+		if ( file_entry->link_name )
+			free(file_entry->link_name);
 		free(file_entry);
 	}
 	return(buffer);
@@ -315,7 +328,7 @@
 		/* raw_header[60] wont be '\n' as it should, but it doesnt matter */
 		memmove(ar.raw, &ar.raw[1], 59);
 	}
-		
+	
 	typed = (file_header_t *) xcalloc(1, sizeof(file_header_t));
 
 	typed->size = (size_t) atoi(ar.formated.size);
--- busybox-0.60.5.orig/libbb/unzip.c
+++ busybox-0.60.5/libbb/unzip.c
@@ -1076,6 +1076,8 @@
 	if (waitpid(gunzip_pid, NULL, 0) == -1) {
 		printf("Couldnt wait ?");
 	}
+	if (window)
 		free(window);
+	if (crc_table)
 		free(crc_table);
 }


More information about the busybox mailing list