Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
5 : : * Copyright (c) 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/param.h>
31 : : #include <sys/stat.h>
32 : :
33 : : #include <err.h>
34 : : #include <getopt.h>
35 : : #include <stdio.h>
36 : : #include <string.h>
37 : : #include <unistd.h>
38 : : #include <kvec.h>
39 : : #include <fnmatch.h>
40 : :
41 : : #include <pkg.h>
42 : : #include "pkgcli.h"
43 : :
44 : : typedef kvec_t(char *) charlist;
45 : :
46 : : void
47 : 0 : usage_which(void)
48 : : {
49 : 0 : fprintf(stderr, "Usage: pkg which [-mqgop] <file>\n\n");
50 : 0 : fprintf(stderr, "For more information see 'pkg help which'.\n");
51 : 0 : }
52 : :
53 : : static bool is_there(char *);
54 : : int get_match(char **, char **, char *);
55 : :
56 : : static bool
57 : 0 : already_in_list(charlist *list, const char *pattern)
58 : : {
59 : : size_t i;
60 : :
61 [ # # ]: 0 : for (i = 0; i < kv_size(*list); i++)
62 [ # # ]: 0 : if (strcmp(kv_A(*list, i), pattern) == 0)
63 : 0 : return (true);
64 : :
65 : 0 : return (false);
66 : 0 : }
67 : :
68 : : int
69 : 0 : exec_which(int argc, char **argv)
70 : : {
71 : 0 : struct pkgdb *db = NULL;
72 : 0 : struct pkgdb_it *it = NULL;
73 : 0 : struct pkg *pkg = NULL;
74 : 0 : struct pkg_file *file = NULL;
75 : : char pathabs[MAXPATHLEN];
76 : : char *p, *path, *match, *savedpath;
77 : 0 : int retcode = EXIT_FAILURE;
78 : 0 : int ch, res, pathlen = 0;
79 : : size_t i;
80 : 0 : bool orig = false;
81 : 0 : bool glob = false;
82 : 0 : bool search = false;
83 : 0 : bool search_s = false;
84 : 0 : bool show_match = false;
85 : : charlist patterns;
86 : :
87 : 0 : struct option longopts[] = {
88 : : { "glob", no_argument, NULL, 'g' },
89 : : { "origin", no_argument, NULL, 'o' },
90 : : { "path-search", no_argument, NULL, 'p' },
91 : : { "quiet", no_argument, NULL, 'q' },
92 : : { "show-match", no_argument, NULL, 'm' },
93 : : { NULL, 0, NULL, 0 },
94 : : };
95 : :
96 : 0 : path = NULL;
97 : :
98 [ # # ]: 0 : while ((ch = getopt_long(argc, argv, "+gopqm", longopts, NULL)) != -1) {
99 [ # # # # : 0 : switch (ch) {
# # ]
100 : : case 'g':
101 : 0 : glob = true;
102 : 0 : break;
103 : : case 'o':
104 : 0 : orig = true;
105 : 0 : break;
106 : : case 'p':
107 : 0 : search_s = true;
108 : 0 : break;
109 : : case 'q':
110 : 0 : quiet = true;
111 : 0 : break;
112 : : case 'm':
113 : 0 : show_match = true;
114 : 0 : break;
115 : : default:
116 : 0 : usage_which();
117 : 0 : return (EXIT_FAILURE);
118 : : }
119 : : }
120 : :
121 : 0 : argc -= optind;
122 : 0 : argv += optind;
123 : :
124 [ # # ]: 0 : if (argc < 1) {
125 : 0 : usage_which();
126 : 0 : return (EXIT_FAILURE);
127 : : }
128 : :
129 [ # # ]: 0 : if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
130 : 0 : return (EXIT_FAILURE);
131 : : }
132 : :
133 [ # # ]: 0 : if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
134 : 0 : pkgdb_close(db);
135 : 0 : warnx("Cannot get a read lock on a database, it is locked by another process");
136 : 0 : return (EXIT_FAILURE);
137 : : }
138 : :
139 [ # # ]: 0 : if (search_s) {
140 [ # # ]: 0 : if ((path = getenv("PATH")) == NULL) {
141 : 0 : printf("$PATH is not set, falling back to non-search behaviour\n");
142 : 0 : search_s = false;
143 : 0 : } else {
144 : 0 : pathlen = strlen(path) + 1;
145 : : }
146 : 0 : }
147 : :
148 [ # # ]: 0 : while (argc >= 1) {
149 : 0 : kv_init(patterns);
150 : 0 : retcode = EXIT_FAILURE;
151 [ # # ]: 0 : if (search_s) {
152 [ # # # # ]: 0 : if ((argv[0][0] == '.') || (argv[0][0] == '/')) {
153 : 0 : search = false;
154 : 0 : } else {
155 : 0 : search = true;
156 : :
157 [ # # ]: 0 : if (strlen(argv[0]) >= FILENAME_MAX) {
158 : 0 : retcode = EXIT_FAILURE;
159 : 0 : goto cleanup;
160 : : }
161 : :
162 : 0 : p = malloc(pathlen);
163 [ # # ]: 0 : if (p == NULL) {
164 : 0 : retcode = EXIT_FAILURE;
165 : 0 : goto cleanup;
166 : : }
167 : 0 : strlcpy(p, path, pathlen);
168 : :
169 : 0 : match = NULL;
170 : 0 : savedpath=p;
171 : 0 : for (;;) {
172 : 0 : res = get_match(&match, &p, argv[0]);
173 [ # # ]: 0 : if (p == NULL)
174 : 0 : break;
175 : :
176 [ # # ]: 0 : if (res == (EXIT_FAILURE)) {
177 : 0 : printf("%s was not found in PATH, falling back to non-search behaviour\n", argv[0]);
178 : 0 : search = false;
179 [ # # ]: 0 : } else if (res == (EXIT_FAILURE)) {
180 : 0 : retcode = EXIT_FAILURE;
181 : 0 : free(savedpath);
182 : 0 : goto cleanup;
183 : : } else {
184 : 0 : pkg_absolutepath(match, pathabs, sizeof(pathabs), false);
185 : : /* ensure not not append twice an entry if PATH is messy */
186 [ # # ]: 0 : if (already_in_list(&patterns, pathabs))
187 : 0 : continue;
188 [ # # # # ]: 0 : kv_push(char *, patterns, strdup(pathabs));
189 : 0 : free(match);
190 : : }
191 : : }
192 : 0 : free(savedpath);
193 : : }
194 : 0 : }
195 : :
196 [ # # # # ]: 0 : if (!glob && !search) {
197 : 0 : pkg_absolutepath(argv[0], pathabs, sizeof(pathabs), false);
198 [ # # # # ]: 0 : kv_push(char *, patterns, strdup(pathabs));
199 [ # # ]: 0 : } else if (!search) {
200 [ # # ]: 0 : if (strlcpy(pathabs, argv[0], sizeof(pathabs)) >= sizeof(pathabs)) {
201 : 0 : retcode = EXIT_FAILURE;
202 : 0 : goto cleanup;
203 : : }
204 [ # # # # ]: 0 : kv_push(char *, patterns, strdup(pathabs));
205 : 0 : }
206 : :
207 : :
208 [ # # ]: 0 : for (i = 0; i < kv_size(patterns); i++) {
209 [ # # ]: 0 : if ((it = pkgdb_query_which(db, kv_A(patterns, i), glob)) == NULL) {
210 : 0 : retcode = EXIT_FAILURE;
211 : 0 : goto cleanup;
212 : : }
213 : :
214 : 0 : pkg = NULL;
215 [ # # ]: 0 : while (pkgdb_it_next(it, &pkg, PKG_LOAD_FILES) == EPKG_OK) {
216 : 0 : retcode = EXIT_SUCCESS;
217 [ # # # # : 0 : if (quiet && orig && !show_match)
# # ]
218 : 0 : pkg_printf("%o\n", pkg);
219 [ # # # # : 0 : else if (quiet && !orig && !show_match)
# # ]
220 : 0 : pkg_printf("%n-%v\n", pkg, pkg);
221 [ # # # # : 0 : else if (!quiet && orig && !show_match)
# # ]
222 : 0 : pkg_printf("%S was installed by package %o\n", kv_A(patterns, i), pkg);
223 [ # # # # : 0 : else if (!quiet && !orig && !show_match)
# # ]
224 : 0 : pkg_printf("%S was installed by package %n-%v\n", kv_A(patterns, i), pkg, pkg);
225 [ # # # # ]: 0 : else if (glob && show_match) {
226 [ # # ]: 0 : if (!quiet)
227 : 0 : pkg_printf("%S was glob searched and found in package %n-%v\n", kv_A(patterns, i), pkg, pkg, pkg);
228 [ # # ]: 0 : while(pkg_files(pkg, &file) == EPKG_OK) {
229 : 0 : pkg_asprintf(&match, "%Fn", file);
230 [ # # ]: 0 : if (match == NULL)
231 : 0 : err(EXIT_FAILURE, "pkg_asprintf");
232 [ # # ]: 0 : if(!fnmatch(kv_A(patterns, i), match, 0))
233 : 0 : printf("%s\n", match);
234 : 0 : free(match);
235 : : }
236 : 0 : }
237 : : }
238 [ # # # # ]: 0 : if (retcode != EXIT_SUCCESS && !quiet)
239 : 0 : printf("%s was not found in the database\n", kv_A(patterns, i));
240 : :
241 : 0 : pkg_free(pkg);
242 : 0 : pkgdb_it_free(it);
243 : :
244 : 0 : }
245 : 0 : kv_destroy(patterns);
246 : :
247 : 0 : argc--;
248 : 0 : argv++;
249 : :
250 : : }
251 : :
252 : : cleanup:
253 : 0 : pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
254 : 0 : pkgdb_close(db);
255 : :
256 : 0 : return (retcode);
257 : 0 : }
258 : :
259 : :
260 : : static bool
261 : 0 : is_there(char *candidate)
262 : : {
263 : 0 : return (access(candidate, F_OK) == 0);
264 : : }
265 : :
266 : : int
267 : 0 : get_match(char **pathabs, char **path, char *filename)
268 : : {
269 : : char candidate[PATH_MAX];
270 : : const char *d;
271 : : int len;
272 : :
273 [ # # ]: 0 : while ((d = strsep(path, ":")) != NULL) {
274 [ # # # # : 0 : if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
# # ]
275 : 0 : filename) >= (int)sizeof(candidate))
276 : 0 : continue;
277 [ # # ]: 0 : if (is_there(candidate)) {
278 : 0 : len = strlen(candidate) + 1;
279 : 0 : *pathabs = malloc(len);
280 [ # # ]: 0 : if (*pathabs == NULL)
281 : 0 : return (EXIT_FAILURE);
282 : 0 : strlcpy(*pathabs, candidate, len);
283 : 0 : return (EXIT_SUCCESS);
284 : : }
285 : : }
286 : 0 : return (EXIT_FAILURE);
287 : 0 : }
|