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

[PATCH] sub directories for /var/lib/dpkg/info



Just got around to noticing how over-populated my /var/lib/dpkg/info
directory was getting. Over 2500 files. I think this is mostly due to the
usr/doc->usr/share/doc transition which is requiring that every new
package have a postinst and a prerm script. Also, now with debconf adding
two more files to packages that support it, the directory promises to grow
even more in woody.

This didn't seem like a problem to me at first, until I checked the dpkg
code, which loops over readdir() in /var/lib/dpkg/info for every single
package you install. Now that's 2500+ loops * every package, when I
apt-get upgrade. Might not notice it much on this 270mhz ultrasparc, but I
bet the < 200mhz && < 16 Meg ram group really notices it. So I figured how
much can it hurt (if not help) to put all of the control files in a
subdirectory. SO instead of

/var/lib/dpkg/info/foo.list
/var/lib/dpkg/info/foo.conffiles
/var/lib/dpkg/info/foo.md5sums
/var/lib/dpkg/info/foo.postinst
/var/lib/dpkg/info/foo.prerm

You can have

/var/lib/dpkg/info/foo/
	list
	conffiles
	md5sums
	postinst
	prerm

I directory for each package, and all of it's files contained within. Now,
this would be a bigger win if it didn't have to be backward compatible,
but of course it does. So this included patch provides not only support
for this layout, but it automagically starts migrating to it as you
install/upgrade packages (actually, all of the .list files are done on the
first run). I wanted to just convert the entire directory, but I can't
think of a safe way to do it, so this was the better option. Please be
advised, there is currently no way to downgrade after you start using
this. I need to write a quick downgrade script for that purpose if this is
to become mainline, but right now it is mostly a RFC.

This is against the current dpkg head branch (the 1.7.0 in CVS).

-- 
 -----------=======-=-======-=========-----------=====------------=-=------
/  Ben Collins  --  ...on that fantastic voyage...  --  Debian GNU/Linux   \
`  bcollins@debian.org  --  bcollins@openldap.org  --  bcollins@linux.com  '
 `---=========------=======-------------=-=-----=-===-======-------=--=---'
--- main/filesdb.c	1999/12/12 23:44:47	1.12
+++ main/filesdb.c	2000/04/14 15:34:18
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <errno.h>
 #include <sys/stat.h>
+#include <dirent.h>
 
 #include <config.h>
 #include <dpkg.h>
@@ -229,23 +230,17 @@
 void write_filelist_except(struct pkginfo *pkg, struct fileinlist *list, int leaveout) {
   /* If leaveout is nonzero, will not write any file whose filenamenode
    * has the fnnf_elide_other_lists flag set.
+   *
+   * XXX: oldvb is backwards compatible filename for the oldstyle
+   * pkg.controlfile naming scheme. We now setup as pkg/controlfile
    */
-  static struct varbuf vb, newvb;
+  const char *vb = pkgadminfile(pkg,LISTFILE);
+  char newvb[PATH_MAX];
   FILE *file;
 
-  varbufreset(&vb);
-  varbufaddstr(&vb,admindir);
-  varbufaddstr(&vb,"/" INFODIR);
-  varbufaddstr(&vb,pkg->name);
-  varbufaddstr(&vb,"." LISTFILE);
-  varbufaddc(&vb,0);
-
-  varbufreset(&newvb);
-  varbufaddstr(&newvb,vb.buf);
-  varbufaddstr(&newvb,NEWDBEXT);
-  varbufaddc(&newvb,0);
-  
-  file= fopen(newvb.buf,"w+");
+  snprintf(newvb, sizeof(newvb), "%s" NEWDBEXT, vb);
+
+  file= fopen(newvb,"w+");
   if (!file)
     ohshite(_("unable to create updated files list file for package %s"),pkg->name);
   push_cleanup(cu_closefile,ehflag_bombout, 0,0, 1,(void*)file);
@@ -265,7 +260,7 @@
   pop_cleanup(ehflag_normaltidy); /* file= fopen() */
   if (fclose(file))
     ohshite(_("failed to close updated files list file for package %s"),pkg->name);
-  if (rename(newvb.buf,vb.buf))
+  if (rename(newvb,vb))
     ohshite(_("failed to install updated files list file for package %s"),pkg->name);
 
   note_must_reread_files_inpackage(pkg);
--- main/help.c	1999/12/05 18:04:27	1.9
+++ main/help.c	2000/04/14 15:34:19
@@ -154,15 +154,58 @@
 }
 
 const char *pkgadminfile(struct pkginfo *pkg, const char *whichfile) {
-  static struct varbuf vb;
-  varbufreset(&vb);
-  varbufaddstr(&vb,admindir);
-  varbufaddstr(&vb,"/" INFODIR);
-  varbufaddstr(&vb,pkg->name);
-  varbufaddc(&vb,'.');
-  varbufaddstr(&vb,whichfile);
-  varbufaddc(&vb,0);
-  return vb.buf;
+  char vb[PATH_MAX], *p;
+  static char newvb[PATH_MAX]; /* we pass this as the return */
+  struct stat svb;
+
+  snprintf(vb, sizeof(vb), "%s/" INFODIR "%s.%s", admindir, pkg->name, whichfile);
+  snprintf(newvb, sizeof(newvb), "%s/" INFODIR "%s/%s", admindir, pkg->name, whichfile);
+
+  p = strrchr(newvb, '/');
+  *p = '\0';
+  if (stat(newvb, &svb)) {
+    if (errno != ENOENT)
+      ohshite(_("failed to check for control directory for package %s"), pkg->name);
+    if (mkdir(newvb, 0755)) {
+      if (errno != EACCES)
+	ohshite(_("failed to create control directory %s for package %s"), newvb, pkg->name);
+      else {
+	/* otherwise, we might be running as non-root, so return the old name */
+	strcpy(newvb,vb);
+	return newvb;
+      }
+    }
+  } else {
+    if (! S_ISDIR(svb.st_mode))
+      ohshite(_("control directory %s exists, but it isn't a directory"), newvb);
+  }
+  *p = '/';
+
+  /* Now check to see if we have an old style control file that needs to
+   * be moved to the new style setup */
+  if (stat(vb, &svb)) {
+    if (errno != ENOENT)
+      ohshite(_("failed to check for old style control file `%s' in package %s"),
+	      whichfile, pkg->name);
+    /* good, we don't need to do anything */
+  } else {
+    /* alright, need to move over...sanity check here, let's also make
+     * sure we don't have _both_ files. If we do, then delete the old one
+     * instead of renaming it */
+    if (stat(newvb,&svb)) {
+      if (errno != ENOENT)
+	ohshite(_("failed to check for new style control file `%s' in package %s"),
+		whichfile, pkg->name);
+      if (rename(vb,newvb))
+	ohshite(_("failed to rename old style control file `%s' to new style for package %s"),
+		whichfile, pkg->name);
+    } else {
+      if (unlink(vb))
+	ohshite(_("failed to delete old style control file `%s' in package %s"), whichfile,
+		pkg->name);
+    }
+  }
+  return newvb;
 }
 
 static const char* preexecscript(const char *path, char *const *argv) {
--- main/processarc.c	2000/02/09 02:58:17	1.17
+++ main/processarc.c	2000/04/14 15:34:23
@@ -640,34 +640,58 @@
   debug(dbg_general, "process_archive updating info directory");
   varbufreset(&infofnvb);
   varbufaddstr(&infofnvb,admindir);
-  varbufaddstr(&infofnvb,"/" INFODIR "/");
+  varbufaddstr(&infofnvb,"/" INFODIR);
   infodirlen= infofnvb.used;
   varbufaddc(&infofnvb,0);
   dsd= opendir(infofnvb.buf);
   if (!dsd) ohshite(_("cannot read info directory"));
   push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
+  /* Ok, this loop actually doesn't do anything really useful other than
+   * move our oldstyle files to the new style subdir setup, the real work
+   * starts below */
   while ((de= readdir(dsd)) != 0) {
     debug(dbg_veryverbose, "process_archive info file `%s'", de->d_name);
     if (de->d_name[0] == '.') continue; /* ignore dotfiles, including `.' and `..' */
     p= strrchr(de->d_name,'.'); if (!p) continue; /* ignore anything odd */
     if (strlen(pkg->name) != p-de->d_name ||
         strncmp(de->d_name,pkg->name,p-de->d_name)) continue;
     debug(dbg_stupidlyverbose, "process_archive info this pkg");
     /* Right do we have one ? */
     p++; /* skip past the full stop */
-    if (!strcmp(p,LISTFILE)) continue; /* We do the list separately */
+    if (!strcmp(p,LISTFILE)) continue; /* When dpkg starts up the first time,
+					  it takes care of all of the list files automagically */
     if (strlen(p) > MAXCONTROLFILENAME)
       ohshit(_("old version of package has overly-long info file name starting `%.250s'"),
              de->d_name);
-    infofnvb.used= infodirlen;
+    pkgadminfile(pkg,p); /* this converts the file over to the subdir */
+    debug(dbg_scripts, "process_archive %s moved to new format",p);
+  }
+  pop_cleanup(ehflag_normaltidy); /* closedir */
+  /* Here's the real workhorse */
+  infofnvb.used = infodirlen;
+  varbufaddstr(&infofnvb,pkg->name);
+  varbufaddc(&infofnvb,'/');
+  infodirlen = infofnvb.used;
+  varbufaddc(&infofnvb,0);
+  if (stat(infofnvb.buf,&stab)) /* this should exist by now */
+    ohshite(_("failed to stat control subdir for package %s"), pkg->name);
+  if (! S_ISDIR(stab.st_mode)) /* and it better be a directory */
+    ohshite(_("%s exists, but is not a directory"), infofnvb.buf);
+  dsd= opendir(infofnvb.buf); if (!dsd) ohshite(_("cannot read info subdirectory"));
+  push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
+  while ((de= readdir(dsd)) != 0) {
+    /* we do everything in here, since they all presumably belong
+     * to this package */
+    if (de->d_name[0] == '.') continue;
+    if (!strcmp(de->d_name,LISTFILE)) continue;
+    infofnvb.used = infodirlen;
     varbufaddstr(&infofnvb,de->d_name);
     varbufaddc(&infofnvb,0);
-    strcpy(cidirrest,p);
+    strcpy(cidirrest,de->d_name);
     if (!rename(cidir,infofnvb.buf)) {
       debug(dbg_scripts, "process_archive info installed %s as %s",
             cidir, infofnvb.buf);
-    } else if (errno == ENOENT) {
-      /* Right, no new version. */
+    } else if (errno != ENOENT) {
       if (unlink(infofnvb.buf))
         ohshite(_("unable to remove obsolete info file `%.250s'"),infofnvb.buf);
       debug(dbg_scripts, "process_archive info unlinked %s",infofnvb.buf);
@@ -899,7 +925,41 @@
       debug(dbg_scripts, "process_archive info unlinked %s",fnvb.buf);
     }
     pop_cleanup(ehflag_normaltidy); /* closedir */
-    
+
+    /* do it again for the package subdir */
+    fnvb.used = infodirbaseused;
+    varbufaddstr(&fnvb,pkg->name);
+    varbufaddc(&fnvb,'/');
+    infodirbaseused = fnvb.used;
+    varbufaddc(&fnvb,0);
+    if (stat(fnvb.buf,&stab)) /* this should exist by now */
+      ohshite(_("failed to stat control subdir for package %s"), pkg->name);
+    if (! S_ISDIR(stab.st_mode)) /* and it better be a directory */
+      ohshite(_("%s exists, but is not a directory"), fnvb.buf);
+    dsd= opendir(fnvb.buf); if (!dsd) ohshite(_("cannot read info subdirectory"));
+    push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
+    while ((de= readdir(dsd)) != 0) {
+      /* we do everything in here, since they all presumably belong
+       * to this package */
+      if (de->d_name[0] == '.') continue;
+      fnvb.used = infodirbaseused;
+      varbufaddstr(&fnvb,de->d_name);
+      varbufaddc(&fnvb,0);
+      if (unlink(fnvb.buf))
+	ohshite(_("unable to delete disappearing control info file `%.250s'"),fnvb.buf);
+      debug(dbg_scripts, "process_archive info unlinked %s",fnvb.buf);
+    }
+    /* Now remove the subdir */
+    fnvb.used = infodirbaseused;
+    varbufaddc(&fnvb,0);
+    if (rmdir(fnvb.buf) && errno != ENOTEMPTY) {
+      if (errno != ENOTEMPTY)
+	ohshite(_("unable to delete disappearing package subdir `%.250s'"),fnvb.buf);
+      else
+	fprintf(stderr, "warning: can't remove directory `%.250s', not empty\n",
+		fnvb.buf);
+    }
+
     otherpkg->status= stat_notinstalled;
     otherpkg->want= want_purge;
     otherpkg->eflag= eflagv_ok;
--- main/remove.c	2000/02/15 19:05:39	1.4
+++ main/remove.c	2000/04/14 15:34:25
@@ -309,6 +310,34 @@
       debug(dbg_scripts, "removal_bulk info unlinked %s",fnvb.buf);
     }
     pop_cleanup(ehflag_normaltidy); /* closedir */
+
+    /* go back and do it for our subdir too */
+    fnvb.used = infodirbaseused;
+    varbufaddstr(&fnvb,pkg->name);
+    varbufaddc(&fnvb,'/');
+    infodirbaseused = fnvb.used;
+    varbufaddc(&fnvb,0);
+    if (stat(fnvb.buf,&stab))
+      ohshite(_("failed to stat control subdir for package %s"), pkg->name);
+    if (! S_ISDIR(stab.st_mode))
+      ohshite(_("%s exists, but is not a directory"), fnvb.buf);
+    dsd= opendir(fnvb.buf); if (!dsd) ohshite(_("cannot read info subdirectory"));
+    push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
+    debug(dbg_general, "removal_bulk cleaning info subdirectory");
+    while ((de= readdir(dsd)) != 0) {
+      /* we do everything in here, since they all presumably belong
+       * to this package */
+      if (de->d_name[0] == '.') continue;
+      if (!strcmp(de->d_name,LISTFILE)) continue;
+      if (!strcmp(de->d_name,POSTRMFILE)) continue;
+      debug(dbg_stupidlyverbose, "removal_bulk info sub not postrm or list");
+      fnvb.used = infodirbaseused;
+      varbufaddstr(&fnvb,de->d_name);
+      varbufaddc(&fnvb,0);
+      if (unlink(fnvb.buf))
+        ohshite(_("unable to delete control info sub file `%.250s'"),fnvb.buf);
+    }
+    pop_cleanup(ehflag_normaltidy); /* closedir */
     
     pkg->status= stat_configfiles;
     pkg->installed.essential= 0;
@@ -449,22 +478,13 @@
   if (pkg->want == want_purge) {
 
     /* ie, either of the two branches above. */
-    varbufreset(&fnvb);
-    varbufaddstr(&fnvb,admindir);
-    varbufaddstr(&fnvb,"/" INFODIR);
-    varbufaddstr(&fnvb,pkg->name);
-    pkgnameused= fnvb.used;
-    
-    varbufaddstr(&fnvb,"." LISTFILE);
-    varbufaddc(&fnvb,0);
     debug(dbg_general, "removal_bulk purge done, removing list `%s'",fnvb.buf);
-    if (unlink(fnvb.buf) && errno != ENOENT) ohshite(_("cannot remove old files list"));
+    if (unlink(pkgadminfile(pkg,LISTFILE)) && errno != ENOENT)
+      ohshite(_("cannot remove old files list"));
     
-    fnvb.used= pkgnameused;
-    varbufaddstr(&fnvb,"." POSTRMFILE);
-    varbufaddc(&fnvb,0);
     debug(dbg_general, "removal_bulk purge done, removing postrm `%s'",fnvb.buf);
-    if (unlink(fnvb.buf) && errno != ENOENT) ohshite(_("can't remove old postrm script"));
+    if (unlink(pkgadminfile(pkg,POSTRMFILE)) && errno != ENOENT)
+      ohshite(_("can't remove old postrm script"));
 
     pkg->status= stat_notinstalled;
 

Reply to: