]> err.no Git - dpkg/commitdiff
Add support for excluding bits of packages as they are unpacked.
authorTollef Fog Heen <tfheen@err.no>
Thu, 3 Apr 2008 06:21:56 +0000 (08:21 +0200)
committerGuillem Jover <guillem@debian.org>
Sun, 20 Jul 2008 14:34:00 +0000 (17:34 +0300)
src/Makefile.am
src/archives.c
src/filters.c [new file with mode: 0644]
src/filters.h [new file with mode: 0644]
src/main.c

index 25c3757e951c113799295c9adfeac733c1cf582d..fa6aeef44db26be964f0105a87bb7408aa4a03a4 100644 (file)
@@ -4,6 +4,7 @@ localedir = $(datadir)/locale
 INCLUDES = \
        -DLOCALEDIR=\"$(localedir)\" \
        -DADMINDIR=\"$(admindir)\" \
+       -DCONFIGDIR=\"$(pkgconfdir)\" \
        -idirafter $(top_srcdir)/libcompat \
        -I$(top_srcdir)/lib
 
@@ -18,6 +19,7 @@ dpkg_SOURCES = \
        enquiry.c \
        errors.c \
        filesdb.c filesdb.h \
+       filters.c filters.h \
        help.c \
        main.c main.h \
        packages.c \
index 70fe4c5a601ded23ae43506721e5d811a8364db1..6789e52f54cd92ab002a19110cb727811fc1876c 100644 (file)
@@ -52,6 +52,7 @@ static security_context_t scontext    = NULL;
 #include "filesdb.h"
 #include "main.h"
 #include "archives.h"
+#include "filters.h"
 
 #define MAXCONFLICTORS 20
 
@@ -434,6 +435,15 @@ int tarobject(struct TarInfo *ti) {
         nifd->namenode->divert && nifd->namenode->divert->useinstead
         ? nifd->namenode->divert->useinstead->name : "<none>");
 
