public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Fabian Groffen" <grobian@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/portage-utils:master commit in: /
Date: Thu, 20 Dec 2018 18:24:45 +0000 (UTC)	[thread overview]
Message-ID: <1545330270.e3d45aadf559ba2ff9c929715bbeade5a42e3634.grobian@gentoo> (raw)

commit:     e3d45aadf559ba2ff9c929715bbeade5a42e3634
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Thu Dec 20 18:11:43 2018 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Thu Dec 20 18:24:30 2018 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=e3d45aad

qmerge: support "negative" INSTALL_MASK entries

Reworked qmerge install_mask handling to support negative entries in
INSTALL_MASK, which "undo" (part of) a previous masking.
This should implement the same behaviour as
https://archives.gentoo.org/gentoo-portage-dev/message/29e128a9f41122fa0420c1140f7b7f94

Along the way some behavioural changes were made:
- pretend mode now prints what would be merged (use with -y to be
  useful)
- directory objects are recorded and merged again

Bug: https://bugs.gentoo.org/656318
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 qmerge.c | 561 ++++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 393 insertions(+), 168 deletions(-)

diff --git a/qmerge.c b/qmerge.c
index a1b5a86..535966e 100644
--- a/qmerge.c
+++ b/qmerge.c
@@ -1,9 +1,10 @@
 /*
- * Copyright 2005-2018 Gentoo Foundation
+ * Copyright 2005-2018 Gentoo Authors
  * Distributed under the terms of the GNU General Public License v2
  *
  * Copyright 2005-2010 Ned Ludd        - <solar@gentoo.org>
  * Copyright 2005-2014 Mike Frysinger  - <vapier@gentoo.org>
+ * Copyright 2018-     Fabian Groffen  - <grobian@gentoo.org>
  */
 
 #ifdef APPLET_qmerge
@@ -100,7 +101,7 @@ typedef struct llist_char_t llist_char;
 
 static void pkg_fetch(int, const depend_atom *, const struct pkg_t *);
 static void pkg_merge(int, const depend_atom *, const struct pkg_t *);
-static int pkg_unmerge(q_vdb_pkg_ctx *, queue *);
+static int pkg_unmerge(q_vdb_pkg_ctx *, queue *, int, char **, int, char **);
 static struct pkg_t *grab_binpkg_info(const char *);
 static char *find_binpkg(const char *);
 
@@ -289,52 +290,252 @@ config_protected(const char *buf, int cp_argc, char **cp_argv,
 }
 
 static void
-crossmount_rm(const char *fname, const struct stat * const st)
+crossmount_rm(const char *fname, const struct stat * const st,
+		int fd, char *qpth)
 {
 	struct stat lst;
 
-	assert(pretend == 0);
-
-	if (lstat(fname, &lst) == -1)
+	if (fstatat(fd, fname, &lst, AT_SYMLINK_NOFOLLOW) == -1)
 		return;
 	if (lst.st_dev != st->st_dev) {
 		warn("skipping crossmount install masking: %s", fname);
 		return;
 	}
-	qprintf("%s<<<%s %s\n", YELLOW, NORM, fname);
-	rm_rf(fname);
+	qprintf("%s<<<%s %s/%s (INSTALL_MASK)\n", YELLOW, NORM, qpth, fname);
+	rm_rf_at(fd, fname);
+}
+
+static int
+q_merge_filter_self_parent(const struct dirent *de)
+{
+	if (de->d_name[0] == '.' && (de->d_name[1] == '\0' ||
+			 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
+		return 0;
+
+	return 1;
 }
 
+enum inc_exc { INCLUDE = 1, EXCLUDE = 2 };
+
 static void
-install_mask_pwd(int iargc, char **iargv, const struct stat * const st)
+install_mask_check_dir(
+		char ***maskv,
+		int maskc,
+		const struct stat * const st,
+		int fd,
+		ssize_t level,
+		enum inc_exc parent_mode,
+		char *qpth)
 {
-	char buf[1024];
+	struct dirent **files;
+	int cnt;
 	int i;
+	int j;
+	enum inc_exc mode;
+	enum inc_exc child_mode;
+#ifndef DT_DIR
+	struct stat s;
+#endif
+	char *npth = qpth + strlen(qpth);
+
+	cnt = scandirat(fd, ".", &files, q_merge_filter_self_parent, alphasort);
+	for (j = 0; j < cnt; j++) {
+		mode = child_mode = parent_mode;
+		for (i = 0; i < maskc; i++) {
+			if ((ssize_t)maskv[i][0] < 0) {
+				/* relative matches need to be a "file", as the Portage
+				 * implementation suggests, so that's easy for us here,
+				 * since we can just match it against each component in
+				 * the path */
+				if ((ssize_t)maskv[i][0] < -1)
+					continue;  /* this is unsupported, so skip it */
+				/* this also works if maskv happens to be a glob */
+				if (fnmatch(maskv[i][1], files[j]->d_name, FNM_PERIOD) != 0)
+					continue;
+				mode = child_mode = maskv[i][2] ? INCLUDE : EXCLUDE;
+			} else if ((ssize_t)maskv[i][0] < level) {
+				/* either this is a mask that didn't match, or it
+				 * matched, but a negative match exists for a deeper
+				 * level, parent_mode should reflect this */
+				continue;
+			} else {
+				if (fnmatch(maskv[i][level], files[j]->d_name, FNM_PERIOD) != 0)
+					continue;
 
-	for (i = 1; i < iargc; i++) {
+				if ((ssize_t)maskv[i][0] == level)  /* full mask match */
+					mode = child_mode =
+						(ssize_t)maskv[i][level + 1] ? INCLUDE : EXCLUDE;
+				else if (maskv[i][(ssize_t)maskv[i][0] + 1])
+					/* partial include mask */
+					mode = INCLUDE;
+			}
+		}
 
-		if (iargv[i][0] != '/')
+		DBG("%s/%s: %s/%s", qpth, files[j]->d_name,
+				mode == EXCLUDE       ? "EXCLUDE" : "INCLUDE",
+				child_mode == EXCLUDE ? "EXCLUDE" : "INCLUDE");
+		if (mode == EXCLUDE) {
+			crossmount_rm(files[j]->d_name, st, fd, qpth);
 			continue;
+		}
 
-		snprintf(buf, sizeof(buf), ".%s", iargv[i]);
+#ifdef DT_DIR
+		if (files[j]->d_type == DT_DIR) {
+#else
+		if (fstatat(fd, files[j]->d_name, &s, AT_SYMLINK_NOFOLLOW) != 0)
+			continue;
+		if (S_ISDIR(s.st_mode)) {
+#endif
+			int subfd = openat(fd, files[j]->d_name, O_RDONLY);
+			if (subfd < 0)
+				continue;
+			snprintf(npth, _Q_PATH_MAX - (npth - qpth),
+					"/%s", files[j]->d_name);
+			install_mask_check_dir(maskv, maskc, st, subfd,
+					level + 1, child_mode, qpth);
+			close(subfd);
+			*npth = '\0';
+		}
+	}
+}
 
-		if ((strchr(iargv[i], '*') != NULL) || (strchr(iargv[i], '{') != NULL)) {
-			int g;
-			glob_t globbuf;
+static void
+install_mask_pwd(int iargc, char **iargv, const struct stat * const st, int fd)
+{
+	char *p;
+	int i;
+	size_t cnt;
+	size_t maxdirs;
+	char **masks;
+	size_t masksc;
+	char ***masksv;
+	char qpth[_Q_PATH_MAX];
+
+	/* we have to deal with "negative" masks, see
+	 * https://archives.gentoo.org/gentoo-portage-dev/message/29e128a9f41122fa0420c1140f7b7f94
+	 * which means we'll need to see what thing matches last
+	 * (inclusion or exclusion) for *every* file :( */
+
+   /*
+	example package contents:
+	/e/t1
+    /u/b/t1
+	/u/b/t2
+	/u/l/lt1
+	/u/s/d/t1
+	/u/s/m/m1/t1
+	/u/s/m/m5/t2
+
+	masking rules:     array encoding:
+	 /u/s              2 u s 0          relative=0 include=0
+	-/u/s/m/m1         4 u s m m1 1     relative=0 include=1
+	 e                -1 e 0            relative=1 include=0
+
+	should result in:
+	/u/b/t1
+	/u/b/t2
+	/u/l/lt1
+	/u/s/m/m1/t1
+	strategy:
+	- for each dir level
+	  - find if there is a match on that level in rules
+	  - if the last match is the full mask
+	    - if the mask is negated, do not remove entry
+	    - else, remove entry
+	  - if the last match is negated, partial and a full mask matched before
+	    - do not remove entry
+	practice:
+	/e | matches "e" -> remove
+	/u | matches partial last negated -> continue
+	  /b | doesn't match -> leave subtree
+	  /l | doesn't match -> leave subtree
+	  /s | match, partial last negated match -> remember match, continue
+	    /d | doesn't match -> remembered match, remove subtree
+		/m | partial match negated -> continue
+		  /m1 | match negated -> leave subtree
+		  /m5 | doesn't match -> remembered match, remove subtree
+	*/
+
+	/* find the longest path so we can allocate a matrix */
+	maxdirs = 0;
+	for (i = 1; i < iargc; i++) {
+		char lastc = '/';
+
+		cnt = 1; /* we always have "something", right? */
+		p = iargv[i];
+		if (*p == '-')
+			p++;
+		for (; *p != '\0'; p++) {
+			/* eliminate duplicate /-es, also ignore the leading / in
+			 * the count */
+			if (*p == '/' && *p != lastc)
+				cnt++;
+			lastc = *p;
+		}
+		if (cnt > maxdirs)
+			maxdirs = cnt;
+	}
+	maxdirs += 2;  /* allocate plus relative and include elements */
 
-			globbuf.gl_offs = 0;
-			if (glob(buf, GLOB_DOOFFS|GLOB_BRACE, NULL, &globbuf) == 0) {
-				for (g = 0; g < (int)globbuf.gl_pathc; g++) {
-					strncpy(buf, globbuf.gl_pathv[g], sizeof(buf));
-					/* qprintf("globbed: %s\n", globbuf.gl_pathv[g]); */
-					crossmount_rm(globbuf.gl_pathv[g], st);
-				}
-				globfree(&globbuf);
+	/* allocate and populate matrix */
+	masksc = iargc - 1;
+	masks = xmalloc(sizeof(char *) * (maxdirs * masksc));
+	masksv = xmalloc(sizeof(char **) * (masksc));
+	for (i = 1; i < iargc; i++) {
+		masksv[i - 1] = &masks[(i - 1) * maxdirs];
+		p = iargv[i];
+		cnt = 1;  /* start after count */
+		/* ignore include marker */
+		if (*p == '-')
+			p++;
+		/* strip of leading slash(es) */
+		while (*p == '/')
+			p++;
+		masks[((i - 1) * maxdirs) + cnt] = p;
+		for (; *p != '\0'; p++) {
+			if (*p == '/') {
+				/* fold duplicate slashes */
+				do {
+					*p++ = '\0';
+				} while (*p == '/');
+				cnt++;
+				masks[((i - 1) * maxdirs) + cnt] = p;
 			}
-			continue;
 		}
-		crossmount_rm(iargv[i], st);
+		/* brute force cast below values, a pointer basically is size_t,
+		 * which is large enough to store what we need here */
+		p = iargv[i];
+		/* set include bit */
+		if (*p == '-') {
+			masks[((i - 1) * maxdirs) + cnt + 1] = (char *)1;
+			p++;
+		} else {
+			masks[((i - 1) * maxdirs) + cnt + 1] = (char *)0;
+		}
+		/* set count */
+		masks[((i - 1) * maxdirs) + 0] =
+			(char *)((*p == '/' ? 1 : -1) * cnt);
 	}
+
+#if EBUG
+	printf("applying install masks:\n");
+	for (cnt = 0; cnt < masksc; cnt++) {
+		ssize_t plen = (ssize_t)masksv[cnt][0];
+		printf("%3zd  ", plen);
+		if (plen < 0)
+			plen = -plen;
+		for (i = 1; i <= plen; i++)
+			printf("%s ", masksv[cnt][i]);
+		printf(" %zd\n", (size_t)masksv[cnt][i]);
+	}
+#endif
+
+	cnt = snprintf(qpth, _Q_PATH_MAX, "%s", CONFIG_EPREFIX);
+	cnt--;
+	if (qpth[cnt] == '/')
+		qpth[cnt] = '\0';
+
+	install_mask_check_dir(masksv, masksc, st, fd, 1, INCLUDE, qpth);
 }
 
 static char *
@@ -492,7 +693,7 @@ pkg_run_func_at(int dirfd, const char *vdb_path, const char *phases, const char
 /* Copy one tree (the single package) to another tree (ROOT) */
 static int
 merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
-              FILE *contents, queue **objs, char **cpathp, int iargc, char **iargv,
+              FILE *contents, queue **objs, char **cpathp,
               int cp_argc, char **cp_argv, int cpm_argc, char **cpm_argv)
 {
 	int i, ret, subfd_src, subfd_dst;
@@ -538,15 +739,6 @@ merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
 		}
 		strcpy(cpath + clen + 1, name);
 
-		/* Check INSTALL_MASK */
-		for (i = 1; i < iargc; ++i) {
-			if (fnmatch(iargv[i], cpath, 0) == 0) {
-				unlinkat(subfd_src, name, 0);
-				unlinkat(subfd_dst, name, 0);
-				continue;
-			}
-		}
-
 		/* Find out what the source path is */
 		if (fstatat(subfd_src, name, &st, AT_SYMLINK_NOFOLLOW)) {
 			warnp("could not read %s", cpath);
@@ -555,34 +747,32 @@ merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
 
 		/* Migrate a directory */
 		if (S_ISDIR(st.st_mode)) {
-			if (mkdirat(subfd_dst, name, st.st_mode)) {
+			if (!pretend && mkdirat(subfd_dst, name, st.st_mode)) {
 				if (errno != EEXIST) {
-					warnp("could not read %s", cpath);
+					warnp("could not create %s", cpath);
 					continue;
 				}
 
 				/* XXX: update times of dir ? */
 			}
 
-#if 0		/* We filter out "dir" as it's generally unnecessary cruft */
 			/* syntax: dir dirname */
-			fprintf(contents, "dir %s\n", cpath);
+			if (!pretend)
+				fprintf(contents, "dir %s\n", cpath);
 			*objs = add_set(cpath, *objs);
 			qprintf("%s>>>%s %s%s%s/\n", GREEN, NORM, DKBLUE, cpath, NORM);
-#endif
 
 			/* Copy all of these contents */
-			merge_tree_at(subfd_src, name, subfd_dst, name, contents, objs, cpathp,
-				iargc, iargv, cp_argc, cp_argv, cpm_argc, cpm_argv);
+			merge_tree_at(subfd_src, name, subfd_dst, name, contents, objs,
+					cpathp, cp_argc, cp_argv, cpm_argc, cpm_argv);
 			cpath = *cpathp;
 			mnlen = 0;
 
 			/* In case we didn't install anything, prune the empty dir */
-			unlinkat(subfd_dst, name, AT_REMOVEDIR);
-		}
-
-		/* Migrate a file */
-		else if (S_ISREG(st.st_mode)) {
+			if (!pretend)
+				unlinkat(subfd_dst, name, AT_REMOVEDIR);
+		} else if (S_ISREG(st.st_mode)) {
+			/* Migrate a file */
 			struct timespec times[2];
 			int fd_srcf, fd_dstf;
 			unsigned char *hash;
@@ -590,7 +780,9 @@ merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
 
 			/* syntax: obj filename hash mtime */
 			hash = hash_file_at(subfd_src, name, HASH_MD5);
-			fprintf(contents, "obj %s %s %"PRIu64"\n", cpath, hash, (uint64_t)st.st_mtime);
+			if (!pretend)
+				fprintf(contents, "obj %s %s %"PRIu64"\n",
+						cpath, hash, (uint64_t)st.st_mtime);
 			free(hash);
 
 			/* Check CONFIG_PROTECT */
@@ -617,6 +809,9 @@ merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
 			}
 			*objs = add_set(cpath, *objs);
 
+			if (pretend)
+				continue;
+
 			/* First try fast path -- src/dst are same device */
 			if (renameat(subfd_src, dname, subfd_dst, name) == 0)
 				continue;
@@ -633,7 +828,8 @@ merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
 			 * XXX: Should we make this random ?
 			 */
 			tmpname = ".qmerge.update";
-			fd_dstf = openat(subfd_dst, tmpname, O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC, st.st_mode);
+			fd_dstf = openat(subfd_dst, tmpname,
+					O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC, st.st_mode);
 			if (fd_dstf < 0) {
 				warnp("could not write %s", cpath);
 				close(fd_srcf);
@@ -674,10 +870,8 @@ merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
 				warnp("could not rename %s to %s", tmpname, cpath);
 				continue;
 			}
-		}
-
-		/* Migrate a symlink */
-		else if (S_ISLNK(st.st_mode)) {
+		} else if (S_ISLNK(st.st_mode)) {
+			/* Migrate a symlink */
 			size_t len = st.st_size;
 			char *sym = alloca(len + 1);
 
@@ -689,10 +883,16 @@ merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
 			sym[len] = '\0';
 
 			/* syntax: sym src -> dst mtime */
-			fprintf(contents, "sym %s -> %s %"PRIu64"\n", cpath, sym, (uint64_t)st.st_mtime);
-			qprintf("%s>>>%s %s%s -> %s%s\n", GREEN, NORM, CYAN, cpath, sym, NORM);
+			if (!pretend)
+				fprintf(contents, "sym %s -> %s %"PRIu64"\n",
+						cpath, sym, (uint64_t)st.st_mtime);
+			qprintf("%s>>>%s %s%s -> %s%s\n", GREEN, NORM,
+					CYAN, cpath, sym, NORM);
 			*objs = add_set(cpath, *objs);
 
+			if (pretend)
+				continue;
+
 			/* Make it in the dest tree */
 			if (symlinkat(sym, subfd_dst, name)) {
 				/* If the symlink exists, unlink it and try again */
@@ -708,10 +908,8 @@ merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
 			times[0] = get_stat_mtime(&st);
 			times[1] = get_stat_mtime(&st);
 			utimensat(subfd_dst, name, times, AT_SYMLINK_NOFOLLOW);
-		}
-
-		/* WTF is this !? */
-		else {
+		} else {
+			/* WTF is this !? */
 			warnp("unknown file type %s", cpath);
 			continue;
 		}
@@ -726,34 +924,6 @@ merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
 	return ret;
 }
 
-/* Copy one tree (the single package) to another tree (ROOT) */
-static int
-merge_tree(const char *src, const char *dst, FILE *contents,
-           queue **objs, int iargc, char **iargv)
-{
-	int ret;
-	int cp_argc, cpm_argc;
-	char **cp_argv, **cpm_argv;
-	char *cpath;
-
-	/* XXX: be nice to pull this out of the current func
-	 *      so we don't keep reparsing the same env var
-	 *      when unmerging multiple packages.
-	 */
-	makeargv(config_protect, &cp_argc, &cp_argv);
-	makeargv(config_protect_mask, &cpm_argc, &cpm_argv);
-
-	cpath = xstrdup("");
-	ret = merge_tree_at(AT_FDCWD, src, AT_FDCWD, dst, contents, objs, &cpath,
-		iargc, iargv, cp_argc, cp_argv, cpm_argc, cpm_argv);
-	free(cpath);
-
-	freeargv(cp_argc, cp_argv);
-	freeargv(cpm_argc, cpm_argv);
-
-	return ret;
-}
-
 /* oh shit getting into pkg mgt here. FIXME: write a real dep resolver. */
 static void
 pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
@@ -774,6 +944,10 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
 	char c;
 	int iargc;
 	const char *compr;
+	int cp_argc;
+	int cpm_argc;
+	char **cp_argv;
+	char **cpm_argv;
 
 	if (!install || !pkg || !atom)
 		return;
@@ -830,30 +1004,39 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
 
 						resolved = find_binpkg(name);
 
-						IF_DEBUG(fprintf(stderr, "+Atom: argv0(%s) resolved(%s)\n", name, resolved));
+						IF_DEBUG(fprintf(stderr,
+									"+Atom: argv0(%s) resolved(%s)\n",
+									name, resolved));
 
 						if (strlen(resolved) < 1) {
-							warn("Cant find a binpkg for %s from rdepend(%s)", name, pkg->RDEPEND);
+							warn("Cant find a binpkg for %s from rdepend(%s)",
+									name, pkg->RDEPEND);
 							continue;
 						}
 
 						/* ratom = atom_explode(resolved); */
-						subpkg = grab_binpkg_info(resolved);	/* free me later */
+						subpkg = grab_binpkg_info(resolved); /* free me later */
 
 						assert(subpkg != NULL);
-						IF_DEBUG(fprintf(stderr, "+Subpkg: %s/%s\n", subpkg->CATEGORY, subpkg->PF));
+						IF_DEBUG(fprintf(stderr, "+Subpkg: %s/%s\n",
+									subpkg->CATEGORY, subpkg->PF));
 
-						/* look at installed versions now. If NULL or < merge this pkg */
-						snprintf(buf, sizeof(buf), "%s/%s", subpkg->CATEGORY, subpkg->PF);
+						/* look at installed versions now.
+						 * If NULL or < merge this pkg */
+						snprintf(buf, sizeof(buf), "%s/%s",
+								subpkg->CATEGORY, subpkg->PF);
 
 						ratom = atom_explode(buf);
 
-						p = best_version(subpkg->CATEGORY, subpkg->PF, subpkg->SLOT);
+						p = best_version(subpkg->CATEGORY,
+								subpkg->PF, subpkg->SLOT);
 
 						/* we dont want to remerge equal versions here */
 						IF_DEBUG(fprintf(stderr, "+Installed: %s\n", p));
 						if (strlen(p) < 1)
-							if (!((strcmp(pkg->PF, subpkg->PF) == 0) && (strcmp(pkg->CATEGORY, subpkg->CATEGORY) == 0)))
+							if (!((strcmp(pkg->PF, subpkg->PF) == 0) &&
+										(strcmp(pkg->CATEGORY,
+												subpkg->CATEGORY) == 0)))
 								pkg_fetch(level+1, ratom, subpkg);
 
 						atom_implode(subatom);
@@ -867,8 +1050,6 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
 		}
 		freeargv(ARGC, ARGV);
 	}
-	if (pretend)
-		return;
 
 	/* Get a handle on the main vdb repo */
 	vdb_ctx = q_vdb_open();
@@ -1000,13 +1181,11 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
 
 	/* extract the binary package data */
 	mkdir("image", 0755);
-	if (compr[0] != 'I')
-	{
+	if (compr[0] != 'I') {
 		snprintf(buf, sizeof(buf),
 			BUSYBOX " tar -x%s%s -f %s.tar.bz2 -C image/",
 			((verbose > 1) ? "v" : ""), compr, pkg->PF);
-	} else
-	{
+	} else {
 		/* busybox's tar has no -I option. Thus, although we possibly
 		 * use busybox's shell and tar, we thus pipe, expecting the
 		 * corresponding (de)compression tool to be in PATH; if not,
@@ -1025,48 +1204,75 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
 	pkg_run_func("vdb", phases, "pkg_setup", D, T);
 	pkg_run_func("vdb", phases, "pkg_preinst", D, T);
 
-	/* XXX: kill this off */
-	xchdir("image");
-
-	if (stat(".", &st) == -1)
-		err("Cant stat pwd");
-
-	/* Initialize INSTALL_MASK and common stuff */
-	makeargv(install_mask, &iargc, &iargv);
-	/* XXX: Would be better if INSTALL_MASK deleted from image/
-	 *      so we didn't have to parse it while doing merge_tree() */
-	install_mask_pwd(iargc, iargv, &st);
-
-	if (strstr(features, "noinfo")) rm_rf("./usr/share/info");
-	if (strstr(features, "noman" )) rm_rf("./usr/share/man");
-	if (strstr(features, "nodoc" )) rm_rf("./usr/share/doc");
+	{
+		int imagefd = open("image" CONFIG_EPREFIX, O_RDONLY);
+		size_t masklen = strlen(install_mask) + 1 +
+				15 + 1 + 14 + 1 + 14 + 1 + 1;  /* worst case scenario */
+		char *imask = xmalloc(masklen);
+		size_t maskp;
+
+		if (fstat(imagefd, &st) == -1) {
+			close(imagefd);
+			err("Cannot stat image dirfd");
+		}
 
-	/* we dont care about the return code */
-	rmdir("./usr/share");
+		/* rely on INSTALL_MASK code to remove optional dirs */
+		maskp = snprintf(imask, masklen, "%s ", install_mask);
+		if (strstr(features, "noinfo") != NULL)
+			maskp += snprintf(imask + maskp, masklen - maskp,
+					"/usr/share/info ");
+		if (strstr(features, "noman" ) != NULL)
+			maskp += snprintf(imask + maskp, masklen - maskp,
+					"/usr/share/man ");
+		if (strstr(features, "nodoc" ) != NULL)
+			maskp += snprintf(imask + maskp, masklen - maskp,
+					"/usr/share/doc ");
+
+		/* Initialize INSTALL_MASK and common stuff */
+		makeargv(imask, &iargc, &iargv);
+		free(imask);
+		install_mask_pwd(iargc, iargv, &st, imagefd);
+		freeargv(iargc, iargv);
+
+		/* we dont care about the return code, if it's empty, we want it
+		 * gone */
+		unlinkat(imagefd, "./usr/share", AT_REMOVEDIR);
+
+		close(imagefd);
+	}
 
-	/* XXX: Once we kill xchdir(image), this can die too */
-	xchdir("..");
+	makeargv(config_protect, &cp_argc, &cp_argv);
+	makeargv(config_protect_mask, &cpm_argc, &cpm_argv);
 
 	if ((contents = fopen("vdb/CONTENTS", "w")) == NULL)
 		errf("come on wtf?");
 	objs = NULL;
-	if (merge_tree("image", portroot, contents, &objs, iargc, iargv))
-		errp("failed to merge to %s", portroot);
-	fclose(contents);
+	{
+		char *cpath;
+		int ret;
+
+		cpath = xstrdup("");  /* xrealloced in merge_tree_at */
 
-	freeargv(iargc, iargv);
+		ret = merge_tree_at(AT_FDCWD, "image", AT_FDCWD, portroot, contents,
+					&objs, &cpath, cp_argc, cp_argv, cpm_argc, cpm_argv);
+
+		free(cpath);
+
+		if (ret != 0)
+			errp("failed to merge to %s", portroot);
+	}
+	fclose(contents);
 
 	/* run postinst */
-	pkg_run_func("vdb", phases, "pkg_postinst", D, T);
+	if (!pretend)
+		pkg_run_func("vdb", phases, "pkg_postinst", D, T);
 
 	/* XXX: hmm, maybe we'll want to strip more ? */
 	unlink("vdb/environment");
 
-	/* FIXME */ /* move unmerging to around here ? */
-	/* check for an already installed pkg */
-
-	/* Unmerge any stray pieces from the older version which we didn't replace */
-	/* XXX: Should see about merging with unmerge_packages() */
+	/* Unmerge any stray pieces from the older version which we didn't
+	 * replace */
+	/* TODO: Should see about merging with unmerge_packages() */
 	while (1) {
 		int ret;
 		q_vdb_pkg_ctx *pkg_ctx;
@@ -1085,7 +1291,8 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
 			case NEWER:
 			case OLDER:
 			case EQUAL:
-				/* We need to really set this unmerge pending after we look at contents of the new pkg */
+				/* We need to really set this unmerge pending after we
+				 * look at contents of the new pkg */
 				break;
 			default:
 				warn("no idea how we reached here.");
@@ -1094,14 +1301,18 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
 				goto next_pkg;
 		}
 
-		qprintf("%s+++%s %s/%s %s %s/%s\n", GREEN, NORM, atom->CATEGORY, pkg->PF,
-			booga[ret], cat_ctx->name, pkg_ctx->name);
+		qprintf("%s+++%s %s/%s %s %s/%s\n",
+				GREEN, NORM, atom->CATEGORY, pkg->PF,
+				booga[ret], cat_ctx->name, pkg_ctx->name);
 
-		pkg_unmerge(pkg_ctx, objs);
+		pkg_unmerge(pkg_ctx, objs, cp_argc, cp_argv, cpm_argc, cpm_argv);
  next_pkg:
 		q_vdb_close_pkg(pkg_ctx);
 	}
 
+	freeargv(cp_argc, cp_argv);
+	freeargv(cpm_argc, cpm_argv);
+
 	/* Clean up the package state */
 	free_sets(objs);
 	free(D);
@@ -1113,14 +1324,17 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
 		fclose(fp);
 	}
 
-	/* move the local vdb copy to the final place */
-	snprintf(buf, sizeof(buf), "%s%s/%s/", portroot, portvdb, pkg->CATEGORY);
-	mkdir_p(buf, 0755);
-	strcat(buf, pkg->PF);
-	if (rename("vdb", buf)) {
-		xasprintf(&p, "mv vdb '%s'", buf);
-		xsystem(p);
-		free(p);
+	if (!pretend) {
+		/* move the local vdb copy to the final place */
+		snprintf(buf, sizeof(buf), "%s%s/%s/",
+				portroot, portvdb, pkg->CATEGORY);
+		mkdir_p(buf, 0755);
+		strcat(buf, pkg->PF);
+		if (rename("vdb", buf)) {
+			xasprintf(&p, "mv vdb '%s'", buf);
+			xsystem(p);
+			free(p);
+		}
 	}
 
 	/* clean up our local temp dir */
@@ -1129,13 +1343,15 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
 	/* don't care about return */
 	rmdir("../qmerge");
 
-	printf("%s>>>%s %s%s%s/%s%s%s\n", YELLOW, NORM, WHITE, atom->CATEGORY, NORM, CYAN, atom->PN, NORM);
+	printf("%s>>>%s %s%s%s/%s%s%s\n",
+			YELLOW, NORM, WHITE, atom->CATEGORY, NORM, CYAN, atom->PN, NORM);
 
 	q_vdb_close(vdb_ctx);
 }
 
 static int
-pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep)
+pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep,
+		int cp_argc, char **cp_argv, int cpm_argc, char **cpm_argv)
 {
 	q_vdb_cat_ctx *cat_ctx = pkg_ctx->cat_ctx;
 	const char *cat = cat_ctx->name;
@@ -1147,15 +1363,15 @@ pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep)
 	char *buf;
 	FILE *fp;
 	int ret, portroot_fd;
-	int cp_argc, cpm_argc;
-	char **cp_argv, **cpm_argv;
 	llist_char *dirs = NULL;
+	bool unmerge_config_protected;
 
 	ret = 1;
 	buf = phases = NULL;
 	T = "${PWD}/temp";
 
-	printf("%s<<<%s %s%s%s/%s%s%s\n", YELLOW, NORM, WHITE, cat, NORM, CYAN, pkgname, NORM);
+	printf("%s<<<%s %s%s%s/%s%s%s\n",
+			YELLOW, NORM, WHITE, cat, NORM, CYAN, pkgname, NORM);
 
 	if (pretend == 100)
 		return 0;
@@ -1174,14 +1390,8 @@ pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep)
 		pkg_run_func_at(pkg_ctx->fd, ".", phases, "pkg_prerm", T, T);
 	}
 
-	/* XXX: be nice to pull this out of the current func
-	 *      so we don't keep reparsing the same env var
-	 *      when unmerging multiple packages.
-	 */
-	makeargv(config_protect, &cp_argc, &cp_argv);
-	makeargv(config_protect_mask, &cpm_argc, &cpm_argv);
-
-	bool unmerge_config_protected = !!strstr(features, "config-protect-if-modified");
+	unmerge_config_protected =
+		strstr(features, "config-protect-if-modified") != NULL;
 
 	while (getline(&buf, &buflen, fp) != -1) {
 		queue *q;
@@ -1194,7 +1404,8 @@ pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep)
 		if (!e)
 			continue;
 
-		protected = config_protected(e->name, cp_argc, cp_argv, cpm_argc, cpm_argv);
+		protected = config_protected(e->name,
+				cp_argc, cp_argv, cpm_argc, cpm_argv);
 
 		/* This should never happen ... */
 		assert(e->name[0] == '/' && e->name[1] != '/');
@@ -1213,16 +1424,19 @@ pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep)
 			case CONTENTS_OBJ:
 				if (protected && unmerge_config_protected) {
 					/* If the file wasn't modified, unmerge it */
-					unsigned char *hash = hash_file_at(portroot_fd, e->name + 1, HASH_MD5);
+					unsigned char *hash = hash_file_at(portroot_fd,
+							e->name + 1, HASH_MD5);
 					protected = strcmp(e->digest, (const char *)hash);
 					free(hash);
 				}
 				break;
 
 			case CONTENTS_SYM:
