[PATCH] =?utf-8?q?conffile=20handling=20"proof=20of=20concept".=20=20every=20package=20has=20a=20"conffiles
From: Sean Finney <seanius@seanius.net>
---
lib/dpkg.h | 1 +
src/Makefile.am | 1 +
src/archives.c | 16 +++++-
src/conffiles.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/conffiles.h | 48 +++++++++++++++++++
src/configure.c | 4 ++
src/processarc.c | 4 ++
src/remove.c | 3 +
8 files changed, 207 insertions(+), 3 deletions(-)
create mode 100644 src/conffiles.c
create mode 100644 src/conffiles.h
diff --git a/lib/dpkg.h b/lib/dpkg.h
index d0e15fe..a450716 100644
--- a/lib/dpkg.h
+++ b/lib/dpkg.h
@@ -93,6 +93,7 @@
#define UPDATESDIR "updates/"
#define INFODIR "info/"
#define PARTSDIR "parts/"
+#define CONFFILESDIR "conffiles/"
#define CONTROLDIRTMP "tmp.ci/"
#define IMPORTANTTMP "tmp.i"
#define REASSEMBLETMP "reassemble" DEBEXT
diff --git a/src/Makefile.am b/src/Makefile.am
index 80e61e7..b9998cc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,6 +13,7 @@ bin_PROGRAMS = dpkg dpkg-query
dpkg_SOURCES = \
archives.c archives.h \
cleanup.c \
+ conffiles.c conffiles.h \
configure.c \
depcon.c \
enquiry.c \
diff --git a/src/archives.c b/src/archives.c
index 5987c23..47ccb12 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -52,6 +52,7 @@ static security_context_t scontext = NULL;
#include "filesdb.h"
#include "main.h"
#include "archives.h"
+#include "conffiles.h"
#define MAXCONFLICTORS 20
@@ -317,7 +318,7 @@ int tarobject(struct TarInfo *ti) {
struct conffile *conff;
struct tarcontext *tc= (struct tarcontext*)ti->UserData;
- int statr, fd, i, existingdirectory, keepexisting;
+ int statr, fd, i, existingdirectory, keepexisting, copyfd;
ssize_t r;
struct stat stab, stabtmp;
char databuf[TARBLKSZ];
@@ -583,10 +584,19 @@ int tarobject(struct TarInfo *ti) {
}
#endif /* WITH_SELINUX */
-
+ /* in the case of a conffile we may want to extract the file somewhere
+ * else first, thus we use a "middleman" variable to keep the code clean
+ * and generalizable
+ */
+ copyfd = tc->backendpipe;
/* Extract whatever it is as .dpkg-new ... */
switch (ti->Type) {
case NormalFile0: case NormalFile1:
+ /* if the file is a conffile... */
+ if (nifd->namenode->flags & fnnf_new_conff) {
+ conff_reg_fd(tc->pkg->name, fnamevb.buf, copyfd, ti->Size);
+ copyfd = conff_get_fd(tc->pkg->name, fnamevb.buf, conff_db_new);
+ }
/* We create the file with mode 0 to make sure nobody can do anything with
* it until we apply the proper mode, which might be a statoverride.
*/
@@ -596,7 +606,7 @@ int tarobject(struct TarInfo *ti) {
debug(dbg_eachfiledetail,"tarobject NormalFile[01] open size=%lu",
(unsigned long)ti->Size);
{ char fnamebuf[256];
- fd_fd_copy(tc->backendpipe, fd, ti->Size, _("backend dpkg-deb during `%.255s'"),quote_filename(fnamebuf,256,ti->Name));
+ fd_fd_copy(copyfd, fd, ti->Size, _("backend dpkg-deb during `%.255s'"),quote_filename(fnamebuf,256,ti->Name));
}
r= ti->Size % TARBLKSZ;
if (r > 0) r= safe_read(tc->backendpipe,databuf,TARBLKSZ - r);
diff --git a/src/conffiles.c b/src/conffiles.c
new file mode 100644
index 0000000..a520717
--- /dev/null
+++ b/src/conffiles.c
@@ -0,0 +1,133 @@
+#include "conffiles.h"
+
+#include <config.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <dpkg.h>
+#include <dpkg-db.h>
+#include "main.h"
+
+/* return a pointer to a char* which has the full on-disk location of
+ * the file in the "conffile db" registered for the file at path. pass
+ * flags f to indicate whether you want the "new", "old", or "current" version.
+ *
+ * no checking is done that the file actually exists, this is just where it
+ * ought to be. your job to free() the result.
+ */
+static char* conff_db_path(const char *pkg, const char *path, conff_flag f){
+ char *p = NULL;
+ const char *ext = NULL;
+ size_t ext_sz = 0, cfgdb_root_sz = 0, p_sz = 0, path_sz = 0;
+
+ cfgdb_root_sz = strlen(admindir)+1+strlen(CONFFILESDIR)+strlen(pkg);
+
+ if(path!=NULL) path_sz = strlen(path);
+
+ switch(f){
+ case conff_db_new:
+ ext=DPKGNEWEXT;
+ ext_sz=strlen(DPKGNEWEXT);
+ break;
+ case conff_db_old:
+ ext=DPKGOLDEXT;
+ ext_sz=strlen(DPKGOLDEXT);
+ break;
+ case conff_db_cur:
+ break;
+ default:
+ ohshit("conff_db_path called with unsupported flags %x", f);
+ break;
+ }
+
+ p_sz = cfgdb_root_sz + ext_sz + path_sz + 1;
+ p = m_malloc(p_sz);
+
+ /* this is the path to the conffile db root for pkg */
+ snprintf(p, p_sz, "%s/%s%s", admindir, CONFFILESDIR, pkg);
+
+ /* append the extension if relevant */
+ if(ext_sz) {
+ strncat(p, ext, ext_sz);
+ /* replace '.' with '_' to avoid namespace conflicts. a better
+ * approach would be to have seperate dirs for new/old, or use a flat
+ * hash-based approach with an index. none of which would require
+ * extensive changes from what's done here, though
+ */
+ p[p_sz-(p_sz-cfgdb_root_sz)] = '_';
+ }
+
+ /* append the pathname if relevant */
+ if(path_sz) strncat(p, path, path_sz);
+
+ printf("conff_db_path(%s, %s, %x) = %s\n", pkg, path, f, p);
+ return p;
+}
+
+void conff_reg_fd(const char *pkg, const char *path, int fd, size_t sz){
+ int cfgfd;
+ /* get the path to where the registered file goes */
+ char *p = conff_db_path(pkg, path, conff_db_new);
+ char fnamebuf[256];
+
+ printf("conffile_reg_fd: %s, %s, %s\n", pkg, path, p);
+ /* create any leading components */
+ ensure_parent_directory(p);
+ /* make a mode 600 copy of file to p */
+ cfgfd = open(p, (O_CREAT|O_EXCL|O_WRONLY), (S_IRUSR|S_IWUSR));
+ if (cfgfd < 0) ohshite(_("unable to create `%.255s'"),p);
+ fd_fd_copy(fd, cfgfd, sz, _("backend dpkg-deb during `%.255s'"),
+ quote_filename(fnamebuf,256,p));
+ if(close(cfgfd)) ohshite("can't close %s", p);
+ free(p);
+}
+
+int conff_get_fd(const char *pkg, const char *path, conff_flag f){
+ int fd=-1;
+ char *p = conff_db_path(pkg, path, f);
+ if( (fd=open(p, O_RDONLY)) == -1){
+ ohshite("error opening conffile registered at %s", p);
+ }
+ free(p);
+ return fd;
+}
+
+void conff_commit_new(const char *pkg){
+ /* update the conffiles "db" dir. this consists of the following steps:
+ * - ensure that foo_dpkg-old does not exist
+ * - move the the db for foo to foo_dpkg-old
+ * - move the the new db for foo from foo_dpkg-new to foo
+ * - ensure that foo_dpkg-old does not exist
+ */
+ char *cfgdb=NULL, *cfgdbold=NULL, *cfgdbnew=NULL;
+
+ cfgdb = conff_db_path(pkg, NULL, conff_db_cur);
+ cfgdbold = conff_db_path(pkg, NULL, conff_db_old);
+ cfgdbnew = conff_db_path(pkg, NULL, conff_db_new);
+
+ /* excuse the copious debug output here... just gotta be
+ * extra sure when doing rm -rf's :)
+ */
+ printf("conff_commit_new: rm -rf %s\n", cfgdbold);
+ ensure_pathname_nonexisting(cfgdbold);
+ printf("conff_commit_new: mv %s %s\n", cfgdb, cfgdbold);
+ rename(cfgdb, cfgdbold);
+ printf("conff_commit_new: mv %s %s\n", cfgdbnew, cfgdbold);
+ rename(cfgdbnew, cfgdb);
+ printf("conff_commit_new: rm -rf %s\n", cfgdbold);
+ ensure_pathname_nonexisting(cfgdbold);
+
+ free(cfgdb);
+ free(cfgdbold);
+ free(cfgdbnew);
+}
+
+void conff_db_remove(const char *pkg, conff_flag f){
+ char *cfgdb= conff_db_path(pkg, NULL, f);
+ printf("conff_db_remove(%s): removing %s\n", pkg, cfgdb);
+ ensure_pathname_nonexisting(cfgdb);
+ free(cfgdb);
+}
diff --git a/src/conffiles.h b/src/conffiles.h
new file mode 100644
index 0000000..2de5eed
--- /dev/null
+++ b/src/conffiles.h
@@ -0,0 +1,48 @@
+/*
+ * conffiles.h
+ *
+ * module for registering, deregistering, and otherwise handling conffiles
+ *
+ */
+#ifndef CONFFILES_H
+#define CONFFILES_H
+
+#include <sys/types.h>
+
+/* XXX do I really need to reinvent this or can we share with namenode flags? */
+typedef enum {
+ conff_db_old=0x1,
+ conff_db_cur=0x2,
+ conff_db_new=0x4,
+} conff_flag;
+
+/* register a new conffile for package pkg at path... um... path, reading
+ * the contents of the distributed conffile from fd, which is expected to
+ * be sz bytes
+ *
+ * after calling this function it can be expected that the conffile is
+ * "registered" as a new conffile, which will be later processed in the
+ * package configuration stage, where it will be checked for stuff like
+ * new/changed/obsoleted/etc.
+ */
+void conff_reg_fd(const char *pkg, const char *path, int fd, size_t sz);
+
+/* return an fd opened for reading the contents of the "registered" conffile
+ * which is expected to be installed at path... path from package pkg. the
+ * flag f is used to determine which version of the conffile is requested
+ * (i.e. old/new/current)
+ */
+int conff_get_fd(const char *pkg, const char *path, conff_flag f);
+
+/* remove the on-disk conffile database for package pkg, using the flag f
+ * to determine which version of the database to remove (new/cur/old)
+ */
+void conff_db_remove(const char *pkg, conff_flag f);
+
+/* update the conffiles db so that the latest "new" files are now recorded
+ * as "current" for package pkg.
+ */
+void conff_commit_new(const char *pkg);
+
+#endif /* CONFFILES_H */
+
diff --git a/src/configure.c b/src/configure.c
index 9c73f8d..e0afb6d 100644
--- a/src/configure.c
+++ b/src/configure.c
@@ -43,6 +43,7 @@
#include <dpkg-db.h>
#include "filesdb.h"
+#include "conffiles.h"
#include "main.h"
int conffoptcells[2][2]= { CONFFOPTCELLS };
@@ -288,6 +289,9 @@ void deferred_configure(struct pkginfo *pkg) {
varbuffree(&cdr);
varbuffree(&cdr2);
+ /* commit the conffiles database for the new version of this package */
+ conff_commit_new(pkg->name);
+
pkg->status= stat_halfconfigured;
}
diff --git a/src/processarc.c b/src/processarc.c
index aeeba77..e76d883 100644
--- a/src/processarc.c
+++ b/src/processarc.c
@@ -43,6 +43,7 @@
#include "filesdb.h"
#include "main.h"
#include "archives.h"
+#include "conffiles.h"
void process_archive(const char *filename) {
static const struct TarFunctions tf = {
@@ -299,6 +300,9 @@ void process_archive(const char *filename) {
return;
}
+ /* make sure the new conffiles dir does not exist at this point */
+ conff_db_remove(pkg->name, conff_db_new);
+
/* OK, we're going ahead. First we read the conffiles, and copy the
* hashes across.
*/
diff --git a/src/remove.c b/src/remove.c
index e985170..92b085b 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -53,6 +53,7 @@
#include <myopt.h>
#include "filesdb.h"
+#include "conffiles.h"
#include "main.h"
static void checkforremoval(struct pkginfo *pkgtoremove,
@@ -508,6 +509,8 @@ static void removal_bulk_remove_configfiles(struct pkginfo *pkg) {
pop_cleanup(ehflag_normaltidy); /* closedir */
}
+ /* remove the current conffile db for this package */
+ conff_db_remove(pkg->name, conff_db_cur);
pkg->installed.conffiles = NULL;
modstatdb_note(pkg);
--
1.5.4.3
Reply to: