LCOV - code coverage report
Current view: top level - src - query.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 176 611 28.8 %
Date: 2015-08-15 Functions: 5 6 83.3 %

          Line data    Source code
       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             : #include <sys/sbuf.h>
      32             : 
      33             : #include <ctype.h>
      34             : #include <err.h>
      35             : #include <getopt.h>
      36             : #include <inttypes.h>
      37             : #include <pkg.h>
      38             : #include <stdio.h>
      39             : #include <stdlib.h>
      40             : #include <string.h>
      41             : #include <sysexits.h>
      42             : #include <unistd.h>
      43             : 
      44             : #include "pkgcli.h"
      45             : 
      46             : static struct query_flags accepted_query_flags[] = {
      47             :         { 'd', "nov",         1, PKG_LOAD_DEPS },
      48             :         { 'r', "nov",         1, PKG_LOAD_RDEPS },
      49             :         { 'C', "",            1, PKG_LOAD_CATEGORIES },
      50             :         { 'F', "ps",          1, PKG_LOAD_FILES },
      51             :         { 'O', "kvdD",                1, PKG_LOAD_OPTIONS },
      52             :         { 'D', "",            1, PKG_LOAD_DIRS },
      53             :         { 'L', "",            1, PKG_LOAD_LICENSES },
      54             :         { 'U', "",            1, PKG_LOAD_USERS },
      55             :         { 'G', "",            1, PKG_LOAD_GROUPS },
      56             :         { 'B', "",            1, PKG_LOAD_SHLIBS_REQUIRED },
      57             :         { 'b', "",            1, PKG_LOAD_SHLIBS_PROVIDED },
      58             :         { 'A', "tv",            1, PKG_LOAD_ANNOTATIONS },
      59             :         { '?', "drCFODLUGBbA",        1, PKG_LOAD_BASIC },    /* dbflags handled in analyse_query_string() */
      60             :         { '#', "drCFODLUGBbA",        1, PKG_LOAD_BASIC },    /* dbflags handled in analyse_query_string() */
      61             :         { 's', "hb",          0, PKG_LOAD_BASIC },
      62             :         { 'n', "",            0, PKG_LOAD_BASIC },
      63             :         { 'v', "",            0, PKG_LOAD_BASIC },
      64             :         { 'o', "",            0, PKG_LOAD_BASIC },
      65             :         { 'p', "",            0, PKG_LOAD_BASIC },
      66             :         { 'm', "",            0, PKG_LOAD_BASIC },
      67             :         { 'c', "",            0, PKG_LOAD_BASIC },
      68             :         { 'e', "",            0, PKG_LOAD_BASIC },
      69             :         { 'w', "",            0, PKG_LOAD_BASIC },
      70             :         { 'l', "",            0, PKG_LOAD_BASIC },
      71             :         { 'q', "",            0, PKG_LOAD_BASIC },
      72             :         { 'a', "",            0, PKG_LOAD_BASIC },
      73             :         { 'k', "",            0, PKG_LOAD_BASIC },
      74             :         { 'M', "",            0, PKG_LOAD_BASIC },
      75             :         { 't', "",            0, PKG_LOAD_BASIC },
      76             :         { 'R', "",              0, PKG_LOAD_ANNOTATIONS },
      77             : };
      78             : 
      79             : static void
      80           9 : format_str(struct pkg *pkg, struct sbuf *dest, const char *qstr, const void *data)
      81             : {
      82             :         bool automatic;
      83             :         bool locked;
      84             : 
      85           9 :         sbuf_clear(dest);
      86             : 
      87          31 :         while (qstr[0] != '\0') {
      88          13 :                 if (qstr[0] == '%') {
      89          11 :                         qstr++;
      90          11 :                         switch (qstr[0]) {
      91             :                         case 'n':
      92           4 :                                 pkg_sbuf_printf(dest, "%n", pkg);
      93           4 :                                 break;
      94             :                         case 'v':
      95           0 :                                 pkg_sbuf_printf(dest, "%v", pkg);
      96           0 :                                 break;
      97             :                         case 'o':
      98           0 :                                 pkg_sbuf_printf(dest, "%o", pkg);
      99           0 :                                 break;
     100             :                         case 'R':
     101           0 :                                 pkg_sbuf_printf(dest, "%N", pkg);
     102           0 :                                 break;
     103             :                         case 'p':
     104           0 :                                 pkg_sbuf_printf(dest, "%p", pkg);
     105           0 :                                 break;
     106             :                         case 'm':
     107           0 :                                 pkg_sbuf_printf(dest, "%m", pkg);
     108           0 :                                 break;
     109             :                         case 'c':
     110           0 :                                 pkg_sbuf_printf(dest, "%c", pkg);
     111           0 :                                 break;
     112             :                         case 'w':
     113           0 :                                 pkg_sbuf_printf(dest, "%w", pkg);
     114           0 :                                 break;
     115             :                         case 'a':
     116           5 :                                 pkg_get(pkg, PKG_AUTOMATIC, &automatic);
     117           5 :                                 sbuf_printf(dest, "%d", automatic);
     118           5 :                                 break;
     119             :                         case 'k':
     120           0 :                                 pkg_get(pkg, PKG_LOCKED, &locked);
     121           0 :                                 sbuf_printf(dest, "%d", locked);
     122           0 :                                 break;
     123             :                         case 't':
     124           0 :                                 pkg_sbuf_printf(dest, "%t", pkg);
     125           0 :                                 break;
     126             :                         case 's':
     127           0 :                                 qstr++;
     128           0 :                                 if (qstr[0] == 'h') 
     129           0 :                                         pkg_sbuf_printf(dest, "%#sB", pkg);
     130           0 :                                 else if (qstr[0] == 'b')
     131           0 :                                         pkg_sbuf_printf(dest, "%s", pkg);
     132           0 :                                 break;
     133             :                         case 'e':
     134           0 :                                 pkg_sbuf_printf(dest, "%e", pkg);
     135           0 :                                 break;
     136             :                         case '?':
     137           1 :                                 qstr++;
     138           1 :                                 switch (qstr[0]) {
     139             :                                 case 'd':
     140           0 :                                         pkg_sbuf_printf(dest, "%?d", pkg);
     141           0 :                                         break;
     142             :                                 case 'r':
     143           0 :                                         pkg_sbuf_printf(dest, "%?r", pkg);
     144           0 :                                         break;
     145             :                                 case 'C':
     146           0 :                                         pkg_sbuf_printf(dest, "%?C", pkg);
     147           0 :                                         break;
     148             :                                 case 'F':
     149           0 :                                         pkg_sbuf_printf(dest, "%?F", pkg);
     150           0 :                                         break;
     151             :                                 case 'O':
     152           1 :                                         pkg_sbuf_printf(dest, "%?O", pkg);
     153           1 :                                         break;
     154             :                                 case 'D':
     155           0 :                                         pkg_sbuf_printf(dest, "%?D", pkg);
     156           0 :                                         break;
     157             :                                 case 'L':
     158           0 :                                         pkg_sbuf_printf(dest, "%?L", pkg);
     159           0 :                                         break;
     160             :                                 case 'U':
     161           0 :                                         pkg_sbuf_printf(dest, "%?U", pkg);
     162           0 :                                         break;
     163             :                                 case 'G':
     164           0 :                                         pkg_sbuf_printf(dest, "%?G", pkg);
     165           0 :                                         break;
     166             :                                 case 'B':
     167           0 :                                         pkg_sbuf_printf(dest, "%?B", pkg);
     168           0 :                                         break;
     169             :                                 case 'b':
     170           0 :                                         pkg_sbuf_printf(dest, "%?b", pkg);
     171           0 :                                         break;
     172             :                                 case 'A':
     173           0 :                                         pkg_sbuf_printf(dest, "%?A", pkg);
     174           0 :                                         break;
     175             :                                 }
     176           1 :                                 break;
     177             :                         case '#':
     178           1 :                                 qstr++;
     179           1 :                                 switch (qstr[0]) {
     180             :                                 case 'd':
     181           0 :                                         pkg_sbuf_printf(dest, "%#d", pkg);
     182           0 :                                         break;
     183             :                                 case 'r':
     184           0 :                                         pkg_sbuf_printf(dest, "%#r", pkg);
     185           0 :                                         break;
     186             :                                 case 'C':
     187           0 :                                         pkg_sbuf_printf(dest, "%#C", pkg);
     188           0 :                                         break;
     189             :                                 case 'F':
     190           0 :                                         pkg_sbuf_printf(dest, "%#F", pkg);
     191           0 :                                         break;
     192             :                                 case 'O':
     193           1 :                                         pkg_sbuf_printf(dest, "%#O", pkg);
     194           1 :                                         break;
     195             :                                 case 'D':
     196           0 :                                         pkg_sbuf_printf(dest, "%#D", pkg);
     197           0 :                                         break;
     198             :                                 case 'L':
     199           0 :                                         pkg_sbuf_printf(dest, "%#L", pkg);
     200           0 :                                         break;
     201             :                                 case 'U':
     202           0 :                                         pkg_sbuf_printf(dest, "%#U", pkg);
     203           0 :                                         break;
     204             :                                 case 'G':
     205           0 :                                         pkg_sbuf_printf(dest, "%#G", pkg);
     206           0 :                                         break;
     207             :                                 case 'B':
     208           0 :                                         pkg_sbuf_printf(dest, "%#B", pkg);
     209           0 :                                         break;
     210             :                                 case 'b':
     211           0 :                                         pkg_sbuf_printf(dest, "%#b", pkg);
     212           0 :                                         break;
     213             :                                 case 'A':
     214           0 :                                         pkg_sbuf_printf(dest, "%#A", pkg);
     215           0 :                                         break;
     216             :                                 }
     217           1 :                                 break;
     218             :                         case 'q':
     219           0 :                                 pkg_sbuf_printf(dest, "%q", pkg);
     220           0 :                                 break;
     221             :                         case 'l':
     222           0 :                                 pkg_sbuf_printf(dest, "%l", pkg);
     223           0 :                                 break;
     224             :                         case 'd':
     225           0 :                                 qstr++;
     226           0 :                                 if (qstr[0] == 'n')
     227           0 :                                         pkg_sbuf_printf(dest, "%dn", data);
     228           0 :                                 else if (qstr[0] == 'o')
     229           0 :                                         pkg_sbuf_printf(dest, "%do", data);
     230           0 :                                 else if (qstr[0] == 'v')
     231           0 :                                         pkg_sbuf_printf(dest, "%dv", data);
     232           0 :                                 break;
     233             :                         case 'r':
     234           0 :                                 qstr++;
     235           0 :                                 if (qstr[0] == 'n')
     236           0 :                                         pkg_sbuf_printf(dest, "%rn", data);
     237           0 :                                 else if (qstr[0] == 'o')
     238           0 :                                         pkg_sbuf_printf(dest, "%ro", data);
     239           0 :                                 else if (qstr[0] == 'v')
     240           0 :                                         pkg_sbuf_printf(dest, "%rv", data);
     241           0 :                                 break;
     242             :                         case 'C':
     243           0 :                                 pkg_sbuf_printf(dest, "%Cn", data);
     244           0 :                                 break;
     245             :                         case 'F':
     246           0 :                                 qstr++;
     247           0 :                                 if (qstr[0] == 'p')
     248           0 :                                         pkg_sbuf_printf(dest, "%Fn", data);
     249           0 :                                 else if (qstr[0] == 's')
     250           0 :                                         pkg_sbuf_printf(dest, "%Fs", data);
     251           0 :                                 break;
     252             :                         case 'O':
     253           0 :                                 qstr++;
     254           0 :                                 if (qstr[0] == 'k')
     255           0 :                                         pkg_sbuf_printf(dest, "%On", data);
     256           0 :                                 else if (qstr[0] == 'v')
     257           0 :                                         pkg_sbuf_printf(dest, "%Ov", data);
     258           0 :                                 else if (qstr[0] == 'd') /* default value */
     259           0 :                                         pkg_sbuf_printf(dest, "%Od", data);
     260           0 :                                 else if (qstr[0] == 'D') /* description */
     261           0 :                                         pkg_sbuf_printf(dest, "%OD", data);
     262           0 :                                 break;
     263             :                         case 'D':
     264           0 :                                 pkg_sbuf_printf(dest, "%Dn", data);
     265           0 :                                 break;
     266             :                         case 'L':
     267           0 :                                 pkg_sbuf_printf(dest, "%Ln", data);
     268           0 :                                 break;
     269             :                         case 'U':
     270           0 :                                 pkg_sbuf_printf(dest, "%Un", data);
     271           0 :                                 break;
     272             :                         case 'G':
     273           0 :                                 pkg_sbuf_printf(dest, "%Gn", data);
     274           0 :                                 break;
     275             :                         case 'B':
     276           0 :                                 pkg_sbuf_printf(dest, "%Bn", data);
     277           0 :                                 break;
     278             :                         case 'b':
     279           0 :                                 pkg_sbuf_printf(dest, "%bn", data);
     280           0 :                                 break;
     281             :                         case 'A':
     282           0 :                                 qstr++;
     283           0 :                                 if (qstr[0] == 't')
     284           0 :                                         pkg_sbuf_printf(dest, "%An", data);
     285           0 :                                 else if (qstr[0] == 'v')
     286           0 :                                         pkg_sbuf_printf(dest, "%Av", data);
     287           0 :                                 break;
     288             :                         case 'M':
     289           0 :                                 if (pkg_has_message(pkg))
     290           0 :                                         pkg_sbuf_printf(dest, "%M", pkg);
     291           0 :                                 break;
     292             :                         case '%':
     293           0 :                                 sbuf_putc(dest, '%');
     294           0 :                                 break;
     295             :                         }
     296           2 :                 } else  if (qstr[0] == '\\') {
     297           0 :                         qstr++;
     298           0 :                         switch (qstr[0]) {
     299             :                         case 'n':
     300           0 :                                 sbuf_putc(dest, '\n');
     301           0 :                                 break;
     302             :                         case 'a':
     303           0 :                                 sbuf_putc(dest, '\a');
     304           0 :                                 break;
     305             :                         case 'b':
     306           0 :                                 sbuf_putc(dest, '\b');
     307           0 :                                 break;
     308             :                         case 'f':
     309           0 :                                 sbuf_putc(dest, '\f');
     310           0 :                                 break;
     311             :                         case 'r':
     312           0 :                                 sbuf_putc(dest, '\r');
     313           0 :                                 break;
     314             :                         case '\\':
     315           0 :                                 sbuf_putc(dest, '\\');
     316           0 :                                 break;
     317             :                         case 't':
     318           0 :                                 sbuf_putc(dest, '\t');
     319           0 :                                 break;
     320             :                         }
     321             :                 } else {
     322           2 :                         sbuf_putc(dest, qstr[0]);
     323             :                 }
     324          13 :                 qstr++;
     325             :         }
     326           9 :         sbuf_finish(dest);
     327           9 : }
     328             : 
     329             : void
     330           9 : print_query(struct pkg *pkg, char *qstr, char multiline)
     331             : {
     332           9 :         struct sbuf             *output = sbuf_new_auto();
     333           9 :         struct pkg_dep          *dep    = NULL;
     334           9 :         struct pkg_option       *option = NULL;
     335           9 :         struct pkg_file         *file   = NULL;
     336           9 :         struct pkg_dir          *dir    = NULL;
     337             :         char                    *buf;
     338             :         struct pkg_kv           *kv;
     339             :         struct pkg_strel        *list;
     340             : 
     341           9 :         switch (multiline) {
     342             :         case 'd':
     343           0 :                 while (pkg_deps(pkg, &dep) == EPKG_OK) {
     344           0 :                         format_str(pkg, output, qstr, dep);
     345           0 :                         printf("%s\n", sbuf_data(output));
     346             :                 }
     347           0 :                 break;
     348             :         case 'r':
     349           0 :                 while (pkg_rdeps(pkg, &dep) == EPKG_OK) {
     350           0 :                         format_str(pkg, output, qstr, dep);
     351           0 :                         printf("%s\n", sbuf_data(output));
     352             :                 }
     353           0 :                 break;
     354             :         case 'C':
     355           0 :                 pkg_get(pkg, PKG_CATEGORIES, &list);
     356           0 :                 while (list != NULL) {
     357           0 :                         format_str(pkg, output, qstr, list);
     358           0 :                         printf("%s\n", sbuf_data(output));
     359           0 :                         list = list->next;
     360             :                 }
     361           0 :                 break;
     362             :         case 'O':
     363           0 :                 while (pkg_options(pkg, &option) == EPKG_OK) {
     364           0 :                         format_str(pkg, output, qstr, option);
     365           0 :                         printf("%s\n", sbuf_data(output));
     366             :                 }
     367           0 :                 break;
     368             :         case 'F':
     369           0 :                 while (pkg_files(pkg, &file) == EPKG_OK) {
     370           0 :                         format_str(pkg, output, qstr, file);
     371           0 :                         printf("%s\n", sbuf_data(output));
     372             :                 }
     373           0 :                 break;
     374             :         case 'D':
     375           0 :                 while (pkg_dirs(pkg, &dir) == EPKG_OK) {
     376           0 :                         format_str(pkg, output, qstr, dir);
     377           0 :                         printf("%s\n", sbuf_data(output));
     378             :                 }
     379           0 :                 break;
     380             :         case 'L':
     381           0 :                 pkg_get(pkg, PKG_LICENSES, &list);
     382           0 :                 while (list != NULL) {
     383           0 :                         format_str(pkg, output, qstr, list);
     384           0 :                         printf("%s\n", sbuf_data(output));
     385           0 :                         list = list->next;
     386             :                 }
     387           0 :                 break;
     388             :         case 'U':
     389           0 :                 buf = NULL;
     390           0 :                 while (pkg_users(pkg, &buf) == EPKG_OK) {
     391           0 :                         format_str(pkg, output, qstr, buf);
     392           0 :                         printf("%s\n", sbuf_data(output));
     393             :                 }
     394           0 :                 break;
     395             :         case 'G':
     396           0 :                 buf = NULL;
     397           0 :                 while (pkg_groups(pkg, &buf) == EPKG_OK) {
     398           0 :                         format_str(pkg, output, qstr, buf);
     399           0 :                         printf("%s\n", sbuf_data(output));
     400             :                 }
     401           0 :                 break;
     402             :         case 'B':
     403           0 :                 buf = NULL;
     404           0 :                 while (pkg_shlibs_required(pkg, &buf) == EPKG_OK) {
     405           0 :                         format_str(pkg, output, qstr, buf);
     406           0 :                         printf("%s\n", sbuf_data(output));
     407             :                 }
     408           0 :                 break;
     409             :         case 'b':
     410           0 :                 buf = NULL;
     411           0 :                 while (pkg_shlibs_provided(pkg, &buf) == EPKG_OK) {
     412           0 :                         format_str(pkg, output, qstr, buf);
     413           0 :                         printf("%s\n", sbuf_data(output));
     414             :                 }
     415           0 :                 break;
     416             :         case 'A':
     417           0 :                 pkg_get(pkg, PKG_ANNOTATIONS, &kv);
     418           0 :                 while (kv != NULL) {
     419           0 :                         format_str(pkg, output, qstr, kv);
     420           0 :                         printf("%s\n", sbuf_data(output));
     421           0 :                         kv = kv->next;
     422             :                 }
     423           0 :                 break;
     424             :         default:
     425           9 :                 format_str(pkg, output, qstr, dep);
     426           9 :                 printf("%s\n", sbuf_data(output));
     427           9 :                 break;
     428             :         }
     429           9 :         sbuf_delete(output);
     430           9 : }
     431             : 
     432             : typedef enum {
     433             :         NONE,
     434             :         NEXT_IS_INT,
     435             :         OPERATOR_INT,
     436             :         INT,
     437             :         NEXT_IS_STRING,
     438             :         OPERATOR_STRING,
     439             :         STRING,
     440             :         QUOTEDSTRING,
     441             :         SQUOTEDSTRING,
     442             :         POST_EXPR,
     443             : } state_t;
     444             : 
     445             : int
     446           2 : format_sql_condition(const char *str, struct sbuf *sqlcond, bool for_remote)
     447             : {
     448           2 :         state_t state = NONE;
     449           2 :         unsigned int bracket_level = 0;
     450             :         const char *sqlop;
     451             : 
     452           2 :         sbuf_cat(sqlcond, " WHERE ");
     453          14 :         while (str[0] != '\0') {
     454          10 :                 if (state == NONE) {
     455           2 :                         if (str[0] == '%') {
     456           2 :                                 str++;
     457           2 :                                 switch (str[0]) {
     458             :                                 case 'n':
     459           0 :                                         sbuf_cat(sqlcond, "name");
     460           0 :                                         state = OPERATOR_STRING;
     461           0 :                                         break;
     462             :                                 case 'o':
     463           0 :                                         sbuf_cat(sqlcond, "origin");
     464           0 :                                         state = OPERATOR_STRING;
     465           0 :                                         break;
     466             :                                 case 'p':
     467           0 :                                         sbuf_cat(sqlcond, "prefix");
     468           0 :                                         state = OPERATOR_STRING;
     469           0 :                                         break;
     470             :                                 case 'm':
     471           0 :                                         sbuf_cat(sqlcond, "maintainer");
     472           0 :                                         state = OPERATOR_STRING;
     473           0 :                                         break;
     474             :                                 case 'c':
     475           0 :                                         sbuf_cat(sqlcond, "comment");
     476           0 :                                         state = OPERATOR_STRING;
     477           0 :                                         break;
     478             :                                 case 'w':
     479           0 :                                         sbuf_cat(sqlcond, "www");
     480           0 :                                         state = OPERATOR_STRING;
     481           0 :                                         break;
     482             :                                 case 's':
     483           0 :                                         sbuf_cat(sqlcond, "flatsize");
     484           0 :                                         state = OPERATOR_INT;
     485           0 :                                         break;
     486             :                                 case 'a':
     487           0 :                                         if (for_remote)
     488           0 :                                                 goto bad_option;
     489           0 :                                         sbuf_cat(sqlcond, "automatic");
     490           0 :                                         state = OPERATOR_INT;
     491           0 :                                         break;
     492             :                                 case 'q':
     493           0 :                                         sbuf_cat(sqlcond, "arch");
     494           0 :                                         state = OPERATOR_STRING;
     495           0 :                                         break;
     496             :                                 case 'k':
     497           0 :                                         if (for_remote)
     498           0 :                                                 goto bad_option;
     499           0 :                                         sbuf_cat(sqlcond, "locked");
     500           0 :                                         state = OPERATOR_INT;
     501           0 :                                         break;
     502             :                                 case 'M':
     503           0 :                                         if (for_remote)
     504           0 :                                                 goto bad_option;
     505           0 :                                         sbuf_cat(sqlcond, "message");
     506           0 :                                         state = OPERATOR_STRING;
     507           0 :                                         break;
     508             :                                 case 't':
     509           0 :                                         if (for_remote)
     510           0 :                                                 goto bad_option;
     511           0 :                                         sbuf_cat(sqlcond, "time");
     512           0 :                                         state = OPERATOR_INT;
     513           0 :                                         break;
     514             :                                 case 'e':
     515           0 :                                         sbuf_cat(sqlcond, "desc");
     516           0 :                                         state = OPERATOR_STRING;
     517           0 :                                         break;
     518             :                                 case '#': /* FALLTHROUGH */
     519             :                                 case '?':
     520           2 :                                         sqlop = (str[0] == '#' ? "COUNT(*)" : "COUNT(*) > 0");
     521           2 :                                         str++;
     522           2 :                                         switch (str[0]) {
     523             :                                                 case 'd':
     524           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM deps AS d WHERE d.package_id=p.id)", sqlop);
     525           0 :                                                         break;
     526             :                                                 case 'r':
     527           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM deps AS d WHERE d.origin=p.origin)", sqlop);
     528           0 :                                                         break;
     529             :                                                 case 'C':
     530           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM pkg_categories AS d WHERE d.package_id=p.id)", sqlop);
     531           0 :                                                         break;
     532             :                                                 case 'F':
     533           0 :                                                         if (for_remote)
     534           0 :                                                                 goto bad_option;
     535           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM files AS d WHERE d.package_id=p.id)", sqlop);
     536           0 :                                                         break;
     537             :                                                 case 'O':
     538           2 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM pkg_option AS d WHERE d.package_id=p.id)", sqlop);
     539           2 :                                                         break;
     540             :                                                 case 'D':
     541           0 :                                                         if (for_remote)
     542           0 :                                                                 goto bad_option;
     543           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM pkg_directories AS d WHERE d.package_id=p.id)", sqlop);
     544           0 :                                                         break;
     545             :                                                 case 'L':
     546           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM pkg_licenses AS d WHERE d.package_id=p.id)", sqlop);
     547           0 :                                                         break;
     548             :                                                 case 'U':
     549           0 :                                                         if (for_remote)
     550           0 :                                                                 goto bad_option;
     551           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM pkg_users AS d WHERE d.package_id=p.id)", sqlop);
     552           0 :                                                         break;
     553             :                                                 case 'G':
     554           0 :                                                         if (for_remote)
     555           0 :                                                                 goto bad_option;
     556           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM pkg_groups AS d WHERE d.package_id=p.id)", sqlop);
     557           0 :                                                         break;
     558             :                                                 case 'B':
     559           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM pkg_shlibs_required AS d WHERE d.package_id=p.id)", sqlop);
     560           0 :                                                         break;
     561             :                                                 case 'b':
     562           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM pkg_shlibs_provided AS d WHERE d.package_id=p.id)", sqlop);
     563           0 :                                                         break;
     564             :                                                 case 'A':
     565           0 :                                                         sbuf_printf(sqlcond, "(SELECT %s FROM pkg_annotation AS d WHERE d.package_id=p.id)", sqlop);
     566           0 :                                                         break;
     567             :                                                 default:
     568           0 :                                                         goto bad_option;
     569             :                                         }
     570           2 :                                         state = OPERATOR_INT;
     571           2 :                                         break;
     572             :                                 default:
     573             : bad_option:
     574           0 :                                         fprintf(stderr, "malformed evaluation string\n");
     575           0 :                                         return (EPKG_FATAL);
     576             :                                 }
     577             :                         } else {
     578           0 :                                 switch (str[0]) {
     579             :                                 case '(':
     580           0 :                                         bracket_level++;
     581           0 :                                         sbuf_putc(sqlcond, str[0]);
     582           0 :                                         break;
     583             :                                 case ' ':
     584             :                                 case '\t':
     585           0 :                                         break;
     586             :                                 default:
     587           0 :                                         fprintf(stderr, "unexpected character: %c\n", str[0]);
     588           0 :                                         return (EPKG_FATAL);
     589             :                                 }
     590             :                         }
     591           8 :                 } else if (state == POST_EXPR) {
     592           0 :                         switch (str[0]) {
     593             :                         case ')':
     594           0 :                                 if (bracket_level == 0) {
     595           0 :                                         fprintf(stderr, "too many closing brackets.\n");
     596           0 :                                         return (EPKG_FATAL);
     597             :                                 }
     598           0 :                                 bracket_level--;
     599           0 :                                 sbuf_putc(sqlcond, str[0]);
     600           0 :                                 break;
     601             :                         case ' ':
     602             :                         case '\t':
     603           0 :                                 break;
     604             :                         case '|':
     605           0 :                                 if (str[1] == '|') {
     606           0 :                                         str++;
     607           0 :                                         state = NONE;
     608           0 :                                         sbuf_cat(sqlcond, " OR ");
     609           0 :                                         break;
     610             :                                 } else {
     611           0 :                                         fprintf(stderr, "unexpected character %c\n", str[1]);
     612           0 :                                         return (EPKG_FATAL);
     613             :                                 }
     614             :                         case '&':
     615           0 :                                 if (str[1] == '&') {
     616           0 :                                         str++;
     617           0 :                                         state = NONE;
     618           0 :                                         sbuf_cat(sqlcond, " AND ");
     619           0 :                                         break;
     620             :                                 } else {
     621           0 :                                         fprintf(stderr, "unexpected character %c\n", str[1]);
     622           0 :                                         return (EPKG_FATAL);
     623             :                                 }
     624             :                         default:
     625           0 :                                 fprintf(stderr, "unexpected character %c\n", str[0]);
     626           0 :                                 return (EPKG_FATAL);
     627             :                         }
     628           8 :                 } else if (state == OPERATOR_STRING || state == OPERATOR_INT) {
     629             :                         /* only operators or space are allowed here */
     630           8 :                         if (isspace(str[0])) {
     631             :                                 /* do nothing */
     632           2 :                         } else if (str[0] == '~' ) {
     633           0 :                                 if (state != OPERATOR_STRING) {
     634           0 :                                         fprintf(stderr, "~ expected only for string testing\n");
     635           0 :                                         return (EPKG_FATAL);
     636             :                                 }
     637           0 :                                 state = NEXT_IS_STRING;
     638           0 :                                 sbuf_cat(sqlcond, " GLOB ");
     639           2 :                         } else if (str[0] == '>' || str[0] == '<') {
     640           1 :                                 if (state != OPERATOR_INT) {
     641           0 :                                         fprintf(stderr, "> expected only for integers\n");
     642           0 :                                         return (EPKG_FATAL);
     643             :                                 }
     644           1 :                                 state = NEXT_IS_INT;
     645           1 :                                 sbuf_putc(sqlcond, str[0]);
     646           2 :                                 if (str[1] == '=') {
     647           0 :                                         str++;
     648           0 :                                         sbuf_putc(sqlcond, str[0]);
     649             :                                 }
     650           1 :                         } else if (str[0] == '=') {
     651           1 :                                 if (state == OPERATOR_STRING) {
     652           0 :                                         state = NEXT_IS_STRING;
     653             :                                 } else {
     654           1 :                                         state = NEXT_IS_INT;
     655             :                                 }
     656           1 :                                 sbuf_putc(sqlcond, str[0]);
     657           1 :                                 if (str[1] == '=') {
     658           1 :                                         str++;
     659           1 :                                         sbuf_putc(sqlcond, str[0]);
     660             :                                 }
     661           0 :                         } else if (str[0] == '!') {
     662           0 :                                 if (str[1] != '=') {
     663           0 :                                         fprintf(stderr, "expecting = after !\n");
     664           0 :                                         return (EPKG_FATAL);
     665             :                                 }
     666           0 :                                 if (state == OPERATOR_STRING) {
     667           0 :                                         state = NEXT_IS_STRING;
     668             :                                 } else {
     669           0 :                                         state = NEXT_IS_INT;
     670             :                                 }
     671           0 :                                 sbuf_putc(sqlcond, str[0]);
     672           0 :                                 str++;
     673           0 :                                 sbuf_putc(sqlcond, str[0]);
     674             :                         } else {
     675           0 :                                 fprintf(stderr, "an operator is expected, got %c\n", str[0]);
     676           0 :                                 return (EPKG_FATAL);
     677             :                         }
     678           4 :                 } else if (state == NEXT_IS_STRING || state == NEXT_IS_INT) {
     679           8 :                         if (isspace(str[0])) {
     680             :                                 /* do nothing */
     681             :                         } else {
     682           2 :                                 if (state == NEXT_IS_STRING) {
     683           0 :                                         if (str[0] == '"') {
     684           0 :                                                 state = QUOTEDSTRING;
     685           0 :                                         } else if (str[0] == '\'') {
     686           0 :                                                 state = SQUOTEDSTRING;
     687             :                                         } else {
     688           0 :                                                 state = STRING;
     689           0 :                                                 str--;
     690             :                                         }
     691           0 :                                         sbuf_putc(sqlcond, '\'');
     692             :                                 } else {
     693           2 :                                         if (!isdigit(str[0])) {
     694           0 :                                                 fprintf(stderr, "a number is expected, got: %c\n", str[0]);
     695           0 :                                                 return (EPKG_FATAL);
     696             :                                         }
     697           2 :                                         state = INT;
     698           2 :                                         sbuf_putc(sqlcond, str[0]);
     699             :                                 }
     700             :                         }
     701           0 :                 } else if (state == INT) {
     702           0 :                         if (!isdigit(str[0])) {
     703           0 :                                 state = POST_EXPR;
     704           0 :                                 str--;
     705             :                         } else {
     706           0 :                                 sbuf_putc(sqlcond, str[0]);
     707             :                         }
     708           0 :                 } else if (state == STRING || state == QUOTEDSTRING || state == SQUOTEDSTRING) {
     709           0 :                         if ((state == STRING && isspace(str[0])) ||
     710           0 :                             (state == QUOTEDSTRING && str[0] == '"') ||
     711           0 :                             (state == SQUOTEDSTRING && str[0] == '\'')) {
     712           0 :                                 sbuf_putc(sqlcond, '\'');
     713           0 :                                 state = POST_EXPR;
     714             :                         } else {
     715           0 :                                 sbuf_putc(sqlcond, str[0]);
     716           0 :                                 if (str[0] == '\'')
     717           0 :                                         sbuf_putc(sqlcond, str[0]);
     718           0 :                                 else if (str[0] == '%' && for_remote)
     719           0 :                                         sbuf_putc(sqlcond, str[0]);
     720             :                         }
     721             :                 }
     722          10 :                 str++;
     723             :         }
     724           2 :         if (state == STRING) {
     725           0 :                 sbuf_putc(sqlcond, '\'');
     726           0 :                 state = POST_EXPR;
     727             :         }
     728             : 
     729           2 :         if (state != POST_EXPR && state != INT) {
     730           0 :                 fprintf(stderr, "unexpected end of expression\n");
     731           0 :                 return (EPKG_FATAL);
     732           2 :         } else if (bracket_level > 0) {
     733           0 :                 fprintf(stderr, "unexpected end of expression (too many open brackets)\n");
     734           0 :                 return (EPKG_FATAL);
     735             :         }
     736             : 
     737           2 :         return (EPKG_OK);
     738             : }
     739             : 
     740             : int
     741          10 : analyse_query_string(char *qstr, struct query_flags *q_flags, const unsigned int q_flags_len, int *flags, char *multiline)
     742             : {
     743             :         unsigned int i, j, k;
     744          10 :         unsigned int valid_flag = 0;
     745          10 :         unsigned int valid_opts = 0;
     746             : 
     747          10 :         j = 0; /* shut up scanbuild */
     748             : 
     749          10 :         if (strchr(qstr, '%') == NULL) {
     750           0 :                 fprintf(stderr, "Invalid query: query should contain a format string\n");
     751           0 :                 return (EPKG_FATAL);
     752             :         }
     753             : 
     754          34 :         while (qstr[0] != '\0') {
     755          14 :                 if (qstr[0] == '%') {
     756          12 :                         qstr++;
     757          12 :                         valid_flag = 0;
     758             : 
     759         237 :                         for (i = 0; i < q_flags_len; i++) {
     760             :                                 /* found the flag */
     761         237 :                                 if (qstr[0] == q_flags[i].flag) {
     762          12 :                                         valid_flag = 1;
     763             : 
     764             :                                         /* if the flag is followed by additional options */
     765          12 :                                         if (q_flags[i].options[0] != '\0') {
     766           2 :                                                 qstr++;
     767           2 :                                                 valid_opts = 0;
     768             : 
     769          10 :                                                 for (j = 0; j < strlen(q_flags[i].options); j++) {
     770          10 :                                                         if (qstr[0] == q_flags[i].options[j]) {
     771           2 :                                                                 valid_opts = 1;
     772           2 :                                                                 break;
     773             :                                                         }
     774             :                                                 }
     775             : 
     776           2 :                                                 if (valid_opts == 0) {
     777           0 :                                                         fprintf(stderr, "Invalid query: '%%%c' should be followed by:", q_flags[i].flag);
     778             : 
     779           0 :                                                         for (j = 0; j < strlen(q_flags[i].options); j++)
     780           0 :                                                                 fprintf(stderr, " %c%c", q_flags[i].options[j],
     781           0 :                                                                                 q_flags[i].options[j + 1] == '\0' ?
     782             :                                                                                 '\n' : ',');
     783             : 
     784           0 :                                                         return (EPKG_FATAL);
     785             :                                                 }
     786             :                                         }
     787             : 
     788             :                                         /* if this is a multiline flag */
     789          12 :                                         if (q_flags[i].multiline == 1) {
     790           2 :                                                 if (*multiline != 0 && *multiline != q_flags[i].flag) {
     791           0 :                                                         fprintf(stderr, "Invalid query: '%%%c' and '%%%c' cannot be queried at the same time\n",
     792           0 :                                                                         *multiline, q_flags[i].flag);
     793           0 :                                                         return (EPKG_FATAL);
     794             :                                                 } else {
     795           2 :                                                         *multiline = q_flags[i].flag;
     796             :                                                 }
     797             :                                         }
     798             : 
     799             :                                         /* handle the '?' flag cases */
     800          14 :                                         if (q_flags[i].flag == '?' || q_flags[i].flag == '#') {
     801          10 :                                                 for (k = 0; k < q_flags_len; k++)
     802          10 :                                                         if (q_flags[k].flag == q_flags[i].options[j]) {
     803           2 :                                                                 *flags |= q_flags[k].dbflags;
     804           2 :                                                                 break;
     805             :                                                         }
     806             :                                         } else {
     807          10 :                                                 *flags |= q_flags[i].dbflags;
     808             :                                         }
     809             : 
     810          12 :                                         break; /* don't iterate over the rest of the flags */
     811             :                                 }
     812             :                         }
     813             : 
     814          12 :                         if (valid_flag == 0) {
     815           0 :                                 fprintf(stderr, "Unknown query format key: '%%%c'\n", qstr[0]);
     816           0 :                                 return (EPKG_FATAL);
     817             :                         }
     818             :                 }
     819             : 
     820          14 :                 qstr++;
     821             :         }
     822             : 
     823          10 :         return (EPKG_OK);
     824             : }
     825             : 
     826             : void
     827           0 : usage_query(void)
     828             : {
     829           0 :         fprintf(stderr, "Usage: pkg query <query-format> <pkg-name>\n");
     830           0 :         fprintf(stderr, "       pkg query [-a] <query-format>\n");
     831           0 :         fprintf(stderr, "       pkg query -F <pkg-name> <query-format>\n");
     832           0 :         fprintf(stderr, "       pkg query -e <evaluation> <query-format>\n");
     833           0 :         fprintf(stderr, "       pkg query [-Cgix] <query-format> <pattern> <...>\n\n");
     834           0 :         fprintf(stderr, "For more information see 'pkg help query.'\n");
     835           0 : }
     836             : 
     837             : int
     838          10 : exec_query(int argc, char **argv)
     839             : {
     840          10 :         struct pkgdb            *db = NULL;
     841          10 :         struct pkgdb_it         *it = NULL;
     842          10 :         struct pkg              *pkg = NULL;
     843          10 :         struct pkg_manifest_key *keys = NULL;
     844          10 :         char                    *pkgname = NULL;
     845          10 :         int                      query_flags = PKG_LOAD_BASIC;
     846          10 :         match_t                  match = MATCH_EXACT;
     847             :         int                      ch;
     848             :         int                      ret;
     849          10 :         int                      retcode = EX_OK;
     850             :         int                      i;
     851          10 :         char                     multiline = 0;
     852          10 :         char                    *condition = NULL;
     853          10 :         struct sbuf             *sqlcond = NULL;
     854          10 :         const unsigned int       q_flags_len = NELEM(accepted_query_flags);
     855             : 
     856          10 :         struct option longopts[] = {
     857             :                 { "all",              no_argument,            NULL,   'a' },
     858             :                 { "case-sensitive",   no_argument,            NULL,   'C' },
     859             :                 { "evaluate",         required_argument,      NULL,   'e' },
     860             :                 { "file",             required_argument,      NULL,   'F' },
     861             :                 { "glob",             no_argument,            NULL,   'g' },
     862             :                 { "case-insensitive", no_argument,            NULL,   'i' },
     863             :                 { "regex",            no_argument,            NULL,   'x' },
     864             :                 { NULL,                 0,                      NULL,   0   },
     865             :         };
     866             : 
     867          22 :         while ((ch = getopt_long(argc, argv, "+aCe:F:gix", longopts, NULL)) != -1) {
     868           2 :                 switch (ch) {
     869             :                 case 'a':
     870           0 :                         match = MATCH_ALL;
     871           0 :                         break;
     872             :                 case 'C':
     873           0 :                         pkgdb_set_case_sensitivity(true);
     874           0 :                         break;
     875             :                 case 'e':
     876           2 :                         match = MATCH_CONDITION;
     877           2 :                         condition = optarg;
     878           2 :                         break;
     879             :                 case 'F':
     880           0 :                         pkgname = optarg;
     881           0 :                         break;
     882             :                 case 'g':
     883           0 :                         match = MATCH_GLOB;
     884           0 :                         break;
     885             :                 case 'i':
     886           0 :                         pkgdb_set_case_sensitivity(false);
     887           0 :                         break;
     888             :                 case 'x':
     889           0 :                         match = MATCH_REGEX;
     890           0 :                         break;
     891             :                 default:
     892           0 :                         usage_query();
     893           0 :                         return (EX_USAGE);
     894             :                 }
     895             :         }
     896             : 
     897          10 :         argc -= optind;
     898          10 :         argv += optind;
     899             : 
     900          10 :         if (argc == 0) {
     901           0 :                 usage_query();
     902           0 :                 return (EX_USAGE);
     903             :         }
     904             : 
     905             :         /* Default to all packages if no pkg provided */
     906          10 :         if (argc == 1 && pkgname == NULL && condition == NULL && match == MATCH_EXACT) {
     907           3 :                 match = MATCH_ALL;
     908           7 :         } else if (((argc == 1) ^ (match == MATCH_ALL)) && pkgname == NULL
     909           2 :                         && condition == NULL) {
     910           0 :                 usage_query();
     911           0 :                 return (EX_USAGE);
     912             :         }
     913             : 
     914          10 :         if (analyse_query_string(argv[0], accepted_query_flags, q_flags_len,
     915             :                         &query_flags, &multiline) != EPKG_OK)
     916           0 :                 return (EX_USAGE);
     917             : 
     918          10 :         if (pkgname != NULL) {
     919           0 :                 pkg_manifest_keys_new(&keys);
     920           0 :                 if (pkg_open(&pkg, pkgname, keys, 0) != EPKG_OK) {
     921           0 :                         return (EX_IOERR);
     922             :                 }
     923             : 
     924           0 :                 pkg_manifest_keys_free(keys);
     925           0 :                 print_query(pkg, argv[0], multiline);
     926           0 :                 pkg_free(pkg);
     927           0 :                 return (EX_OK);
     928             :         }
     929             : 
     930          10 :         if (condition != NULL) {
     931           2 :                 sqlcond = sbuf_new_auto();
     932           2 :                 if (format_sql_condition(condition, sqlcond, false) != EPKG_OK) {
     933           0 :                         sbuf_delete(sqlcond);
     934           0 :                         return (EX_USAGE);
     935             :                 }
     936           2 :                 sbuf_finish(sqlcond);
     937             :         }
     938             : 
     939          10 :         ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
     940          10 :         if (ret == EPKG_ENOACCESS) {
     941           0 :                 warnx("Insufficient privileges to query the package database");
     942           0 :                 return (EX_NOPERM);
     943          10 :         } else if (ret == EPKG_ENODB) {
     944           0 :                 if (!quiet)
     945           0 :                         warnx("No packages installed");
     946           0 :                 return (EX_OK);
     947          10 :         } else if (ret != EPKG_OK)
     948           0 :                 return (EX_IOERR);
     949             : 
     950          10 :         ret = pkgdb_open(&db, PKGDB_DEFAULT);
     951          10 :         if (ret != EPKG_OK)
     952           0 :                 return (EX_IOERR);
     953             : 
     954          10 :         if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
     955           0 :                 pkgdb_close(db);
     956           0 :                 warnx("Cannot get a read lock on a database, it is locked by another process");
     957           0 :                 return (EX_TEMPFAIL);
     958             :         }
     959             : 
     960          15 :         if (match == MATCH_ALL || match == MATCH_CONDITION) {
     961           5 :                 const char *condition_sql = NULL;
     962           5 :                 if (match == MATCH_CONDITION && sqlcond)
     963           2 :                         condition_sql = sbuf_data(sqlcond);
     964           5 :                 if ((it = pkgdb_query(db, condition_sql, match)) == NULL)
     965           0 :                         return (EX_IOERR);
     966             : 
     967          14 :                 while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK)
     968           4 :                         print_query(pkg, argv[0],  multiline);
     969             : 
     970           5 :                 if (ret != EPKG_END)
     971           0 :                         retcode = EX_SOFTWARE;
     972             : 
     973           5 :                 pkgdb_it_free(it);
     974             :         } else {
     975           5 :                 int nprinted = 0;
     976          10 :                 for (i = 1; i < argc; i++) {
     977           5 :                         pkgname = argv[i];
     978             : 
     979           5 :                         if ((it = pkgdb_query(db, pkgname, match)) == NULL) {
     980           0 :                                 retcode = EX_IOERR;
     981           0 :                                 goto cleanup;
     982             :                         }
     983             : 
     984          15 :                         while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
     985           5 :                                 nprinted++;
     986           5 :                                 print_query(pkg, argv[0], multiline);
     987             :                         }
     988             : 
     989           5 :                         if (ret != EPKG_END) {
     990           0 :                                 retcode = EX_SOFTWARE;
     991           0 :                                 break;
     992             :                         }
     993             : 
     994           5 :                         pkgdb_it_free(it);
     995             :                 }
     996           5 :                 if (nprinted == 0 && retcode == EX_OK) {
     997             :                         /* ensure to return a non-zero status when no package
     998             :                          were found. */
     999           0 :                         retcode = EX_UNAVAILABLE;
    1000             :                 }
    1001             :         }
    1002             : 
    1003             : cleanup:
    1004          10 :         pkg_free(pkg);
    1005             : 
    1006          10 :         pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
    1007          10 :         pkgdb_close(db);
    1008             : 
    1009          10 :         return (retcode);
    1010             : }

Generated by: LCOV version 1.10