-				if (fstatat(portroot_fd, e->name + 1, &st, AT_SYMLINK_NOFOLLOW)) {
+				if (fstatat(portroot_fd,
+							e->name + 1, &st, AT_SYMLINK_NOFOLLOW)) {
 					if (errno != ENOENT) {
-						warnp("stat failed for %s -> '%s'", e->name, e->sym_target);
+						warnp("stat failed for %s -> '%s'",
+								e->name, e->sym_target);
 						continue;
 					} else
 						break;
@@ -1235,11 +1449,14 @@ pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep)
 				break;
 
 			default:
-				warn("%s???%s %s%s%s (%d)", RED, NORM, WHITE, e->name, NORM, e->type);
+				warn("%s???%s %s%s%s (%d)", RED, NORM,
+						WHITE, e->name, NORM, e->type);
 				continue;
 		}
 
-		snprintf(zing, sizeof(zing), "%s%s%s", protected ? YELLOW : GREEN, protected ? "***" : "<<<" , NORM);
+		snprintf(zing, sizeof(zing), "%s%s%s",
+				protected ? YELLOW : GREEN,
+				protected ? "***" : "<<<" , NORM);
 
 		if (protected) {
 			qprintf("%s %s\n", zing, e->name);
@@ -1264,7 +1481,7 @@ pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep)
 		if (!keep || q) {
 			char *p;
 
-			if (unlinkat(portroot_fd, e->name + 1, 0)) {
+			if (!pretend && unlinkat(portroot_fd, e->name + 1, 0)) {
 				/* If a file was already deleted, ignore the error */
 				if (errno != ENOENT)
 					errp("could not unlink: %s%s", portroot, e->name + 1);
@@ -1273,7 +1490,8 @@ pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep)
 			p = strrchr(e->name, '/');
 			if (p) {
 				*p = '\0';
-				rmdir_r_at(portroot_fd, e->name + 1);
+				if (!pretend)
+					rmdir_r_at(portroot_fd, e->name + 1);
 			}
 		}
 	}
