Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/src/which.c
2065 views
1
/*-
2
* Copyright (c) 2011-2025 Baptiste Daroussin <[email protected]>
3
* Copyright (c) 2011-2012 Julien Laffaye <[email protected]>
4
* Copyright (c) 2011-2012 Marin Atanasov Nikolov <[email protected]>
5
* Copyright (c) 2014 Matthew Seaman <[email protected]>
6
*
7
* SPDX-License-Identifier: BSD-2-Clause
8
*/
9
10
#include <sys/param.h>
11
#include <sys/stat.h>
12
13
#include <err.h>
14
#include <getopt.h>
15
#include <stdio.h>
16
#include <string.h>
17
#include <unistd.h>
18
#include <fnmatch.h>
19
20
#include <pkg.h>
21
#include "pkgcli.h"
22
#include <string.h>
23
#include <xmalloc.h>
24
25
void
26
usage_which(void)
27
{
28
fprintf(stderr, "Usage: pkg which [-mqgop] <file>\n\n");
29
fprintf(stderr, "For more information see 'pkg help which'.\n");
30
}
31
32
static bool is_there(char *);
33
int get_match(char **, char **, char *);
34
35
static bool
36
already_in_list(charv_t *list, const char *pattern)
37
{
38
vec_foreach(*list, i) {
39
if (STREQ(list->d[i], pattern))
40
return (true);
41
}
42
43
return (false);
44
}
45
46
int
47
exec_which(int argc, char **argv)
48
{
49
struct pkgdb *db = NULL;
50
struct pkgdb_it *it = NULL;
51
struct pkg *pkg = NULL;
52
struct pkg_file *file = NULL;
53
char pathabs[MAXPATHLEN];
54
char *p, *path, *match, *savedpath;
55
int retcode = EXIT_FAILURE;
56
int ch, res, pathlen = 0;
57
bool orig = false;
58
bool glob = false;
59
bool search = false;
60
bool search_s = false;
61
bool show_match = false;
62
charv_t patterns = vec_init();
63
64
struct option longopts[] = {
65
{ "glob", no_argument, NULL, 'g' },
66
{ "origin", no_argument, NULL, 'o' },
67
{ "path-search", no_argument, NULL, 'p' },
68
{ "quiet", no_argument, NULL, 'q' },
69
{ "show-match", no_argument, NULL, 'm' },
70
{ NULL, 0, NULL, 0 },
71
};
72
73
path = NULL;
74
75
while ((ch = getopt_long(argc, argv, "+gopqm", longopts, NULL)) != -1) {
76
switch (ch) {
77
case 'g':
78
glob = true;
79
break;
80
case 'o':
81
orig = true;
82
break;
83
case 'p':
84
search_s = true;
85
break;
86
case 'q':
87
quiet = true;
88
break;
89
case 'm':
90
show_match = true;
91
break;
92
default:
93
usage_which();
94
return (EXIT_FAILURE);
95
}
96
}
97
98
argc -= optind;
99
argv += optind;
100
101
if (argc < 1) {
102
usage_which();
103
return (EXIT_FAILURE);
104
}
105
106
if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
107
return (EXIT_FAILURE);
108
}
109
110
if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
111
pkgdb_close(db);
112
warnx("Cannot get a read lock on a database, it is locked by another process");
113
return (EXIT_FAILURE);
114
}
115
116
if (search_s) {
117
if ((path = getenv("PATH")) == NULL) {
118
printf("$PATH is not set, falling back to non-search behaviour\n");
119
search_s = false;
120
} else {
121
pathlen = strlen(path) + 1;
122
}
123
}
124
125
while (argc >= 1) {
126
retcode = EXIT_FAILURE;
127
if (search_s) {
128
if ((argv[0][0] == '.') || (argv[0][0] == '/')) {
129
search = false;
130
} else {
131
search = true;
132
133
if (strlen(argv[0]) >= FILENAME_MAX) {
134
retcode = EXIT_FAILURE;
135
goto cleanup;
136
}
137
138
p = malloc(pathlen);
139
if (p == NULL) {
140
retcode = EXIT_FAILURE;
141
goto cleanup;
142
}
143
strlcpy(p, path, pathlen);
144
145
match = NULL;
146
savedpath=p;
147
for (;;) {
148
res = get_match(&match, &p, argv[0]);
149
if (p == NULL)
150
break;
151
152
if (res == (EXIT_FAILURE)) {
153
printf("%s was not found in PATH, falling back to non-search behaviour\n", argv[0]);
154
search = false;
155
} else if (res == (EXIT_FAILURE)) {
156
retcode = EXIT_FAILURE;
157
free(savedpath);
158
goto cleanup;
159
} else {
160
pkg_absolutepath(match, pathabs, sizeof(pathabs), false);
161
/* ensure not not append twice an entry if PATH is messy */
162
if (already_in_list(&patterns, pathabs))
163
continue;
164
vec_push(&patterns, xstrdup(pathabs));
165
free(match);
166
}
167
}
168
free(savedpath);
169
}
170
}
171
172
if (!glob && !search) {
173
pkg_absolutepath(argv[0], pathabs, sizeof(pathabs), false);
174
vec_push(&patterns, xstrdup(pathabs));
175
} else if (!search) {
176
if (strlcpy(pathabs, argv[0], sizeof(pathabs)) >= sizeof(pathabs)) {
177
retcode = EXIT_FAILURE;
178
goto cleanup;
179
}
180
vec_push(&patterns, xstrdup(pathabs));
181
}
182
183
184
vec_foreach(patterns, i) {
185
if ((it = pkgdb_query_which(db, patterns.d[i], glob)) == NULL) {
186
retcode = EXIT_FAILURE;
187
goto cleanup;
188
}
189
190
pkg = NULL;
191
while (pkgdb_it_next(it, &pkg, (glob && show_match) ? PKG_LOAD_FILES : PKG_LOAD_BASIC) == EPKG_OK) {
192
retcode = EXIT_SUCCESS;
193
if (quiet && orig && !show_match)
194
pkg_printf("%o\n", pkg);
195
else if (quiet && !orig && !show_match)
196
pkg_printf("%n-%v\n", pkg, pkg);
197
else if (!quiet && orig && !show_match)
198
pkg_printf("%S was installed by package %o\n", patterns.d[i], pkg);
199
else if (!quiet && !orig && !show_match)
200
pkg_printf("%S was installed by package %n-%v\n", patterns.d[i], pkg, pkg);
201
else if (glob && show_match) {
202
if (!quiet)
203
pkg_printf("%S was glob searched and found in package %n-%v\n", patterns.d[i], pkg, pkg, pkg);
204
while(pkg_files(pkg, &file) == EPKG_OK) {
205
pkg_asprintf(&match, "%Fn", file);
206
if (match == NULL)
207
err(EXIT_FAILURE, "pkg_asprintf");
208
if(!fnmatch(patterns.d[i], match, 0))
209
printf("%s\n", match);
210
free(match);
211
}
212
}
213
}
214
if (retcode != EXIT_SUCCESS && !quiet)
215
printf("%s was not found in the database\n", patterns.d[i]);
216
217
pkg_free(pkg);
218
pkgdb_it_free(it);
219
220
}
221
vec_free_and_free(&patterns, free);
222
223
argc--;
224
argv++;
225
226
}
227
228
cleanup:
229
pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
230
pkgdb_close(db);
231
232
return (retcode);
233
}
234
235
236
static bool
237
is_there(char *candidate)
238
{
239
return (access(candidate, F_OK) == 0);
240
}
241
242
int
243
get_match(char **pathabs, char **path, char *filename)
244
{
245
char candidate[PATH_MAX];
246
const char *d;
247
int len;
248
249
while ((d = strsep(path, ":")) != NULL) {
250
if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
251
filename) >= (int)sizeof(candidate))
252
continue;
253
if (is_there(candidate)) {
254
len = strlen(candidate) + 1;
255
*pathabs = malloc(len);
256
if (*pathabs == NULL)
257
return (EXIT_FAILURE);
258
strlcpy(*pathabs, candidate, len);
259
return (EXIT_SUCCESS);
260
}
261
}
262
return (EXIT_FAILURE);
263
}
264
265