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