@@ -1295,9 +1513,6 @@ pkg_unmerge(q_vdb_pkg_ctx *pkg_ctx, queue *keep)
 		free(list);
 	}
 
-	freeargv(cp_argc, cp_argv);
-	freeargv(cpm_argc, cpm_argv);
-
 	if (!pretend) {
 		/* Then execute the pkg_postrm step */
 		pkg_run_func_at(pkg_ctx->fd, ".", phases, "pkg_postrm", T, T);
@@ -1495,13 +1710,23 @@ static int
 qmerge_unmerge_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv)
 {
 	queue *todo = priv;
+	int cp_argc;
+	int cpm_argc;
+	char **cp_argv;
+	char **cpm_argv;
+
+	makeargv(config_protect, &cp_argc, &cp_argv);
+	makeargv(config_protect_mask, &cpm_argc, &cpm_argv);
 
 	while (todo) {
 		if (qlist_match(pkg_ctx, todo->name, NULL, true))
-			pkg_unmerge(pkg_ctx, NULL);
+			pkg_unmerge(pkg_ctx, NULL, cp_argc, cp_argv, cpm_argc, cpm_argv);
 		todo = todo->next;
 	}
 
+	freeargv(cp_argc, cp_argv);
+	freeargv(cpm_argc, cpm_argv);
+
 	return 0;
 }
 


             reply	other threads:[~2018-12-20 18:24 UTC|newest]

