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