Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2014 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
5 : : * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
6 : : * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
7 : : * Copyright (c) 2015 Matthew Seaman <matthew@FreeBSD.org>
8 : : * All rights reserved.
9 : : *
10 : : * Redistribution and use in source and binary forms, with or without
11 : : * modification, are permitted provided that the following conditions
12 : : * are met:
13 : : * 1. Redistributions of source code must retain the above copyright
14 : : * notice, this list of conditions and the following disclaimer
15 : : * in this position and unchanged.
16 : : * 2. Redistributions in binary form must reproduce the above copyright
17 : : * notice, this list of conditions and the following disclaimer in the
18 : : * documentation and/or other materials provided with the distribution.
19 : : *
20 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
21 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
24 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 : : */
31 : :
32 : : #ifdef HAVE_CONFIG_H
33 : : #include "pkg_config.h"
34 : : #endif
35 : :
36 : : #include <sys/resource.h>
37 : : #include <sys/types.h>
38 : : #ifdef HAVE_LIBJAIL
39 : : #include <sys/sysctl.h>
40 : : #endif
41 : : #include <sys/wait.h>
42 : : #include <sys/socket.h>
43 : :
44 : : #ifdef HAVE_CAPSICUM
45 : : #include <sys/capsicum.h>
46 : : #endif
47 : :
48 : : #include <err.h>
49 : : #include <string.h>
50 : : #include <unistd.h>
51 : : #include <errno.h>
52 : : #include <time.h>
53 : : #include <signal.h>
54 : : #ifdef HAVE_LIBUTIL_H
55 : : #include <libutil.h>
56 : : #endif
57 : : #include <kvec.h>
58 : :
59 : : #include <bsd_compat.h>
60 : :
61 : : #include "pkg.h"
62 : : #include "pkgcli.h"
63 : :
64 : : #define STALL_TIME 5
65 : :
66 : : xstring *messages = NULL;
67 : : xstring *conflicts = NULL;
68 : :
69 : : struct cleanup {
70 : : void *data;
71 : : void (*cb)(void *);
72 : : };
73 : :
74 : : static char *progress_message = NULL;
75 : : static xstring *msg_buf = NULL;
76 : : static int last_progress_percent = -1;
77 : : static bool progress_started = false;
78 : : static bool progress_interrupted = false;
79 : : static bool progress_debit = false;
80 : : static int64_t last_tick = 0;
81 : : static int64_t stalled;
82 : : static int64_t bytes_per_second;
83 : : static time_t last_update;
84 : : static time_t begin = 0;
85 : : static int add_deps_depth;
86 : : static kvec_t(struct cleanup *) cleanup_list;
87 : : static bool signal_handler_installed = false;
88 : :
89 : : /* units for format_size */
90 : : static const char *unit_SI[] = { " ", "k", "M", "G", "T", };
91 : :
92 : : static void draw_progressbar(int64_t current, int64_t total);
93 : :
94 : : static void
95 : 0 : cleanup_handler(int dummy __unused)
96 : : {
97 : : struct cleanup *ev;
98 : : size_t i;
99 : :
100 [ # # ]: 0 : if (kv_size(cleanup_list) == 0)
101 : 0 : return;
102 : 0 : warnx("\nsignal received, cleaning up");
103 [ # # ]: 0 : for (i = 0; i < kv_size(cleanup_list); i++) {
104 : 0 : ev = kv_A(cleanup_list, i);
105 : 0 : ev->cb(ev->data);
106 : 0 : }
107 : 0 : exit(1);
108 : : }
109 : :
110 : : static void
111 : 0 : format_rate_SI(char *buf, int size, off_t bytes)
112 : : {
113 : : int i;
114 : :
115 : 0 : bytes *= 100;
116 [ # # ]: 0 : for (i = 0; bytes >= 100*1000 && unit_SI[i][0] != 'T'; i++)
117 : 0 : bytes = (bytes + 500) / 1000;
118 : 0 : if (i == 0) {
119 : 0 : i++;
120 : 0 : bytes = (bytes + 500) / 1000;
121 : 0 : }
122 : 0 : snprintf(buf, size, "%3lld.%1lld%sB",
123 : 0 : (long long) (bytes + 5) / 100,
124 : 0 : (long long) (bytes + 5) / 10 % 10,
125 : 0 : unit_SI[i]);
126 : 0 : }
127 : :
128 : : void
129 : 0 : job_status_end(xstring *msg)
130 : : {
131 : 0 : fflush(msg->fp);
132 : 0 : printf("%s\n", msg->buf);
133 : 0 : xstring_reset(msg);
134 : 0 : }
135 : :
136 : : void
137 : 1763 : job_status_begin(xstring *msg)
138 : : {
139 : : int n;
140 : :
141 : 1763 : xstring_reset(msg);
142 : : #ifdef HAVE_LIBJAIL
143 : : static char hostname[MAXHOSTNAMELEN] = "";
144 : : static int jailed = -1;
145 : : size_t intlen;
146 : :
147 : 1763 : if (jailed == -1) {
148 : 894 : intlen = sizeof(jailed);
149 : 1788 : if (sysctlbyname("security.jail.jailed", &jailed, &intlen,
150 : 894 : NULL, 0) == -1)
151 : 0 : jailed = 0;
152 : 894 : }
153 : :
154 : 1788 : if (jailed == 1) {
155 : 0 : if (hostname[0] == '\0')
156 : 0 : gethostname(hostname, sizeof(hostname));
157 : :
158 : 0 : fprintf(msg->fp, "[%s] ", hostname);
159 : 0 : }
160 : : #endif
161 : :
162 : : /* Only used for pkg-add right now. */
163 : 47 : if (add_deps_depth) {
164 : 47 : if (add_deps_depth > 1) {
165 [ # # ]: 0 : for (n = 0; n < (2 * add_deps_depth); ++n) {
166 : 0 : if (n % 4 == 0 && n < (2 * add_deps_depth))
167 : 0 : fprintf(msg->fp, "|");
168 : : else
169 : 0 : fprintf(msg->fp, " ");
170 : 0 : }
171 : 0 : }
172 : 47 : fprintf(msg->fp, "`-- ");
173 : 47 : }
174 : :
175 : 1743 : if ((nbtodl > 0 || nbactions > 0) && nbdone > 0)
176 [ + + ]: 691 : fprintf(msg->fp, "[%d/%d] ", nbdone, (nbtodl) ? nbtodl : nbactions);
177 : 1362 : if (nbtodl > 0 && nbtodl == nbdone) {
178 : 20 : nbtodl = 0;
179 : 20 : nbdone = 0;
180 : 20 : }
181 : 1763 : }
182 : :
183 : : static int
184 : 20 : event_sandboxed_call(pkg_sandbox_cb func, int fd, void *ud)
185 : : {
186 : : pid_t pid;
187 : : int status, ret;
188 : : struct rlimit rl_zero;
189 : :
190 : 20 : ret = -1;
191 : 20 : pid = fork();
192 : :
193 [ - - + ]: 20 : switch(pid) {
194 : : case -1:
195 : 0 : warn("fork failed");
196 : 0 : return (EPKG_FATAL);
197 : : break;
198 : : case 0:
199 : 0 : break;
200 : : default:
201 : : /* Parent process */
202 : 20 : while (waitpid(pid, &status, 0) == -1) {
203 [ # # ]: 0 : if (errno != EINTR) {
204 : 0 : warn("Sandboxed process pid=%d", (int)pid);
205 : 0 : ret = -1;
206 : 0 : break;
207 : : }
208 : : }
209 : :
210 : 20 : if (WIFEXITED(status)) {
211 : 20 : ret = WEXITSTATUS(status);
212 : 20 : }
213 : 20 : if (WIFSIGNALED(status)) {
214 : : /* Process got some terminating signal, hence stop the loop */
215 : 0 : fprintf(stderr, "Sandboxed process pid=%d terminated abnormally by signal: %d\n",
216 : 0 : (int)pid, WTERMSIG(status));
217 : 0 : ret = -1;
218 : 0 : }
219 : 20 : return (ret);
220 : : }
221 : :
222 : 0 : rl_zero.rlim_cur = rl_zero.rlim_max = 0;
223 [ # # ]: 0 : if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
224 : 0 : err(EXIT_FAILURE, "Unable to setrlimit(RLIMIT_NPROC)");
225 : :
226 : : /* Here comes child process */
227 : : #ifdef HAVE_CAPSICUM
228 : : #ifndef PKG_COVERAGE
229 : : if (cap_enter() < 0 && errno != ENOSYS) {
230 : : warn("cap_enter() failed");
231 : : _exit(EXIT_FAILURE);
232 : : }
233 : : #endif
234 : : #endif
235 : :
236 : 0 : ret = func(fd, ud);
237 : :
238 : 0 : _exit(ret);
239 : 20 : }
240 : :
241 : : static int
242 : 244 : event_sandboxed_get_string(pkg_sandbox_cb func, char **result, int64_t *len,
243 : : void *ud)
244 : : {
245 : : pid_t pid;
246 : : struct rlimit rl_zero;
247 : 244 : int status, ret = EPKG_OK;
248 : 244 : int pair[2], r, allocated_len = 0, off = 0;
249 : 244 : char *buf = NULL;
250 : :
251 [ - + ]: 244 : if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
252 : 0 : warn("socketpair failed");
253 : 0 : return (EPKG_FATAL);
254 : : }
255 : :
256 : 244 : pid = fork();
257 : :
258 [ - - + ]: 244 : switch(pid) {
259 : : case -1:
260 : 0 : warn("fork failed");
261 : 0 : return (EPKG_FATAL);
262 : : break;
263 : : case 0:
264 : 0 : break;
265 : : default:
266 : : /* Parent process */
267 : 244 : close(pair[0]);
268 : : /*
269 : : * We use blocking IO here as if the child is terminated we would have
270 : : * EINTR here
271 : : */
272 : 244 : buf = malloc(BUFSIZ);
273 [ - + ]: 244 : if (buf == NULL) {
274 : 0 : warn("malloc failed");
275 : 0 : return (EPKG_FATAL);
276 : : }
277 : 244 : allocated_len = BUFSIZ;
278 : 244 : do {
279 : 244 : if (off >= allocated_len) {
280 : 0 : allocated_len *= 2;
281 : 0 : buf = realloc(buf, allocated_len);
282 [ # # ]: 0 : if (buf == NULL) {
283 : 0 : warn("realloc failed");
284 : 0 : return (EPKG_FATAL);
285 : : }
286 : 0 : }
287 : :
288 : 0 : r = read(pair[1], buf + off, allocated_len - off);
289 : 0 : if (r == -1 && errno != EINTR) {
290 : 0 : free(buf);
291 : 0 : warn("read failed");
292 : 0 : return (EPKG_FATAL);
293 : : }
294 : 23 : else if (r > 0) {
295 : 23 : off += r;
296 : 23 : }
297 : 267 : } while (r > 0);
298 : :
299 : : /* Fill the result buffer */
300 : 244 : *len = off;
301 : 244 : *result = buf;
302 : 244 : if (*result == NULL) {
303 : 0 : warn("malloc failed");
304 : 0 : kill(pid, SIGTERM);
305 : 0 : ret = EPKG_FATAL;
306 : 0 : }
307 : 244 : while (waitpid(pid, &status, 0) == -1) {
308 [ # # ]: 0 : if (errno != EINTR) {
309 : 0 : warn("Sandboxed process pid=%d", (int)pid);
310 : 0 : ret = -1;
311 : 0 : break;
312 : : }
313 : : }
314 : :
315 : 244 : if (WIFEXITED(status)) {
316 : 244 : ret = WEXITSTATUS(status);
317 : 244 : }
318 : 244 : if (WIFSIGNALED(status)) {
319 : : /* Process got some terminating signal, hence stop the loop */
320 : 0 : fprintf(stderr, "Sandboxed process pid=%d terminated abnormally by signal: %d\n",
321 : 0 : (int)pid, WTERMSIG(status));
322 : 0 : ret = -1;
323 : 0 : }
324 : 244 : return (ret);
325 : : }
326 : :
327 : : /* Here comes child process */
328 : 0 : close(pair[1]);
329 : :
330 : 0 : drop_privileges();
331 : :
332 : 0 : rl_zero.rlim_cur = rl_zero.rlim_max = 0;
333 [ # # ]: 0 : if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
334 : 0 : err(EXIT_FAILURE, "Unable to setrlimit(RLIMIT_NPROC)");
335 : :
336 : : #ifdef HAVE_CAPSICUM
337 : : #ifndef PKG_COVERAGE
338 : : if (cap_enter() < 0 && errno != ENOSYS) {
339 : : warn("cap_enter() failed");
340 : : return (EPKG_FATAL);
341 : : }
342 : : #endif
343 : : #endif
344 : :
345 : 0 : ret = func(pair[0], ud);
346 : :
347 : 0 : close(pair[0]);
348 : :
349 : 0 : _exit(ret);
350 : 244 : }
351 : :
352 : : void
353 : 5137 : progressbar_start(const char *pmsg)
354 : : {
355 : 5137 : free(progress_message);
356 : 5137 : progress_message = NULL;
357 : :
358 [ + + ]: 5137 : if (quiet)
359 : 3307 : return;
360 [ + + ]: 1830 : if (pmsg != NULL)
361 : 1083 : progress_message = strdup(pmsg);
362 : : else {
363 : 747 : fflush(msg_buf->fp);
364 : 747 : progress_message = strdup(msg_buf->buf);
365 : : }
366 : 1830 : last_progress_percent = -1;
367 : 1830 : last_tick = 0;
368 : 1830 : begin = last_update = time(NULL);
369 : 1830 : bytes_per_second = 0;
370 : 1830 : stalled = 0;
371 : :
372 : 1830 : progress_started = true;
373 : 1830 : progress_interrupted = false;
374 [ + - ]: 1830 : if (!isatty(STDOUT_FILENO))
375 : 1830 : printf("%s: ", progress_message);
376 : : else
377 : 0 : printf("%s: 0%%", progress_message);
378 : 5137 : }
379 : :
380 : : void
381 : 8842 : progressbar_tick(int64_t current, int64_t total)
382 : : {
383 : : int percent;
384 : :
385 : 8842 : if (!quiet && progress_started) {
386 [ - + ]: 4204 : if (isatty(STDOUT_FILENO))
387 : 0 : draw_progressbar(current, total);
388 : : else {
389 [ + + ]: 4204 : if (progress_interrupted) {
390 : 8 : printf("%s...", progress_message);
391 : 4204 : } else if (!getenv("NO_TICK")){
392 [ # # ]: 0 : percent = (total != 0) ? (current * 100. / total) : 100;
393 : 0 : if (last_progress_percent / 10 < percent / 10) {
394 : 0 : last_progress_percent = percent;
395 : 0 : printf(".");
396 : 0 : fflush(stdout);
397 : 0 : }
398 : 0 : }
399 : 4204 : if (current >= total)
400 : 1830 : progressbar_stop();
401 : : }
402 : 4204 : }
403 : 8842 : progress_interrupted = false;
404 : 8842 : }
405 : :
406 : : void
407 : 1830 : progressbar_stop(void)
408 : : {
409 : 1830 : if (progress_started) {
410 : 1830 : if (!isatty(STDOUT_FILENO))
411 : 1830 : printf(" done");
412 [ + - ]: 1830 : putchar('\n');
413 : 1830 : }
414 : 1830 : last_progress_percent = -1;
415 : 1830 : progress_started = false;
416 : 1830 : progress_interrupted = false;
417 : 1830 : }
418 : :
419 : : static void
420 : 0 : draw_progressbar(int64_t current, int64_t total)
421 : : {
422 : : int percent;
423 : : int64_t transferred;
424 : 0 : time_t elapsed = 0, now = 0;
425 : : char buf[8];
426 : : int64_t bytes_left;
427 : : int cur_speed;
428 : : int hours, minutes, seconds;
429 : : float age_factor;
430 : :
431 [ # # ]: 0 : if (!progress_started) {
432 : 0 : progressbar_stop();
433 : 0 : return;
434 : : }
435 : :
436 : 0 : if (progress_debit) {
437 : 0 : now = time(NULL);
438 [ # # ]: 0 : elapsed = (now >= last_update) ? now - last_update : 0;
439 : 0 : }
440 : :
441 [ # # ]: 0 : percent = (total != 0) ? (current * 100. / total) : 100;
442 : :
443 : : /**
444 : : * Wait for interval for debit bars to keep calc per second.
445 : : * If not debit, show on every % change, or if ticking after
446 : : * an interruption (which removed our progressbar output).
447 : : */
448 : 0 : if (current >= total || (progress_debit && elapsed >= 1) ||
449 : 0 : (!progress_debit &&
450 : 0 : (percent != last_progress_percent || progress_interrupted))) {
451 : 0 : last_progress_percent = percent;
452 : :
453 : 0 : printf("\r%s: %3d%%", progress_message, percent);
454 : 0 : if (progress_debit) {
455 : 0 : transferred = current - last_tick;
456 : 0 : last_tick = current;
457 : 0 : bytes_left = total - current;
458 : 0 : if (bytes_left <= 0) {
459 : 0 : elapsed = now - begin;
460 : : /* Always show at least 1 second at end. */
461 : 0 : if (elapsed == 0)
462 : 0 : elapsed = 1;
463 : : /* Calculate true total speed when done */
464 : 0 : transferred = total;
465 : 0 : bytes_per_second = 0;
466 : 0 : }
467 : :
468 [ # # ]: 0 : if (elapsed != 0)
469 : 0 : cur_speed = (transferred / elapsed);
470 : : else
471 : 0 : cur_speed = transferred;
472 : :
473 : : #define AGE_FACTOR_SLOW_START 3
474 [ # # ]: 0 : if (now - begin <= AGE_FACTOR_SLOW_START)
475 : 0 : age_factor = 0.4;
476 : : else
477 : 0 : age_factor = 0.9;
478 : :
479 [ # # ]: 0 : if (bytes_per_second != 0) {
480 : 0 : bytes_per_second =
481 : 0 : (bytes_per_second * age_factor) +
482 : 0 : (cur_speed * (1.0 - age_factor));
483 : 0 : } else
484 : 0 : bytes_per_second = cur_speed;
485 : :
486 : 0 : humanize_number(buf, sizeof(buf),
487 : 0 : current,"B", HN_AUTOSCALE, HN_IEC_PREFIXES);
488 : 0 : printf(" %*s", (int)sizeof(buf), buf);
489 : :
490 [ # # ]: 0 : if (bytes_left > 0)
491 : 0 : format_rate_SI(buf, sizeof(buf), transferred);
492 : : else /* Show overall speed when done */
493 : 0 : format_rate_SI(buf, sizeof(buf),
494 : 0 : bytes_per_second);
495 : 0 : printf(" %s/s ", buf);
496 : :
497 [ # # ]: 0 : if (!transferred)
498 : 0 : stalled += elapsed;
499 : : else
500 : 0 : stalled = 0;
501 : :
502 [ # # ]: 0 : if (stalled >= STALL_TIME)
503 : 0 : printf(" - stalled -");
504 : 0 : else if (bytes_per_second == 0 && bytes_left > 0)
505 : 0 : printf(" --:-- ETA");
506 : : else {
507 [ # # ]: 0 : if (bytes_left > 0)
508 : 0 : seconds = bytes_left / bytes_per_second;
509 : : else
510 : 0 : seconds = elapsed;
511 : :
512 : 0 : hours = seconds / 3600;
513 : 0 : seconds -= hours * 3600;
514 : 0 : minutes = seconds / 60;
515 : 0 : seconds -= minutes * 60;
516 : :
517 [ # # ]: 0 : if (hours != 0)
518 : 0 : printf("%02d:%02d:%02d", hours,
519 : 0 : minutes, seconds);
520 : : else
521 : 0 : printf(" %02d:%02d", minutes, seconds);
522 : :
523 [ # # ]: 0 : if (bytes_left > 0)
524 : 0 : printf(" ETA");
525 : : else
526 : 0 : printf(" ");
527 : : }
528 : 0 : last_update = now;
529 : 0 : }
530 : 0 : fflush(stdout);
531 : 0 : }
532 : 0 : if (current >= total)
533 : 0 : progressbar_stop();
534 : 0 : }
535 : :
536 : : int
537 : 25918 : event_callback(void *data, struct pkg_event *ev)
538 : : {
539 : 25918 : struct pkg *pkg = NULL, *pkg_new, *pkg_old;
540 : : struct cleanup *evtmp;
541 : 25918 : int *debug = data;
542 : : size_t i;
543 : : struct pkg_event_conflict *cur_conflict;
544 : : const char *filename, *reponame;
545 : :
546 : 25918 : if (msg_buf == NULL) {
547 : 2633 : msg_buf = xstring_new();
548 : 2633 : }
549 : :
550 : : /*
551 : : * If a progressbar has been interrupted by another event, then
552 : : * we need to add a newline to prevent bad formatting.
553 : : */
554 : 4212 : if (progress_started && ev->type != PKG_EVENT_PROGRESS_TICK &&
555 : 8 : !progress_interrupted) {
556 [ + - ]: 8 : putchar('\n');
557 : 8 : progress_interrupted = true;
558 : 8 : }
559 : :
560 [ - + + - : 23800 : switch(ev->type) {
- - + + +
+ + + + +
+ + - + +
+ + + + -
- - - + -
- + - - -
- - + + -
- + + + +
- - + + +
+ + - ]
561 : : case PKG_EVENT_ERRNO:
562 : 0 : warnx("%s(%s): %s", ev->e_errno.func, ev->e_errno.arg,
563 : 0 : strerror(ev->e_errno.no));
564 : 0 : break;
565 : : case PKG_EVENT_ERROR:
566 : 218 : warnx("%s", ev->e_pkg_error.msg);
567 : 218 : break;
568 : : case PKG_EVENT_NOTICE:
569 : 20 : if (!quiet)
570 : 16 : printf("%s\n", ev->e_pkg_notice.msg);
571 : 20 : break;
572 : : case PKG_EVENT_DEVELOPER_MODE:
573 : 0 : warnx("DEVELOPER_MODE: %s", ev->e_pkg_error.msg);
574 : 0 : break;
575 : : case PKG_EVENT_UPDATE_ADD:
576 : 0 : if (quiet || !isatty(STDOUT_FILENO))
577 : 0 : break;
578 : 0 : printf("\rPushing new entries %d/%d", ev->e_upd_add.done, ev->e_upd_add.total);
579 : 0 : if (ev->e_upd_add.total == ev->e_upd_add.done)
580 : 0 : printf("\n");
581 : 0 : break;
582 : : case PKG_EVENT_UPDATE_REMOVE:
583 : 0 : if (quiet || !isatty(STDOUT_FILENO))
584 : 0 : break;
585 : 0 : printf("\rRemoving entries %d/%d", ev->e_upd_remove.done, ev->e_upd_remove.total);
586 : 0 : if (ev->e_upd_remove.total == ev->e_upd_remove.done)
587 : 0 : printf("\n");
588 : 0 : break;
589 : : case PKG_EVENT_FETCH_BEGIN:
590 : 496 : if (nbtodl > 0)
591 : 4 : nbdone++;
592 [ + + ]: 496 : if (quiet)
593 : 78 : break;
594 : 418 : filename = strrchr(ev->e_fetching.url, '/');
595 [ + - ]: 418 : if (filename != NULL) {
596 : 418 : filename++;
597 : 418 : } else {
598 : : /*
599 : : * We failed at being smart, so display
600 : : * the entire url.
601 : : */
602 : 0 : filename = ev->e_fetching.url;
603 : : }
604 : 418 : job_status_begin(msg_buf);
605 : 418 : progress_debit = true;
606 : 418 : fprintf(msg_buf->fp, "Fetching %s", filename);
607 : 418 : break;
608 : : case PKG_EVENT_FETCH_FINISHED:
609 : 496 : progress_debit = false;
610 : 496 : break;
611 : : case PKG_EVENT_INSTALL_BEGIN:
612 [ + + ]: 984 : if (quiet)
613 : 224 : break;
614 : 760 : job_status_begin(msg_buf);
615 : :
616 : 760 : pkg = ev->e_install_begin.pkg;
617 : 1520 : pkg_fprintf(msg_buf->fp, "Installing %n-%v...\n", pkg,
618 : 760 : pkg);
619 : 760 : fflush(msg_buf->fp);
620 : 760 : printf("%s", msg_buf->buf);
621 : 760 : break;
622 : : case PKG_EVENT_INSTALL_FINISHED:
623 [ + + ]: 937 : if (quiet)
624 : 224 : break;
625 : 713 : break;
626 : : case PKG_EVENT_EXTRACT_BEGIN:
627 [ + + ]: 440 : if (quiet)
628 : 184 : break;
629 : : else {
630 : 256 : job_status_begin(msg_buf);
631 : 256 : pkg = ev->e_install_begin.pkg;
632 : 256 : pkg_fprintf(msg_buf->fp, "Extracting %n-%v", pkg, pkg);
633 : 256 : fflush(msg_buf->fp);
634 : : }
635 : 256 : break;
636 : : case PKG_EVENT_EXTRACT_FINISHED:
637 : 440 : break;
638 : : case PKG_EVENT_ADD_DEPS_BEGIN:
639 : 203 : ++add_deps_depth;
640 : 203 : break;
641 : : case PKG_EVENT_ADD_DEPS_FINISHED:
642 : 203 : --add_deps_depth;
643 : 203 : break;
644 : : case PKG_EVENT_INTEGRITYCHECK_BEGIN:
645 [ + + ]: 637 : if (quiet)
646 : 263 : break;
647 : 374 : printf("Checking integrity...");
648 : 374 : break;
649 : : case PKG_EVENT_INTEGRITYCHECK_FINISHED:
650 [ + + ]: 637 : if (quiet)
651 : 263 : break;
652 : 374 : printf(" done (%d conflicting)\n", ev->e_integrity_finished.conflicting);
653 : 374 : if (conflicts != NULL) {
654 : 36 : fflush(conflicts->fp);
655 : 36 : printf("%s", conflicts->buf);
656 : 36 : xstring_free(conflicts);
657 : 36 : conflicts = NULL;
658 : 36 : }
659 : 374 : break;
660 : : case PKG_EVENT_INTEGRITYCHECK_CONFLICT:
661 [ # # ]: 0 : if (*debug == 0)
662 : 0 : break;
663 : 0 : printf("\nConflict found on path %s between %s and ",
664 : 0 : ev->e_integrity_conflict.pkg_path,
665 : 0 : ev->e_integrity_conflict.pkg_uid);
666 : 0 : cur_conflict = ev->e_integrity_conflict.conflicts;
667 [ # # ]: 0 : while (cur_conflict) {
668 [ # # ]: 0 : if (cur_conflict->next)
669 : 0 : printf("%s, ", cur_conflict->uid);
670 : : else
671 : 0 : printf("%s", cur_conflict->uid);
672 : :
673 : 0 : cur_conflict = cur_conflict->next;
674 : : }
675 : 0 : printf("\n");
676 : 0 : break;
677 : : case PKG_EVENT_DEINSTALL_BEGIN:
678 [ + + ]: 172 : if (quiet)
679 : 24 : break;
680 : :
681 : 148 : job_status_begin(msg_buf);
682 : :
683 : 148 : pkg = ev->e_install_begin.pkg;
684 : 148 : pkg_fprintf(msg_buf->fp, "Deinstalling %n-%v...\n", pkg, pkg);
685 : 148 : fflush(msg_buf->fp);
686 : 148 : printf("%s", msg_buf->buf);
687 : 148 : break;
688 : : case PKG_EVENT_DEINSTALL_FINISHED:
689 [ + + ]: 172 : if (quiet)
690 : 24 : break;
691 : 148 : break;
692 : : case PKG_EVENT_DELETE_FILES_BEGIN:
693 [ + + ]: 93 : if (quiet)
694 : 20 : break;
695 : : else {
696 : 73 : job_status_begin(msg_buf);
697 : 73 : pkg = ev->e_install_begin.pkg;
698 : 146 : pkg_fprintf(msg_buf->fp, "Deleting files for %n-%v",
699 : 73 : pkg, pkg);
700 : : }
701 : 73 : break;
702 : : case PKG_EVENT_DELETE_FILES_FINISHED:
703 : 93 : break;
704 : : case PKG_EVENT_UPGRADE_BEGIN:
705 [ + + ]: 132 : if (quiet)
706 : 24 : break;
707 : 108 : pkg_new = ev->e_upgrade_begin.n;
708 : 108 : pkg_old = ev->e_upgrade_begin.o;
709 : :
710 : 108 : job_status_begin(msg_buf);
711 : :
712 [ - + + ]: 108 : switch (pkg_version_change_between(pkg_new, pkg_old)) {
713 : : case PKG_DOWNGRADE:
714 : 0 : pkg_fprintf(msg_buf->fp, "Downgrading %n from %v to %v...\n",
715 : 0 : pkg_new, pkg_old, pkg_new);
716 : 0 : break;
717 : : case PKG_REINSTALL:
718 : 50 : pkg_fprintf(msg_buf->fp, "Reinstalling %n-%v...\n",
719 : 25 : pkg_old, pkg_old);
720 : 25 : break;
721 : : case PKG_UPGRADE:
722 : 166 : pkg_fprintf(msg_buf->fp, "Upgrading %n from %v to %v...\n",
723 : 83 : pkg_new, pkg_old, pkg_new);
724 : 83 : break;
725 : : }
726 : 108 : fflush(msg_buf->fp);
727 : 108 : printf("%s", msg_buf->buf);
728 : 108 : break;
729 : : case PKG_EVENT_UPGRADE_FINISHED:
730 [ + + ]: 132 : if (quiet)
731 : 24 : break;
732 : 108 : break;
733 : : case PKG_EVENT_LOCKED:
734 : 0 : pkg = ev->e_locked.pkg;
735 : 0 : pkg_printf("\n%n-%v is locked and may not be modified\n", pkg, pkg);
736 : 0 : break;
737 : : case PKG_EVENT_REQUIRED:
738 : 0 : pkg = ev->e_required.pkg;
739 : 0 : pkg_printf("\n%n-%v is required by: %r%{%rn-%rv%| %}", pkg, pkg, pkg);
740 [ # # ]: 0 : if (ev->e_required.force == 1)
741 : 0 : fprintf(stderr, ", deleting anyway\n");
742 : : else
743 : 0 : fprintf(stderr, "\n");
744 : 0 : break;
745 : : case PKG_EVENT_ALREADY_INSTALLED:
746 [ # # ]: 0 : if (quiet)
747 : 0 : break;
748 : 0 : pkg = ev->e_already_installed.pkg;
749 : 0 : pkg_printf("the most recent version of %n-%v is already installed\n",
750 : 0 : pkg, pkg);
751 : 0 : break;
752 : : case PKG_EVENT_NOT_FOUND:
753 : 0 : printf("Package '%s' was not found in "
754 : 0 : "the repositories\n", ev->e_not_found.pkg_name);
755 : 0 : break;
756 : : case PKG_EVENT_MISSING_DEP:
757 : 65 : warnx("Missing dependency '%s'",
758 : 65 : pkg_dep_name(ev->e_missing_dep.dep));
759 : 65 : break;
760 : : case PKG_EVENT_NOREMOTEDB:
761 : 0 : fprintf(stderr, "Unable to open remote database \"%s\". "
762 : 0 : "Try running '%s update' first.\n", ev->e_remotedb.repo,
763 : 0 : getprogname());
764 : 0 : break;
765 : : case PKG_EVENT_NOLOCALDB:
766 : 0 : fprintf(stderr, "Local package database nonexistent!\n");
767 : 0 : break;
768 : : case PKG_EVENT_NEWPKGVERSION:
769 : 13 : newpkgversion = true;
770 : 13 : printf("New version of pkg detected; it needs to be "
771 : : "installed first.\n");
772 : 13 : break;
773 : : case PKG_EVENT_FILE_MISMATCH:
774 : 0 : pkg = ev->e_file_mismatch.pkg;
775 : 0 : pkg_fprintf(stderr, "%n-%v: checksum mismatch for %Fn\n", pkg,
776 : 0 : pkg, ev->e_file_mismatch.file);
777 : 0 : break;
778 : : case PKG_EVENT_FILE_MISSING:
779 : 0 : pkg = ev->e_file_missing.pkg;
780 : 0 : pkg_fprintf(stderr, "%n-%v: missing file %Fn\n", pkg, pkg,
781 : 0 : ev->e_file_missing.file);
782 : 0 : break;
783 : : case PKG_EVENT_PLUGIN_ERRNO:
784 : 0 : warnx("%s: %s(%s): %s",
785 : 0 : pkg_plugin_get(ev->e_plugin_errno.plugin, PKG_PLUGIN_NAME),
786 : 0 : ev->e_plugin_errno.func, ev->e_plugin_errno.arg,
787 : 0 : strerror(ev->e_plugin_errno.no));
788 : 0 : break;
789 : : case PKG_EVENT_PLUGIN_ERROR:
790 : 0 : warnx("%s: %s",
791 : 0 : pkg_plugin_get(ev->e_plugin_error.plugin, PKG_PLUGIN_NAME),
792 : 0 : ev->e_plugin_error.msg);
793 : 0 : break;
794 : : case PKG_EVENT_PLUGIN_INFO:
795 [ # # ]: 0 : if (quiet)
796 : 0 : break;
797 : 0 : printf("%s: %s\n",
798 : 0 : pkg_plugin_get(ev->e_plugin_info.plugin, PKG_PLUGIN_NAME),
799 : 0 : ev->e_plugin_info.msg);
800 : 0 : break;
801 : : case PKG_EVENT_INCREMENTAL_UPDATE:
802 : 244 : if (!quiet)
803 : 205 : printf("%s repository update completed. %d packages processed.\n",
804 : 205 : ev->e_incremental_update.reponame,
805 : 205 : ev->e_incremental_update.processed);
806 : 244 : break;
807 : : case PKG_EVENT_DEBUG:
808 : 176 : fprintf(stderr, "DBG(%d)[%d]> %s\n", ev->e_debug.level,
809 : 88 : (int)getpid(), ev->e_debug.msg);
810 : 88 : break;
811 : : case PKG_EVENT_QUERY_YESNO:
812 [ # # ]: 0 : return ( ev->e_query_yesno.deft ?
813 : 0 : query_yesno(true, ev->e_query_yesno.msg, "[Y/n]") :
814 : 0 : query_yesno(false, ev->e_query_yesno.msg, "[y/N]") );
815 : : break;
816 : : case PKG_EVENT_QUERY_SELECT:
817 : 0 : return query_select(ev->e_query_select.msg, ev->e_query_select.items,
818 : 0 : ev->e_query_select.ncnt, ev->e_query_select.deft);
819 : : break;
820 : : case PKG_EVENT_SANDBOX_CALL:
821 : 40 : return ( event_sandboxed_call(ev->e_sandbox_call.call,
822 : 20 : ev->e_sandbox_call.fd,
823 : 20 : ev->e_sandbox_call.userdata) );
824 : : break;
825 : : case PKG_EVENT_SANDBOX_GET_STRING:
826 : 488 : return ( event_sandboxed_get_string(ev->e_sandbox_call_str.call,
827 : 244 : ev->e_sandbox_call_str.result,
828 : 244 : ev->e_sandbox_call_str.len,
829 : 244 : ev->e_sandbox_call_str.userdata) );
830 : : break;
831 : : case PKG_EVENT_PROGRESS_START:
832 : 5137 : progressbar_start(ev->e_progress_start.msg);
833 : 5137 : break;
834 : : case PKG_EVENT_PROGRESS_TICK:
835 : 17684 : progressbar_tick(ev->e_progress_tick.current,
836 : 8842 : ev->e_progress_tick.total);
837 : 8842 : break;
838 : : case PKG_EVENT_BACKUP:
839 : 0 : fprintf(msg_buf->fp, "Backing up");
840 : 0 : break;
841 : : case PKG_EVENT_RESTORE:
842 : 0 : fprintf(msg_buf->fp, "Restoring");
843 : 0 : break;
844 : : case PKG_EVENT_NEW_ACTION:
845 : 906 : nbdone++;
846 : 906 : break;
847 : : case PKG_EVENT_MESSAGE:
848 : 112 : if (messages == NULL)
849 : 108 : messages = xstring_new();
850 : 112 : fprintf(messages->fp, "%s", ev->e_pkg_message.msg);
851 : 112 : break;
852 : : case PKG_EVENT_CLEANUP_CALLBACK_REGISTER:
853 : 696 : if (!signal_handler_installed) {
854 : 503 : kv_init(cleanup_list);
855 : 503 : signal(SIGINT, cleanup_handler);
856 : 503 : signal_handler_installed = true;
857 : 503 : }
858 : 696 : evtmp = malloc(sizeof(struct cleanup));
859 : 696 : evtmp->cb = ev->e_cleanup_callback.cleanup_cb;
860 : 696 : evtmp->data = ev->e_cleanup_callback.data;
861 [ - + ]: 696 : kv_push(struct cleanup *, cleanup_list, evtmp);
862 : 696 : break;
863 : : case PKG_EVENT_CLEANUP_CALLBACK_UNREGISTER:
864 [ + + ]: 868 : if (!signal_handler_installed)
865 : 172 : break;
866 : 696 : for (i = 0; i < kv_size(cleanup_list); i++) {
867 : 696 : evtmp = kv_A(cleanup_list, i);
868 : 696 : if (evtmp->cb == ev->e_cleanup_callback.cleanup_cb &&
869 : 696 : evtmp->data == ev->e_cleanup_callback.data) {
870 : 696 : kv_del(struct cleanup *, cleanup_list, i);
871 : 696 : break;
872 : : }
873 : 0 : }
874 : 696 : break;
875 : : case PKG_EVENT_CONFLICTS:
876 : 60 : if (conflicts == NULL) {
877 : 36 : conflicts = xstring_new();
878 : 36 : }
879 : 128 : pkg_fprintf(conflicts->fp, " - %n-%v",
880 : 64 : ev->e_conflicts.p1, ev->e_conflicts.p1);
881 : 64 : if (pkg_repos_total_count() > 1) {
882 : 8 : pkg_get(ev->e_conflicts.p1, PKG_REPONAME, &reponame);
883 : 16 : fprintf(conflicts->fp, " [%s]",
884 [ - + ]: 8 : reponame == NULL ? "installed" : reponame);
885 : 8 : }
886 : 16 : pkg_fprintf(conflicts->fp, " conflicts with %n-%v",
887 : 8 : ev->e_conflicts.p2, ev->e_conflicts.p2);
888 : 8 : if (pkg_repos_total_count() > 1) {
889 : 8 : pkg_get(ev->e_conflicts.p2, PKG_REPONAME, &reponame);
890 : 16 : fprintf(conflicts->fp, " [%s]",
891 [ + + ]: 8 : reponame == NULL ? "installed" : reponame);
892 : 8 : }
893 : 120 : fprintf(conflicts->fp, " on %s\n",
894 : 60 : ev->e_conflicts.path);
895 : 60 : break;
896 : : case PKG_EVENT_TRIGGER:
897 : 0 : if (!quiet) {
898 [ # # ]: 0 : if (ev->e_trigger.cleanup)
899 : 0 : printf("==> Cleaning up trigger: %s\n", ev->e_trigger.name);
900 : : else
901 : 0 : printf("==> Running trigger: %s\n", ev->e_trigger.name);
902 : 0 : }
903 : : default:
904 : 2118 : break;
905 : : }
906 : :
907 : 25654 : return 0;
908 : 25918 : }
|