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 : 32 : exec_rquery(int argc, char **argv)
104 : : {
105 : 32 : struct pkgdb *db = NULL;
106 : 32 : struct pkgdb_it *it = NULL;
107 : 32 : struct pkg *pkg = NULL;
108 : 32 : char *pkgname = NULL;
109 : 32 : int query_flags = PKG_LOAD_BASIC;
110 : 32 : match_t match = MATCH_EXACT;
111 : : int ch;
112 : 32 : int ret = EPKG_OK;
113 : 32 : int retcode = EXIT_SUCCESS;
114 : : int i;
115 : 32 : char multiline = 0;
116 : 32 : char *condition = NULL;
117 : 32 : const char *condition_sql = NULL;
118 : : const char *portsdir;
119 : 32 : xstring *sqlcond = NULL;
120 : 32 : const unsigned int q_flags_len = NELEM(accepted_rquery_flags);
121 : 32 : const char *reponame = NULL;
122 : 32 : bool onematched = false;
123 : : bool old_quiet;
124 : 32 : bool index_output = false;
125 : :
126 : 32 : 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 : 32 : portsdir = pkg_object_string(pkg_config_get("PORTSDIR"));
140 : :
141 [ + + ]: 60 : while ((ch = getopt_long(argc, argv, "+aCgiIxe:r:U", longopts, NULL)) != -1) {
142 [ + - + - : 28 : switch (ch) {
- - - - -
- ]
143 : : case 'a':
144 : 8 : match = MATCH_ALL;
145 : 8 : break;
146 : : case 'C':
147 : 0 : pkgdb_set_case_sensitivity(true);
148 : 0 : break;
149 : : case 'e':
150 : 20 : condition = optarg;
151 : 20 : break;
152 : : case 'g':
153 : 0 : match = MATCH_GLOB;
154 : 0 : break;
155 : : case 'i':
156 : 0 : pkgdb_set_case_sensitivity(false);
157 : 0 : break;
158 : : case 'I':
159 : 0 : index_output = true;
160 : 0 : break;
161 : : case 'r':
162 : 0 : reponame = optarg;
163 : 0 : break;
164 : : case 'U':
165 : 0 : auto_update = false;
166 : 0 : break;
167 : : case 'x':
168 : 0 : match = MATCH_REGEX;
169 : 0 : break;
170 : : default:
171 : 0 : usage_rquery();
172 : 0 : return (EXIT_FAILURE);
173 : : }
174 : : }
175 : :
176 : 32 : argc -= optind;
177 : 32 : argv += optind;
178 : :
179 [ - + # # ]: 32 : if (argc == 0 && !index_output) {
180 : 0 : usage_rquery();
181 : 0 : return (EXIT_FAILURE);
182 : : }
183 : :
184 : : /* Default to all packages if no pkg provided */
185 [ - + ]: 32 : if (!index_output) {
186 [ + + + + ]: 32 : if (argc == 1 && match == MATCH_EXACT) {
187 : 12 : match = MATCH_ALL;
188 [ - + # # ]: 32 : } else if (((argc == 1) ^ (match == MATCH_ALL )) && condition == NULL) {
189 : 0 : usage_rquery();
190 : 0 : return (EXIT_FAILURE);
191 : : }
192 : 32 : } else {
193 [ # # ]: 0 : if (argc == 0)
194 : 0 : match = MATCH_ALL;
195 : : }
196 : :
197 [ + - + - ]: 32 : if (!index_output && analyse_query_string(argv[0], accepted_rquery_flags, q_flags_len, &query_flags, &multiline) != EPKG_OK)
198 : 0 : return (EXIT_FAILURE);
199 : :
200 [ + + ]: 32 : if (condition != NULL) {
201 : 20 : sqlcond = xstring_new();
202 [ - + ]: 20 : if (format_sql_condition(condition, sqlcond, true) != EPKG_OK) {
203 : 0 : xstring_free(sqlcond);
204 : 0 : return (EXIT_FAILURE);
205 : : }
206 : 20 : }
207 : :
208 : 32 : ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_REPO);
209 [ - + ]: 32 : if (ret == EPKG_ENOACCESS) {
210 : 0 : warnx("Insufficient privileges to query the package database");
211 : 0 : xstring_free(sqlcond);
212 : 0 : return (EXIT_FAILURE);
213 [ - + ]: 32 : } else if (ret != EPKG_OK) {
214 : 0 : xstring_free(sqlcond);
215 : 0 : return (EXIT_FAILURE);
216 : : }
217 : :
218 : : /* first update the remote repositories if needed */
219 : 32 : old_quiet = quiet;
220 : 32 : quiet = true;
221 [ + - - + ]: 32 : if (auto_update && (ret = pkgcli_update(false, false, reponame)) != EPKG_OK) {
222 : 0 : xstring_free(sqlcond);
223 : 0 : return (ret);
224 : : }
225 : 32 : quiet = old_quiet;
226 : :
227 : 32 : ret = pkgdb_open_all(&db, PKGDB_REMOTE, reponame);
228 [ - + ]: 32 : if (ret != EPKG_OK) {
229 : 0 : xstring_free(sqlcond);
230 : 0 : return (EXIT_FAILURE);
231 : : }
232 : 32 : drop_privileges();
233 : :
234 [ + - ]: 32 : if (index_output)
235 : 0 : query_flags = PKG_LOAD_BASIC|PKG_LOAD_CATEGORIES|PKG_LOAD_DEPS;
236 : :
237 [ + + ]: 32 : if (sqlcond) {
238 : 20 : fflush(sqlcond->fp);
239 : 20 : condition_sql = sqlcond->buf;
240 : 20 : }
241 [ + + ]: 32 : if (match == MATCH_ALL) {
242 [ + - ]: 20 : if ((it = pkgdb_repo_query_cond(db, condition_sql, NULL, match, reponame)) == NULL) {
243 : 0 : xstring_free(sqlcond);
244 : 0 : return (EXIT_FAILURE);
245 : : }
246 : :
247 [ + + ]: 36 : while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
248 [ - + ]: 16 : if (index_output)
249 : 0 : print_index(pkg, portsdir);
250 : : else
251 : 16 : print_query(pkg, argv[0], multiline);
252 : : }
253 : :
254 [ + - ]: 20 : if (ret != EPKG_END)
255 : 0 : retcode = EXIT_FAILURE;
256 : :
257 : 20 : pkgdb_it_free(it);
258 : 20 : } else {
259 [ + + ]: 24 : for (i = (index_output ? 0 : 1); i < argc; i++) {
260 : 12 : pkgname = argv[i];
261 : :
262 [ + - ]: 12 : if ((it = pkgdb_repo_query_cond(db, condition_sql, pkgname, match, reponame)) == NULL) {
263 : 0 : xstring_free(sqlcond);
264 : 0 : return (EXIT_FAILURE);
265 : : }
266 : :
267 [ + + ]: 16 : while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
268 : 4 : onematched = true;
269 [ - + ]: 4 : if (index_output)
270 : 0 : print_index(pkg, portsdir);
271 : : else
272 : 4 : print_query(pkg, argv[0], multiline);
273 : : }
274 : :
275 [ + - ]: 12 : if (ret != EPKG_END) {
276 : 0 : retcode = EXIT_FAILURE;
277 : 0 : break;
278 : : }
279 : :
280 : 12 : pkgdb_it_free(it);
281 : 12 : }
282 [ + + + - ]: 12 : if (!onematched && retcode == EXIT_SUCCESS)
283 : 8 : retcode = EXIT_FAILURE;
284 : : }
285 : :
286 : 32 : xstring_free(sqlcond);
287 : 32 : pkg_free(pkg);
288 : 32 : pkgdb_close(db);
289 : :
290 : 32 : return (retcode);
291 : 32 : }
|