Sophie

Sophie

distrib > Mageia > 5 > i586 > media > core-updates-src > by-pkgid > c454047046288fa22cc04811dc0287e0 > files > 28

rpm-4.12.0.1-20.3.mga5.src.rpm

unchanged:
diff -Nurpa -x '*~' -x '*.orig' -x '*.rej' -x '*.swp' rpm-4.9.1.2/doc/manual/filetriggers rpm-4.9.1.2/doc/manual/filetriggers
--- rpm-4.9.1.2/doc/manual/filetriggers	1970-01-01 02:00:00.000000000 +0200
+++ rpm-4.9.1.2/doc/manual/filetriggers	2011-12-23 18:44:52.023585938 +0200
@@ -0,0 +1,88 @@
+== Introduction ==
+
+Filetriggers allow to run some scripts when some file has been added or removed.
+
+The typical use cases are:
+
+* updating /etc/ld.so.cache when some libraries have been added/removed in /usr/lib or /lib
+* running update-menus to update menus of non-XDG compliant desktops when some *.desktop have been added/removed in /usr/share/applications
+
+== Usage ==
+
+Add the following to your macros to enable filetriggers:
+
+<pre>
+%_filetriggers_dir /var/lib/rpm/filetriggers
+</pre>
+
+Then install your watchers:
+
+<pre>
+% cat /var/lib/rpm/filetriggers/ldconfig.filter
+^.(/lib|/usr/lib)/[^/]*\.so\.
+% cat /var/lib/rpm/filetriggers/ldconfig.script
+#!/bin/sh
+ldconfig -X
+% cat /var/lib/rpm/filetriggers/gtk-icon-cache-hicolor.filter
+^./usr/share/icons/hicolor/
+% cat /var/lib/rpm/filetriggers/gtk-icon-cache-hicolor.script
+#!/bin/sh
+/usr/bin/gtk-update-icon-cache --force --quiet /usr/share/icons/hicolor
+</pre>
+
+== Implementation ==
+
+=== files-awaiting-filetriggers ===
+
+When a package is successfully installed (or removed), rpm will append the
+installed (resp. removed) files to {{file|/var/lib/rpm/files-awaiting-filetriggers}}.
+
+The format is quite simple: <installed-or-removed> <filename>
+
+where <installed-or-removed> ::= "+" | "-"
+
+For example, after installing hexedit:
+
+<pre>
++/usr/bin/hexedit
++/usr/share/doc/hexedit
++/usr/share/doc/hexedit/COPYING
++/usr/share/doc/hexedit/TODO
++/usr/share/doc/hexedit/hexedit-1.2.12.lsm
++/usr/share/man/man1/hexedit.1.lzma
+</pre>
+
+=== rpmRunFileTriggers ===
+
+This function is called before running {{macro|%posttrans}} scriptlets. It can be
+disabled using --noscripts or --notriggers (no special command line option
+introduced for now).
+
+For each {{file|%_filetriggers_dir/*.filter}}, the regexp (POSIX Extended Regular
+Expression) on the first line is applied on {{file|files-awaiting-filetriggers}}. If
+some files match, the corresponding {{prog|%_filetriggers_dir/<name>.script}} is
+called, with matching lines passed in stdin.
+
+Note that this is done in parallel, so multiple {{prog|<name>.script}} may be running
+at the same time.
+
+When it's done, {{file|/var/lib/rpm/files-awaiting-filetriggers}} is removed.
+
+== Comments ==
+
+Characteristics of this implementation :
+* if the transaction is aborted, the next successful transaction will run on every succesful package installation/removal. This is due to files-awaiting-filetriggers which allows to keep state of what is done or not.
+* it needs only a light patch in rpm
+* files-awaiting-filetriggers may be getting big (eg: 5MB on a big transaction of 1000 packages)
+* not fully integrated in rpm:
+** --nofiletriggers and RPMTRANS_FLAG_NOFILETRIGGERS should be added
+** a new command {{cmd|rpm --run-filetriggers}} would be useful to force running filetriggers, and only them.
+
+Some links about filetriggers:
+* triggers in dpkg: 
+** http://www.dpkg.org/dpkg/Triggers
+** http://lists.debian.org/debian-devel/2008/03/msg00931.html
+** http://lists.debian.org/debian-dpkg/2007/04/msg00076.html
+* what may get in rpm.org:
+** http://www.mail-archive.com/rpm-maint@lists.rpm.org/msg00789.html
+** http://www.mail-archive.com/rpm-maint@lists.rpm.org/msg00788.html
diff -Nurpa -x '*~' -x '*.orig' -x '*.rej' -x '*.swp' rpm-4.9.1.2/lib/filetriggers.c rpm-4.9.1.2/lib/filetriggers.c
--- rpm-4.9.1.2/lib/filetriggers.c	1970-01-01 02:00:00.000000000 +0200
+++ rpm-4.9.1.2/lib/filetriggers.c	2011-12-23 18:44:52.023585938 +0200
@@ -0,0 +1,268 @@
+#include "system.h"
+#include <rpm/rpmlib.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmmacro.h>	/* XXX for rpmExpand */
+
+#include "rpmfi.h"
+#include "misc.h" /* mayAddToFilesAwaitingFiletriggers rpmRunFileTriggers */
+#include "errno.h"
+#include "signal.h"
+
+#include <rpm/rpmfileutil.h>
+
+#include <regex.h>
+
+static const char *files_awaiting_filetriggers = "/var/lib/rpm/files-awaiting-filetriggers";
+
+#define FILTER_EXTENSION ".filter"
+
+static char *_filetriggers_dir = NULL;
+static char *filetriggers_dir(void)
+{
+     if (!_filetriggers_dir) _filetriggers_dir = rpmExpand("%{?_filetriggers_dir}", NULL);
+     return _filetriggers_dir && _filetriggers_dir[0] ? _filetriggers_dir : NULL;
+}
+
+static char *get_filter_name(const char *filter_filename) {
+     char *p = strrchr(filter_filename, '/');
+     return p ? strndup(p+1, strlen(p+1) - strlen(FILTER_EXTENSION)) : NULL;
+}
+
+int mayAddToFilesAwaitingFiletriggers(const char *rootDir, rpmfi fi, int install_or_erase)
+{
+    int rc = RPMRC_FAIL;
+
+    if (!filetriggers_dir()) return RPMRC_OK;
+
+    fi = rpmfiInit(fi, 0);
+    if (fi == NULL) return RPMRC_OK;
+
+    char *file = rpmGenPath(rootDir, files_awaiting_filetriggers, NULL);
+    if (!file) return RPMRC_FAIL;
+
+    FILE *f = fopen(file, "a");
+
+    if (f == NULL) {
+        rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), file, strerror(errno));
+	goto exit;
+    }
+
+    while (rpmfiNext(fi) >= 0)
+    {
+        fputc(install_or_erase ? '+' : '-', f);
+        fputs(rpmfiFN(fi), f);
+	fputc('\n', f);
+    }
+    fclose(f);
+    rc = RPMRC_OK;
+exit:
+    _free(file);
+    return rc;
+}
+
+struct filetrigger_raw {
+     char *regexp;
+     char *name;
+};
+struct filetrigger {
+     regex_t regexp;
+     char *name;
+     int command_pipe;
+     int command_pid;
+};
+
+static int getFiletriggers_raw(const char *rootDir, int *nb, struct filetrigger_raw **list_raw)
+{
+     char *globstr = rpmGenPath(rootDir, filetriggers_dir(), "*" FILTER_EXTENSION);
+     ARGV_t filter_files = NULL;
+     int i;
+     struct stat st;
+
+     rpmGlob(globstr, nb, &filter_files);
+     if (*nb == 0) return RPMRC_OK;
+
+     *list_raw = calloc(*nb, sizeof(**list_raw));
+
+     for (i = 0; i < *nb; i++) {
+	  int filter = open(filter_files[i], O_RDONLY);
+	  if (filter == -1) {
+	       rpmlog(RPMLOG_ERR, "opening %s failed: %s\n", filter_files[i], strerror(errno));
+	       continue;
+	  }
+	  if (fstat(filter, &st) == 0 && st.st_size > 0) {
+	       char *regexp = malloc(st.st_size+1);
+	       regexp[st.st_size] = '\0';
+	       if (read(filter, regexp, st.st_size) != st.st_size) {
+		    rpmlog(RPMLOG_ERR, "reading %s failed: %s\n", filter_files[i], strerror(errno));
+	       } else {
+		    char *p = strchr(regexp, '\n');
+		    if (p) *p = '\0';
+		    (*list_raw)[i].regexp = regexp;
+		    (*list_raw)[i].name = get_filter_name(filter_files[i]);
+	       }
+	  }
+	  close(filter);
+     }
+     _free(globstr);
+     argvFree(filter_files);
+
+     return RPMRC_OK;
+}
+
+static char *computeMatchesAnyFilter(int nb, struct filetrigger_raw *list_raw)
+{
+     int i, regexp_str_size = 0;
+
+     for (i = 0; i < nb; i++) regexp_str_size += strlen(list_raw[i].regexp) + 1;
+
+     char *matches_any = malloc(regexp_str_size);
+     char *p = stpcpy(matches_any, list_raw[0].regexp);
+
+     for (i = 1; i < nb; i++) {
+	  *p++ = '|';
+	  p = stpcpy(p, list_raw[i].regexp);
+     }
+     rpmlog(RPMLOG_DEBUG, "[filetriggers] matches-any regexp is %s\n", matches_any);
+     return matches_any;
+}
+
+static void compileFiletriggersRegexp(char *raw, regex_t *regexp)
+{
+     if (regcomp(regexp, raw, REG_NOSUB | REG_EXTENDED | REG_NEWLINE) != 0) {
+	  rpmlog(RPMLOG_ERR, "failed to compile filetrigger filter: %s\n", raw);
+     }
+     free(raw);
+}
+
+static void getFiletriggers(const char *rootDir, regex_t *matches_any, int *nb, struct filetrigger **list)
+{
+     struct filetrigger_raw *list_raw;
+
+     getFiletriggers_raw(rootDir, nb, &list_raw);
+     if (*nb == 0) return;
+
+     compileFiletriggersRegexp(computeMatchesAnyFilter(*nb, list_raw), matches_any);
+
+     *list = calloc(*nb, sizeof(**list));
+     int i;
+     for (i = 0; i < *nb; i++) {
+	  (*list)[i].name = list_raw[i].name;
+	  compileFiletriggersRegexp(list_raw[i].regexp, &(*list)[i].regexp);
+     }
+     free(list_raw);
+}
+
+static void freeFiletriggers(regex_t *matches_any, int nb, struct filetrigger *list)
+{
+     regfree(matches_any);
+     int i;
+     for (i = 0; i < nb; i++) {
+	  regfree(&list[i].regexp);
+	  free(list[i].name);
+     }
+     free(list);
+}
+
+static int is_regexp_matching(regex_t *re, const char *s)
+{
+     return regexec(re, s, (size_t) 0, NULL, 0) == 0;
+}
+
+static int popen_with_root(const char *rootDir, const char *cmd, int *pid)
+{
+     int pipes[2];
+     long fd_attrs;
+
+     if (pipe(pipes) != 0) return 0;
+     fd_attrs = fcntl(pipes[1], F_GETFD);
+     if (fd_attrs == -1) {
+	 rpmlog(RPMLOG_ERR, "failed to set CLOEXEC on pipe write FD");
+         return 0;
+     }
+     fcntl(pipes[1], F_SETFD, fd_attrs | FD_CLOEXEC);
+     *pid = fork();
+     if (*pid == 0) {
+	  dup2(pipes[0], STDIN_FILENO);
+	  if (pipes[0] != STDIN_FILENO) {
+	       close(pipes[0]);
+	  }
+
+	  if (rootDir != NULL && strcmp(rootDir, "/") != 0) {
+	       if (chroot(rootDir) != 0) {
+		    rpmlog(RPMLOG_ERR, "chroot to %s failed\n", rootDir);
+		    _exit(-1);
+	       }
+	       chdir("/");
+	  }
+	  const char *argv[2];
+	  argv[0] = cmd;
+	  argv[1] = NULL;
+	  execv(argv[0], (char *const *) argv);
+	  _exit(-1);
+     }
+    
+     close(pipes[0]);
+
+     return pipes[1];   
+}
+
+static void mayStartFiletrigger(const char *rootDir, struct filetrigger *trigger)
+{
+     if (!trigger->command_pipe) {
+	  char *cmd = NULL;
+	  if (asprintf(&cmd, "%s/%s.script", filetriggers_dir(), trigger->name) != -1) {
+	    rpmlog(RPMLOG_DEBUG, "[filetriggers] spawning %s\n", cmd);
+	    trigger->command_pipe = popen_with_root(rootDir, cmd, &trigger->command_pid);
+	    _free(cmd);
+	  }
+     }
+}
+
+void rpmRunFileTriggers(const char *rootDir)
+{
+     regex_t matches_any;
+     int nb = 0;
+     struct filetrigger *list = NULL;
+
+     if (!filetriggers_dir()) return;
+     rpmlog(RPMLOG_DEBUG, _("[filetriggers] starting\n"));
+     
+     getFiletriggers(rootDir, &matches_any, &nb, &list);
+
+     char *file = rpmGenPath(rootDir, files_awaiting_filetriggers, NULL);
+
+     FILE *awaiting = NULL;
+     if (nb > 0)
+          awaiting = fopen(file, "r");
+     if (awaiting) {
+	  char tmp[1024];
+
+	  void *oldhandler = signal(SIGPIPE, SIG_IGN);
+
+	  while (fgets(tmp, sizeof(tmp), awaiting))
+	       if (is_regexp_matching(&matches_any, tmp)) {
+		    rpmlog(RPMLOG_DEBUG, "[filetriggers] matches-any regexp found %s", tmp);
+		    int i;
+		    for (i = 0; i < nb; i++)
+			 if (is_regexp_matching(&list[i].regexp, tmp)) {
+			      mayStartFiletrigger(rootDir, &list[i]);
+			      write(list[i].command_pipe, tmp, strlen(tmp));
+			 }
+	       }
+	  fclose(awaiting);
+
+	  int i;
+	  for (i = 0; i < nb; i++)
+	       if (list[i].command_pipe) {
+		    close(list[i].command_pipe);
+		    int status;
+		    rpmlog(RPMLOG_DEBUG, "[filetriggers] waiting for %s to end\n", list[i].name);
+		    waitpid(list[i].command_pid, &status, 0);
+	       }
+	  freeFiletriggers(&matches_any, nb, list);
+
+	  signal(SIGPIPE, oldhandler);
+     }
+     unlink(file);
+     _free(file);
+}
diff -Nurpa -x '*~' -x '*.orig' -x '*.rej' -x '*.swp' rpm-4.9.1.2/lib/Makefile.am rpm-4.9.1.2/lib/Makefile.am
--- rpm-4.9.1.2/lib/Makefile.am	2011-12-23 18:44:51.943585368 +0200
+++ rpm-4.9.1.2/lib/Makefile.am	2011-12-23 18:44:52.023585938 +0200
@@ -35,7 +36,7 @@
 	rpmlead.c rpmlead.h rpmps.c rpmprob.c rpmrc.c \
 	rpmte.c rpmte_internal.h rpmts.c rpmfs.h rpmfs.c \
 	rpmvercmp.c signature.c signature.h transaction.c \
