/ src / query.c
query.c
   1  /*-
   2   * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
   3   * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
   4   * Copyright (c) 2012 Bryan Drewery <bryan@shatow.net>
   5   * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org>
   6   * All rights reserved.
   7   *
   8   * Redistribution and use in source and binary forms, with or without
   9   * modification, are permitted provided that the following conditions
  10   * are met:
  11   * 1. Redistributions of source code must retain the above copyright
  12   *    notice, this list of conditions and the following disclaimer
  13   *    in this position and unchanged.
  14   * 2. Redistributions in binary form must reproduce the above copyright
  15   *    notice, this list of conditions and the following disclaimer in the
  16   *    documentation and/or other materials provided with the distribution.
  17   *
  18   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  19   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21   * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  22   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28   */
  29  
  30  #include <sys/types.h>
  31  
  32  #include <ctype.h>
  33  #include <err.h>
  34  #include <getopt.h>
  35  #include <inttypes.h>
  36  #include <stdio.h>
  37  #include <stdlib.h>
  38  #include <string.h>
  39  #include <unistd.h>
  40  
  41  #include <pkg.h>
  42  #include "pkgcli.h"
  43  
  44  static const struct query_flags accepted_query_flags[] = {
  45  	{ 'd', "nov",		1, PKG_LOAD_DEPS },
  46  	{ 'r', "nov",		1, PKG_LOAD_RDEPS },
  47  	{ 'C', "",		1, PKG_LOAD_CATEGORIES },
  48  	{ 'F', "psugmftl",	1, PKG_LOAD_FILES },
  49  	{ 'O', "kvdD",		1, PKG_LOAD_OPTIONS },
  50  	{ 'D', "",		1, PKG_LOAD_DIRS },
  51  	{ 'S', "pugmf",		1, PKG_LOAD_DIRS }, /* sub directories - directory with options */
  52  	{ 'L', "",		1, PKG_LOAD_LICENSES },
  53  	{ 'U', "",		1, PKG_LOAD_USERS },
  54  	{ 'G', "",		1, PKG_LOAD_GROUPS },
  55  	{ 'B', "",		1, PKG_LOAD_SHLIBS_REQUIRED },
  56  	{ 'b', "",		1, PKG_LOAD_SHLIBS_PROVIDED },
  57  	{ 'y', "",		1, PKG_LOAD_PROVIDES },
  58  	{ 'Y', "",		1, PKG_LOAD_REQUIRES },
  59  	{ 'A', "tv",            1, PKG_LOAD_ANNOTATIONS },
  60  	{ '?', "drCFODLUGBbAyY",	1, PKG_LOAD_BASIC },	/* dbflags handled in analyse_query_string() */
  61  	{ '#', "drCFODLUGBbAyY",	1, PKG_LOAD_BASIC },	/* dbflags handled in analyse_query_string() */
  62  	{ 's', "hb",		0, PKG_LOAD_BASIC },
  63  	{ 'Q', "",		0, PKG_LOAD_BASIC },
  64  	{ 'n', "",		0, PKG_LOAD_BASIC },
  65  	{ 'v', "",		0, PKG_LOAD_BASIC },
  66  	{ 'o', "",		0, PKG_LOAD_BASIC },
  67  	{ 'p', "",		0, PKG_LOAD_BASIC },
  68  	{ 'm', "",		0, PKG_LOAD_BASIC },
  69  	{ 'c', "",		0, PKG_LOAD_BASIC },
  70  	{ 'e', "",		0, PKG_LOAD_BASIC },
  71  	{ 'w', "",		0, PKG_LOAD_BASIC },
  72  	{ 'l', "",		0, PKG_LOAD_BASIC },
  73  	{ 'q', "",		0, PKG_LOAD_BASIC },
  74  	{ 'a', "",		0, PKG_LOAD_BASIC },
  75  	{ 'k', "",		0, PKG_LOAD_BASIC },
  76  	{ 'M', "",		0, PKG_LOAD_BASIC },
  77  	{ 't', "",		0, PKG_LOAD_BASIC },
  78  	{ 'R', "",              0, PKG_LOAD_ANNOTATIONS },
  79  	{ 'V', "",		0, PKG_LOAD_BASIC },
  80  	{ 'X', "",		0, PKG_LOAD_BASIC | PKG_LOAD_SCRIPTS | PKG_LOAD_LUA_SCRIPTS },
  81  };
  82  
  83  static void
  84  format_str(struct pkg *pkg, xstring *dest, const char *qstr, const void *data)
  85  {
  86  	bool automatic = false;
  87  	bool locked = false;
  88  	bool vital = false;
  89  
  90  	xstring_reset(dest);
  91  
  92  	while (qstr[0] != '\0') {
  93  		if (qstr[0] == '%') {
  94  			qstr++;
  95  			switch (qstr[0]) {
  96  			case 'n':
  97  				pkg_fprintf(dest->fp, "%n", pkg);
  98  				break;
  99  			case 'v':
 100  				pkg_fprintf(dest->fp, "%v", pkg);
 101  				break;
 102  			case 'o':
 103  				pkg_fprintf(dest->fp, "%o", pkg);
 104  				break;
 105  			case 'R':
 106  				pkg_fprintf(dest->fp, "%N", pkg);
 107  				break;
 108  			case 'p':
 109  				pkg_fprintf(dest->fp, "%p", pkg);
 110  				break;
 111  			case 'm':
 112  				pkg_fprintf(dest->fp, "%m", pkg);
 113  				break;
 114  			case 'c':
 115  				pkg_fprintf(dest->fp, "%c", pkg);
 116  				break;
 117  			case 'w':
 118  				pkg_fprintf(dest->fp, "%w", pkg);
 119  				break;
 120  			case 'a':
 121  				pkg_get(pkg, PKG_ATTR_AUTOMATIC, &automatic);
 122  				fprintf(dest->fp, "%d", automatic);
 123  				break;
 124  			case 'k':
 125  				pkg_get(pkg, PKG_ATTR_LOCKED, &locked);
 126  				fprintf(dest->fp, "%d", locked);
 127  				break;
 128  			case 't':
 129  				pkg_fprintf(dest->fp, "%t", pkg);
 130  				break;
 131  			case 's':
 132  				qstr++;
 133  				if (qstr[0] == 'h')
 134  					pkg_fprintf(dest->fp, "%#sB", pkg);
 135  				else if (qstr[0] == 'b')
 136  					pkg_fprintf(dest->fp, "%s", pkg);
 137  				break;
 138  			case 'e':
 139  				pkg_fprintf(dest->fp, "%e", pkg);
 140  				break;
 141  			case '?':
 142  				qstr++;
 143  				switch (qstr[0]) {
 144  				case 'd':
 145  					pkg_fprintf(dest->fp, "%?d", pkg);
 146  					break;
 147  				case 'r':
 148  					pkg_fprintf(dest->fp, "%?r", pkg);
 149  					break;
 150  				case 'C':
 151  					pkg_fprintf(dest->fp, "%?C", pkg);
 152  					break;
 153  				case 'F':
 154  					pkg_fprintf(dest->fp, "%?F", pkg);
 155  					break;
 156  				case 'O':
 157  					pkg_fprintf(dest->fp, "%?O", pkg);
 158  					break;
 159  				case 'D':
 160  				case 'S':
 161  					pkg_fprintf(dest->fp, "%?D", pkg);
 162  					break;
 163  				case 'L':
 164  					pkg_fprintf(dest->fp, "%?L", pkg);
 165  					break;
 166  				case 'U':
 167  					pkg_fprintf(dest->fp, "%?U", pkg);
 168  					break;
 169  				case 'G':
 170  					pkg_fprintf(dest->fp, "%?G", pkg);
 171  					break;
 172  				case 'B':
 173  					pkg_fprintf(dest->fp, "%?B", pkg);
 174  					break;
 175  				case 'b':
 176  					pkg_fprintf(dest->fp, "%?b", pkg);
 177  					break;
 178  				case 'y':
 179  					pkg_fprintf(dest->fp, "%?y", pkg);
 180  					break;
 181  				case 'Y':
 182  					pkg_fprintf(dest->fp, "%?Y", pkg);
 183  					break;
 184  				case 'A':
 185  					pkg_fprintf(dest->fp, "%?A", pkg);
 186  					break;
 187  				}
 188  				break;
 189  			case '#':
 190  				qstr++;
 191  				switch (qstr[0]) {
 192  				case 'd':
 193  					pkg_fprintf(dest->fp, "%#d", pkg);
 194  					break;
 195  				case 'r':
 196  					pkg_fprintf(dest->fp, "%#r", pkg);
 197  					break;
 198  				case 'C':
 199  					pkg_fprintf(dest->fp, "%#C", pkg);
 200  					break;
 201  				case 'F':
 202  					pkg_fprintf(dest->fp, "%#F", pkg);
 203  					break;
 204  				case 'O':
 205  					pkg_fprintf(dest->fp, "%#O", pkg);
 206  					break;
 207  				case 'D':
 208  					pkg_fprintf(dest->fp, "%#D", pkg);
 209  					break;
 210  				case 'L':
 211  					pkg_fprintf(dest->fp, "%#L", pkg);
 212  					break;
 213  				case 'U':
 214  					pkg_fprintf(dest->fp, "%#U", pkg);
 215  					break;
 216  				case 'G':
 217  					pkg_fprintf(dest->fp, "%#G", pkg);
 218  					break;
 219  				case 'B':
 220  					pkg_fprintf(dest->fp, "%#B", pkg);
 221  					break;
 222  				case 'b':
 223  					pkg_fprintf(dest->fp, "%#b", pkg);
 224  					break;
 225  				case 'y':
 226  					pkg_fprintf(dest->fp, "%#y", pkg);
 227  					break;
 228  				case 'Y':
 229  					pkg_fprintf(dest->fp, "%#Y", pkg);
 230  					break;
 231  				case 'A':
 232  					pkg_fprintf(dest->fp, "%#A", pkg);
 233  					break;
 234  				}
 235  				break;
 236  			case 'Q':
 237  				pkg_fprintf(dest->fp, "%Q", pkg);
 238  				break;
 239  			case 'q':
 240  				pkg_fprintf(dest->fp, "%q", pkg);
 241  				break;
 242  			case 'l':
 243  				pkg_fprintf(dest->fp, "%l", pkg);
 244  				break;
 245  			case 'd':
 246  				qstr++;
 247  				if (qstr[0] == 'n')
 248  					pkg_fprintf(dest->fp, "%dn", data);
 249  				else if (qstr[0] == 'o')
 250  					pkg_fprintf(dest->fp, "%do", data);
 251  				else if (qstr[0] == 'v')
 252  					pkg_fprintf(dest->fp, "%dv", data);
 253  				break;
 254  			case 'r':
 255  				qstr++;
 256  				if (qstr[0] == 'n')
 257  					pkg_fprintf(dest->fp, "%rn", data);
 258  				else if (qstr[0] == 'o')
 259  					pkg_fprintf(dest->fp, "%ro", data);
 260  				else if (qstr[0] == 'v')
 261  					pkg_fprintf(dest->fp, "%rv", data);
 262  				break;
 263  			case 'C':
 264  				pkg_fprintf(dest->fp, "%Cn", data);
 265  				break;
 266  			case 'F':
 267  				qstr++;
 268  				if (qstr[0] == 'p')
 269  					pkg_fprintf(dest->fp, "%Fn", data);
 270  				else if (qstr[0] == 's')
 271  					pkg_fprintf(dest->fp, "%Fs", data);
 272  				else if (qstr[0] == 'u')
 273  					pkg_fprintf(dest->fp, "%Fu", data);
 274  				else if (qstr[0] == 'g')
 275  					pkg_fprintf(dest->fp, "%Fg", data);
 276  				else if (qstr[0] == 'm')
 277  					pkg_fprintf(dest->fp, "%Fp", data);
 278  				else if (qstr[0] == 'f')
 279  					pkg_fprintf(dest->fp, "%Ff", data);
 280  				else if (qstr[0] == 't')
 281  					pkg_fprintf(dest->fp, "%Ft", data);
 282  				else if (qstr[0] == 'l')
 283  					pkg_fprintf(dest->fp, "%Fl", data);
 284  				break;
 285  			case 'O':
 286  				qstr++;
 287  				if (qstr[0] == 'k')
 288  					pkg_fprintf(dest->fp, "%On", data);
 289  				else if (qstr[0] == 'v')
 290  					pkg_fprintf(dest->fp, "%Ov", data);
 291  				else if (qstr[0] == 'd') /* default value */
 292  					pkg_fprintf(dest->fp, "%Od", data);
 293  				else if (qstr[0] == 'D') /* description */
 294  					pkg_fprintf(dest->fp, "%OD", data);
 295  				break;
 296  			case 'D':
 297  				pkg_fprintf(dest->fp, "%Dn", data);
 298  				break;
 299  			case 'S':
 300  				qstr++;
 301  				if (qstr[0] == 'p')
 302  					pkg_fprintf(dest->fp, "%Dn", data);
 303  				else if (qstr[0] == 'u')
 304  					pkg_fprintf(dest->fp, "%Du", data);
 305  				else if (qstr[0] == 'g')
 306  					pkg_fprintf(dest->fp, "%Dg", data);
 307  				else if (qstr[0] == 'm')
 308  					pkg_fprintf(dest->fp, "%Dp", data);
 309  				else if (qstr[0] == 'f')
 310  					pkg_fprintf(dest->fp, "%Df", data);
 311  				break;
 312  			case 'L':
 313  				pkg_fprintf(dest->fp, "%Ln", data);
 314  				break;
 315  			case 'U':
 316  				pkg_fprintf(dest->fp, "%Un", data);
 317  				break;
 318  			case 'G':
 319  				pkg_fprintf(dest->fp, "%Gn", data);
 320  				break;
 321  			case 'B':
 322  				pkg_fprintf(dest->fp, "%Bn", data);
 323  				break;
 324  			case 'b':
 325  				pkg_fprintf(dest->fp, "%bn", data);
 326  				break;
 327  			case 'y':
 328  				fprintf(dest->fp, "%s", (const char *)data);
 329  				break;
 330  			case 'Y':
 331  				fprintf(dest->fp, "%s", (const char *)data);
 332  				break;
 333  			case 'A':
 334  				qstr++;
 335  				if (qstr[0] == 't')
 336  					pkg_fprintf(dest->fp, "%An", data);
 337  				else if (qstr[0] == 'v')
 338  					pkg_fprintf(dest->fp, "%Av", data);
 339  				break;
 340  			case 'M':
 341  				if (pkg_has_message(pkg))
 342  					pkg_fprintf(dest->fp, "%M", pkg);
 343  				break;
 344  			case 'V':
 345  				pkg_get(pkg, PKG_ATTR_VITAL, &vital);
 346  				fprintf(dest->fp, "%d", vital);
 347  				break;
 348  			case 'X':
 349  				pkg_fprintf(dest->fp, "%X", pkg);
 350  				break;
 351  			case '%':
 352  				fputc('%', dest->fp);
 353  				break;
 354  			}
 355  		} else  if (qstr[0] == '\\') {
 356  			qstr++;
 357  			switch (qstr[0]) {
 358  			case 'n':
 359  				fputc('\n', dest->fp);
 360  				break;
 361  			case 'a':
 362  				fputc('\a', dest->fp);
 363  				break;
 364  			case 'b':
 365  				fputc('\b', dest->fp);
 366  				break;
 367  			case 'f':
 368  				fputc('\f', dest->fp);
 369  				break;
 370  			case 'r':
 371  				fputc('\r', dest->fp);
 372  				break;
 373  			case '\\':
 374  				fputc('\\', dest->fp);
 375  				break;
 376  			case 't':
 377  				fputc('\t', dest->fp);
 378  				break;
 379  			}
 380  		} else {
 381  			fputc(qstr[0], dest->fp);
 382  		}
 383  		qstr++;
 384  	}
 385  	fflush(dest->fp);
 386  }
 387  
 388  static bool
 389  query_has_nonmultiline(const char *qstr)
 390  {
 391  	while (*qstr) {
 392  		if (*qstr == '%') {
 393  			qstr++;
 394  			for (unsigned int i = 0; i < NELEM(accepted_query_flags); i++) {
 395  				if (*qstr == accepted_query_flags[i].flag &&
 396  				    accepted_query_flags[i].multiline == 0) {
 397  					return (true);
 398  				}
 399  			}
 400  		}
 401  		if (*qstr)
 402  			qstr++;
 403  	}
 404  	return (false);
 405  }
 406  
 407  void
 408  print_query(struct pkg *pkg, char *qstr, char multiline)
 409  {
 410  	xstring			*output;
 411  	struct pkg_dep		*dep    = NULL;
 412  	struct pkg_option	*option = NULL;
 413  	struct pkg_file		*file   = NULL;
 414  	struct pkg_dir		*dir    = NULL;
 415  	const char		*str = NULL;
 416  	struct pkg_kv		*kv = NULL;
 417  	struct pkg_stringlist	*sl = NULL;
 418  	struct pkg_stringlist_iterator	*slit;
 419  	struct pkg_kvlist	*kl = NULL;
 420  	struct pkg_kvlist_iterator	*kit;
 421  
 422  	output = xstring_new();
 423  	bool printed = false;
 424  
 425  	switch (multiline) {
 426  	case 'd':
 427  		while (pkg_deps(pkg, &dep) == EPKG_OK) {
 428  			format_str(pkg, output, qstr, dep);
 429  			printf("%s\n", output->buf);
 430  			printed = true;
 431  		}
 432  		break;
 433  	case 'r':
 434  		while (pkg_rdeps(pkg, &dep) == EPKG_OK) {
 435  			format_str(pkg, output, qstr, dep);
 436  			printf("%s\n", output->buf);
 437  			printed = true;
 438  		}
 439  		break;
 440  	case 'C':
 441  	case 'L':
 442  	case 'U':
 443  	case 'G':
 444  	case 'B':
 445  	case 'b':
 446  	case 'y':
 447  	case 'Y':;
 448  		int attr;
 449  		switch (multiline) {
 450  		case 'C': attr = PKG_ATTR_CATEGORIES; break;
 451  		case 'L': attr = PKG_ATTR_LICENSES; break;
 452  		case 'U': attr = PKG_ATTR_USERS; break;
 453  		case 'G': attr = PKG_ATTR_GROUPS; break;
 454  		case 'B': attr = PKG_ATTR_SHLIBS_REQUIRED; break;
 455  		case 'b': attr = PKG_ATTR_SHLIBS_PROVIDED; break;
 456  		case 'y': attr = PKG_ATTR_PROVIDES; break;
 457  		case 'Y': attr = PKG_ATTR_REQUIRES; break;
 458  		default: __unreachable();
 459  		}
 460  		pkg_get(pkg, attr, &sl);
 461  		slit = pkg_stringlist_iterator(sl);
 462  		while ((str = pkg_stringlist_next(slit))) {
 463  			format_str(pkg, output, qstr, str);
 464  			printf("%s\n", output->buf);
 465  			printed = true;
 466  		}
 467  		free(slit);
 468  		free(sl);
 469  		break;
 470  	case 'O':
 471  		while (pkg_options(pkg, &option) == EPKG_OK) {
 472  			format_str(pkg, output, qstr, option);
 473  			printf("%s\n", output->buf);
 474  			printed = true;
 475  		}
 476  		break;
 477  	case 'F':
 478  		while (pkg_files(pkg, &file) == EPKG_OK) {
 479  			format_str(pkg, output, qstr, file);
 480  			printf("%s\n", output->buf);
 481  			printed = true;
 482  		}
 483  		break;
 484  	case 'D':
 485  	case 'S':
 486  		while (pkg_dirs(pkg, &dir) == EPKG_OK) {
 487  			format_str(pkg, output, qstr, dir);
 488  			printf("%s\n", output->buf);
 489  			printed = true;
 490  		}
 491  		break;
 492  	case 'A':
 493  		pkg_get(pkg, PKG_ATTR_ANNOTATIONS, &kl);
 494  		kit = pkg_kvlist_iterator(kl);
 495  		while ((kv = pkg_kvlist_next(kit))) {
 496  			format_str(pkg, output, qstr, kv);
 497  			printf("%s\n", output->buf);
 498  			printed = true;
 499  		}
 500  		free(kit);
 501  		free(kl);
 502  		break;
 503  	default:
 504  		format_str(pkg, output, qstr, dep);
 505  		printf("%s\n", output->buf);
 506  		printed = true;
 507  		break;
 508  	}
 509  	if (!printed && query_has_nonmultiline(qstr)) {
 510  		format_str(pkg, output, qstr, NULL);
 511  		printf("%s\n", output->buf);
 512  	}
 513  	xstring_free(output);
 514  }
 515  
 516  typedef enum {
 517  	NONE,
 518  	NEXT_IS_INT,
 519  	OPERATOR_INT,
 520  	INT,
 521  	NEXT_IS_STRING,
 522  	OPERATOR_STRING,
 523  	STRING,
 524  	QUOTEDSTRING,
 525  	SQUOTEDSTRING,
 526  	POST_EXPR,
 527  } state_t;
 528  
 529  int
 530  format_sql_condition(const char *str, xstring *sqlcond, bool for_remote)
 531  {
 532  	state_t state = NONE;
 533  	unsigned int bracket_level = 0;
 534  	const char *sqlop;
 535  	bool collate_nocase = false;
 536  	bool multiline_subquery = false;
 537  	const char *pending_subquery = NULL;
 538  
 539  	fprintf(sqlcond->fp, " WHERE ");
 540  	while (str[0] != '\0') {
 541  		if (state == NONE) {
 542  			if (str[0] == '%') {
 543  				str++;
 544  				switch (str[0]) {
 545  				case 'n':
 546  					fprintf(sqlcond->fp, "p.name");
 547  					state = OPERATOR_STRING;
 548  					break;
 549  				case 'o':
 550  					fprintf(sqlcond->fp, "origin");
 551  					state = OPERATOR_STRING;
 552  					break;
 553  				case 'p':
 554  					fprintf(sqlcond->fp, "prefix");
 555  					state = OPERATOR_STRING;
 556  					break;
 557  				case 'm':
 558  					fprintf(sqlcond->fp, "maintainer");
 559  					state = OPERATOR_STRING;
 560  					break;
 561  				case 'c':
 562  					fprintf(sqlcond->fp, "comment");
 563  					state = OPERATOR_STRING;
 564  					break;
 565  				case 'w':
 566  					fprintf(sqlcond->fp, "www");
 567  					state = OPERATOR_STRING;
 568  					break;
 569  				case 's':
 570  					fprintf(sqlcond->fp, "flatsize");
 571  					state = OPERATOR_INT;
 572  					break;
 573  				case 'a':
 574  					if (for_remote)
 575  						goto bad_option;
 576  					fprintf(sqlcond->fp, "automatic");
 577  					state = OPERATOR_INT;
 578  					break;
 579  				case 'q':
 580  					fprintf(sqlcond->fp, "arch");
 581  					state = OPERATOR_STRING;
 582  					break;
 583  				case 'k':
 584  					if (for_remote)
 585  						goto bad_option;
 586  					fprintf(sqlcond->fp, "locked");
 587  					state = OPERATOR_INT;
 588  					break;
 589  				case 'M':
 590  					if (for_remote)
 591  						goto bad_option;
 592  					fprintf(sqlcond->fp, "message");
 593  					state = OPERATOR_STRING;
 594  					break;
 595  				case 't':
 596  					if (for_remote)
 597  						goto bad_option;
 598  					fprintf(sqlcond->fp, "time");
 599  					state = OPERATOR_INT;
 600  					break;
 601  				case 'e':
 602  					fprintf(sqlcond->fp, "desc");
 603  					state = OPERATOR_STRING;
 604  					break;
 605  				case 'V':
 606  					if (for_remote)
 607  						goto bad_option;
 608  					fprintf(sqlcond->fp, "vital");
 609  					state = OPERATOR_INT;
 610  					break;
 611  				case '#': /* FALLTHROUGH */
 612  				case '?':
 613  					sqlop = (str[0] == '#' ? "COUNT(*)" : "COUNT(*) > 0");
 614  					str++;
 615  					switch (str[0]) {
 616  						case 'd':
 617  							fprintf(sqlcond->fp, "(SELECT %s FROM deps AS d WHERE d.package_id=p.id)", sqlop);
 618  							break;
 619  						case 'r':
 620  							fprintf(sqlcond->fp, "(SELECT %s FROM deps AS d WHERE d.name=p.name)", sqlop);
 621  							break;
 622  						case 'C':
 623  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_categories AS d WHERE d.package_id=p.id)", sqlop);
 624  							break;
 625  						case 'F':
 626  							if (for_remote)
 627  								goto bad_option;
 628  							fprintf(sqlcond->fp, "(SELECT %s FROM files AS d WHERE d.package_id=p.id)", sqlop);
 629  							break;
 630  						case 'O':
 631  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_option AS d WHERE d.package_id=p.id)", sqlop);
 632  							break;
 633  						case 'D':
 634  						case 'S':
 635  							if (for_remote)
 636  								goto bad_option;
 637  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_directories AS d WHERE d.package_id=p.id)", sqlop);
 638  							break;
 639  						case 'L':
 640  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_licenses AS d WHERE d.package_id=p.id)", sqlop);
 641  							break;
 642  						case 'U':
 643  							if (for_remote)
 644  								goto bad_option;
 645  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_users AS d WHERE d.package_id=p.id)", sqlop);
 646  							break;
 647  						case 'G':
 648  							if (for_remote)
 649  								goto bad_option;
 650  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_groups AS d WHERE d.package_id=p.id)", sqlop);
 651  							break;
 652  						case 'B':
 653  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_shlibs_required AS d WHERE d.package_id=p.id)", sqlop);
 654  							break;
 655  						case 'b':
 656  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_shlibs_provided AS d WHERE d.package_id=p.id)", sqlop);
 657  							break;
 658  						case 'y':
 659  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_provides AS d WHERE d.package_id=p.id)", sqlop);
 660  							break;
 661  						case 'Y':
 662  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_requires AS d WHERE d.package_id=p.id)", sqlop);
 663  							break;
 664  						case 'A':
 665  							fprintf(sqlcond->fp, "(SELECT %s FROM pkg_annotation AS d WHERE d.package_id=p.id)", sqlop);
 666  							break;
 667  						default:
 668  							goto bad_option;
 669  					}
 670  					state = OPERATOR_INT;
 671  					break;
 672  				case 'd':
 673  					str++;
 674  					if (str[0] == 'n')
 675  						pending_subquery = "SELECT * FROM deps AS d WHERE d.package_id=p.id AND name";
 676  					else if (str[0] == 'o')
 677  						pending_subquery = "SELECT * FROM deps AS d WHERE d.package_id=p.id AND origin";
 678  					else if (str[0] == 'v')
 679  						pending_subquery = "SELECT * FROM deps AS d WHERE d.package_id=p.id AND version";
 680  					multiline_subquery = true;
 681  					state = OPERATOR_STRING;
 682  					break;
 683  				case 'r':
 684  					str++;
 685  					if (str[0] == 'n')
 686  						pending_subquery = "SELECT * FROM packages AS p2 JOIN deps AS d ON d.package_id=p2.id WHERE d.name=p.name AND p2.name";
 687  					else if (str[0] == 'o')
 688  						pending_subquery = "SELECT * FROM packages AS p2 JOIN deps AS d ON d.package_id=p2.id WHERE d.name=p.name AND p2.origin";
 689  					else if (str[0] == 'v')
 690  						pending_subquery = "SELECT * FROM packages AS p2 JOIN deps AS d ON d.package_id=p2.id WHERE d.name=p.name AND p2.version";
 691  					multiline_subquery = true;
 692  					state = OPERATOR_STRING;
 693  					break;
 694  				case 'C':
 695  					pending_subquery = "SELECT * FROM categories AS c JOIN pkg_categories AS pc ON c.id=pc.category_id WHERE pc.package_id=p.id AND c.name";
 696  					multiline_subquery = true;
 697  					state = OPERATOR_STRING;
 698  					break;
 699  				case 'L':
 700  					pending_subquery = "SELECT * FROM licenses AS l JOIN pkg_licenses AS pl ON l.id=pl.license_id WHERE pl.package_id=p.id AND l.name";
 701  					multiline_subquery = true;
 702  					state = OPERATOR_STRING;
 703  					break;
 704  				case 'B':
 705  					pending_subquery = "SELECT * FROM shlibs AS s JOIN pkg_shlibs_required AS ps ON s.id=ps.shlib_id WHERE ps.package_id=p.id AND s.name";
 706  					multiline_subquery = true;
 707  					state = OPERATOR_STRING;
 708  					break;
 709  				case 'b':
 710  					pending_subquery = "SELECT * FROM shlibs AS s JOIN pkg_shlibs_provided AS ps ON s.id=ps.shlib_id WHERE ps.package_id=p.id AND s.name";
 711  					multiline_subquery = true;
 712  					state = OPERATOR_STRING;
 713  					break;
 714  				case 'y':
 715  					pending_subquery = "SELECT * FROM provides AS s JOIN pkg_provides AS ps ON s.id=ps.provide_id WHERE ps.package_id=p.id AND s.provide";
 716  					multiline_subquery = true;
 717  					state = OPERATOR_STRING;
 718  					break;
 719  				case 'Y':
 720  					pending_subquery = "SELECT * FROM requires AS s JOIN pkg_requires AS ps ON s.id=ps.require_id WHERE ps.package_id=p.id AND s.require";
 721  					multiline_subquery = true;
 722  					state = OPERATOR_STRING;
 723  					break;
 724  				case 'A':
 725  					str++;
 726  					if (str[0] == 't')
 727  						pending_subquery = "SELECT * FROM annotation AS a JOIN pkg_annotation AS pa ON a.annotation_id=pa.tag_id WHERE pa.package_id=p.id AND a.annotation";
 728  					else if (str[0] == 'v')
 729  						pending_subquery = "SELECT * FROM annotation AS a JOIN pkg_annotation AS pa ON a.annotation_id=pa.value_id WHERE pa.package_id=p.id AND a.annotation";
 730  					multiline_subquery = true;
 731  					state = OPERATOR_STRING;
 732  					break;
 733  				default:
 734  bad_option:
 735  					fprintf(stderr, "malformed evaluation string\n");
 736  					return (EPKG_FATAL);
 737  				}
 738  			} else {
 739  				switch (str[0]) {
 740  				case '(':
 741  					bracket_level++;
 742  					fprintf(sqlcond->fp, "%c", str[0]);
 743  					break;
 744  				case ' ':
 745  				case '\t':
 746  					break;
 747  				default:
 748  					fprintf(stderr, "unexpected character: %c\n", str[0]);
 749  					return (EPKG_FATAL);
 750  				}
 751  			}
 752  		} else if (state == POST_EXPR) {
 753  			switch (str[0]) {
 754  			case ')':
 755  				if (bracket_level == 0) {
 756  					fprintf(stderr, "too many closing brackets.\n");
 757  					return (EPKG_FATAL);
 758  				}
 759  				bracket_level--;
 760  				fprintf(sqlcond->fp, "%c", str[0]);
 761  				break;
 762  			case ' ':
 763  			case '\t':
 764  				break;
 765  			case '|':
 766  				if (str[1] == '|') {
 767  					str++;
 768  					state = NONE;
 769  					fprintf(sqlcond->fp, " OR ");
 770  					break;
 771  				} else {
 772  					fprintf(stderr, "unexpected character %c\n", str[1]);
 773  					return (EPKG_FATAL);
 774  				}
 775  			case '&':
 776  				if (str[1] == '&') {
 777  					str++;
 778  					state = NONE;
 779  					fprintf(sqlcond->fp, " AND ");
 780  					break;
 781  				} else {
 782  					fprintf(stderr, "unexpected character %c\n", str[1]);
 783  					return (EPKG_FATAL);
 784  				}
 785  			default:
 786  				fprintf(stderr, "unexpected character %c\n", str[0]);
 787  				return (EPKG_FATAL);
 788  			}
 789  		} else if (state == OPERATOR_STRING || state == OPERATOR_INT) {
 790  			/* only operators or space are allowed here */
 791  			if (isspace(str[0])) {
 792  				/* do nothing */
 793  			} else if (str[0] == '~' ) {
 794  				if (state != OPERATOR_STRING) {
 795  					fprintf(stderr, "~ expected only for string testing\n");
 796  					return (EPKG_FATAL);
 797  				}
 798  				if (pending_subquery) {
 799  					fprintf(sqlcond->fp, "EXISTS (%s", pending_subquery);
 800  					pending_subquery = NULL;
 801  				}
 802  				state = NEXT_IS_STRING;
 803  				fprintf(sqlcond->fp, " GLOB ");
 804  			} else if (str[0] == '>' || str[0] == '<') {
 805  				if (state != OPERATOR_INT) {
 806  					fprintf(stderr, "> expected only for integers\n");
 807  					return (EPKG_FATAL);
 808  				}
 809  				if (pending_subquery) {
 810  					fprintf(sqlcond->fp, "EXISTS (%s", pending_subquery);
 811  					pending_subquery = NULL;
 812  				}
 813  				state = NEXT_IS_INT;
 814  				fprintf(sqlcond->fp, "%c", str[0]);
 815  				if (str[1] == '=') {
 816  					str++;
 817  					fprintf(sqlcond->fp, "%c", str[0]);
 818  				}
 819  			} else if (str[0] == '=') {
 820  				if (state == OPERATOR_STRING) {
 821  					state = NEXT_IS_STRING;
 822  				} else {
 823  					state = NEXT_IS_INT;
 824  				}
 825  				if (pending_subquery) {
 826  					fprintf(sqlcond->fp, "EXISTS (%s", pending_subquery);
 827  					pending_subquery = NULL;
 828  				}
 829  				fprintf(sqlcond->fp, "%c", str[0]);
 830  				if (str[1] == '=') {
 831  					str++;
 832  				} else if (str[1] == '~' && state == NEXT_IS_STRING) {
 833  					str++;
 834  					collate_nocase = true;
 835  				}
 836  			} else if (str[0] == '!') {
 837  				if (pending_subquery) {
 838  					fprintf(sqlcond->fp, "NOT EXISTS (%s", pending_subquery);
 839  					pending_subquery = NULL;
 840  					if (str[1] == '=') {
 841  						fprintf(sqlcond->fp, "%c", str[1]);
 842  					} else if (str[1] == '~') {
 843  						fprintf(sqlcond->fp, " GLOB ");
 844  					} else {
 845  						fprintf(stderr, "expecting = or ~ after !\n");
 846  						return (EPKG_FATAL);
 847  					}
 848  				} else {
 849  					if (str[1] == '=') {
 850  						fprintf(sqlcond->fp, "%c", str[0]);
 851  						fprintf(sqlcond->fp, "%c", str[1]);
 852  					} else if (str[1] == '~') {
 853  						fprintf(sqlcond->fp, " NOT GLOB ");
 854  					} else {
 855  						fprintf(stderr, "expecting = or ~ after !\n");
 856  						return (EPKG_FATAL);
 857  					}
 858  				}
 859  				str++;
 860  				if (state == OPERATOR_STRING) {
 861  					state = NEXT_IS_STRING;
 862  				} else {
 863  					state = NEXT_IS_INT;
 864  				}
 865  				if (str[0] == '~' && state == NEXT_IS_STRING) {
 866  					str++;
 867  					collate_nocase = true;
 868  				}
 869  			} else {
 870  				fprintf(stderr, "an operator is expected, got %c\n", str[0]);
 871  				return (EPKG_FATAL);
 872  			}
 873  		} else if (state == NEXT_IS_STRING || state == NEXT_IS_INT) {
 874  			if (isspace(str[0])) {
 875  				/* do nothing */
 876  			} else {
 877  				if (state == NEXT_IS_STRING) {
 878  					if (str[0] == '"') {
 879  						state = QUOTEDSTRING;
 880  					} else if (str[0] == '\'') {
 881  						state = SQUOTEDSTRING;
 882  					} else {
 883  						state = STRING;
 884  						str--;
 885  					}
 886  					fprintf(sqlcond->fp, "%c", '\'');
 887  				} else {
 888  					if (!isdigit(str[0])) {
 889  						fprintf(stderr, "a number is expected, got: %c\n", str[0]);
 890  						return (EPKG_FATAL);
 891  					}
 892  					state = INT;
 893  					fprintf(sqlcond->fp, "%c", str[0]);
 894  				}
 895  			}
 896  		} else if (state == INT) {
 897  			if (!isdigit(str[0])) {
 898  				state = POST_EXPR;
 899  				if (multiline_subquery) {
 900  					fprintf(sqlcond->fp, ")");
 901  					multiline_subquery = false;
 902  				}
 903  				str--;
 904  			} else {
 905  				fprintf(sqlcond->fp, "%c", str[0]);
 906  			}
 907  		} else if (state == STRING || state == QUOTEDSTRING || state == SQUOTEDSTRING) {
 908  			if ((state == STRING && isspace(str[0])) ||
 909  			    (state == QUOTEDSTRING && str[0] == '"') ||
 910  			    (state == SQUOTEDSTRING && str[0] == '\'')) {
 911  				fprintf(sqlcond->fp, "%c", '\'');
 912  				state = POST_EXPR;
 913  				if (collate_nocase) {
 914  					fprintf(sqlcond->fp, " COLLATE NOCASE ");
 915  					collate_nocase = false;
 916  				}
 917  				if (multiline_subquery) {
 918  					fprintf(sqlcond->fp, ")");
 919  					multiline_subquery = false;
 920  				}
 921  			} else {
 922  				fprintf(sqlcond->fp, "%c", str[0]);
 923  				if (str[0] == '\'')
 924  					fprintf(sqlcond->fp, "%c", str[0]);
 925  				else if (str[0] == '%' && for_remote)
 926  					fprintf(sqlcond->fp, "%c", str[0]);
 927  			}
 928  		}
 929  		str++;
 930  	}
 931  	if (state == STRING) {
 932  		fprintf(sqlcond->fp, "%c", '\'');
 933  		state = POST_EXPR;
 934  		if (collate_nocase) {
 935  			fprintf(sqlcond->fp, " COLLATE NOCASE ");
 936  			collate_nocase = false;
 937  		}
 938  		if (multiline_subquery) {
 939  			fprintf(sqlcond->fp, ")");
 940  			multiline_subquery = false;
 941  		}
 942  	}
 943  
 944  	if (state != POST_EXPR && state != INT) {
 945  		fprintf(stderr, "unexpected end of expression\n");
 946  		return (EPKG_FATAL);
 947  	} else if (bracket_level > 0) {
 948  		fprintf(stderr, "unexpected end of expression (too many open brackets)\n");
 949  		return (EPKG_FATAL);
 950  	}
 951  
 952  	return (EPKG_OK);
 953  }
 954  
 955  int
 956  analyse_query_string(char *qstr, struct query_flags *q_flags, const unsigned int q_flags_len, int *flags, char *multiline)
 957  {
 958  	unsigned int i, j, k;
 959  	unsigned int valid_flag = 0;
 960  	unsigned int valid_opts = 0;
 961  	size_t len;
 962  
 963  	j = 0; /* shut up scanbuild */
 964  
 965  	if (strchr(qstr, '%') == NULL) {
 966  		fprintf(stderr, "Invalid query: query should contain a format string\n");
 967  		return (EPKG_FATAL);
 968  	}
 969  
 970  	while (qstr[0] != '\0') {
 971  		if (qstr[0] == '%') {
 972  			qstr++;
 973  			valid_flag = 0;
 974  
 975  			for (i = 0; i < q_flags_len; i++) {
 976  				/* found the flag */
 977  				if (qstr[0] == q_flags[i].flag) {
 978  					valid_flag = 1;
 979  
 980  					/* if the flag is followed by additional options */
 981  					if (q_flags[i].options[0] != '\0') {
 982  						qstr++;
 983  						valid_opts = 0;
 984  
 985  						len = strlen(q_flags[i].options);
 986  						for (j = 0; j < len; j++) {
 987  							if (qstr[0] == q_flags[i].options[j]) {
 988  								valid_opts = 1;
 989  								break;
 990  							}
 991  						}
 992  
 993  						if (valid_opts == 0) {
 994  							fprintf(stderr, "Invalid query: '%%%c' should be followed by:", q_flags[i].flag);
 995  
 996  							len = strlen(q_flags[i].options);
 997  							for (j = 0; j < len; j++)
 998  								fprintf(stderr, " %c%c", q_flags[i].options[j],
 999  										q_flags[i].options[j + 1] == '\0' ?
1000  										'\n' : ',');
1001  
1002  							return (EPKG_FATAL);
1003  						}
1004  					}
1005  
1006  					/* if this is a multiline flag */
1007  					if (q_flags[i].multiline == 1) {
1008  						if (*multiline != 0 && *multiline != q_flags[i].flag) {
1009  							fprintf(stderr, "Invalid query: '%%%c' and '%%%c' cannot be queried at the same time\n",
1010  									*multiline, q_flags[i].flag);
1011  							return (EPKG_FATAL);
1012  						} else {
1013  							*multiline = q_flags[i].flag;
1014  						}
1015  					}
1016  
1017  					/* handle the '?' flag cases */
1018  					if (q_flags[i].flag == '?' || q_flags[i].flag == '#') {
1019  						for (k = 0; k < q_flags_len; k++)
1020  							if (q_flags[k].flag == q_flags[i].options[j]) {
1021  								*flags |= q_flags[k].dbflags;
1022  								break;
1023  							}
1024  					} else {
1025  						*flags |= q_flags[i].dbflags;
1026  					}
1027  
1028  					break; /* don't iterate over the rest of the flags */
1029  				}
1030  			}
1031  
1032  			if (valid_flag == 0) {
1033  				fprintf(stderr, "Unknown query format key: '%%%c'\n", qstr[0]);
1034  				return (EPKG_FATAL);
1035  			}
1036  		}
1037  
1038  		qstr++;
1039  	}
1040  
1041  	return (EPKG_OK);
1042  }
1043  
1044  void
1045  usage_query(void)
1046  {
1047  	fprintf(stderr, "Usage: pkg query <query-format> <pkg-name>\n");
1048  	fprintf(stderr, "       pkg query [-a] <query-format>\n");
1049  	fprintf(stderr, "       pkg query -F <pkg-name> <query-format>\n");
1050  	fprintf(stderr, "       pkg query -e <evaluation> <query-format>\n");
1051  	fprintf(stderr, "       pkg query [-Cgix] <query-format> <pattern> <...>\n\n");
1052  	fprintf(stderr, "For more information see 'pkg help query.'\n");
1053  }
1054  
1055  int
1056  exec_query(int argc, char **argv)
1057  {
1058  	struct pkgdb		*db = NULL;
1059  	struct pkgdb_it		*it = NULL;
1060  	struct pkg		*pkg = NULL;
1061  	char			*pkgname = NULL;
1062  	int			 query_flags = PKG_LOAD_BASIC;
1063  	match_t			 match = MATCH_EXACT;
1064  	int			 ch;
1065  	int			 ret;
1066  	int			 retcode = EXIT_SUCCESS;
1067  	int			 i;
1068  	char			 multiline = 0;
1069  	int			 nprinted = 0;
1070  	char			*condition = NULL;
1071  	const char 		*condition_sql = NULL;
1072  	xstring			*sqlcond = NULL;
1073  	const unsigned int	 q_flags_len = NELEM(accepted_query_flags);
1074  
1075  	struct option longopts[] = {
1076  		{ "all",		no_argument,		NULL,	'a' },
1077  		{ "case-sensitive",	no_argument,		NULL,	'C' },
1078  		{ "evaluate",		required_argument,	NULL,	'e' },
1079  		{ "file",		required_argument,	NULL,	'F' },
1080  		{ "glob",		no_argument,		NULL,	'g' },
1081  		{ "case-insensitive",	no_argument,		NULL,	'i' },
1082  		{ "regex",		no_argument,		NULL,	'x' },
1083  		{ NULL,			0,			NULL,	0   },
1084  	};
1085  
1086  	while ((ch = getopt_long(argc, argv, "+aCe:F:gix", longopts, NULL)) != -1) {
1087  		switch (ch) {
1088  		case 'a':
1089  			match = MATCH_ALL;
1090  			break;
1091  		case 'C':
1092  			pkgdb_set_case_sensitivity(true);
1093  			break;
1094  		case 'e':
1095  			condition = optarg;
1096  			break;
1097  		case 'F':
1098  			pkgname = optarg;
1099  			break;
1100  		case 'g':
1101  			match = MATCH_GLOB;
1102  			break;
1103  		case 'i':
1104  			pkgdb_set_case_sensitivity(false);
1105  			break;
1106  		case 'x':
1107  			match = MATCH_REGEX;
1108  			break;
1109  		default:
1110  			usage_query();
1111  			return (EXIT_FAILURE);
1112  		}
1113  	}
1114  
1115  	argc -= optind;
1116  	argv += optind;
1117  
1118  	if ((match == MATCH_ALL || pkgname != NULL)
1119  	    && argc > 1) {
1120  		usage_query();
1121  		retcode = EXIT_FAILURE;
1122  		goto cleanup;
1123  	}
1124  
1125  	if (argc == 0) {
1126  		usage_query();
1127  		retcode = EXIT_FAILURE;
1128  		goto cleanup;
1129  	}
1130  
1131  	/* Default to all packages if no pkg provided */
1132  	if (argc == 1 && pkgname == NULL && match == MATCH_EXACT) {
1133  		match = MATCH_ALL;
1134  	} else if (((argc == 1) ^ (match == MATCH_ALL)) && pkgname == NULL
1135  			&& condition == NULL) {
1136  		usage_query();
1137  		retcode = EXIT_FAILURE;
1138  		goto cleanup;
1139  	}
1140  
1141  	if (analyse_query_string(argv[0], accepted_query_flags, q_flags_len,
1142  			&query_flags, &multiline) != EPKG_OK) {
1143  		retcode = EXIT_FAILURE;
1144  		goto cleanup;
1145  	}
1146  
1147  	if (pkgname != NULL) {
1148  		/* Use a manifest or compact manifest if possible. */
1149  		int open_flags = 0;
1150  		if ((query_flags & ~(PKG_LOAD_DEPS|
1151  				     PKG_LOAD_OPTIONS|
1152  				     PKG_LOAD_CATEGORIES|
1153  				     PKG_LOAD_LICENSES|
1154  				     PKG_LOAD_USERS|
1155  				     PKG_LOAD_GROUPS|
1156  				     PKG_LOAD_SHLIBS_REQUIRED|
1157  				     PKG_LOAD_SHLIBS_PROVIDED|
1158  				     PKG_LOAD_ANNOTATIONS|
1159  				     PKG_LOAD_CONFLICTS|
1160  				     PKG_LOAD_PROVIDES|
1161  				     PKG_LOAD_REQUIRES)) == 0) {
1162  			open_flags = PKG_OPEN_MANIFEST_COMPACT;
1163  		} else if ((query_flags & PKG_LOAD_FILES) == 0) {
1164  			open_flags = PKG_OPEN_MANIFEST_ONLY;
1165  		}
1166  		if (pkg_open(&pkg, pkgname, open_flags) != EPKG_OK) {
1167  			retcode = EXIT_FAILURE;
1168  			goto cleanup;
1169  		}
1170  
1171  		print_query(pkg, argv[0], multiline);
1172  		retcode = EXIT_SUCCESS;
1173  		goto cleanup;
1174  	}
1175  
1176  	if (condition != NULL) {
1177  		sqlcond = xstring_new();
1178  		if (format_sql_condition(condition, sqlcond, false) != EPKG_OK) {
1179  			retcode = EXIT_FAILURE;
1180  			goto cleanup;
1181  		}
1182  	}
1183  
1184  	ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
1185  	if (ret == EPKG_ENOACCESS) {
1186  		warnx("Insufficient privileges to query the package database");
1187  		retcode = EXIT_FAILURE;
1188  		goto cleanup;
1189  	} else if (ret == EPKG_ENODB) {
1190  		if (!quiet)
1191  			warnx("No packages installed");
1192  		retcode = EXIT_SUCCESS;
1193  		goto cleanup;
1194  	} else if (ret != EPKG_OK) {
1195  		retcode = EXIT_FAILURE;
1196  		goto cleanup;
1197  	}
1198  
1199  	ret = pkgdb_open(&db, PKGDB_DEFAULT_READONLY);
1200  	if (ret != EPKG_OK) {
1201  		retcode = EXIT_FAILURE;
1202  		goto cleanup;
1203  	}
1204  
1205  	pkg_drop_privileges();
1206  	if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
1207  		warnx("Cannot get a read lock on a database, it is locked by another process");
1208  		retcode = EXIT_FAILURE;
1209  		goto cleanup;
1210  	}
1211  
1212  	if (sqlcond) {
1213  		fflush(sqlcond->fp);
1214  		condition_sql = sqlcond->buf;
1215  	}
1216          i = 1;
1217          do {
1218  		pkgname = i < argc ? argv[i] : NULL;
1219  
1220  		if ((it = pkgdb_query_cond(db, condition_sql, pkgname, match)) == NULL) {
1221  			warnx("DEBUG: %s/%s\n", condition_sql ? condition_sql : "-", pkgname ? pkgname : "-");
1222  			retcode = EXIT_FAILURE;
1223  			break;
1224  		}
1225  
1226  		while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
1227  			nprinted++;
1228  			print_query(pkg, argv[0], multiline);
1229  		}
1230  
1231  		if (ret != EPKG_END) {
1232  			retcode = EXIT_FAILURE;
1233  			break;
1234  		}
1235  
1236  		pkgdb_it_free(it);
1237  		i++;
1238  	} while (i < argc);
1239  
1240  	if (nprinted == 0 && match != MATCH_ALL && retcode == EXIT_SUCCESS) {
1241  		/* ensure to return a non-zero status when no package
1242  		 were found. */
1243  		retcode = EXIT_FAILURE;
1244  	}
1245  
1246  cleanup:
1247  	xstring_free(sqlcond);
1248  
1249  	pkg_free(pkg);
1250  
1251  	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
1252  	pkgdb_close(db);
1253  
1254  	return (retcode);
1255  }