[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[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: