utils.c
1 /*- 2 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org> 3 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org> 4 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com> 5 * Copyright (c) 2012-2015 Matthew Seaman <matthew@FreeBSD.org> 6 * Copyright (c) 2013-2016 Vsevolod Stakhov <vsevolod@FreeBSD.org> 7 * 8 * SPDX-License-Identifier: BSD-2-Clause 9 */ 10 11 #ifdef HAVE_CONFIG_H 12 #include "pkg_config.h" 13 #endif 14 15 #include <sys/param.h> 16 #include <sys/stat.h> 17 18 #include <err.h> 19 #include <fcntl.h> 20 #include <grp.h> 21 #include <inttypes.h> 22 #if __has_include(<libutil.h>) 23 #include <libutil.h> 24 #endif 25 #include <string.h> 26 #include <unistd.h> 27 #include <stdarg.h> 28 #include <paths.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <errno.h> 32 #include <pwd.h> 33 #include <pkg.h> 34 #include <xmalloc.h> 35 36 #include <bsd_compat.h> 37 38 #include "pkgcli.h" 39 40 struct jobs_sum_number { 41 int install; 42 int reinstall; 43 int downgrade; 44 int upgrade; 45 int delete; 46 int fetch; 47 int group_install; 48 int group_upgrade; 49 }; 50 51 void 52 append_yesno(bool r, char *yesnomsg, size_t len) 53 { 54 static const char trunc[] = "\n[truncated] "; 55 /* These two strings must be the same length. */ 56 static const char yes[] = "[Y/n]: "; 57 static const char no[] = "[y/N]: "; 58 59 size_t msglen = strlen(yesnomsg); 60 61 if (msglen > len - sizeof yes) { 62 yesnomsg[len - sizeof trunc - sizeof yes] = '\0'; 63 strlcat(yesnomsg, trunc, len); 64 } 65 strlcat(yesnomsg, r ? yes : no, len); 66 } 67 68 bool 69 query_tty_yesno(bool r, const char *msg, ...) 70 { 71 int c; 72 va_list ap; 73 int tty_fd; 74 FILE *tty; 75 int tty_flags = O_RDWR; 76 char yesnomsg[65536]; 77 78 #ifdef O_TTY_INIT 79 tty_flags |= O_TTY_INIT; 80 #endif 81 tty_fd = open(_PATH_TTY, tty_flags); 82 if (tty_fd == -1) { 83 /* No ctty -- return the default answer */ 84 if (default_yes) 85 return (true); 86 return (r); 87 } 88 89 tty = fdopen(tty_fd, "r+"); 90 91 strlcpy(yesnomsg, msg, sizeof(yesnomsg)); 92 append_yesno(default_yes || r, yesnomsg, sizeof yesnomsg); 93 94 va_start(ap, msg); 95 pkg_vfprintf(tty, yesnomsg, ap); 96 va_end(ap); 97 98 fflush(tty); 99 c = getc(tty); 100 if (c == 'y' || c == 'Y') 101 r = true; 102 else if (c == 'n' || c == 'N') 103 r = false; 104 else if (c == '\n' || c == EOF) { 105 if (default_yes) 106 r = true; 107 /* Else, r is not modified. It's default value is kept. */ 108 goto cleanup; 109 } 110 111 while ((c = getc(tty)) != '\n' && c != EOF) 112 continue; 113 114 cleanup: 115 fclose(tty); 116 117 return (r); 118 } 119 120 static bool 121 vquery_yesno(bool deft, const char *msg, va_list ap) 122 { 123 char *line = NULL; 124 char *out; 125 size_t linecap = 0; 126 int linelen; 127 bool r = deft; 128 char yesnomsg[65536]; 129 130 /* We use default value of yes or default in case of quiet mode */ 131 if (quiet) 132 return (yes || default_yes || r); 133 134 if (dry_run) 135 return (yes || default_yes || r ); 136 137 /* Do not query user if we have specified yes flag */ 138 if (yes) 139 return (true); 140 141 strlcpy(yesnomsg, msg, sizeof(yesnomsg)); 142 append_yesno(default_yes || r, yesnomsg, sizeof yesnomsg); 143 144 pkg_vasprintf(&out, yesnomsg, ap); 145 printf("%s", out); 146 147 for (;;) { 148 if ((linelen = getline(&line, &linecap, stdin)) != -1) { 149 150 if (linelen == 1 && line[0] == '\n') { 151 if (default_yes) 152 r = true; 153 break; 154 } 155 else if (linelen == 2) { 156 if (line[0] == 'y' || line[0] == 'Y') { 157 r = true; 158 break; 159 } 160 else if (line[0] == 'n' || line[0] == 'N') { 161 r = false; 162 break; 163 } 164 } 165 else { 166 if (STRIEQ(line, "yes\n")) { 167 r = true; 168 break; 169 } 170 else if (STRIEQ(line, "no\n")) { 171 r = false; 172 break; 173 } 174 } 175 printf("Please type 'Y[es]' or 'N[o]' to make a selection\n"); 176 printf("%s", out); 177 } 178 else { 179 if (errno == EINTR) 180 continue; 181 r = default_yes; 182 break; 183 } 184 } 185 186 free(line); 187 free(out); 188 189 return (r); 190 } 191 192 bool 193 query_yesno(bool deft, const char *msg, ...) 194 { 195 va_list ap; 196 bool r; 197 198 va_start(ap, msg); 199 r = vquery_yesno(deft, msg, ap); 200 va_end(ap); 201 202 return (r); 203 } 204 205 int 206 query_select(const char *msg, const char **opts, int ncnt, int deft) 207 { 208 int i; 209 char *str = NULL; 210 char *endpntr = NULL; 211 size_t n = 0; 212 213 printf("%s\n", msg); 214 for (i = 0; i < ncnt; i++) { 215 if (i + 1 == deft) 216 { 217 printf("*[%d] %s\n", 218 i + 1, opts[i]); 219 } else { 220 printf(" [%d] %s\n", 221 i + 1, opts[i]); 222 } 223 } 224 225 i = deft; 226 while (getline(&str, &n, stdin) == -1) { 227 if (errno == EINTR) 228 continue; 229 else 230 goto cleanup; 231 } 232 i = (int) strtoul(str, &endpntr, 10); 233 234 if (endpntr == NULL || *endpntr == '\0') { 235 i = deft; 236 } else if (*endpntr == '\n' || *endpntr == '\r') { 237 if (i > ncnt || i < 1) 238 i = deft; 239 } else 240 i = -1; 241 242 cleanup: 243 free(str); 244 return (i); 245 } 246 247 /* what the pkg needs to load in order to display the requested info */ 248 int 249 info_flags(uint64_t opt, bool remote) 250 { 251 int flags = PKG_LOAD_BASIC; 252 253 if (opt & INFO_CATEGORIES) 254 flags |= PKG_LOAD_CATEGORIES; 255 if (opt & INFO_LICENSES) 256 flags |= PKG_LOAD_LICENSES; 257 if (opt & (INFO_OPTIONS|INFO_OPTION_DEFAULTS|INFO_OPTION_DESCRIPTIONS)) 258 flags |= PKG_LOAD_OPTIONS; 259 if (opt & INFO_SHLIBS_REQUIRED) 260 flags |= PKG_LOAD_SHLIBS_REQUIRED; 261 if (opt & INFO_SHLIBS_PROVIDED) 262 flags |= PKG_LOAD_SHLIBS_PROVIDED; 263 if (opt & INFO_PROVIDED) 264 flags |= PKG_LOAD_PROVIDES; 265 if (opt & INFO_REQUIRED) 266 flags |= PKG_LOAD_REQUIRES; 267 if (opt & INFO_ANNOTATIONS) 268 flags |= PKG_LOAD_ANNOTATIONS; 269 if (opt & INFO_DEPS) 270 flags |= PKG_LOAD_DEPS|PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_REQUIRES; 271 if (opt & INFO_RDEPS) 272 flags |= PKG_LOAD_RDEPS|PKG_LOAD_SHLIBS_PROVIDED|PKG_LOAD_PROVIDES; 273 if (opt & INFO_FILES) 274 flags |= PKG_LOAD_FILES; 275 if (opt & INFO_DIRS) 276 flags |= PKG_LOAD_DIRS; 277 if (opt & INFO_USERS) 278 flags |= PKG_LOAD_USERS; 279 if (opt & INFO_GROUPS) 280 flags |= PKG_LOAD_GROUPS; 281 if (opt & INFO_RAW) { 282 flags |= PKG_LOAD_CATEGORIES | 283 PKG_LOAD_LICENSES | 284 PKG_LOAD_OPTIONS | 285 PKG_LOAD_SHLIBS_REQUIRED | 286 PKG_LOAD_SHLIBS_PROVIDED | 287 PKG_LOAD_PROVIDES | 288 PKG_LOAD_REQUIRES | 289 PKG_LOAD_ANNOTATIONS | 290 PKG_LOAD_DEPS; 291 if (!remote) { 292 flags |= PKG_LOAD_FILES | 293 PKG_LOAD_DIRS | 294 PKG_LOAD_USERS | 295 PKG_LOAD_GROUPS | 296 PKG_LOAD_SCRIPTS | 297 PKG_LOAD_LUA_SCRIPTS; 298 } 299 } 300 301 return flags; 302 } 303 304 typedef struct pkgdb_it *(*pkgdb_query_fn)(struct pkgdb *, const char *); 305 306 static void 307 print_depinfo(struct pkgdb *db, struct pkg *pkg, bool print_tag, 308 int shlib_attr, const char *shlib_label, pkgdb_query_fn shlib_query, 309 int provide_attr, const char *provide_label, pkgdb_query_fn provide_query) 310 { 311 struct pkg_stringlist *sl = NULL; 312 struct pkg_stringlist_iterator *slit; 313 struct pkgbase *pb; 314 bool shlibstag = false; 315 bool reqtag = false; 316 const char *buf; 317 struct pkgdb_it *it; 318 struct pkg *p = NULL; 319 320 pkg_get(pkg, shlib_attr, &sl); 321 pb = pkgbase_new(db); 322 slit = pkg_stringlist_iterator(sl); 323 while ((buf = pkg_stringlist_next(slit))) { 324 if (pkgbase_provide_shlib(pb, buf)) 325 continue; 326 if (!shlibstag) { 327 if (print_tag) 328 printf("%-15s:\n", shlib_label); 329 shlibstag = true; 330 } 331 it = shlib_query(db, buf); 332 while (pkgdb_it_next(it, &p, PKG_LOAD_BASIC) == EPKG_OK) { 333 pkg_printf("\t%n-%v (%S)\n", p, p, buf); 334 } 335 pkgdb_it_free(it); 336 } 337 free(slit); 338 free(sl); 339 340 pkg_get(pkg, provide_attr, &sl); 341 slit = pkg_stringlist_iterator(sl); 342 while ((buf = pkg_stringlist_next(slit))) { 343 if (!reqtag) { 344 if (print_tag) 345 printf("%-15s:\n", provide_label); 346 reqtag = true; 347 } 348 it = provide_query(db, buf); 349 while (pkgdb_it_next(it, &p, PKG_LOAD_BASIC) == EPKG_OK) { 350 pkg_printf("\t%n-%v (%S)\n", p, p, buf); 351 } 352 pkgdb_it_free(it); 353 } 354 free(slit); 355 free(sl); 356 pkgbase_free(pb); 357 } 358 359 void 360 print_info(struct pkgdb *db, struct pkg * const pkg, uint64_t options) 361 { 362 bool print_tag = false; 363 bool show_locks = false; 364 bool is_group = false; 365 const char *repourl = NULL; 366 unsigned opt; 367 int cout = 0; /* Number of characters output */ 368 int info_num; /* Number of different data items to print */ 369 int outflags = PKG_MANIFEST_EMIT_LOCAL_METADATA; 370 371 pkg_get(pkg, PKG_ATTR_REPOURL, &repourl); 372 373 if (options & INFO_RAW) { 374 switch (options & (INFO_RAW_YAML|INFO_RAW_JSON|INFO_RAW_JSON_COMPACT|INFO_RAW_UCL)) { 375 case INFO_RAW_YAML: 376 outflags |= PKG_MANIFEST_EMIT_PRETTY; 377 break; 378 case INFO_RAW_UCL: 379 outflags |= PKG_MANIFEST_EMIT_UCL; 380 break; 381 case INFO_RAW_JSON: 382 outflags |= PKG_MANIFEST_EMIT_JSON; 383 break; 384 case INFO_RAW_JSON_COMPACT: 385 break; 386 default: 387 outflags |= PKG_MANIFEST_EMIT_UCL; 388 } 389 if (pkg_type(pkg) == PKG_REMOTE) 390 outflags |= PKG_MANIFEST_EMIT_COMPACT; 391 392 pkg_emit_manifest_file(pkg, stdout, outflags); 393 return; 394 } 395 396 /* Show locking status when requested to display it and the 397 package is locally installed */ 398 if (pkg_type(pkg) == PKG_INSTALLED && (options & INFO_LOCKED) != 0) 399 show_locks = true; 400 if (pkg_type(pkg) == PKG_GROUP_REMOTE || pkg_type(pkg) == PKG_GROUP_INSTALLED) 401 is_group = true; 402 403 if (!quiet) { 404 /* Print a tag-line identifying the package -- either 405 NAMEVER, ORIGIN or NAME (in that order of 406 preference). This may be the only output from this 407 function */ 408 409 if (options & INFO_TAG_NAMEVER) { 410 if (is_group) 411 cout = pkg_printf("@%n", pkg); 412 else 413 cout = pkg_printf("%n-%v", pkg, pkg); 414 } 415 else if (options & INFO_TAG_ORIGIN) { 416 if (is_group) 417 return; 418 cout = pkg_printf("%o", pkg); 419 } 420 else if (options & INFO_TAG_NAME) { 421 if (is_group) 422 cout = pkg_printf("@%n", pkg); 423 else 424 cout = pkg_printf("%n", pkg); 425 } 426 } 427 428 /* If we printed a tag, and there are no other items to print, 429 then just return now. If there's only one single-line item 430 to print, show it at column 32 on the same line. If there's 431 one multi-line item to print, start a new line. If there is 432 more than one item to print per pkg, use 'key : value' 433 style to show on a new line. */ 434 435 info_num = 0; 436 for (opt = 0x1U; opt <= INFO_LASTFIELD; opt <<= 1) 437 if ((opt & options) != 0) 438 info_num++; 439 440 if (info_num == 0 && cout > 0) { 441 putchar('\n'); 442 return; 443 } 444 445 if (info_num == 1) { 446 /* Only one item to print */ 447 print_tag = false; 448 if (!quiet) { 449 if (options & INFO_MULTILINE) 450 printf(":\n"); 451 else { 452 if (cout < 31) 453 cout = 31 - cout; 454 else 455 cout = 1; 456 printf("%*s", cout, " "); 457 } 458 } 459 } else { 460 /* Several items to print */ 461 print_tag = true; 462 if (!quiet) 463 putchar('\n'); 464 } 465 466 for (opt = 0x1; opt <= INFO_LASTFIELD; opt <<= 1) { 467 if ((opt & options) == 0) 468 continue; 469 470 switch (opt) { 471 case INFO_NAME: 472 if (print_tag) 473 printf("%-15s: ", "Name"); 474 pkg_printf("%n\n", pkg); 475 break; 476 case INFO_INSTALLED: 477 if (pkg_type(pkg) == PKG_INSTALLED) { 478 if (print_tag) { 479 printf("%-15s: ", "Installed on"); 480 pkg_printf("%t%{%c %Z%}\n", pkg); 481 } 482 } else if (!print_tag) 483 putchar('\n'); 484 break; 485 case INFO_VERSION: 486 if (is_group) 487 break; 488 if (print_tag) 489 printf("%-15s: ", "Version"); 490 pkg_printf("%v\n", pkg); 491 break; 492 case INFO_ORIGIN: 493 if (is_group) 494 break; 495 if (print_tag) 496 printf("%-15s: ", "Origin"); 497 pkg_printf("%o\n", pkg); 498 break; 499 case INFO_PREFIX: 500 if (is_group) 501 break; 502 if (print_tag) 503 printf("%-15s: ", "Prefix"); 504 pkg_printf("%p\n", pkg); 505 break; 506 case INFO_REPOSITORY: 507 if (is_group) 508 break; 509 if (pkg_type(pkg) == PKG_REMOTE && 510 repourl != NULL && repourl[0] != '\0') { 511 if (print_tag) 512 printf("%-15s: ", "Repository"); 513 pkg_printf("%N [%S]\n", pkg, repourl); 514 } else if (!print_tag) 515 putchar('\n'); 516 break; 517 case INFO_CATEGORIES: 518 if (is_group) 519 break; 520 if (print_tag) 521 printf("%-15s: ", "Categories"); 522 pkg_printf("%C%{%Cn%| %}\n", pkg); 523 break; 524 case INFO_LICENSES: 525 if (is_group) 526 break; 527 if (print_tag) 528 printf("%-15s: ", "Licenses"); 529 pkg_printf("%L%{%Ln%| %l %}\n", pkg); 530 break; 531 case INFO_MAINTAINER: 532 if (is_group) 533 break; 534 if (print_tag) 535 printf("%-15s: ", "Maintainer"); 536 pkg_printf("%m\n", pkg); 537 break; 538 case INFO_WWW: 539 if (is_group) 540 break; 541 if (print_tag) 542 printf("%-15s: ", "WWW"); 543 pkg_printf("%w\n", pkg); 544 break; 545 case INFO_COMMENT: 546 if (print_tag) 547 printf("%-15s: ", "Comment"); 548 pkg_printf("%c\n", pkg); 549 break; 550 case INFO_OPTIONS: 551 if (pkg_list_count(pkg, PKG_OPTIONS) > 0) { 552 if (print_tag) 553 printf("%-15s:\n", "Options"); 554 if (quiet) 555 pkg_printf("%O%{%-15On: %Ov\n%|%}", pkg); 556 else 557 pkg_printf("%O%{\t%-15On: %Ov\n%|%}", pkg); 558 } 559 break; 560 case INFO_SHLIBS_REQUIRED: 561 if (pkg_list_count(pkg, PKG_SHLIBS_REQUIRED) > 0) { 562 if (print_tag) 563 printf("%-15s:\n", "Shared Libs required"); 564 if (quiet) 565 pkg_printf("%B%{%Bn\n%|%}", pkg); 566 else 567 pkg_printf("%B%{\t%Bn\n%|%}", pkg); 568 } 569 break; 570 case INFO_SHLIBS_PROVIDED: 571 if (pkg_list_count(pkg, PKG_SHLIBS_PROVIDED) > 0) { 572 if (print_tag) 573 printf("%-15s:\n", "Shared Libs provided"); 574 if (quiet) 575 pkg_printf("%b%{%bn\n%|%}", pkg); 576 else 577 pkg_printf("%b%{\t%bn\n%|%}", pkg); 578 } 579 break; 580 case INFO_REQUIRED: 581 if (pkg_list_count(pkg, PKG_REQUIRES) > 0) { 582 if (print_tag) 583 printf("%-15s:\n", "Requires"); 584 if (quiet) 585 pkg_printf("%Y%{%Yn\n%|%}", pkg); 586 else 587 pkg_printf("%Y%{\t%Yn\n%|%}", pkg); 588 } 589 break; 590 case INFO_PROVIDED: 591 if (pkg_list_count(pkg, PKG_PROVIDES) > 0) { 592 if (print_tag) 593 printf("%-15s:\n", "Provides"); 594 if (quiet) 595 pkg_printf("%y%{%yn\n%|%}", pkg); 596 else 597 pkg_printf("%y%{\t%yn\n%|%}", pkg); 598 } 599 break; 600 case INFO_ANNOTATIONS: 601 if (is_group) 602 break; 603 if (print_tag) 604 printf("%-15s:\n", "Annotations"); 605 if (quiet) 606 pkg_printf("%A%{%-15An: %Av\n%|%}", pkg); 607 else 608 pkg_printf("%A%{\t%-15An: %Av\n%|%}", pkg); 609 break; 610 case INFO_FLATSIZE: 611 if (is_group) 612 break; 613 if (print_tag) 614 printf("%-15s: ", "Flat size"); 615 pkg_printf("%#sB\n", pkg); 616 break; 617 case INFO_PKGSIZE: /* Remote pkgs only */ 618 if (pkg_type(pkg) == PKG_REMOTE) { 619 if (print_tag) 620 printf("%-15s: ", "Pkg size"); 621 pkg_printf("%#xB\n", pkg); 622 } else if (!print_tag) 623 putchar('\n'); 624 break; 625 case INFO_DESCR: 626 if (is_group) 627 break; 628 if (print_tag) 629 printf("%-15s:\n", "Description"); 630 pkg_printf("%e\n", pkg); 631 break; 632 case INFO_MESSAGE: 633 if (is_group) 634 break; 635 if (print_tag) 636 printf("%-15s:\n", "Message"); 637 if (pkg_has_message(pkg)) 638 pkg_printf("%M\n", pkg); 639 break; 640 case INFO_DEPS: 641 if (pkg_list_count(pkg, PKG_DEPS) > 0) { 642 if (print_tag) 643 printf("%-15s:\n", "Depends on"); 644 if (quiet) { 645 if (show_locks) 646 pkg_printf("%d%{%dn-%dv%#dk\n%|%}", pkg); 647 else 648 pkg_printf("%d%{%dn-%dv\n%|%}", pkg); 649 } else { 650 if (show_locks) 651 pkg_printf("%d%{\t%dn-%dv%#dk\n%|%}", pkg); 652 else 653 pkg_printf("%d%{\t%dn-%dv\n%|%}", pkg); 654 } 655 } 656 if (db != NULL) 657 print_depinfo(db, pkg, print_tag, 658 PKG_ATTR_SHLIBS_REQUIRED, "Shared library requirements", 659 pkgdb_query_shlib_provide, 660 PKG_ATTR_REQUIRES, "Requirements", 661 pkgdb_query_provide); 662 break; 663 case INFO_RDEPS: 664 if (pkg_list_count(pkg, PKG_RDEPS) > 0) { 665 if (print_tag) 666 printf("%-15s:\n", "Required by"); 667 if (quiet) { 668 if (show_locks) 669 pkg_printf("%r%{%rn-%rv%#rk\n%|%}", pkg); 670 else 671 pkg_printf("%r%{%rn-%rv\n%|%}", pkg); 672 } else { 673 if (show_locks) 674 pkg_printf("%r%{\t%rn-%rv%#rk\n%|%}", pkg); 675 else 676 pkg_printf("%r%{\t%rn-%rv\n%|%}", pkg); 677 } 678 } 679 if (db != NULL) 680 print_depinfo(db, pkg, print_tag, 681 PKG_ATTR_SHLIBS_PROVIDED, "Shared library provided", 682 pkgdb_query_shlib_require, 683 PKG_ATTR_PROVIDES, "Provides", 684 pkgdb_query_require); 685 break; 686 case INFO_FILES: /* Installed pkgs only */ 687 if (pkg_type(pkg) != PKG_REMOTE && 688 pkg_list_count(pkg, PKG_FILES) > 0) { 689 if (print_tag) 690 printf("%-15s:\n", "Files"); 691 if (quiet) 692 pkg_printf("%F%{%Fn\n%|%}", pkg); 693 else 694 pkg_printf("%F%{\t%Fn\n%|%}", pkg); 695 } 696 break; 697 case INFO_DIRS: /* Installed pkgs only */ 698 if (pkg_type(pkg) != PKG_REMOTE && 699 pkg_list_count(pkg, PKG_DIRS) > 0) { 700 if (print_tag) 701 printf("%-15s:\n", "Directories"); 702 if (quiet) 703 pkg_printf("%D%{%Dn\n%|%}", pkg); 704 else 705 pkg_printf("%D%{\t%Dn\n%|%}", pkg); 706 } 707 break; 708 case INFO_USERS: /* Installed pkgs only */ 709 if (pkg_type(pkg) != PKG_REMOTE && 710 pkg_list_count(pkg, PKG_USERS) > 0) { 711 if (print_tag) 712 printf("%-15s: ", "Users"); 713 pkg_printf("%U%{%Un%| %}\n", pkg); 714 } 715 break; 716 case INFO_GROUPS: /* Installed pkgs only */ 717 if (pkg_type(pkg) != PKG_REMOTE && 718 pkg_list_count(pkg, PKG_GROUPS) > 0) { 719 if (print_tag) 720 printf("%-15s: ", "Groups"); 721 pkg_printf("%G%{%Gn%| %}\n", pkg); 722 } 723 break; 724 case INFO_ARCH: 725 if (is_group) 726 break; 727 if (print_tag) 728 printf("%-15s: ", "Architecture"); 729 pkg_printf("%q\n", pkg); 730 break; 731 case INFO_REPOURL: 732 if (pkg_type(pkg) == PKG_REMOTE && 733 repourl != NULL && repourl[0] != '\0') { 734 if (print_tag) 735 printf("%-15s: ", "Pkg URL"); 736 if (repourl[strlen(repourl) -1] == '/') 737 pkg_printf("%S%R\n", repourl, pkg); 738 else 739 pkg_printf("%S/%R\n", repourl, pkg); 740 } else if (!print_tag) 741 putchar('\n'); 742 break; 743 case INFO_LOCKED: 744 if (print_tag) 745 printf("%-15s: ", "Locked"); 746 pkg_printf("%?k\n", pkg); 747 break; 748 } 749 } 750 } 751 752 enum pkg_display_type { 753 PKG_DISPLAY_LOCKED = 0, 754 PKG_DISPLAY_INSTALL, 755 PKG_DISPLAY_UPGRADE, 756 PKG_DISPLAY_DOWNGRADE, 757 PKG_DISPLAY_REINSTALL, 758 PKG_DISPLAY_DELETE, 759 PKG_DISPLAY_FETCH, 760 PKG_DISPLAY_GROUP_INSTALL, 761 PKG_DISPLAY_GROUP_UPGRADE, 762 PKG_DISPLAY_MAX 763 }; 764 struct pkg_solved_display { 765 struct pkg *new, *old; 766 enum pkg_display_type display_type; 767 pkg_solved_t solved_type; 768 }; 769 770 typedef vec_t(struct pkg_solved_display *) pkg_solved_display_t; 771 772 static void 773 set_jobs_summary_pkg(struct pkg_jobs *jobs, struct pkg *new_pkg, 774 struct pkg *old_pkg, pkg_solved_t type, int64_t *oldsize, 775 int64_t *newsize, int64_t *dlsize, pkg_solved_display_t *disp, 776 struct jobs_sum_number *sum) 777 { 778 const char *repopath = NULL, *destdir; 779 char path[MAXPATHLEN]; 780 int ret; 781 struct stat st; 782 int64_t flatsize, oldflatsize, pkgsize; 783 struct pkg_solved_display *it; 784 785 flatsize = oldflatsize = pkgsize = 0; 786 787 pkg_get(new_pkg, PKG_ATTR_FLATSIZE, &flatsize); 788 pkg_get(new_pkg, PKG_ATTR_PKGSIZE, &pkgsize); 789 pkg_get(new_pkg, PKG_ATTR_REPOPATH, &repopath); 790 if (old_pkg != NULL) 791 pkg_get(old_pkg, PKG_ATTR_FLATSIZE, &oldflatsize); 792 793 it = xmalloc(sizeof (*it)); 794 it->new = new_pkg; 795 it->old = old_pkg; 796 it->solved_type = type; 797 it->display_type = PKG_DISPLAY_MAX; 798 799 if (old_pkg != NULL && pkg_is_locked(old_pkg)) { 800 it->display_type = PKG_DISPLAY_LOCKED; 801 vec_push(&disp[it->display_type], it); 802 return; 803 } 804 805 destdir = pkg_jobs_destdir(jobs); 806 807 switch (type) { 808 case PKG_SOLVED_INSTALL: 809 case PKG_SOLVED_UPGRADE: 810 if (destdir == NULL) 811 ret = pkg_repo_cached_name(new_pkg, path, sizeof(path)); 812 else if (repopath != NULL) { 813 snprintf(path, sizeof(path), "%s/%s", destdir, repopath); 814 ret = EPKG_OK; 815 } else 816 break; 817 818 if ((ret == EPKG_OK || ret == EPKG_FATAL) && (stat(path, &st) == -1 || pkgsize != st.st_size)) { 819 /* file looks corrupted (wrong size), 820 assume a checksum mismatch will 821 occur later and the file will be 822 fetched from remote again */ 823 *dlsize += pkgsize; 824 nbtodl += 1; 825 } 826 827 if (pkg_type(new_pkg) == PKG_GROUP_REMOTE) { 828 if (old_pkg == NULL) { 829 it->display_type = PKG_DISPLAY_GROUP_INSTALL; 830 sum->group_install++; 831 } else { 832 it->display_type = PKG_DISPLAY_GROUP_UPGRADE; 833 sum->group_upgrade++; 834 } 835 } else { 836 if (old_pkg != NULL) { 837 switch (pkg_version_change_between(new_pkg, old_pkg)) { 838 case PKG_DOWNGRADE: 839 it->display_type = PKG_DISPLAY_DOWNGRADE; 840 sum->downgrade++; 841 break; 842 case PKG_REINSTALL: 843 it->display_type = PKG_DISPLAY_REINSTALL; 844 sum->reinstall++; 845 break; 846 case PKG_UPGRADE: 847 it->display_type = PKG_DISPLAY_UPGRADE; 848 sum->upgrade++; 849 break; 850 } 851 *oldsize += oldflatsize; 852 *newsize += flatsize; 853 } else { 854 it->display_type = PKG_DISPLAY_INSTALL; 855 sum->install++; 856 *newsize += flatsize; 857 } 858 } 859 break; 860 case PKG_SOLVED_DELETE: 861 *oldsize += flatsize; 862 it->display_type = PKG_DISPLAY_DELETE; 863 sum->delete++; 864 break; 865 case PKG_SOLVED_UPGRADE_INSTALL: 866 case PKG_SOLVED_UPGRADE_REMOVE: 867 /* Ignore split-upgrade packages for display */ 868 free(it); 869 return; 870 871 case PKG_SOLVED_FETCH: 872 *newsize += pkgsize; 873 it->display_type = PKG_DISPLAY_FETCH; 874 if (destdir == NULL) 875 pkg_repo_cached_name(new_pkg, path, sizeof(path)); 876 else 877 snprintf(path, sizeof(path), "%s/%s", destdir, repopath); 878 879 if (stat(path, &st) != -1) { 880 *oldsize += st.st_size; 881 882 if (pkgsize != st.st_size) 883 *dlsize += pkgsize; 884 else { 885 free(it); 886 return; 887 } 888 } 889 else 890 *dlsize += pkgsize; 891 sum->fetch++; 892 893 break; 894 } 895 vec_push(&disp[it->display_type], it); 896 } 897 898 static void 899 display_summary_item(struct pkg_solved_display *it, int64_t dlsize) 900 { 901 const char *why = NULL; 902 int64_t pkgsize = 0; 903 char size[8], tlsize[8]; 904 const char *type; 905 906 pkg_get(it->new, PKG_ATTR_PKGSIZE, &pkgsize); 907 908 switch (it->display_type) { 909 case PKG_DISPLAY_LOCKED: 910 pkg_printf("\tPackage %n-%v is locked ", it->old, it->old); 911 switch (it->solved_type) { 912 case PKG_SOLVED_INSTALL: 913 case PKG_SOLVED_UPGRADE: 914 case PKG_SOLVED_UPGRADE_INSTALL: 915 /* If it's a new install, then it 916 * cannot have been locked yet. */ 917 switch (pkg_version_change_between(it->old, it->new)) { 918 case PKG_DOWNGRADE: 919 type = "downgraded"; 920 break; 921 case PKG_REINSTALL: 922 type = "reinstalled"; 923 break; 924 case PKG_UPGRADE: 925 type = "upgraded"; 926 break; 927 default: /* appease compiler warnings */ 928 type = "upgraded"; 929 break; 930 } 931 pkg_printf("and may not be %S to version %v\n", type, 932 it->new); 933 break; 934 case PKG_SOLVED_DELETE: 935 case PKG_SOLVED_UPGRADE_REMOVE: 936 printf("and may not be deinstalled\n"); 937 return; 938 case PKG_SOLVED_FETCH: 939 printf("but a new package can still be fetched\n"); 940 break; 941 } 942 break; 943 case PKG_DISPLAY_DELETE: 944 pkg_get(it->new, PKG_ATTR_REASON, &why); 945 pkg_printf("\t%n: %v", it->new, it->new); 946 if (why != NULL) 947 printf(" (%s)", why); 948 putchar('\n'); 949 break; 950 case PKG_DISPLAY_INSTALL: 951 pkg_printf("\t%n: %v", it->new, it->new); 952 if (pkg_repos_total_count() > 1) 953 pkg_printf(" [%N]", it->new); 954 putchar('\n'); 955 break; 956 case PKG_DISPLAY_UPGRADE: 957 pkg_printf("\t%n: %v -> %v", it->new, it->old, it->new); 958 if (pkg_repos_total_count() > 1) 959 pkg_printf(" [%N]", it->new); 960 putchar('\n'); 961 break; 962 case PKG_DISPLAY_DOWNGRADE: 963 pkg_printf("\t%n: %v -> %v", it->new, it->old, it->new); 964 if (pkg_repos_total_count() > 1) 965 pkg_printf(" [%N]", it->new); 966 putchar('\n'); 967 break; 968 case PKG_DISPLAY_REINSTALL: 969 pkg_get(it->new, PKG_ATTR_REASON, &why); 970 pkg_printf("\t%n-%v", it->new, it->new); 971 if (pkg_repos_total_count() > 1) 972 pkg_printf(" [%N]", it->new); 973 if (why != NULL) 974 printf(" (%s)", why); 975 putchar('\n'); 976 break; 977 case PKG_DISPLAY_FETCH: 978 humanize_number(size, sizeof(size), pkgsize, "B", 979 HN_AUTOSCALE, HN_IEC_PREFIXES); 980 humanize_number(tlsize, sizeof(size), dlsize, "B", 981 HN_AUTOSCALE, HN_IEC_PREFIXES); 982 983 pkg_printf("\t%n: %v ", it->new, it->new); 984 printf("(%s: %.2f%% of the %s to download)\n", size, 985 ((double)100 * pkgsize) / (double)dlsize, tlsize); 986 break; 987 case PKG_DISPLAY_GROUP_UPGRADE: 988 pkg_printf("\t%n", it->new, it->new); 989 if (pkg_repos_total_count() > 1) 990 pkg_printf(" [%N]", it->new); 991 putchar('\n'); 992 break; 993 case PKG_DISPLAY_GROUP_INSTALL: 994 pkg_printf("\t@%n", it->new, it->new); 995 if (pkg_repos_total_count() > 1) 996 pkg_printf(" [%N]", it->new); 997 putchar('\n'); 998 break; 999 default: 1000 break; 1001 } 1002 } 1003 1004 1005 static const char* pkg_display_messages[PKG_DISPLAY_MAX + 1] = { 1006 [PKG_DISPLAY_LOCKED] = "Installed packages LOCKED", 1007 [PKG_DISPLAY_DELETE] = "Installed packages to be REMOVED", 1008 [PKG_DISPLAY_INSTALL] = "New packages to be INSTALLED", 1009 [PKG_DISPLAY_GROUP_UPGRADE] = "New groups to be UPGRADED", 1010 [PKG_DISPLAY_DOWNGRADE] = "Installed packages to be DOWNGRADED", 1011 [PKG_DISPLAY_REINSTALL] = "Installed packages to be REINSTALLED", 1012 [PKG_DISPLAY_FETCH] = "New packages to be FETCHED", 1013 [PKG_DISPLAY_GROUP_INSTALL] = "New groups to be INSTALLED", 1014 [PKG_DISPLAY_UPGRADE] = "Installed packages to be UPGRADED", 1015 [PKG_DISPLAY_MAX] = NULL 1016 }; 1017 1018 static int 1019 namecmp(const void *a, const void *b) 1020 { 1021 const struct pkg_solved_display *sda = *(const struct pkg_solved_display **) a; 1022 const struct pkg_solved_display *sdb = *(const struct pkg_solved_display **) b; 1023 1024 return (pkg_namecmp(sda->new, sdb->new)); 1025 } 1026 1027 int 1028 print_jobs_summary(struct pkg_jobs *jobs, const char *msg, ...) 1029 { 1030 struct pkg *new_pkg, *old_pkg; 1031 void *iter = NULL; 1032 char size[8]; 1033 va_list ap; 1034 int type, displayed = 0; 1035 int64_t dlsize, oldsize, newsize; 1036 pkg_solved_display_t disp[PKG_DISPLAY_MAX]; 1037 bool first = true; 1038 size_t bytes_change, limbytes; 1039 struct jobs_sum_number sum; 1040 1041 dlsize = oldsize = newsize = 0; 1042 type = pkg_jobs_type(jobs); 1043 memset(disp, 0, sizeof(*disp) * PKG_DISPLAY_MAX); 1044 memset(&sum, 0, sizeof(sum)); 1045 1046 nbtodl = 0; 1047 while (pkg_jobs_iter(jobs, &iter, &new_pkg, &old_pkg, &type)) { 1048 set_jobs_summary_pkg(jobs, new_pkg, old_pkg, type, &oldsize, 1049 &newsize, &dlsize, disp, &sum); 1050 } 1051 1052 for (type = 0; type < PKG_DISPLAY_MAX; type ++) { 1053 if (disp[type].len != 0) { 1054 /* Space between each section. */ 1055 if (!first) 1056 putchar('\n'); 1057 else 1058 first = false; 1059 if (msg != NULL) { 1060 va_start(ap, msg); 1061 vprintf(msg, ap); 1062 va_end(ap); 1063 fflush(stdout); 1064 msg = NULL; 1065 } 1066 printf("%s:\n", pkg_display_messages[type]); 1067 qsort(disp[type].d, disp[type].len, sizeof(disp[type].d[0]), namecmp); 1068 vec_foreach(disp[type], i) { 1069 display_summary_item(disp[type].d[i], dlsize); 1070 displayed ++; 1071 } 1072 vec_free_and_free(&disp[type], free); 1073 } 1074 } 1075 1076 limbytes = pkg_object_int(pkg_config_get("WARN_SIZE_LIMIT")); 1077 bytes_change = (size_t)llabs(newsize - oldsize); 1078 1079 putchar('\n'); 1080 if (sum.delete > 0) 1081 printf("Number of packages to be removed: %d\n", sum.delete); 1082 if (sum.install > 0) 1083 printf("Number of packages to be installed: %d\n", sum.install); 1084 if (sum.upgrade > 0) 1085 printf("Number of packages to be upgraded: %d\n", sum.upgrade); 1086 if (sum.reinstall > 0) 1087 printf("Number of packages to be reinstalled: %d\n", 1088 sum.reinstall); 1089 if (sum.downgrade > 0) 1090 printf("Number of packages to be downgraded: %d\n", 1091 sum.downgrade); 1092 if (sum.fetch > 0) 1093 printf("Number of packages to be fetched: %d\n", sum.fetch); 1094 if (sum.group_install > 0) 1095 printf("Number of groups to be installed: %d\n", sum.group_install); 1096 if (sum.group_upgrade > 0) 1097 printf("Number of groups to be upgraded: %d\n", sum.group_upgrade); 1098 /* Add an extra line before the size output. */ 1099 if (bytes_change > limbytes || dlsize) 1100 putchar('\n'); 1101 1102 if (bytes_change > limbytes) { 1103 if (oldsize > newsize) { 1104 humanize_number(size, sizeof(size), oldsize - newsize, "B", 1105 HN_AUTOSCALE, HN_IEC_PREFIXES); 1106 printf("The operation will free %s.\n", size); 1107 } else if (newsize > oldsize) { 1108 humanize_number(size, sizeof(size), newsize - oldsize, "B", 1109 HN_AUTOSCALE, HN_IEC_PREFIXES); 1110 printf("The process will require %s more space.\n", size); 1111 } 1112 } 1113 1114 if (dlsize > 0) { 1115 humanize_number(size, sizeof(size), dlsize, "B", 1116 HN_AUTOSCALE, HN_IEC_PREFIXES); 1117 printf("%s to be downloaded.\n", size); 1118 } 1119 1120 return (displayed); 1121 } 1122 1123 int 1124 print_pkg(struct pkg *p, void *ctx) 1125 { 1126 int *counter = ctx; 1127 bool locked, vital; 1128 const char *lock_type; 1129 1130 pkg_get(p, PKG_ATTR_LOCKED, &locked); 1131 pkg_get(p, PKG_ATTR_VITAL, &vital); 1132 if (locked) { 1133 if (vital) 1134 lock_type = "vital and locked"; 1135 else 1136 lock_type = "locked"; 1137 } else { 1138 if (vital) 1139 lock_type = "vital"; 1140 else 1141 lock_type = "invalid, report an issue"; 1142 } 1143 pkg_printf("\t%n (%S)\n", p, lock_type); 1144 (*counter)++; 1145 1146 return 0; 1147 } 1148 1149 void 1150 print_repository(struct pkg_repo *repo, bool pad) 1151 { 1152 const char *mirror, *sig; 1153 1154 switch (pkg_repo_mirror_type(repo)) { 1155 case SRV: 1156 mirror = "SRV"; 1157 break; 1158 case HTTP: 1159 mirror = "HTTP"; 1160 break; 1161 case NOMIRROR: 1162 mirror = "NONE"; 1163 break; 1164 default: 1165 mirror = "-unknown-"; 1166 break; 1167 } 1168 switch (pkg_repo_signature_type(repo)) { 1169 case SIG_PUBKEY: 1170 sig = "PUBKEY"; 1171 break; 1172 case SIG_FINGERPRINT: 1173 sig = "FINGERPRINTS"; 1174 break; 1175 case SIG_NONE: 1176 sig = "NONE"; 1177 break; 1178 default: 1179 sig = "-unknown-"; 1180 break; 1181 } 1182 1183 printf("%s%s: { \n %-16s: \"%s\",\n %-16s: %s,\n" 1184 " %-16s: %d", 1185 pad ? " " : "", 1186 pkg_repo_name(repo), 1187 "url", pkg_repo_url(repo), 1188 "enabled", pkg_repo_enabled(repo) ? "yes" : "no", 1189 "priority", pkg_repo_priority(repo)); 1190 1191 if (pkg_repo_mirror_type(repo) != NOMIRROR) 1192 printf(",\n %-16s: \"%s\"", 1193 "mirror_type", mirror); 1194 if (pkg_repo_signature_type(repo) != SIG_NONE) 1195 printf(",\n %-16s: \"%s\"", 1196 "signature_type", sig); 1197 if (pkg_repo_fingerprints(repo) != NULL) 1198 printf(",\n %-16s: \"%s\"", 1199 "fingerprints", pkg_repo_fingerprints(repo)); 1200 if (pkg_repo_key(repo) != NULL) 1201 printf(",\n %-16s: \"%s\"", 1202 "pubkey", pkg_repo_key(repo)); 1203 if (pkg_repo_ssh_args(repo) != NULL) 1204 printf(",\n %-16s: \"%s\"", 1205 "ssh_args", pkg_repo_ssh_args(repo)); 1206 if (pkg_repo_ip_version(repo) != 0) 1207 printf(",\n %-16s: %u", 1208 "ip_version", pkg_repo_ip_version(repo)); 1209 printf("\n }\n"); 1210 } 1211 1212 void 1213 pkgcli_autoremove(struct pkgdb *db, bool flag) 1214 { 1215 struct pkg_jobs *jobs = NULL; 1216 int nbactions; 1217 pkg_flags f = PKG_FLAG_FORCE; 1218 1219 if (!flag && !pkg_object_bool(pkg_config_get("AUTOREMOVE"))) 1220 return; 1221 if (dry_run) 1222 return; 1223 1224 if (pkg_jobs_new(&jobs, PKG_JOBS_AUTOREMOVE, db) != EPKG_OK) 1225 return; 1226 1227 pkg_jobs_set_flags(jobs, f); 1228 1229 if (pkg_jobs_solve(jobs) != EPKG_OK) { 1230 pkg_jobs_free(jobs); 1231 return; 1232 } 1233 1234 if ((nbactions = pkg_jobs_count(jobs)) == 0) { 1235 pkg_jobs_free(jobs); 1236 return; 1237 } 1238 1239 if (!quiet) { 1240 print_jobs_summary(jobs, 1241 "Autoremoval has been requested for the following " 1242 "%d packages:\n\n", nbactions); 1243 } 1244 1245 if (yes || query_yesno(false, 1246 "\nProceed with autoremoval of packages? ")) { 1247 pkg_jobs_apply(jobs); 1248 } 1249 1250 pkg_jobs_free(jobs); 1251 pkgdb_compact(db); 1252 }