[PATCH v4] dpkg: no config file overwrite
Kim B. Heino
Kim.Heino at bluegiga.com
Wed Mar 24 12:15:46 UTC 2010
This patch changes how dpkg handles config files. There are three modes:
1) If config file is unchanged by user then it will be overwritten. If
changed, then new config file will be created as configfile.dpkg-new.
This is how "real dpkg" handles config files. This is the default mode.
2) Parameter --force-confnew. Always overwrite config files.
3) Parameter --force-confold. Never overwrite, always create .dpkg-new.
Changes for v4:
- Long --force-confxxx options instead of non-compatible short ones.
- Add long options for --install, --list, etc.
Changes for v3:
- "Changed by user?" -check added.
- -N and -O options added.
- Not a config option anymore (because of new default mode).
Comments needed:
> In the long run, pain from having noncompatible behavior
> is worse than pain from one-time conversion for the users
> which depend on current behavior.
What should we do about -C, -F and -u if LONG_OPTS is not enabled? Real
dpkg does not have any short options for them.
BusyBox's -C conflicts with real dpkg:
-C|--audit Check for broken package(s).
Signed-off-by: Kim B. Heino <Kim.Heino at bluegiga.com>
diff -ur busybox-1.16.0/archival/dpkg.c dpkg/archival/dpkg.c
--- busybox-1.16.0/archival/dpkg.c 2010-01-25 02:59:38.000000000 +0200
+++ dpkg/archival/dpkg.c 2010-03-24 13:50:20.384479124 +0200
@@ -1489,6 +1489,56 @@
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 *fd;
+ char *filename, *line;
+
+ filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, control_name);
+ if ((fd = fopen_for_read(filename)) != NULL) {
+ while ((line = xmalloc_fgetline(fd)) != NULL)
+ llist_add_to(ll, line);
+ fclose(fd);
+ }
+ free(filename);
+}
+
+static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle)
+{
+ FILE *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) &&
+ (fd = fopen_for_read(name_ptr)) != NULL) {
+ md5_ctx_t md5;
+ char *md5line, *buf;
+ int count;
+
+ /* Calculate MD5 of existing file */
+ buf = xmalloc(4096);
+ md5_begin(&md5);
+ while ((count = fread(buf, 1, 4096, fd)) > 0)
+ md5_hash(buf, count, &md5);
+ md5_end(buf, &md5);
+ fclose(fd);
+
+ md5line = xmalloc(16 * 2 + 2 + strlen(name_ptr) + 1);
+ bin2hex(md5line, buf, 16);
+ sprintf(md5line + 16 * 2, " %s", name_ptr);
+
+ /* 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);
+ free(buf);
+ }
+ return EXIT_SUCCESS;
+}
+
static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle)
{
char *name_ptr = archive_handle->file_header->name;
@@ -1508,10 +1558,12 @@
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)
+ archive_handle->file_header->name[strlen(archive_handle->file_header->name) - 9] = 0;
}
}
-static void unpack_package(deb_file_t *deb_file)
+static void unpack_package(deb_file_t *deb_file, int force_confnew, int force_confold)
{
const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
const unsigned status_num = search_status_hashtable(package_name);
@@ -1521,14 +1573,21 @@
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 (force_confold == 0)
+ 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);
@@ -1556,9 +1615,15 @@
/* Run the preinst prior to extracting */
run_package_script_or_die(package_name, "preinst");
+ /* Don't overwrite existing config files */
+ if (force_confnew == 0)
+ 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,21 +1679,44 @@
int i;
enum {
OPT_configure = 0x1,
- OPT_force_ignore_depends = 0x2,
+ OPT_force = 0x2,
OPT_install = 0x4,
OPT_list_installed = 0x8,
OPT_purge = 0x10,
OPT_remove = 0x20,
OPT_unpack = 0x40,
+ OPT_force_ignore_depends = 0x80,
+ OPT_force_confnew = 0x100,
+ OPT_force_confold = 0x200,
};
+#if ENABLE_LONG_OPTS
+ static const char dpkg_longopts[] ALIGN1 =
+ "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();
}
//if (opt & OPT_install) ... // -i
//if (opt & OPT_list_installed) ... // -l
@@ -1748,10 +1836,10 @@
purge_package(deb_file[i]->package);
}
else if (opt & OPT_unpack) {
- unpack_package(deb_file[i]);
+ unpack_package(deb_file[i], opt & OPT_force_confnew, opt & OPT_force_confold);
}
else if (opt & OPT_install) {
- unpack_package(deb_file[i]);
+ unpack_package(deb_file[i], opt & OPT_force_confnew, opt & OPT_force_confold);
/* package is configured in second pass below */
}
else if (opt & OPT_configure) {
diff -ur busybox-1.16.0/include/usage.h dpkg/include/usage.h
--- busybox-1.16.0/include/usage.h 2010-01-25 02:59:38.000000000 +0200
+++ dpkg/include/usage.h 2010-03-24 12:29:11.176479064 +0200
@@ -926,13 +926,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]"
More information about the busybox
mailing list