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 }