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 <fnmatch.h>
39 : :
40 : : #include <pkg.h>
41 : : #include "pkgcli.h"
42 : : #include <string.h>
43 : : #include <xmalloc.h>
44 : : #include <tllist.h>
45 : :
46 : : typedef tll(char *) charlist;
47 : :
48 : : void
49 : 0 : usage_which(void)
50 : : {
51 : 0 : fprintf(stderr, "Usage: pkg which [-mqgop] <file>\n\n");
52 : 0 : fprintf(stderr, "For more information see 'pkg help which'.\n");
53 : 0 : }
54 : :
55 : : static bool is_there(char *);
56 : : int get_match(char **, char **, char *);
57 : :
58 : : static bool
59 : 0 : already_in_list(charlist *list, const char *pattern)
60 : : {
61 [ # # # # : 0 : tll_foreach(*list, it) {
# # ]
62 [ # # ]: 0 : if (STREQ(it->item, pattern))
63 : 0 : return (true);
64 : 0 : }
65 : :
66 : 0 : return (false);
67 : 0 : }
68 : :
69 : : int
70 : 4 : exec_which(int argc, char **argv)
71 : : {
72 : 4 : struct pkgdb *db = NULL;
73 : 4 : struct pkgdb_it *it = NULL;
74 : 4 : struct pkg *pkg = NULL;
75 : 4 : struct pkg_file *file = NULL;
76 : : char pathabs[MAXPATHLEN];
77 : : char *p, *path, *match, *savedpath;
78 : 4 : int retcode = EXIT_FAILURE;
79 : 4 : int ch, res, pathlen = 0;
80 : 4 : bool orig = false;
81 : 4 : bool glob = false;
82 : 4 : bool search = false;
83 : 4 : bool search_s = false;
84 : 4 : bool show_match = false;
85 : 4 : charlist patterns = tll_init();
86 : :
87 : 4 : 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 : 4 : path = NULL;
97 : :
98 [ + + ]: 6 : while ((ch = getopt_long(argc, argv, "+gopqm", longopts, NULL)) != -1) {
99 [ - - - + : 2 : 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 : 2 : quiet = true;
111 : 2 : 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 : 4 : argc -= optind;
122 : 4 : argv += optind;
123 : :
124 [ - + ]: 4 : if (argc < 1) {
125 : 0 : usage_which();
126 : 0 : return (EXIT_FAILURE);
127 : : }
128 : :
129 [ - + ]: 4 : if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
130 : 0 : return (EXIT_FAILURE);
131 : : }
132 : :
133 [ - + ]: 4 : 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 [ + - ]: 4 : 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 [ + + ]: 8 : while (argc >= 1) {
149 : 4 : retcode = EXIT_FAILURE;
150 [ + - ]: 4 : if (search_s) {
151 [ # # # # ]: 0 : if ((argv[0][0] == '.') || (argv[0][0] == '/')) {
152 : 0 : search = false;
153 : 0 : } else {
154 : 0 : search = true;
155 : :
156 [ # # ]: 0 : if (strlen(argv[0]) >= FILENAME_MAX) {
157 : 0 : retcode = EXIT_FAILURE;
158 : 0 : goto cleanup;
159 : : }
160 : :
161 : 0 : p = malloc(pathlen);
162 [ # # ]: 0 : if (p == NULL) {
163 : 0 : retcode = EXIT_FAILURE;
164 : 0 : goto cleanup;
165 : : }
166 : 0 : strlcpy(p, path, pathlen);
167 : :
168 : 0 : match = NULL;
169 : 0 : savedpath=p;
170 : 0 : for (;;) {
171 : 0 : res = get_match(&match, &p, argv[0]);
172 [ # # ]: 0 : if (p == NULL)
173 : 0 : break;
174 : :
175 [ # # ]: 0 : if (res == (EXIT_FAILURE)) {
176 : 0 : printf("%s was not found in PATH, falling back to non-search behaviour\n", argv[0]);
177 : 0 : search = false;
178 [ # # ]: 0 : } else if (res == (EXIT_FAILURE)) {
179 : 0 : retcode = EXIT_FAILURE;
180 : 0 : free(savedpath);
181 : 0 : goto cleanup;
182 : : } else {
183 : 0 : pkg_absolutepath(match, pathabs, sizeof(pathabs), false);
184 : : /* ensure not not append twice an entry if PATH is messy */
185 [ # # ]: 0 : if (already_in_list(&patterns, pathabs))
186 : 0 : continue;
187 [ # # # # : 0 : tll_push_back(patterns, xstrdup(pathabs));
# # # # #
# ]
188 : 0 : free(match);
189 : : }
190 : : }
191 : 0 : free(savedpath);
192 : : }
193 : 0 : }
194 : :
195 [ + - - + ]: 4 : if (!glob && !search) {
196 : 4 : pkg_absolutepath(argv[0], pathabs, sizeof(pathabs), false);
197 [ - + + - : 4 : tll_push_back(patterns, xstrdup(pathabs));
# # - + -
+ ]
198 [ # # ]: 4 : } else if (!search) {
199 [ # # ]: 0 : if (strlcpy(pathabs, argv[0], sizeof(pathabs)) >= sizeof(pathabs)) {
200 : 0 : retcode = EXIT_FAILURE;
201 : 0 : goto cleanup;
202 : : }
203 [ # # # # : 0 : tll_push_back(patterns, xstrdup(pathabs));
# # # # #
# ]
204 : 0 : }
205 : :
206 : :
207 [ + - + + : 8 : tll_foreach(patterns, item) {
- + ]
208 [ + - ]: 4 : if ((it = pkgdb_query_which(db, item->item, glob)) == NULL) {
209 : 0 : retcode = EXIT_FAILURE;
210 : 0 : goto cleanup;
211 : : }
212 : :
213 : 4 : pkg = NULL;
214 [ - + # # : 8 : while (pkgdb_it_next(it, &pkg, (glob && show_match) ? PKG_LOAD_FILES : PKG_LOAD_BASIC) == EPKG_OK) {
+ + ]
215 : 4 : retcode = EXIT_SUCCESS;
216 [ + + + - : 4 : if (quiet && orig && !show_match)
# # ]
217 : 0 : pkg_printf("%o\n", pkg);
218 [ + + - + : 4 : else if (quiet && !orig && !show_match)
- + ]
219 : 2 : pkg_printf("%n-%v\n", pkg, pkg);
220 [ + - + - : 2 : else if (!quiet && orig && !show_match)
# # ]
221 : 0 : pkg_printf("%S was installed by package %o\n", item->item, pkg);
222 [ + - + - : 2 : else if (!quiet && !orig && !show_match)
- + ]
223 : 2 : pkg_printf("%S was installed by package %n-%v\n", item->item, pkg, pkg);
224 [ # # # # ]: 0 : else if (glob && show_match) {
225 [ # # ]: 0 : if (!quiet)
226 : 0 : pkg_printf("%S was glob searched and found in package %n-%v\n", item->item, pkg, pkg, pkg);
227 [ # # ]: 0 : while(pkg_files(pkg, &file) == EPKG_OK) {
228 : 0 : pkg_asprintf(&match, "%Fn", file);
229 [ # # ]: 0 : if (match == NULL)
230 : 0 : err(EXIT_FAILURE, "pkg_asprintf");
231 [ # # ]: 0 : if(!fnmatch(item->item, match, 0))
232 : 0 : printf("%s\n", match);
233 : 0 : free(match);
234 : : }
235 : 0 : }
236 : : }
237 [ - + # # ]: 4 : if (retcode != EXIT_SUCCESS && !quiet)
238 : 0 : printf("%s was not found in the database\n", item->item);
239 : :
240 : 4 : pkg_free(pkg);
241 : 4 : pkgdb_it_free(it);
242 : :
243 : 4 : }
244 [ + - + + : 8 : tll_free_and_free(patterns, free);
- + ]
245 : :
246 : 4 : argc--;
247 : 4 : argv++;
248 : :
249 : : }
250 : :
251 : : cleanup:
252 : 4 : pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
253 : 4 : pkgdb_close(db);
254 : :
255 : 4 : return (retcode);
256 : 4 : }
257 : :
258 : :
259 : : static bool
260 : 0 : is_there(char *candidate)
261 : : {
262 : 0 : return (access(candidate, F_OK) == 0);
263 : : }
264 : :
265 : : int
266 : 0 : get_match(char **pathabs, char **path, char *filename)
267 : : {
268 : : char candidate[PATH_MAX];
269 : : const char *d;
270 : : int len;
271 : :
272 [ # # ]: 0 : while ((d = strsep(path, ":")) != NULL) {
273 [ # # # # : 0 : if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
# # ]
274 : 0 : filename) >= (int)sizeof(candidate))
275 : 0 : continue;
276 [ # # ]: 0 : if (is_there(candidate)) {
277 : 0 : len = strlen(candidate) + 1;
278 : 0 : *pathabs = malloc(len);
279 [ # # ]: 0 : if (*pathabs == NULL)
280 : 0 : return (EXIT_FAILURE);
281 : 0 : strlcpy(*pathabs, candidate, len);
282 : 0 : return (EXIT_SUCCESS);
283 : : }
284 : : }
285 : 0 : return (EXIT_FAILURE);
286 : 0 : }
|