/ src / utils.c
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  }