-	verify.c rpmlock.c rpmlock.h misc.h relocation.c \
+	filetriggers.c verify.c rpmlock.c rpmlock.h misc.h relocation.c \
 	rpmscript.h rpmscript.c legacy.c \
 	rpmchroot.c rpmchroot.h \
 	rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h
diff -Nurpa -x '*~' -x '*.orig' -x '*.rej' -x '*.swp' rpm-4.9.1.2/lib/misc.h rpm-4.9.1.2/lib/misc.h
--- rpm-4.9.1.2/lib/misc.h	2011-07-15 11:59:12.000000000 +0300
+++ rpm-4.9.1.2/lib/misc.h	2011-12-23 18:44:52.023585938 +0200
@@ -58,6 +58,11 @@
 void rpmRelocationBuild(Header h, rpmRelocation *rawrelocs,
 		int *rnrelocs, rpmRelocation **rrelocs, uint8_t **rbadrelocs);
 
+__attribute__ ((visibility("hidden")))
+  int mayAddToFilesAwaitingFiletriggers(const char *rootDir, rpmfi fi, int install_or_erase);
+
+void rpmRunFileTriggers(const char *rootDir);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/rpmte.c b/lib/rpmte.c
index 87fb391..a395d0f 100644
--- a/lib/rpmte.c
+++ b/lib/rpmte.c
@@ -19,6 +19,7 @@
 #include "lib/rpmfi_internal.h"
 #include "lib/rpmds_internal.h"
 #include "lib/rpmts_internal.h"
+#include "lib/misc.h"
 
 #include "debug.h"
 
@@ -960,6 +961,11 @@ int rpmteProcess(rpmte te, pkgGoal goal)
 
     if (rpmteOpen(te, reset_fi)) {
 	failed = rpmpsmRun(te->ts, te, goal);
+	if (!failed && !test) {
+	    int install_or_erase = (rpmteType(te) == TR_ADDED) ? 1 : 0;
+	    mayAddToFilesAwaitingFiletriggers(rpmtsRootDir(te->ts),
+					      rpmteFI(te), install_or_erase);
+	}
 	rpmteClose(te, reset_fi);
     }
     
diff --git a/lib/transaction.c b/lib/transaction.c
index 02badc6..a13a8fa 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -1492,6 +1492,9 @@
 
     /* Run post-transaction scripts unless disabled */
     if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS))) {
+	if ((rpmtsFlags(ts) & _noTransTriggers) != _noTransTriggers) {
+           rpmRunFileTriggers(rpmtsRootDir(ts));
+	}
 	rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n");
 	runTransScripts(ts, PKG_POSTTRANS);
     }