Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage-utils:master commit in: /, man/
Date: Sun, 27 Oct 2019 12:22:33
Message-Id: 1572178746.c9d7b9de78f1488827cb516bf61a54df28a750ab.grobian@gentoo
1 commit: c9d7b9de78f1488827cb516bf61a54df28a750ab
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Sun Oct 27 12:19:06 2019 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Sun Oct 27 12:19:06 2019 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=c9d7b9de
7
8 qlop: take two at implementing currently running merges
9
10 Probe /proc filesystem for running merges, and use the atoms found there
11 to select the packages to list. In addition, prune any operations that
12 started > 10 days ago so there will be some sort of convergence.
13
14 Bug: https://bugs.gentoo.org/698196
15 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
16
17 main.c | 3 +-
18 man/qlop.1 | 4 +-
19 qlop.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
20 3 files changed, 173 insertions(+), 9 deletions(-)
21
22 diff --git a/main.c b/main.c
23 index 5d4c4cd..0b827fc 100644
24 --- a/main.c
25 +++ b/main.c
26 @@ -501,7 +501,8 @@ read_portage_env_file(const char *configroot, const char *file, env_vars vars[])
27 source_len = strlen(sfile);
28
29 if (buflen <= source_len + file_path_len)
30 - buf = xrealloc(buf, buflen = source_len + file_path_len + 1);
31 + buf = xrealloc(buf,
32 + buflen = source_len + file_path_len + 1);
33 memmove(buf + file_path_len, buf + 7, source_len + 1);
34 memcpy(buf, file, file_path_len);
35 sfile = buf;
36
37 diff --git a/man/qlop.1 b/man/qlop.1
38 index de1e525..58efd09 100644
39 --- a/man/qlop.1
40 +++ b/man/qlop.1
41 @@ -1,5 +1,5 @@
42 .\" generated by mkman.py, please do NOT edit!
43 -.TH qlop "1" "Sep 2019" "Gentoo Foundation" "qlop"
44 +.TH qlop "1" "Oct 2019" "Gentoo Foundation" "qlop"
45 .SH NAME
46 qlop \- emerge log analyzer
47 .SH SYNOPSIS
48 @@ -51,7 +51,7 @@ Print elapssed time in human readable format. This form uses
49 minutes, hours and days instead of just seconds.
50 .TP
51 \fB\-M\fR, \fB\-\-machine\fR
52 -Print elapsed time as seconds with no formatting.
53 +Print start/elapsed time as seconds with no formatting.
54 .TP
55 \fB\-m\fR, \fB\-\-merge\fR
56 Show merge history.
57
58 diff --git a/qlop.c b/qlop.c
59 index 7a93656..6cb2c04 100644
60 --- a/qlop.c
61 +++ b/qlop.c
62 @@ -16,9 +16,11 @@
63 #include <stdlib.h>
64 #include <ctype.h>
65 #include <limits.h>
66 +#include <sys/stat.h>
67
68 #include "atom.h"
69 #include "eat_file.h"
70 +#include "scandirat.h"
71 #include "set.h"
72 #include "xarray.h"
73 #include "xasprintf.h"
74 @@ -51,7 +53,7 @@ static const char * const qlop_opts_help[] = {
75 "Print time taken to complete action",
76 "Print average time taken to complete action",
77 "Print elapsed time in human readable format (use with -t or -a)",
78 - "Print elapsed time as seconds with no formatting",
79 + "Print start/elapsed time as seconds with no formatting",
80 "Show merge history",
81 "Show unmerge history",
82 "Show autoclean unmerge history",
83 @@ -201,10 +203,15 @@ parse_date(const char *sdate, time_t *t)
84 static char _date_buf[48];
85 static char *fmt_date(struct qlop_mode *flags, time_t ts, time_t te)
86 {
87 - time_t t;
88 + time_t t = flags->do_endtime ? te : ts;
89 +
90 + if (flags->do_machine)
91 + snprintf(_date_buf, sizeof(_date_buf),
92 + "%zd", (size_t)t);
93 + else
94 + strftime(_date_buf, sizeof(_date_buf),
95 + "%Y-%m-%dT%H:%M:%S", localtime(&t));
96
97 - t = flags->do_endtime ? te : ts;
98 - strftime(_date_buf, sizeof(_date_buf), "%Y-%m-%dT%H:%M:%S", localtime(&t));
99 return _date_buf;
100 }
101
102 @@ -336,6 +343,21 @@ New format:
103 1550953125: >>> unmerge success: app-admin/pwgen-2.08
104 1550953125: *** exiting successfully.
105 1550953125: *** terminating.
106 +
107 +
108 +Currently running merges can be found in the /proc filesystem:
109 +- Linux: readlink(/proc/<pid>/fd/X)
110 +- Solaris: readlink(/proc/<pid>/path/X)
111 +from here a file should be there that points to the build.log file
112 +$CAT/$P/work/build.log. If so, it's running for $CAT/$P.
113 +This requires being the portage user though, or root.
114 +
115 +Should there be no /proc, we can deduce from the log whether a package
116 +is being emerged, if and only if, there are no parallel merges, and
117 +portage never got interrupted in a way where it could not write its
118 +interruption to the log. Unfortunately these scenarios happen a lot.
119 +As such, we can try to remedy this somewhat by using a rule of thumb
120 +that currently merging packages need to be withinin the last 10 days.
121 */
122 static int do_emerge_log(
123 const char *log,
124 @@ -463,6 +485,7 @@ static int do_emerge_log(
125 tbegin = last_merge;
126 tend = tstart;
127 }
128 +
129 /* loop over lines searching for atoms */
130 while (fgets(buf, sizeof(buf), fp) != NULL) {
131 if ((p = strchr(buf, ':')) == NULL)
132 @@ -821,11 +844,19 @@ static int do_emerge_log(
133 }
134 fclose(fp);
135 if (flags->do_running) {
136 + time_t cutofftime;
137 +
138 + /* emerge.log can be interrupted, incorrect and hopelessly lost,
139 + * so to eliminate some unfinished crap from there, we just
140 + * ignore anything that's > cutofftime, 10 days for now. */
141 + cutofftime = 10 * 24 * 60 * 60; /* when we consider entries stale */
142 +
143 /* can't report endtime for non-finished operations */
144 flags->do_endtime = 0;
145 tstart = time(NULL);
146 sync_time /= sync_cnt;
147 - if (sync_start > 0) {
148 + if (sync_start >= tstart - cutofftime) {
149 + elapsed = tstart - sync_start;
150 if (elapsed >= sync_time)
151 sync_time = 0;
152 if (flags->do_time) {
153 @@ -847,6 +878,9 @@ static int do_emerge_log(
154 time_t maxtime = 0;
155 bool isMax = false;
156
157 + if (pkgw->tbegin < tstart - cutofftime)
158 + continue;
159 +
160 snprintf(afmt, sizeof(afmt), "%s/%s",
161 pkgw->atom->CATEGORY, pkgw->atom->PN);
162
163 @@ -891,6 +925,9 @@ static int do_emerge_log(
164 time_t maxtime = 0;
165 bool isMax = false;
166
167 + if (pkgw->tbegin < tstart - cutofftime)
168 + continue;
169 +
170 snprintf(afmt, sizeof(afmt), "%s/%s",
171 pkgw->atom->CATEGORY, pkgw->atom->PN);
172
173 @@ -978,6 +1015,118 @@ static int do_emerge_log(
174 return 0;
175 }
176
177 +/* scan through /proc for running merges, this requires portage user
178 + * or root */
179 +static array_t *probe_proc(array_t *atoms)
180 +{
181 + struct dirent **procs;
182 + int procslen;
183 + int pi;
184 + struct dirent **links;
185 + int linkslen;
186 + int li;
187 + struct dirent *d;
188 + char npath[_Q_PATH_MAX * 2];
189 + char rpath[_Q_PATH_MAX];
190 + const char *subdir = NULL;
191 + const char *pid;
192 + ssize_t rpathlen;
193 + char *p;
194 + depend_atom *atom;
195 + DECLARE_ARRAY(ret_atoms);
196 + size_t i;
197 +
198 + /* /proc/<pid>/path/<[0-9]+link>
199 + * /proc/<pid>/fd/<[0-9]+link> */
200 + if ((procslen = scandir("/proc", &procs, NULL, NULL)) > 0) {
201 + for (pi = 0; pi < procslen; pi++) {
202 + d = procs[pi];
203 + /* must be [0-9]+ */
204 + if (d->d_name[0] < '0' || d->d_name[0] > '9')
205 + continue;
206 +
207 + if (subdir == NULL) {
208 + struct stat st;
209 +
210 + snprintf(npath, sizeof(npath), "/proc/%s/path", d->d_name);
211 + if (stat(npath, &st) < 0)
212 + subdir = "fd";
213 + else
214 + subdir = "path";
215 + }
216 +
217 + pid = d->d_name;
218 + snprintf(npath, sizeof(npath), "/proc/%s/%s", pid, subdir);
219 + if ((linkslen = scandir(npath, &links, NULL, NULL)) > 0) {
220 + for (li = 0; li < linkslen; li++) {
221 + d = links[li];
222 + /* must be [0-9]+ */
223 + if (d->d_name[0] < '0' || d->d_name[0] > '9')
224 + continue;
225 + snprintf(npath, sizeof(npath), "/proc/%s/%s/%s",
226 + pid, subdir, d->d_name);
227 + rpathlen = readlink(npath, rpath, sizeof(rpath));
228 + if (rpathlen <= 0)
229 + continue;
230 + rpath[rpathlen] = '\0';
231 + /* check if this points to a portage build:
232 + * <somepath>/portage/<cat>/<pf>/temp/build.log */
233 + if (strcmp(rpath + rpathlen -
234 + (sizeof("/temp/build.log") - 1),
235 + "/temp/build.log") == 0 &&
236 + (p = strstr(rpath, "/portage/")) != NULL)
237 + {
238 + p += sizeof("/portage/") - 1;
239 + rpath[rpathlen - (sizeof("/temp/build.log") - 1)] =
240 + '\0';
241 + atom = atom_explode(p);
242 + if (atom == NULL ||
243 + atom->CATEGORY == NULL || atom->P == NULL)
244 + {
245 + if (atom != NULL)
246 + atom_implode(atom);
247 + continue;
248 + }
249 + xarraypush_ptr(ret_atoms, atom);
250 + }
251 + }
252 + scandir_free(links, linkslen);
253 + }
254 + }
255 + scandir_free(procs, procslen);
256 + } else {
257 + /* flag /proc doesn't exist */
258 + return NULL;
259 + }
260 +
261 + if (array_cnt(atoms) > 0) {
262 + size_t j;
263 + depend_atom *atomr;
264 +
265 + /* calculate intersection */
266 + array_for_each(atoms, i, atom) {
267 + array_for_each(ret_atoms, j, atomr) {
268 + if (atom_compare(atomr, atom) != EQUAL) {
269 + xarraydelete_ptr(ret_atoms, j);
270 + atom_implode(atomr);
271 + break;
272 + }
273 + }
274 + atom_implode(atom);
275 + }
276 + xarrayfree_int(atoms);
277 + }
278 +
279 + /* ret_atoms is allocated on the stack, so copy into atoms which is
280 + * empty at this point */
281 + array_for_each(ret_atoms, i, atom)
282 + xarraypush_ptr(atoms, atom);
283 +
284 + xarrayfree_int(ret_atoms);
285 +
286 + return atoms;
287 +}
288 +
289 int qlop_main(int argc, char **argv)
290 {
291 size_t i;
292 @@ -1160,7 +1309,21 @@ int qlop_main(int argc, char **argv)
293 m.fmt = "%[CATEGORY]%[PN]";
294 }
295
296 - do_emerge_log(logfile, &m, atoms, start_time, end_time);
297 + if (m.do_running) {
298 + array_t *new_atoms = probe_proc(atoms);
299 +
300 + if (new_atoms != NULL && array_cnt(new_atoms) == 0) {
301 + /* proc supported, found nothing running */
302 + start_time = LONG_MAX;
303 + } else {
304 + warn("/proc not available, deducing running "
305 + "merges from emerge.log");
306 + }
307 +
308 + }
309 +
310 + if (start_time < LONG_MAX)
311 + do_emerge_log(logfile, &m, atoms, start_time, end_time);
312
313 array_for_each(atoms, i, atom)
314 atom_implode(atom);