+  if (filter_should_skip(ti)) {
+    struct filenamenode *fnn = findnamenode(ti->Name, 0);
+
+    fnn->flags &= ~fnnf_new_inarchive;
+    tarfile_skip_one_forward(ti, oldnifd, nifd);
+
+    return 0;
+  }
+
   if (nifd->namenode->divert && nifd->namenode->divert->camefrom) {
     divpkg= nifd->namenode->divert->pkg;
 
diff --git a/src/filters.c b/src/filters.c
new file mode 100644 (file)
index 0000000..98002a1
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * dpkg - main program for package management
+ * filters.c - filtering routines for excluding bits of packages
+ *
+ * Copyright (C) 2007,2008 Tollef Fog Heen <tfheen@err.no>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fnmatch.h>
+
+#include <dpkg.h>
+#include <dpkg-db.h>
+#include <filesdb.h>
+
+#include "filters.h"
+#include "main.h"
+
+static struct filterlist *filters = NULL;
+  static struct filterlist **filtertail = &filters;
+
+static void loadfilter(const char *fn) {
+  FILE *file;
+  char linebuf[1024];
+
+  file = fopen(fn, "r");
+  if (!file) {
+    warningf(_("failed to open filter file `%.255s' for reading"), fn);
+    return;
+  }
+
+  while (fgets(linebuf, sizeof(linebuf), file)) {
+    struct filterlist *filter;
+
+    filter = m_malloc(sizeof(struct filterlist));
+    memset(filter, 0, sizeof(struct filterlist));
+
+    if (linebuf[0] == '#' || linebuf[0] == '\n') {
+      continue;
+    }
+
+    if (linebuf[strlen(linebuf) - 1] == '\n')
+      linebuf[strlen(linebuf) - 1] = '\0';
+
+    if (linebuf[0] == '+') {
+      filter->positive = 1;
+    } else if (linebuf[0] == '-') {
+      filter->positive = 0;
+    } else {
+      warningf(_("Invalid filter line: `%.255s'"), linebuf);
+      free(filter);
+      continue;
+    }
+
+    filter->filterstring = strdup(&linebuf[1]);
+    if (!filter->filterstring) {
+      ohshite(_("Error allocating memory for filter entry"));
+    }
+
+    *filtertail = filter;
+    filtertail = &filter->next;
+  }
+
+  if (ferror(file))
+    ohshite(_("read error in configuration file `%.255s'"), fn);
+
+  if (fclose(file))
+    ohshite(_("error closing configuration file `%.255s'"), fn);
+}
+
+void loadfilters(void) {
+  struct dirent *dent;
+  char *dirname = CONFIGDIR "/filters.d";
+  DIR *dir = opendir(dirname);
+  if (!dir) {
+    if (errno == ENOENT)
+      return;
+    else
+      ohshite(_("Error opening filters.d"));
+  }
+
+  while ((dent = readdir(dir)) != NULL) {
+    struct stat statbuf;
+    char *file = m_malloc(strlen(dirname) + 1 + strlen(dent->d_name) + 1);
+    sprintf(file, "%s/%s", dirname, dent->d_name);
+    if (stat(file, &statbuf) != 0) {
+      ohshite(_("Error stating file"));
+    }
+    if (S_ISREG(statbuf.st_mode)) {
+      loadfilter(file);
+    }
+    free(file);
+  }
+  closedir(dir);
+}
+
+int filter_should_skip(struct TarInfo *ti) {
+  int remove = 0;
+  if (filters) {
+    struct filterlist *f;
+
+    /* Last match wins */
+    for (f = filters; f != NULL; f = f->next) {
+      debug(dbg_eachfile, "tarobject comparing '%s' and '%s'", &ti->Name[1], f->filterstring);
+      if (fnmatch(f->filterstring, &ti->Name[1], 0) == 0) {
+       if (f->positive == 0) {
+         remove = 1;
+         debug(dbg_eachfile, "do_filter removing %s", ti->Name);
+       } else {
+         remove = 0;
+         debug(dbg_eachfile, "do_filter including %s", ti->Name);
+       }
+      }
+    }
+
+    if (remove) {
+      for (f = filters; f != NULL; f = f->next) {
+       char *pattern;
+
+       pattern = m_malloc(strlen(ti->Name) + 1);
+       strcpy(pattern, &ti->Name[1]);
+       strcat(pattern, "*");
+
+       debug(dbg_eachfile,
+             "tarobject seeing if '%s' needs to be reincluded", &ti->Name[1]);
+       if ((f->positive == 1) &&
+           (ti->Type == Directory) &&
+           (fnmatch(pattern, f->filterstring, 0) == 0)) {
+         remove = 0;
+         debug(dbg_eachfile, "tarobject reincluding %s", ti->Name);
+       }
+      }
+    }
+  }
+  return remove;
+}
diff --git a/src/filters.h b/src/filters.h
new file mode 100644 (file)
index 0000000..540337c
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * dpkg - main program for package management
+ * filters.h - external definitions for filter handling
+ *
+ * Copyright (C) 2007,2008 Tollef Fog Heen <tfheen@err.no>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DPKG_FILTERS_H
+#define DPKG_FILTERS_H
+
+#include "tarfn.h"
+
+void loadfilters(void);
+int filter_should_skip(struct TarInfo *ti);
+
+struct filterlist {
+  int positive;
+  char *filterstring;
+  struct filterlist *next;
+};
+
+#endif
+
index 99ac6c6236120b6fc74df9fcf7d9b401b4308c9b..da7e7e46d3991ac5c6c52a9a6d5cc34d42334b6f 100644 (file)
@@ -40,6 +40,7 @@
 #include <myopt.h>
 
 #include "main.h"
+#include "filters.h"
 
 void
 printversion(void)
@@ -624,6 +625,8 @@ int main(int argc, const char *const *argv) {
   standard_startup(&ejbuf, argc, &argv, DPKG, 1, cmdinfos);
   if (!cipaction) badusage(_("need an action option"));
 
+  loadfilters();
+
   if (!f_triggers)
     f_triggers = (cipaction->arg == act_triggers && *argv) ? -1 : 1;