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