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: /, man/
Date: Sun, 27 Oct 2019 12:22:28 +0000 (UTC)	[thread overview]
Message-ID: <1572178746.c9d7b9de78f1488827cb516bf61a54df28a750ab.grobian@gentoo> (raw)

commit:     c9d7b9de78f1488827cb516bf61a54df28a750ab
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Sun Oct 27 12:19:06 2019 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Sun Oct 27 12:19:06 2019 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=c9d7b9de

qlop: take two at implementing currently running merges

Probe /proc filesystem for running merges, and use the atoms found there
to select the packages to list.  In addition, prune any operations that
started > 10 days ago so there will be some sort of convergence.

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

 main.c     |   3 +-
 man/qlop.1 |   4 +-
 qlop.c     | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 173 insertions(+), 9 deletions(-)

diff --git a/main.c b/main.c
index 5d4c4cd..0b827fc 100644
--- a/main.c
+++ b/main.c
@@ -501,7 +501,8 @@ read_portage_env_file(const char *configroot, const char *file, env_vars vars[])
 				source_len = strlen(sfile);
 
 				if (buflen <= source_len + file_path_len)
-					buf = xrealloc(buf, buflen = source_len + file_path_len + 1);
+					buf = xrealloc(buf,
+							buflen = source_len + file_path_len + 1);
 				memmove(buf + file_path_len, buf + 7, source_len + 1);
 				memcpy(buf, file, file_path_len);
 				sfile = buf;

diff --git a/man/qlop.1 b/man/qlop.1
index de1e525..58efd09 100644
--- a/man/qlop.1
+++ b/man/qlop.1
@@ -1,5 +1,5 @@
 .\" generated by mkman.py, please do NOT edit!
-.TH qlop "1" "Sep 2019" "Gentoo Foundation" "qlop"
+.TH qlop "1" "Oct 2019" "Gentoo Foundation" "qlop"
 .SH NAME
 qlop \- emerge log analyzer
 .SH SYNOPSIS
@@ -51,7 +51,7 @@ Print elapssed time in human readable format.  This form uses
 minutes, hours and days instead of just seconds.
 .TP
 \fB\-M\fR, \fB\-\-machine\fR
-Print elapsed time as seconds with no formatting.
+Print start/elapsed time as seconds with no formatting.
 .TP
 \fB\-m\fR, \fB\-\-merge\fR
 Show merge history.

diff --git a/qlop.c b/qlop.c
index 7a93656..6cb2c04 100644
--- a/qlop.c
+++ b/qlop.c
@@ -16,9 +16,11 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <limits.h>
+#include <sys/stat.h>
 
 #include "atom.h"
 #include "eat_file.h"
+#include "scandirat.h"
 #include "set.h"
 #include "xarray.h"
 #include "xasprintf.h"
@@ -51,7 +53,7 @@ static const char * const qlop_opts_help[] = {
 	"Print time taken to complete action",
 	"Print average time taken to complete action",
 	"Print elapsed time in human readable format (use with -t or -a)",
-	"Print elapsed time as seconds with no formatting",
+	"Print start/elapsed time as seconds with no formatting",
 	"Show merge history",
 	"Show unmerge history",
 	"Show autoclean unmerge history",
@@ -201,10 +203,15 @@ parse_date(const char *sdate, time_t *t)
 static char _date_buf[48];
 static char *fmt_date(struct qlop_mode *flags, time_t ts, time_t te)
 {
-	time_t t;
+	time_t t = flags->do_endtime ? te : ts;
+
+	if (flags->do_machine)
+		snprintf(_date_buf, sizeof(_date_buf),
+				"%zd", (size_t)t);
+	else
+		strftime(_date_buf, sizeof(_date_buf),
+				"%Y-%m-%dT%H:%M:%S", localtime(&t));
 
-	t = flags->do_endtime ? te : ts;
-	strftime(_date_buf, sizeof(_date_buf), "%Y-%m-%dT%H:%M:%S", localtime(&t));
 	return _date_buf;
 }
 
@@ -336,6 +343,21 @@ New format:
 1550953125:  >>> unmerge success: app-admin/pwgen-2.08
 1550953125:  *** exiting successfully.
 1550953125:  *** terminating.
+
+
+Currently running merges can be found in the /proc filesystem:
+- Linux: readlink(/proc/<pid>/fd/X)
+- Solaris: readlink(/proc/<pid>/path/X)
+from here a file should be there that points to the build.log file
+$CAT/$P/work/build.log.  If so, it's running for $CAT/$P.
+This requires being the portage user though, or root.
+
+Should there be no /proc, we can deduce from the log whether a package
+is being emerged, if and only if, there are no parallel merges, and
+portage never got interrupted in a way where it could not write its
+interruption to the log.  Unfortunately these scenarios happen a lot.
+As such, we can try to remedy this somewhat by using a rule of thumb
+that currently merging packages need to be withinin the last 10 days.
 */
 static int do_emerge_log(
 		const char *log,
@@ -463,6 +485,7 @@ static int do_emerge_log(
 		tbegin = last_merge;
 		tend = tstart;
 	}
+
 	/* loop over lines searching for atoms */
 	while (fgets(buf, sizeof(buf), fp) != NULL) {
 		if ((p = strchr(buf, ':')) == NULL)
@@ -821,11 +844,19 @@ static int do_emerge_log(
 	}
 	fclose(fp);
 	if (flags->do_running) {
+		time_t cutofftime;
+
+		/* emerge.log can be interrupted, incorrect and hopelessly lost,
+		 * so to eliminate some unfinished crap from there, we just
+		 * ignore anything that's > cutofftime, 10 days for now. */
+		cutofftime = 10 * 24 * 60 * 60;  /* when we consider entries stale */
+
 		/* can't report endtime for non-finished operations */
 		flags->do_endtime = 0;
 		tstart = time(NULL);
 		sync_time /= sync_cnt;
-		if (sync_start > 0) {
+		if (sync_start >= tstart - cutofftime) {
+			elapsed = tstart - sync_start;
 			if (elapsed >= sync_time)
 				sync_time = 0;
 			if (flags->do_time) {
@@ -847,6 +878,9 @@ static int do_emerge_log(
 			time_t maxtime = 0;
 			bool isMax = false;
 
+			if (pkgw->tbegin < tstart - cutofftime)
+				continue;
+
 			snprintf(afmt, sizeof(afmt), "%s/%s",
 					pkgw->atom->CATEGORY, pkgw->atom->PN);
 
@@ -891,6 +925,9 @@ static int do_emerge_log(
 			time_t maxtime = 0;
 			bool isMax = false;
 
+			if (pkgw->tbegin < tstart - cutofftime)
+				continue;
+
 			snprintf(afmt, sizeof(afmt), "%s/%s",
 					pkgw->atom->CATEGORY, pkgw->atom->PN);
 
@@ -978,6 +1015,118 @@ static int do_emerge_log(
 	return 0;
 }
 
+/* scan through /proc for running merges, this requires portage user
+ * or root */
+static array_t *probe_proc(array_t *atoms)
+{
+	struct dirent **procs;
+	int procslen;
+	int pi;
+	struct dirent **links;
+	int linkslen;
+	int li;
+	struct dirent *d;
+	char npath[_Q_PATH_MAX * 2];
+	char rpath[_Q_PATH_MAX];
+	const char *subdir = NULL;
+	const char *pid;
+	ssize_t rpathlen;
+	char *p;
+	depend_atom *atom;
+	DECLARE_ARRAY(ret_atoms);
+	size_t i;
+
+	/* /proc/<pid>/path/<[0-9]+link>
+	 * /proc/<pid>/fd/<[0-9]+link> */
+	if ((procslen = scandir("/proc", &procs, NULL, NULL)) > 0) {
+		for (pi = 0; pi < procslen; pi++) {
+			d = procs[pi];
+			/* must be [0-9]+ */
+			if (d->d_name[0] < '0' || d->d_name[0] > '9')
+				continue;
+
+			if (subdir == NULL) {
+				struct stat st;
+
+				snprintf(npath, sizeof(npath), "/proc/%s/path", d->d_name);
+				if (stat(npath, &st) < 0)
+					subdir = "fd";
+				else
+					subdir = "path";
+			}
+
+			pid = d->d_name;
+			snprintf(npath, sizeof(npath), "/proc/%s/%s", pid, subdir);
+			if ((linkslen = scandir(npath, &links, NULL, NULL)) > 0) {
+				for (li = 0; li < linkslen; li++) {
+					d = links[li];
+					/* must be [0-9]+ */
+					if (d->d_name[0] < '0' || d->d_name[0] > '9')
+						continue;
+					snprintf(npath, sizeof(npath), "/proc/%s/%s/%s",
+							pid, subdir, d->d_name);
+					rpathlen = readlink(npath, rpath, sizeof(rpath));
+					if (rpathlen <= 0)
+						continue;
+					rpath[rpathlen] = '\0';
+					/* check if this points to a portage build:
+					 * <somepath>/portage/<cat>/<pf>/temp/build.log */
+					if (strcmp(rpath + rpathlen -
+								(sizeof("/temp/build.log") - 1),
+								"/temp/build.log") == 0 &&
+							(p = strstr(rpath, "/portage/")) != NULL)
+					{
+						p += sizeof("/portage/") - 1;
+						rpath[rpathlen - (sizeof("/temp/build.log") - 1)] =
+							'\0';
+						atom = atom_explode(p);
+						if (atom == NULL ||
+								atom->CATEGORY == NULL || atom->P == NULL)
+						{
+							if (atom != NULL)
+								atom_implode(atom);
+							continue;
+						}
+						xarraypush_ptr(ret_atoms, atom);
+					}
+				}
+				scandir_free(links, linkslen);
+			}
+		}
+		scandir_free(procs, procslen);
+	} else {
+		/* flag /proc doesn't exist */
+		return NULL;
+	}
+
+	if (array_cnt(atoms) > 0) {
+		size_t j;
+		depend_atom *atomr;
+
+		/* calculate intersection */
+		array_for_each(atoms, i, atom) {
+			array_for_each(ret_atoms, j, atomr) {
+				if (atom_compare(atomr, atom) != EQUAL) {
+					xarraydelete_ptr(ret_atoms, j);
+					atom_implode(atomr);
+					break;
+				}
+			}
+			atom_implode(atom);
+		}
+		xarrayfree_int(atoms);
+	}
+
+	/* ret_atoms is allocated on the stack, so copy into atoms which is
+	 * empty at this point */
+	array_for_each(ret_atoms, i, atom)
+		xarraypush_ptr(atoms, atom);
+
+	xarrayfree_int(ret_atoms);
+
+	return atoms;
+}
+
 int qlop_main(int argc, char **argv)
 {
 	size_t i;
@@ -1160,7 +1309,21 @@ int qlop_main(int argc, char **argv)
 			m.fmt = "%[CATEGORY]%[PN]";
 	}
 
-	do_emerge_log(logfile, &m, atoms, start_time, end_time);
+	if (m.do_running) {
+		array_t *new_atoms = probe_proc(atoms);
+
+		if (new_atoms != NULL && array_cnt(new_atoms) == 0) {
+			/* proc supported, found nothing running */
+			start_time = LONG_MAX;
+		} else {
+			warn("/proc not available, deducing running "
+					"merges from emerge.log");
+		}
+
+	}
+
+	if (start_time < LONG_MAX)
+		do_emerge_log(logfile, &m, atoms, start_time, end_time);
 
 	array_for_each(atoms, i, atom)
 		atom_implode(atom);


             reply	other threads:[~2019-10-27 12:22 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-27 12:22 Fabian Groffen [this message]
  -- strict thread matches above, loose matches on Subject: below --
2020-05-02  8:45 [gentoo-commits] proj/portage-utils:master commit in: /, man/ Fabian Groffen
2020-01-06 15:03 Fabian Groffen
2019-12-14 17:01 Fabian Groffen
2019-11-24 12:29 Fabian Groffen
2019-11-09 10:13 Fabian Groffen
2019-09-28 13:19 Fabian Groffen
2019-09-10 18:25 Fabian Groffen
2019-07-14 13:09 Fabian Groffen
2019-07-14 10:21 Fabian Groffen
2019-07-14 10:21 Fabian Groffen
2019-07-14 10:21 Fabian Groffen
2019-07-14 10:21 Fabian Groffen
2019-05-20 10:46 Fabian Groffen
2016-03-28  4:53 Mike Frysinger
2016-02-22 20:37 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=1572178746.c9d7b9de78f1488827cb516bf61a54df28a750ab.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