Branch data 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-2013 Bryan Drewery <bdrewery@FreeBSD.org>
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 <pkg.h>
37 : : #include <stdio.h>
38 : : #include <stdlib.h>
39 : : #include <string.h>
40 : : #include <unistd.h>
41 : :
42 : : #include "pkgcli.h"
43 : :
44 : : static struct query_flags accepted_rquery_flags[] = {
45 : : { 'd', "nov", 1, PKG_LOAD_DEPS },
46 : : { 'r', "nov", 1, PKG_LOAD_RDEPS },
47 : : { 'C', "", 1, PKG_LOAD_CATEGORIES },
48 : : { 'O', "kvdD", 1, PKG_LOAD_OPTIONS },
49 : : { 'L', "", 1, PKG_LOAD_LICENSES },
50 : : { 'B', "", 1, PKG_LOAD_SHLIBS_REQUIRED },
51 : : { 'b', "", 1, PKG_LOAD_SHLIBS_PROVIDED },
52 : : { 'A', "tv", 1, PKG_LOAD_ANNOTATIONS },
53 : : { '?', "drCOLBbA", 1, PKG_LOAD_BASIC }, /* dbflags handled in analyse_query_string() */
54 : : { '#', "drCOLBbA", 1, PKG_LOAD_BASIC }, /* dbflags handled in analyse_query_string() */
55 : : { 's', "hb", 0, PKG_LOAD_BASIC },
56 : : { 'n', "", 0, PKG_LOAD_BASIC },
57 : : { 'e', "", 0, PKG_LOAD_BASIC },
58 : : { 'v', "", 0, PKG_LOAD_BASIC },
59 : : { 'o', "", 0, PKG_LOAD_BASIC },
60 : : { 'R', "", 0, PKG_LOAD_BASIC },
61 : : { 'p', "", 0, PKG_LOAD_BASIC },
62 : : { 'm', "", 0, PKG_LOAD_BASIC },
63 : : { 'c', "", 0, PKG_LOAD_BASIC },
64 : : { 'w', "", 0, PKG_LOAD_BASIC },
65 : : { 'l', "", 0, PKG_LOAD_BASIC },
66 : : { 'q', "", 0, PKG_LOAD_BASIC },
67 : : { 'M', "", 0, PKG_LOAD_BASIC }
68 : : };
69 : :
70 : : void
71 : 0 : usage_rquery(void)
72 : : {
73 : 0 : fprintf(stderr, "Usage: pkg rquery [-r reponame] [-I|<query-format>] <pkg-name>\n");
74 : 0 : fprintf(stderr, " pkg rquery [-a] [-r reponame] [-I|<query-format>]\n");
75 : 0 : fprintf(stderr, " pkg rquery -e <evaluation> [-r reponame] <query-format>\n");
76 : 0 : fprintf(stderr, " pkg rquery [-Cgix] [-r reponame] [-I|<query-format>] <pattern> <...>\n\n");
77 : 0 : fprintf(stderr, "For more information see 'pkg help rquery.'\n");
78 : 0 : }
79 : :
80 : : static void
81 : 0 : print_index(struct pkg *pkg, const char *portsdir)
82 : : {
83 : :
84 : 0 : pkg_printf(
85 : : "%n-%v|" /* PKGNAME */
86 : : "%S/%o|" /* PORTDIR */
87 : : "%p|" /* PREFIX */
88 : : "%c|" /* COMMENT */
89 : : "%S/%o/pkg-descr|" /* _DESCR */
90 : : "%m|" /* MAINTAINER */
91 : : "%C%{%Cn%| %}|" /* CATEGORIES */
92 : : "|" /* BUILD_DEPENDS */
93 : : "%d%{%dn-%dv%| %}|" /* RUN_DEPENDS */
94 : : "%w|" /* WWW */
95 : : "|" /* EXTRACT_DEPENDS */
96 : : "|" /* PATCH_DEPENDS */
97 : : "\n", /* FETCH_DEPENDS */
98 : 0 : pkg, pkg, portsdir, pkg, pkg, pkg, portsdir, pkg, pkg, pkg, pkg,
99 : 0 : pkg);
100 : 0 : }
101 : :
102 : : int
103 : 12 : exec_rquery(int argc, char **argv)
104 : : {
105 : 12 : struct pkgdb *db = NULL;
106 : 12 : struct pkgdb_it *it = NULL;
107 : 12 : struct pkg *pkg = NULL;
108 : 12 : char *pkgname = NULL;
109 : 12 : int query_flags = PKG_LOAD_BASIC;
110 : 12 : match_t match = MATCH_EXACT;
111 : : int ch;
112 : 12 : int ret = EPKG_OK;
113 : 12 : int retcode = EXIT_SUCCESS;
114 : : int i;
115 : 12 : char multiline = 0;
116 : 12 : char *condition = NULL;
117 : 12 : const char *condition_sql = NULL;
118 : : const char *portsdir;
119 : 12 : xstring *sqlcond = NULL;
120 : 12 : const unsigned int q_flags_len = NELEM(accepted_rquery_flags);
121 : 12 : bool onematched = false;
122 : : bool old_quiet;
123 : 12 : bool index_output = false;
124 : : c_charv_t reponames;
125 : :
126 : 12 : struct option longopts[] = {
127 : : { "all", no_argument, NULL, 'a' },
128 : : { "case-sensitive", no_argument, NULL, 'C' },
129 : : { "evaluate", required_argument, NULL, 'e' },
130 : : { "glob", no_argument, NULL, 'g' },
131 : : { "case-insensitive", no_argument, NULL, 'i' },
132 : : { "index-line", no_argument, NULL, 'I' },
133 : : { "repository", required_argument, NULL, 'r' },
134 : : { "no-repo-update", no_argument, NULL, 'U' },
135 : : { "regex", no_argument, NULL, 'x' },
136 : : { NULL, 0, NULL, 0 },
137 : : };
138 : :
139 : 12 : portsdir = pkg_object_string(pkg_config_get("PORTSDIR"));
140 : :
141 : 12 : pkgvec_init(&reponames);
142 [ + + ]: 23 : while ((ch = getopt_long(argc, argv, "+aCgiIxe:r:U", longopts, NULL)) != -1) {
143 [ + - + - : 11 : switch (ch) {
- - + - -
- ]
144 : : case 'a':
145 : 2 : match = MATCH_ALL;
146 : 2 : break;
147 : : case 'C':
148 : 0 : pkgdb_set_case_sensitivity(true);
149 : 0 : break;
150 : : case 'e':
151 : 5 : condition = optarg;
152 : 5 : break;
153 : : case 'g':
154 : 0 : match = MATCH_GLOB;
155 : 0 : break;
156 : : case 'i':
157 : 0 : pkgdb_set_case_sensitivity(false);
158 : 0 : break;
159 : : case 'I':
160 : 0 : index_output = true;
161 : 0 : break;
162 : : case 'r':
163 [ # # # # : 0 : pkgvec_push(&reponames, optarg);
# # ]
164 : 0 : break;
165 : : case 'U':
166 : 4 : auto_update = false;
167 : 4 : break;
168 : : case 'x':
169 : 0 : match = MATCH_REGEX;
170 : 0 : break;
171 : : default:
172 : 0 : usage_rquery();
173 : 0 : return (EXIT_FAILURE);
174 : : }
175 : : }
176 : :
177 : 12 : argc -= optind;
178 : 12 : argv += optind;
179 : :
180 [ - + # # ]: 12 : if (argc == 0 && !index_output) {
181 : 0 : usage_rquery();
182 : 0 : return (EXIT_FAILURE);
183 : : }
184 : :
185 : : /* Default to all packages if no pkg provided */
186 [ - + ]: 12 : if (!index_output) {
187 [ + + + + ]: 12 : if (argc == 1 && match == MATCH_EXACT) {
188 : 3 : match = MATCH_ALL;
189 [ - + # # ]: 12 : } else if (((argc == 1) ^ (match == MATCH_ALL )) && condition == NULL) {
190 : 0 : usage_rquery();
191 : 0 : return (EXIT_FAILURE);
192 : : }
193 : 12 : } else {
194 [ # # ]: 0 : if (argc == 0)
195 : 0 : match = MATCH_ALL;
196 : : }
197 : :
198 [ + - + - ]: 12 : if (!index_output && analyse_query_string(argv[0], accepted_rquery_flags, q_flags_len, &query_flags, &multiline) != EPKG_OK)
199 : 0 : return (EXIT_FAILURE);
200 : :
201 [ + + ]: 12 : if (condition != NULL) {
202 : 5 : sqlcond = xstring_new();
203 [ - + ]: 5 : if (format_sql_condition(condition, sqlcond, true) != EPKG_OK) {
204 : 0 : xstring_free(sqlcond);
205 : 0 : return (EXIT_FAILURE);
206 : : }
207 : 5 : }
208 : :
209 : 12 : ret = pkgdb_access2(PKGDB_MODE_READ, PKGDB_DB_REPO, &reponames);
210 [ - + ]: 12 : if (ret == EPKG_ENOACCESS) {
211 : 0 : warnx("Insufficient privileges to query the package database");
212 : 0 : xstring_free(sqlcond);
213 : 0 : return (EXIT_FAILURE);
214 [ - + ]: 12 : } else if (ret != EPKG_OK) {
215 : 0 : xstring_free(sqlcond);
216 : 0 : return (EXIT_FAILURE);
217 : : }
218 : :
219 : : /* first update the remote repositories if needed */
220 : 12 : old_quiet = quiet;
221 : 12 : quiet = true;
222 [ + + - + ]: 12 : if (auto_update && (ret = pkgcli_update(false, false, &reponames)) != EPKG_OK) {
223 : 0 : xstring_free(sqlcond);
224 : 0 : return (ret);
225 : : }
226 : 12 : quiet = old_quiet;
227 : :
228 : 12 : ret = pkgdb_open_all2(&db, PKGDB_REMOTE, &reponames);
229 [ - + ]: 12 : if (ret != EPKG_OK) {
230 : 0 : xstring_free(sqlcond);
231 : 0 : return (EXIT_FAILURE);
232 : : }
233 : 12 : pkg_drop_privileges();
234 : :
235 [ + - ]: 12 : if (index_output)
236 : 0 : query_flags = PKG_LOAD_BASIC|PKG_LOAD_CATEGORIES|PKG_LOAD_DEPS;
237 : :
238 [ + + ]: 12 : if (sqlcond) {
239 : 5 : fflush(sqlcond->fp);
240 : 5 : condition_sql = sqlcond->buf;
241 : 5 : }
242 [ + + ]: 12 : if (match == MATCH_ALL) {
243 [ + - ]: 5 : if ((it = pkgdb_repo_query_cond2(db, condition_sql, NULL, match, &reponames)) == NULL) {
244 : 0 : xstring_free(sqlcond);
245 : 0 : return (EXIT_FAILURE);
246 : : }
247 : :
248 [ + + ]: 9 : while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
249 [ - + ]: 4 : if (index_output)
250 : 0 : print_index(pkg, portsdir);
251 : : else
252 : 4 : print_query(pkg, argv[0], multiline);
253 : : }
254 : :
255 [ + - ]: 5 : if (ret != EPKG_END)
256 : 0 : retcode = EXIT_FAILURE;
257 : :
258 : 5 : pkgdb_it_free(it);
259 : 5 : } else {
260 [ + + ]: 14 : for (i = (index_output ? 0 : 1); i < argc; i++) {
261 : 7 : pkgname = argv[i];
262 : :
263 [ + - ]: 7 : if ((it = pkgdb_repo_query_cond2(db, condition_sql, pkgname, match, &reponames)) == NULL) {
264 : 0 : xstring_free(sqlcond);
265 : 0 : return (EXIT_FAILURE);
266 : : }
267 : :
268 [ + + ]: 12 : while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
269 : 5 : onematched = true;
270 [ - + ]: 5 : if (index_output)
271 : 0 : print_index(pkg, portsdir);
272 : : else
273 : 5 : print_query(pkg, argv[0], multiline);
274 : : }
275 : :
276 [ - + ]: 7 : if (ret != EPKG_END) {
277 : 0 : retcode = EXIT_FAILURE;
278 : 0 : break;
279 : : }
280 : :
281 : 7 : pkgdb_it_free(it);
282 : 7 : }
283 [ + + - + ]: 7 : if (!onematched && retcode == EXIT_SUCCESS)
284 : 2 : retcode = EXIT_FAILURE;
285 : : }
286 : :
287 : 12 : xstring_free(sqlcond);
288 : 12 : pkg_free(pkg);
289 : 12 : pkgdb_close(db);
290 : :
291 : 12 : return (retcode);
292 : 12 : }
|