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