Thread overview: 592+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-20 18:24 Fabian Groffen [this message]
  -- strict thread matches above, loose matches on Subject: below --
2024-07-03 19:44 [gentoo-commits] proj/portage-utils:master commit in: / Fabian Groffen
2024-06-28 19:51 Fabian Groffen
2024-06-27 19:19 Fabian Groffen
2024-04-20 13:05 Fabian Groffen
2024-03-29 11:22 Fabian Groffen
2024-03-29 10:58 Fabian Groffen
2024-03-29 10:57 Fabian Groffen
2024-01-02 13:16 Fabian Groffen
2024-01-02 13:16 Fabian Groffen
2024-01-02  7:57 Fabian Groffen
2024-01-01 10:37 Fabian Groffen
2023-12-20 21:32 Mike Frysinger
2023-07-18  6:28 Fabian Groffen
2023-07-18  6:28 Fabian Groffen
2023-04-21 19:11 Fabian Groffen
2023-03-01 21:00 Fabian Groffen
2023-02-22 20:06 Fabian Groffen
2023-02-07  8:10 Fabian Groffen
2022-12-15  9:13 Fabian Groffen
2022-12-15  9:03 Fabian Groffen
2022-12-15  9:03 Fabian Groffen
2022-11-16  8:59 Fabian Groffen
2022-08-29  8:44 Fabian Groffen
2022-08-29  8:44 Fabian Groffen
2022-08-28 12:26 Fabian Groffen
2022-08-28 12:26 Fabian Groffen
2022-06-14  6:36 Fabian Groffen
2022-05-26 14:53 Fabian Groffen
2022-05-20 17:15 Fabian Groffen
2022-04-06 19:31 Fabian Groffen
2022-02-27 12:29 Fabian Groffen
2022-02-23 11:57 Fabian Groffen
2022-02-23 11:57 Fabian Groffen
2022-02-12 18:31 Fabian Groffen
2022-02-12 18:31 Fabian Groffen
2022-02-12 18:31 Fabian Groffen
2022-02-12 17:13 Fabian Groffen
2022-02-12 17:13 Fabian Groffen
2022-02-12 17:13 Fabian Groffen
2022-02-12 17:13 Fabian Groffen
2022-02-12 17:13 Fabian Groffen
2022-02-12 16:14 Fabian Groffen
2022-02-07  7:16 Fabian Groffen
2022-02-06 15:21 Fabian Groffen
2022-02-06 14:51 Fabian Groffen
2022-02-06 14:29 Fabian Groffen
2022-02-06 14:29 Fabian Groffen
2022-01-31  8:01 Fabian Groffen
2021-12-31 15:36 Fabian Groffen
2021-12-31 15:36 Fabian Groffen
2021-12-31 15:36 Fabian Groffen
2021-12-29 12:20 Fabian Groffen
2021-12-27 18:13 Fabian Groffen
2021-12-26 13:59 Fabian Groffen
2021-12-25  9:15 Fabian Groffen
2021-12-23 12:55 Fabian Groffen
2021-12-21 11:30 Fabian Groffen
2021-12-13  8:39 Fabian Groffen
2021-12-13  8:39 Fabian Groffen
2021-12-13  8:39 Fabian Groffen
2021-11-13 14:27 Fabian Groffen
2021-11-13 14:27 Fabian Groffen
2021-11-07 10:53 Fabian Groffen
2021-10-09 12:03 Fabian Groffen
2021-10-03 11:15 Fabian Groffen
2021-10-03  8:54 Fabian Groffen
2021-09-27 18:14 Fabian Groffen
2021-07-06  6:43 Fabian Groffen
2021-07-05  8:40 Fabian Groffen
2021-07-01 10:07 Fabian Groffen
2021-07-01 10:05 Fabian Groffen
2021-06-30  6:26 Fabian Groffen
2021-06-24  6:44 Fabian Groffen
2021-06-23  7:14 Fabian Groffen
2021-06-21 20:04 Fabian Groffen
2021-06-17  6:27 Fabian Groffen
2021-06-16 20:11 Fabian Groffen
2021-06-16 19:21 Fabian Groffen
2021-06-16 19:21 Fabian Groffen
2021-06-16 19:21 Fabian Groffen
2021-06-16 19:21 Fabian Groffen
2021-06-16 19:21 Fabian Groffen
2021-06-16 19:21 Fabian Groffen
2021-06-16 19:19 Fabian Groffen
2021-06-01 19:43 Fabian Groffen
2021-06-01 19:43 Fabian Groffen
2021-05-31 19:14 Fabian Groffen
2021-05-15 12:19 Fabian Groffen
2021-05-10  9:16 Fabian Groffen
2021-05-02 11:32 Fabian Groffen
2021-05-02 11:25 Fabian Groffen
2021-05-02 11:25 Fabian Groffen
2021-05-01 19:32 Fabian Groffen
2021-05-01  8:40 Fabian Groffen
2021-03-13 20:32 Fabian Groffen
2021-02-20 12:06 Fabian Groffen
2021-02-20 11:44 Fabian Groffen
2021-02-20 11:44 Fabian Groffen
2021-02-17 20:23 Fabian Groffen
2020-11-29  9:13 Fabian Groffen
2020-11-21 10:53 Fabian Groffen
2020-11-21 10:45 Fabian Groffen
2020-11-21 10:00 Fabian Groffen
2020-11-21  9:53 Fabian Groffen
2020-11-21  8:53 Fabian Groffen
2020-11-14 17:06 Fabian Groffen
2020-11-14 17:06 Fabian Groffen
2020-11-13  9:32 Fabian Groffen
2020-10-04 19:30 Fabian Groffen
2020-10-04 19:06 Fabian Groffen
2020-10-04 18:46 Fabian Groffen
2020-10-04 18:44 Fabian Groffen
2020-10-04 12:33 Fabian Groffen
2020-10-04 11:54 Fabian Groffen
2020-10-04 11:31 Fabian Groffen
2020-10-04 11:09 Fabian Groffen
2020-08-17 14:34 Fabian Groffen
2020-08-17 13:08 Fabian Groffen
2020-08-17 13:08 Fabian Groffen
2020-08-14 10:44 Fabian Groffen
2020-08-14 10:09 Fabian Groffen
2020-08-14  9:35 Fabian Groffen
2020-08-14  9:35 Fabian Groffen
2020-08-02  7:39 Fabian Groffen
2020-07-08  8:12 Fabian Groffen
2020-06-28 19:11 Fabian Groffen
2020-06-28 15:58 Fabian Groffen
2020-06-27  9:38 Fabian Groffen
2020-06-27  9:38 Fabian Groffen
2020-05-25 19:01 Fabian Groffen
2020-05-25 18:29 Fabian Groffen
2020-05-25 18:25 Fabian Groffen
2020-05-25 18:08 Fabian Groffen
2020-05-25 18:05 Fabian Groffen
2020-05-25 11:20 Fabian Groffen
2020-05-25 11:12 Fabian Groffen
2020-05-25 10:43 Fabian Groffen
2020-05-25 10:43 Fabian Groffen
2020-05-21 11:13 Fabian Groffen
2020-05-17 12:35 Fabian Groffen
2020-05-17 12:35 Fabian Groffen
2020-05-17 12:35 Fabian Groffen
2020-05-17 12:35 Fabian Groffen
2020-05-17  8:27 Fabian Groffen
2020-05-17  8:27 Fabian Groffen
2020-05-17  8:15 Fabian Groffen
2020-05-16 18:51 Fabian Groffen
2020-05-16 14:30 Fabian Groffen
2020-05-16 13:06 Fabian Groffen
2020-05-16 13:06 Fabian Groffen
2020-05-02  8:45 Fabian Groffen
2020-04-27  7:46 Fabian Groffen
2020-02-21  8:50 Fabian Groffen
2020-02-21  8:18 Fabian Groffen
2020-01-31 14:45 Fabian Groffen
2020-01-31 13:26 Fabian Groffen
2020-01-31 13:26 Fabian Groffen
2020-01-31 13:26 Fabian Groffen
2020-01-31 10:49 Fabian Groffen
2020-01-31 10:49 Fabian Groffen
2020-01-31 10:49 Fabian Groffen
2020-01-26 19:31 Fabian Groffen
2020-01-25 12:20 Fabian Groffen
2020-01-25 12:20 Fabian Groffen
2020-01-25 12:11 Fabian Groffen
2020-01-25 10:01 Fabian Groffen
2020-01-25  9:45 Fabian Groffen
2020-01-25  9:11 Fabian Groffen
2020-01-25  9:11 Fabian Groffen
2020-01-25  9:03 Fabian Groffen
2020-01-25  9:03 Fabian Groffen
2020-01-25  9:03 Fabian Groffen
2020-01-25  9:03 Fabian Groffen
2020-01-25  9:03 Fabian Groffen
2020-01-22 20:11 Fabian Groffen
2020-01-22 20:11 Fabian Groffen
2020-01-22 20:11 Fabian Groffen
2020-01-22 20:04 Fabian Groffen
2020-01-22 20:04 Fabian Groffen
2020-01-22 20:04 Fabian Groffen
2020-01-22 20:04 Fabian Groffen
2020-01-22 19:54 Fabian Groffen
2020-01-22 19:54 Fabian Groffen
2020-01-22 19:54 Fabian Groffen
2020-01-22 19:54 Fabian Groffen
2020-01-22 19:54 Fabian Groffen
2020-01-22 19:54 Fabian Groffen
2020-01-22 19:54 Fabian Groffen
2020-01-20 19:54 Fabian Groffen
2020-01-19 19:36 Fabian Groffen
2020-01-19 19:36 Fabian Groffen
2020-01-19 19:36 Fabian Groffen
2020-01-19 19:36 Fabian Groffen
2020-01-19 19:36 Fabian Groffen
2020-01-19 19:36 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 16:40 Fabian Groffen
2020-01-19 16:37 Fabian Groffen
2020-01-19 16:37 Fabian Groffen
2020-01-19 12:37 Fabian Groffen
2020-01-19 12:37 Fabian Groffen
2020-01-19 12:37 Fabian Groffen
2020-01-19 12:37 Fabian Groffen
2020-01-19 12:37 Fabian Groffen
2020-01-19 12:37 Fabian Groffen
2020-01-19 12:37 Fabian Groffen
2020-01-19 12:37 Fabian Groffen
2020-01-18 13:09 Fabian Groffen
2020-01-06  8:03 Fabian Groffen
2020-01-06  7:36 Fabian Groffen
2020-01-05 16:08 Fabian Groffen
2020-01-05 16:08 Fabian Groffen
2020-01-05 16:08 Fabian Groffen
2020-01-05 13:28 Fabian Groffen
2020-01-04 20:02 Fabian Groffen
2020-01-04 19:48 Fabian Groffen
2020-01-04 13:28 Fabian Groffen
2020-01-04 10:44 Fabian Groffen
2020-01-04 10:38 Fabian Groffen
2020-01-04 10:27 Fabian Groffen
2020-01-04 10:20 Fabian Groffen
2020-01-03 15:05 Fabian Groffen
2020-01-03 14:58 Fabian Groffen
2020-01-03 10:36 Fabian Groffen
2020-01-02 20:27 Fabian Groffen
2020-01-02 20:00 Fabian Groffen
2020-01-02 15:32 Fabian Groffen
2020-01-02 15:09 Fabian Groffen
2020-01-02 15:09 Fabian Groffen
2020-01-02 14:07 Fabian Groffen
2020-01-02 14:07 Fabian Groffen
2020-01-02 14:07 Fabian Groffen
2020-01-02 14:07 Fabian Groffen
2020-01-02 11:55 Fabian Groffen
2020-01-02  9:47 Fabian Groffen
2020-01-01 19:57 Fabian Groffen
2019-12-31  9:10 Fabian Groffen
2019-12-31  9:05 Fabian Groffen
2019-12-29 12:35 Fabian Groffen
2019-12-29  9:57 Fabian Groffen
2019-12-27 21:45 Fabian Groffen
2019-12-27 21:14 Fabian Groffen
2019-12-27 19:16 Fabian Groffen
2019-12-14 17:01 Fabian Groffen
2019-12-14 17:01 Fabian Groffen
2019-12-14 17:01 Fabian Groffen
2019-12-08 11:53 Fabian Groffen
2019-11-29 13:56 Fabian Groffen
2019-11-29 13:22 Fabian Groffen
2019-11-25 19:51 Fabian Groffen
2019-11-25 19:39 Fabian Groffen
2019-11-19 20:28 Fabian Groffen
2019-11-19 20:28 Fabian Groffen
2019-11-17 15:12 Fabian Groffen
2019-11-17 15:12 Fabian Groffen
2019-11-17 15:12 Fabian Groffen
2019-11-17 15:12 Fabian Groffen
2019-11-17 15:12 Fabian Groffen
2019-11-15 13:52 Fabian Groffen
2019-11-13 18:19 Fabian Groffen
2019-11-13 12:59 Fabian Groffen
2019-11-13 12:53 Fabian Groffen
2019-11-13 12:53 Fabian Groffen
2019-11-09 10:35 Fabian Groffen
2019-10-27 12:23 Fabian Groffen
2019-10-20 10:11 Fabian Groffen
2019-10-12 12:47 Fabian Groffen
2019-10-03 11:50 Fabian Groffen
2019-09-29 12:18 Fabian Groffen
2019-09-28 13:28 Fabian Groffen
2019-09-28 13:06 Fabian Groffen
2019-09-26 19:28 Fabian Groffen
2019-09-26 19:28 Fabian Groffen
2019-09-26 14:06 Fabian Groffen
2019-09-26 14:06 Fabian Groffen
2019-09-21 20:23 Fabian Groffen
2019-09-21 20:17 Fabian Groffen
2019-09-21 19:53 Fabian Groffen
2019-09-10 18:25 Fabian Groffen
2019-08-17  8:37 Fabian Groffen
2019-07-18 17:55 Fabian Groffen
2019-07-14 18:51 Fabian Groffen
2019-07-14 16:27 Fabian Groffen
2019-07-14 16:27 Fabian Groffen
2019-07-14 16:00 Fabian Groffen
2019-07-14 13:09 Fabian Groffen
2019-07-14 13:09 Fabian Groffen
2019-07-14  8:37 Fabian Groffen
2019-06-27  8:54 Fabian Groffen
2019-06-26 19:32 Fabian Groffen
2019-06-19 10:44 Fabian Groffen
2019-06-13 10:52 Fabian Groffen
2019-06-13  9:28 Fabian Groffen
2019-06-13  8:41 Fabian Groffen
2019-06-11 17:55 Fabian Groffen
2019-06-10 18:38 Fabian Groffen
2019-06-10 15:29 Fabian Groffen
2019-06-10 13:31 Fabian Groffen
2019-06-10 12:50 Fabian Groffen
2019-06-10 10:12 Fabian Groffen
2019-06-10 10:09 Fabian Groffen
2019-06-10 10:09 Fabian Groffen
2019-06-10 10:09 Fabian Groffen
2019-06-10 10:09 Fabian Groffen
2019-06-10 10:09 Fabian Groffen
2019-06-09  9:23 Fabian Groffen
2019-06-08 18:42 Fabian Groffen
2019-06-08 18:25 Fabian Groffen
2019-06-08 18:13 Fabian Groffen
2019-06-08 18:13 Fabian Groffen
2019-06-08 18:13 Fabian Groffen
2019-06-08 18:13 Fabian Groffen
2019-06-07 12:20 Fabian Groffen
2019-06-06 13:52 Fabian Groffen
2019-06-06 13:46 Fabian Groffen
2019-06-06 13:46 Fabian Groffen
2019-06-06  8:14 Fabian Groffen
2019-06-05  7:57 Fabian Groffen
2019-05-30 10:23 Fabian Groffen
2019-05-30 10:09 Fabian Groffen
2019-05-30  8:55 Fabian Groffen
2019-05-25 16:04 Fabian Groffen
2019-05-25 14:54 Fabian Groffen
2019-05-25 14:04 Fabian Groffen
2019-05-25 12:19 Fabian Groffen
2019-05-24 12:26 Fabian Groffen
2019-05-22  8:54 Fabian Groffen
2019-05-21 14:42 Fabian Groffen
2019-05-21 14:37 Fabian Groffen
2019-05-21 14:12 Fabian Groffen
2019-05-21 14:12 Fabian Groffen
2019-05-20 12:15 Fabian Groffen
2019-05-20 10:46 Fabian Groffen
2019-05-16 17:13 Fabian Groffen
2019-05-16 17:13 Fabian Groffen
2019-05-16 17:13 Fabian Groffen
2019-05-16 17:13 Fabian Groffen
2019-05-16 13:18 Fabian Groffen
2019-05-15  9:42 Fabian Groffen
2019-05-13 13:39 Fabian Groffen
2019-05-12  9:58 Fabian Groffen
2019-05-12  9:58 Fabian Groffen
2019-05-12  9:58 Fabian Groffen
2019-05-11 11:11 Fabian Groffen
2019-05-11  7:14 Fabian Groffen
2019-05-11  7:14 Fabian Groffen
2019-05-11  7:14 Fabian Groffen
2019-05-11  7:14 Fabian Groffen
2019-05-10 15:32 Fabian Groffen
2019-05-10 15:32 Fabian Groffen
2019-05-10  7:30 Fabian Groffen
2019-05-10  7:30 Fabian Groffen
2019-05-10  7:30 Fabian Groffen
2019-05-07  6:19 Fabian Groffen
2019-05-07  6:19 Fabian Groffen
2019-05-06 16:04 Fabian Groffen
2019-05-06  6:41 Fabian Groffen
2019-05-04 17:23 Fabian Groffen
2019-05-04 11:53 Fabian Groffen
2019-05-03 11:45 Fabian Groffen
2019-05-03  8:50 Fabian Groffen
2019-05-03  8:50 Fabian Groffen
2019-05-03  8:50 Fabian Groffen
2019-05-03  8:50 Fabian Groffen
2019-05-02 16:09 Fabian Groffen
2019-05-02  8:29 Fabian Groffen
2019-04-30  8:02 Fabian Groffen
2019-04-30  7:54 Fabian Groffen
2019-04-28 18:10 Fabian Groffen
2019-04-27  9:01 Fabian Groffen
2019-04-27  8:33 Fabian Groffen
2019-04-25 17:36 Fabian Groffen
2019-04-25  9:48 Fabian Groffen
2019-04-25  9:48 Fabian Groffen
2019-04-25  9:48 Fabian Groffen
2019-04-25  9:22 Fabian Groffen
2019-04-25  9:22 Fabian Groffen
2019-04-25  9:22 Fabian Groffen
2019-04-25  9:22 Fabian Groffen
2019-04-14 10:52 Fabian Groffen
2019-03-27 20:52 Fabian Groffen
2019-03-27 20:37 Fabian Groffen
2019-03-27 20:18 Fabian Groffen
2019-03-18 13:14 Fabian Groffen
2019-03-18 13:14 Fabian Groffen
2019-03-18 13:14 Fabian Groffen
2019-03-12  8:05 Fabian Groffen
2019-03-01 13:51 Fabian Groffen
2019-02-28 18:37 Fabian Groffen
2019-02-28 18:37 Fabian Groffen
2019-02-27 21:18 Fabian Groffen
2019-02-27 20:53 Fabian Groffen
2019-02-23 15:22 Fabian Groffen
2018-12-28  9:08 Fabian Groffen
2018-12-24 16:02 Fabian Groffen
2018-12-20 18:24 Fabian Groffen
2018-12-09 10:42 Fabian Groffen
2018-11-20 14:25 Fabian Groffen
2018-10-26 13:50 Fabian Groffen
2018-10-26 13:50 Fabian Groffen
2018-08-06  7:25 Fabian Groffen
2018-08-06  7:25 Fabian Groffen
2018-08-01 13:28 Fabian Groffen
2018-07-18 20:20 Fabian Groffen
2018-06-28  9:35 Fabian Groffen
2018-06-28  9:35 Fabian Groffen
2018-05-18 16:58 Fabian Groffen
2018-05-18 12:19 Fabian Groffen
2018-05-18 12:19 Fabian Groffen
2018-05-18 10:15 Fabian Groffen
2018-04-18 13:58 Fabian Groffen
2018-04-17 20:12 Fabian Groffen
2018-04-15 15:41 Fabian Groffen
2018-04-15 15:38 Fabian Groffen
2018-04-09  7:15 Fabian Groffen
2018-04-09  7:15 Fabian Groffen
2018-04-04 13:16 Fabian Groffen
2018-04-03 20:13 Fabian Groffen
2018-04-03 13:39 Fabian Groffen
2018-04-02 17:27 Fabian Groffen
2018-04-01 10:22 Fabian Groffen
2018-04-01 10:22 Fabian Groffen
2018-03-31  6:54 Fabian Groffen
2018-03-31  6:54 Fabian Groffen
2018-03-31  6:54 Fabian Groffen
2018-03-31  6:54 Fabian Groffen
2018-03-30  5:56 Fabian Groffen
2018-03-30  5:56 Fabian Groffen
2018-03-26 19:08 Fabian Groffen
2018-03-25 14:00 Fabian Groffen
2018-03-23 20:17 Fabian Groffen
2018-03-23 20:17 Fabian Groffen
2018-03-23 15:27 Fabian Groffen
2018-03-23 15:27 Fabian Groffen
2018-03-23 13:17 Fabian Groffen
2018-03-23 11:29 Fabian Groffen
2018-03-23 11:08 Fabian Groffen
2018-03-23  9:37 Fabian Groffen
2018-01-08 12:33 Fabian Groffen
2018-01-08 12:33 Fabian Groffen
2017-12-29 11:45 Fabian Groffen
2017-12-29 11:45 Fabian Groffen
2017-12-29 11:45 Fabian Groffen
2017-11-27  7:55 Robin H. Johnson
2017-11-27  7:55 Robin H. Johnson
2017-02-07  3:03 Mike Frysinger
2016-12-29  2:33 Mike Frysinger
2016-12-29  2:25 Mike Frysinger
2016-12-29  2:25 Mike Frysinger
2016-12-29  2:25 Mike Frysinger
2016-12-29  2:25 Mike Frysinger
2016-12-29  2:25 Mike Frysinger
2016-12-29  2:25 Mike Frysinger
2016-12-20 19:15 Mike Frysinger
2016-12-20 16:55 Mike Frysinger
2016-11-27  5:46 Mike Frysinger
2016-11-27  5:46 Mike Frysinger
2016-11-27  5:46 Mike Frysinger
2016-11-27  1:52 Mike Frysinger
2016-11-27  1:50 Mike Frysinger
2016-11-27  0:00 Mike Frysinger
2016-11-26 23:48 Mike Frysinger
2016-11-26 23:46 Mike Frysinger
2016-11-26 23:24 Mike Frysinger
2016-11-26 23:17 Mike Frysinger
2016-11-15  3:34 Mike Frysinger
2016-11-15  3:34 Mike Frysinger
2016-11-15  3:34 Mike Frysinger
2016-11-15  3:34 Mike Frysinger
2016-11-15  3:34 Mike Frysinger
2016-11-12 17:17 Mike Frysinger
2016-06-21 20:53 Mike Frysinger
2016-06-20  3:22 Mike Frysinger
2016-04-04 15:47 Mike Frysinger
2016-04-01 21:42 Mike Frysinger
2016-04-01 21:42 Mike Frysinger
2016-03-28  4:53 Mike Frysinger
2016-03-28  4:53 Mike Frysinger
2016-03-28  4:53 Mike Frysinger
2016-02-22 20:37 Mike Frysinger
2016-02-22 20:37 Mike Frysinger
2016-02-22 20:37 Mike Frysinger
2016-02-22 20:37 Mike Frysinger
2016-02-17  7:15 Mike Frysinger
2016-02-14  1:26 Mike Frysinger
2016-02-14  1:26 Mike Frysinger
2016-02-14  1:26 Mike Frysinger
2016-01-29  5:53 Mike Frysinger
2016-01-05  0:25 Mike Frysinger
2015-12-17  5:06 Mike Frysinger
2015-12-17  5:06 Mike Frysinger
2015-12-17  5:06 Mike Frysinger
2015-12-17  5:06 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-28  2:44 Mike Frysinger
2015-11-26 10:52 Mike Frysinger
2015-11-26 10:52 Mike Frysinger
2015-11-26 10:39 Mike Frysinger
2015-11-26 10:39 Mike Frysinger
2015-11-26 10:39 Mike Frysinger
2015-11-26 10:39 Mike Frysinger
2015-11-26 10:39 Mike Frysinger
2015-11-26 10:39 Mike Frysinger
2015-11-26 10:39 Mike Frysinger
2015-11-26  8:59 Mike Frysinger
2015-11-26  8:00 Mike Frysinger
2015-09-15 18:27 Mike Frysinger
2015-06-23  8:58 Mike Frysinger
2015-06-06  6:20 Mike Frysinger
2015-06-06  6:20 Mike Frysinger
2015-06-06  6:20 Mike Frysinger
2015-06-06  6:20 Mike Frysinger
2015-06-03 15:44 Mike Frysinger
2015-06-03 15:44 Mike Frysinger
2015-05-31  8:31 Mike Frysinger
2015-05-19 17:37 Mike Frysinger
2015-05-19 17:37 Mike Frysinger
2015-05-19 17:37 Mike Frysinger
2015-05-19 17:37 Mike Frysinger
2015-05-19 17:37 Mike Frysinger
2015-05-19 17:37 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-21 18:06 Mike Frysinger
2015-02-21  0:00 Mike Frysinger
2015-02-21  0:00 Mike Frysinger
2015-02-20 22:28 Mike Frysinger
2015-02-19  7:49 Mike Frysinger
2014-10-19 16:56 Mike Frysinger
2014-06-16 18:01 Mike Frysinger
2014-03-16  6:34 Mike Frysinger
2014-03-16  6:34 Mike Frysinger
2014-03-16  6:14 Mike Frysinger
2014-03-16  6:14 Mike Frysinger
2014-03-16  6:14 Mike Frysinger
2014-03-15  6:02 Mike Frysinger
2014-03-11  4:53 Mike Frysinger
2014-03-11  4:53 Mike Frysinger
2014-03-10  8:45 Mike Frysinger
2014-03-10  8:45 Mike Frysinger
2014-03-10  8:45 Mike Frysinger
2014-03-10  6:00 Mike Frysinger
2014-03-10  6:00 Mike Frysinger
2014-03-10  6:00 Mike Frysinger
2014-03-10  6:00 Mike Frysinger
2014-03-10  6:00 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1545330270.e3d45aadf559ba2ff9c929715bbeade5a42e3634.grobian@gentoo \
    --to=grobian@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox