[git commit master] dpkg: support config file overwrite options

Denys Vlasenko vda.linux at googlemail.com
Mon Mar 29 12:18:27 UTC 2010


commit: http://git.busybox.net/busybox/commit/?id=3d43aed10c94bfcfc4a85b9b66bc60c18d22c2b1
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
filter_rename_config                                   -     244    +244
static.dpkg_longopts                                   -     112    +112
dpkg_main                                           3901    3980     +79
unpack_package                                       515     587     +72
append_control_file_to_llist                           -      72     +72
data_extract_all_prefix                               88     116     +28
------------------------------------------------------------------------------
(add/remove: 3/0 grow/shrink: 3/0 up/down: 607/0)             Total: 607 bytes

Signed-off-by: Kim B. Heino <Kim.Heino at bluegiga.com>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 archival/dpkg.c |  126 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 include/usage.h |   17 +++++++-
 2 files changed, 127 insertions(+), 16 deletions(-)

diff --git a/archival/dpkg.c b/archival/dpkg.c
index 7187ad6..befb91d 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -1308,7 +1308,7 @@ static void list_packages(const char *pattern)
 			name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name];
 			vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version];
 
-			if (pattern && fnmatch(pattern, name_str, 0))
+			if (pattern && fnmatch(pattern, name_str, 0) != 0)
 				continue;
 
 			/* get abbreviation for status field 1 */
@@ -1491,6 +1491,58 @@ static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, lli
 	return ar_handle->dpkg__sub_archive->dpkg__buffer;
 }
 
+static void append_control_file_to_llist(const char *package_name, const char *control_name, llist_t **ll)
+{
+	FILE *fp;
+	char *filename, *line;
+
+	filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, control_name);
+	fp = fopen_for_read(filename);
+	free(filename);
+	if (fp != NULL) {
+		while ((line = xmalloc_fgetline(fp)) != NULL)
+			llist_add_to(ll, line);
+		fclose(fp);
+	}
+}
+
+static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle)
+{
+	int fd;
+	char *name_ptr = archive_handle->file_header->name + 1;
+
+	/* Is this file marked as config file? */
+	if (!find_list_entry(archive_handle->accept, name_ptr))
+		return EXIT_SUCCESS; /* no */
+
+	fd = open(name_ptr, O_RDONLY);
+	if (fd >= 0) {
+		md5_ctx_t md5;
+		char *md5line, *buf;
+		int count;
+
+		/* Calculate MD5 of existing file */
+		buf = xmalloc(4096);
+		md5_begin(&md5);
+		while ((count = safe_read(fd, buf, 4096)) > 0)
+			md5_hash(buf, count, &md5);
+		md5_end(buf, &md5); /* using buf as result storage */
+		close(fd);
+
+		md5line = xmalloc(16 * 2 + 2 + strlen(name_ptr) + 1);
+		sprintf(bin2hex(md5line, buf, 16), "  %s", name_ptr);
+		free(buf);
+
+		/* Is it changed after install? */
+		if (find_list_entry(archive_handle->accept, md5line) == NULL) {
+			printf("Warning: Creating %s as %s.dpkg-new\n", name_ptr, name_ptr);
+			archive_handle->file_header->name = xasprintf("%s.dpkg-new", archive_handle->file_header->name);
+		}
+		free(md5line);
+	}
+	return EXIT_SUCCESS;
+}
+
 static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle)
 {
 	char *name_ptr = archive_handle->file_header->name;
@@ -1500,7 +1552,7 @@ static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle)
 		name_ptr++;
 	/* Skip all leading "./" and "../" */
 	while (name_ptr[0] == '.') {
-		if (name_ptr[1] == '.' && name_ptr[2] == '/')
+		if (name_ptr[1] == '.')
 			name_ptr++;
 		if (name_ptr[1] != '/')
 			break;
@@ -1510,9 +1562,26 @@ static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle)
 	if (name_ptr[0] != '\0') {
 		archive_handle->file_header->name = xasprintf("%s%s", archive_handle->dpkg__buffer, name_ptr);
 		data_extract_all(archive_handle);
+		if (fnmatch("*.dpkg-new", archive_handle->file_header->name, 0) == 0) {
+			/* remove .dpkg-new suffix */
+			archive_handle->file_header->name[strlen(archive_handle->file_header->name) - 9] = '\0';
+		}
 	}
 }
 
+enum {
+	OPT_configure            = (1 << 0),
+	OPT_force                = (1 << 1),
+	OPT_install              = (1 << 2),
+	OPT_list_installed       = (1 << 3),
+	OPT_purge                = (1 << 4),
+	OPT_remove               = (1 << 5),
+	OPT_unpack               = (1 << 6),
+	OPT_force_ignore_depends = (1 << 7),
+	OPT_force_confnew        = (1 << 8),
+	OPT_force_confold        = (1 << 9),
+};
+
 static void unpack_package(deb_file_t *deb_file)
 {
 	const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
@@ -1523,14 +1592,21 @@ static void unpack_package(deb_file_t *deb_file)
 	archive_handle_t *archive_handle;
 	FILE *out_stream;
 	llist_t *accept_list;
+	llist_t *conffile_list;
 	int i;
 
 	/* If existing version, remove it first */
+	conffile_list = NULL;
 	if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) {
 		/* Package is already installed, remove old version first */
 		printf("Preparing to replace %s %s (using %s)...\n", package_name,
 			name_hashtable[package_hashtable[status_package_num]->version],
 			deb_file->filename);
+
+		/* Read md5sums from old package */
+		if (!(option_mask32 & OPT_force_confold))
+			append_control_file_to_llist(package_name, "md5sums", &conffile_list);
+
 		remove_package(status_package_num, 0);
 	} else {
 		printf("Unpacking %s (from %s)...\n", package_name, deb_file->filename);
@@ -1558,9 +1634,15 @@ static void unpack_package(deb_file_t *deb_file)
 	/* Run the preinst prior to extracting */
 	run_package_script_or_die(package_name, "preinst");
 
+	/* Don't overwrite existing config files */
+	if (!(option_mask32 & OPT_force_confnew))
+		append_control_file_to_llist(package_name, "conffiles", &conffile_list);
+
 	/* Extract data.tar.gz to the root directory */
 	archive_handle = init_archive_deb_ar(deb_file->filename);
 	init_archive_deb_data(archive_handle);
+	archive_handle->dpkg__sub_archive->accept = conffile_list;
+	archive_handle->dpkg__sub_archive->filter = filter_rename_config;
 	archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix;
 	archive_handle->dpkg__sub_archive->dpkg__buffer = (char*)"/"; /* huh? */
 	archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD;
@@ -1614,23 +1696,37 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv)
 	int state_status;
 	int status_num;
 	int i;
-	enum {
-		OPT_configure = 0x1,
-		OPT_force_ignore_depends = 0x2,
-		OPT_install = 0x4,
-		OPT_list_installed = 0x8,
-		OPT_purge = 0x10,
-		OPT_remove = 0x20,
-		OPT_unpack = 0x40,
-	};
+#if ENABLE_LONG_OPTS
+	static const char dpkg_longopts[] ALIGN1 =
+// FIXME: we use -C non-compatibly, should be:
+// "-C|--audit Check for broken package(s)"
+		"configure\0"      No_argument        "C"
+		"force\0"          Required_argument  "F"
+		"install\0"        No_argument        "i"
+		"list\0"           No_argument        "l"
+		"purge\0"          No_argument        "P"
+		"remove\0"         No_argument        "r"
+		"unpack\0"         No_argument        "u"
+		"force-depends\0"  No_argument        "\xff"
+		"force-confnew\0"  No_argument        "\xfe"
+		"force-confold\0"  No_argument        "\xfd"
+		;
+#endif
 
 	INIT_G();
 
+	IF_LONG_OPTS(applet_long_options = dpkg_longopts);
 	opt = getopt32(argv, "CF:ilPru", &str_f);
 	//if (opt & OPT_configure) ... // -C
-	if (opt & OPT_force_ignore_depends) { // -F (--force in official dpkg)
-		if (strcmp(str_f, "depends"))
-			opt &= ~OPT_force_ignore_depends;
+	if (opt & OPT_force) { // -F (--force in official dpkg)
+		if (strcmp(str_f, "depends") == 0)
+			opt |= OPT_force_ignore_depends;
+		else if (strcmp(str_f, "confnew") == 0)
+			opt |= OPT_force_confnew;
+		else if (strcmp(str_f, "confold") == 0)
+			opt |= OPT_force_confold;
+		else bb_show_usage();
+		option_mask32 = opt;
 	}
 	//if (opt & OPT_install) ... // -i
 	//if (opt & OPT_list_installed) ... // -l
@@ -1639,7 +1735,7 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv)
 	//if (opt & OPT_unpack) ... // -u (--unpack in official dpkg)
 	argv += optind;
 	/* check for non-option argument if expected  */
-	if (!opt || (!argv[0] && !(opt && OPT_list_installed)))
+	if (!opt || (!argv[0] && !(opt & OPT_list_installed)))
 		bb_show_usage();
 
 /*	puts("(Reading database ... xxxxx files and directories installed.)"); */
diff --git a/include/usage.h b/include/usage.h
index 8b026b4..cf576c6 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -931,13 +931,28 @@
 #define dpkg_full_usage "\n\n" \
        "Install, remove and manage Debian packages\n" \
      "\nOptions:" \
+	IF_LONG_OPTS( \
+     "\n	-i,--install	Install the package" \
+     "\n	-l,--list	List of installed packages" \
+     "\n	--configure	Configure an unpackaged package" \
+     "\n	-P,--purge	Purge all files of a package" \
+     "\n	-r,--remove	Remove all but the configuration files for a package" \
+     "\n	--unpack	Unpack a package, but don't configure it" \
+     "\n	--force-depends	Ignore dependency problems" \
+     "\n	--force-confnew	Overwrite existing config files when installing" \
+     "\n	--force-confold	Keep old config files when installing" \
+	) \
+	IF_NOT_LONG_OPTS( \
      "\n	-i		Install the package" \
      "\n	-l		List of installed packages" \
      "\n	-C		Configure an unpackaged package" \
-     "\n	-F depends	Ignore dependency problems" \
      "\n	-P		Purge all files of a package" \
      "\n	-r		Remove all but the configuration files for a package" \
      "\n	-u		Unpack a package, but don't configure it" \
+     "\n	-F depends	Ignore dependency problems" \
+     "\n	-F confnew	Overwrite existing config files when installing" \
+     "\n	-F confold	Keep old config files when installing" \
+	)
 
 #define dpkg_deb_trivial_usage \
        "[-cefxX] FILE [argument]"
-- 
1.6.3.3



More information about the busybox-cvs mailing list