Lines 9-30
Link Here
|
9 |
|
9 |
|
10 |
#ifdef APPLET_qfile |
10 |
#ifdef APPLET_qfile |
11 |
|
11 |
|
12 |
#define QFILE_FLAGS "eo" COMMON_FLAGS |
12 |
#define QFILE_FLAGS "eoR" COMMON_FLAGS |
13 |
static struct option const qfile_long_opts[] = { |
13 |
static struct option const qfile_long_opts[] = { |
14 |
{"exact", no_argument, NULL, 'e'}, |
14 |
{"exact", no_argument, NULL, 'e'}, |
15 |
{"orphans", no_argument, NULL, 'o'}, |
15 |
{"orphans", no_argument, NULL, 'o'}, |
|
|
16 |
{"root-prefix", no_argument, NULL, 'R'}, |
16 |
COMMON_LONG_OPTS |
17 |
COMMON_LONG_OPTS |
17 |
}; |
18 |
}; |
18 |
static const char *qfile_opts_help[] = { |
19 |
static const char *qfile_opts_help[] = { |
19 |
"Exact match", |
20 |
"Exact match", |
20 |
"List orphan files", |
21 |
"List orphan files", |
|
|
22 |
"Assume arguments are already prefixed by $ROOT", |
21 |
COMMON_OPTS_HELP |
23 |
COMMON_OPTS_HELP |
22 |
}; |
24 |
}; |
23 |
static char qfile_rcsid[] = "$Id: qfile.c,v 1.34 2006/07/19 16:20:41 solar Exp $"; |
25 |
static char qfile_rcsid[] = "$Id: qfile.c,v 1.34 2006/07/19 16:20:41 solar Exp $"; |
24 |
#define qfile_usage(ret) usage(ret, QFILE_FLAGS, qfile_long_opts, qfile_opts_help, lookup_applet_idx("qfile")) |
26 |
#define qfile_usage(ret) usage(ret, QFILE_FLAGS, qfile_long_opts, qfile_opts_help, lookup_applet_idx("qfile")) |
25 |
|
27 |
|
26 |
void qfile(char *path, int argc, char **base_names, char **dir_names, char **real_dir_names, short * non_orphans); |
28 |
static inline short qfile_is_prefix(const char* path, const char* prefix, int prefix_length) { |
27 |
void qfile(char *path, int argc, char **base_names, char **dir_names, char **real_dir_names, short * non_orphans) |
29 |
return !prefix_length |
|
|
30 |
|| (strlen(path) >= prefix_length |
31 |
&& (path[prefix_length] == '/' || path[prefix_length] == '\0') |
32 |
&& !strncmp(path, prefix, prefix_length)); |
33 |
} |
34 |
|
35 |
void qfile(char *path, int argc, char* root, char* real_root, char* bn_firstchars, |
36 |
char **base_names, char **dir_names, char **real_dir_names, short * non_orphans); |
37 |
void qfile(char *path, int argc, char* root, char* real_root, char* bn_firstchars, |
38 |
char **base_names, char **dir_names, char **real_dir_names, short * non_orphans) |
28 |
{ |
39 |
{ |
29 |
FILE *fp; |
40 |
FILE *fp; |
30 |
DIR *dir; |
41 |
DIR *dir; |
Lines 36-41
Link Here
|
36 |
char pkg[126]; |
47 |
char pkg[126]; |
37 |
depend_atom *atom; |
48 |
depend_atom *atom; |
38 |
int i, path_ok; |
49 |
int i, path_ok; |
|
|
50 |
char bn_firstchar; |
39 |
|
51 |
|
40 |
if (chdir(path) != 0 || (dir = opendir(".")) == NULL) |
52 |
if (chdir(path) != 0 || (dir = opendir(".")) == NULL) |
41 |
return; |
53 |
return; |
Lines 62-67
Link Here
|
62 |
continue; |
74 |
continue; |
63 |
entry_basename++; |
75 |
entry_basename++; |
64 |
|
76 |
|
|
|
77 |
// used to cut the number of strcmp() calls |
78 |
bn_firstchar = entry_basename[0]; |
79 |
|
65 |
for(i = 0; i < argc; i++) { |
80 |
for(i = 0; i < argc; i++) { |
66 |
if (base_names[i] == NULL) |
81 |
if (base_names[i] == NULL) |
67 |
continue; |
82 |
continue; |
Lines 69-75
Link Here
|
69 |
continue; |
84 |
continue; |
70 |
path_ok = (dir_names[i] == NULL && real_dir_names[i] == NULL); |
85 |
path_ok = (dir_names[i] == NULL && real_dir_names[i] == NULL); |
71 |
|
86 |
|
72 |
if (strcmp(entry_basename, base_names[i]) != 0) |
87 |
if (bn_firstchar != bn_firstchars[i] |
|
|
88 |
|| strcmp(entry_basename, base_names[i])) |
73 |
continue; |
89 |
continue; |
74 |
|
90 |
|
75 |
if (!path_ok) { |
91 |
if (!path_ok) { |
Lines 93-114
Link Here
|
93 |
// real_dir_name == dirname(CONTENTS) |
109 |
// real_dir_name == dirname(CONTENTS) |
94 |
path_ok = 1; |
110 |
path_ok = 1; |
95 |
else { |
111 |
else { |
96 |
char rpath[_Q_PATH_MAX]; |
112 |
char rpath[_Q_PATH_MAX+1]; |
|
|
113 |
char * fullpath = entry_dirname; |
97 |
errno = 0; |
114 |
errno = 0; |
98 |
realpath(entry_dirname, rpath); |
115 |
if (real_root != NULL && real_root[0] != '\0') |
|
|
116 |
xasprintf(&fullpath, "%s%s", real_root, entry_dirname); |
117 |
realpath(fullpath, rpath); |
99 |
if (errno != 0) { |
118 |
if (errno != 0) { |
100 |
if (verbose) { |
119 |
if (verbose) { |
101 |
warn("Could not read real path of \"%s\": %s", p, strerror(errno)); |
120 |
warn("Could not read real path of \"%s\" (from %s): %s", |
102 |
warn("We'll never know whether it was a result for your query..."); |
121 |
fullpath, pkg, strerror(errno)); |
|
|
122 |
warn("We'll never know whether \"%s/%s\" was a result for your query...", |
123 |
entry_dirname, entry_basename); |
103 |
} |
124 |
} |
|
|
125 |
} else if (!qfile_is_prefix(rpath, real_root, strlen(real_root))) { |
126 |
if (verbose) |
127 |
warn("Real path of \"%s\" is not under ROOT: %s", fullpath, rpath); |
104 |
} else if (dir_names[i] != NULL && |
128 |
} else if (dir_names[i] != NULL && |
105 |
strcmp(rpath, dir_names[i]) == 0) |
129 |
strcmp(rpath + strlen(real_root), dir_names[i]) == 0) |
106 |
// dir_name == realpath(dirname(CONTENTS)) |
130 |
// dir_name == realpath(dirname(CONTENTS)) |
107 |
path_ok = 1; |
131 |
path_ok = 1; |
108 |
else if (real_dir_names[i] != NULL && |
132 |
else if (real_dir_names[i] != NULL && |
109 |
strcmp(rpath, real_dir_names[i]) == 0) |
133 |
strcmp(rpath + strlen(real_root), real_dir_names[i]) == 0) |
110 |
// real_dir_name == realpath(dirname(CONTENTS)) |
134 |
// real_dir_name == realpath(dirname(CONTENTS)) |
111 |
path_ok = 1; |
135 |
path_ok = 1; |
|
|
136 |
if (fullpath != entry_dirname) |
137 |
free(fullpath); |
112 |
} |
138 |
} |
113 |
free(entry_dirname); |
139 |
free(entry_dirname); |
114 |
} |
140 |
} |
Lines 125-130
Link Here
|
125 |
(exact ? dentry->d_name : atom->PN), NORM); |
151 |
(exact ? dentry->d_name : atom->PN), NORM); |
126 |
if (quiet) |
152 |
if (quiet) |
127 |
puts(""); |
153 |
puts(""); |
|
|
154 |
else if (root != NULL) |
155 |
printf(" (%s%s)\n", root, e->name); |
128 |
else |
156 |
else |
129 |
printf(" (%s)\n", e->name); |
157 |
printf(" (%s)\n", e->name); |
130 |
|
158 |
|
Lines 146-159
Link Here
|
146 |
{ |
174 |
{ |
147 |
DIR *dir; |
175 |
DIR *dir; |
148 |
struct dirent *dentry; |
176 |
struct dirent *dentry; |
149 |
int i; |
177 |
int i, nb_of_queries; |
150 |
char *p; |
178 |
char *p; |
151 |
char ** basenames; |
179 |
char ** basenames; |
152 |
char ** dirnames; |
180 |
char ** dirnames; |
153 |
char ** realdirnames; |
181 |
char ** realdirnames; |
154 |
char * pwd; |
182 |
char * basenames_firstchars; |
|
|
183 |
char * pwd = NULL; |
155 |
short * non_orphans = NULL; |
184 |
short * non_orphans = NULL; |
156 |
short search_orphans = 0; |
185 |
short search_orphans = 0; |
|
|
186 |
short assume_root_prefix = 0; |
187 |
char * root_prefix; |
188 |
char * real_root; |
189 |
int real_root_length; |
190 |
char tmppath[_Q_PATH_MAX+1]; |
191 |
char abspath[_Q_PATH_MAX+1]; |
157 |
|
192 |
|
158 |
DBG("argc=%d argv[0]=%s argv[1]=%s", |
193 |
DBG("argc=%d argv[0]=%s argv[1]=%s", |
159 |
argc, argv[0], argc > 1 ? argv[1] : "NULL?"); |
194 |
argc, argv[0], argc > 1 ? argv[1] : "NULL?"); |
Lines 163-254
Link Here
|
163 |
COMMON_GETOPTS_CASES(qfile) |
198 |
COMMON_GETOPTS_CASES(qfile) |
164 |
case 'e': exact = 1; break; |
199 |
case 'e': exact = 1; break; |
165 |
case 'o': search_orphans = 1; break; |
200 |
case 'o': search_orphans = 1; break; |
|
|
201 |
case 'R': assume_root_prefix = 1; break; |
166 |
} |
202 |
} |
167 |
} |
203 |
} |
168 |
if (!exact && verbose) exact++; |
204 |
if (!exact && verbose) exact++; |
169 |
if (argc == optind) |
205 |
if (argc == optind) |
170 |
qfile_usage(EXIT_FAILURE); |
206 |
qfile_usage(EXIT_FAILURE); |
|
|
207 |
nb_of_queries = argc - optind; |
171 |
|
208 |
|
172 |
if (chdir(portroot)) |
209 |
if (chdir(portroot)) |
173 |
errp("could not chdir(%s) for ROOT", portroot); |
210 |
errp("could not chdir(%s) for ROOT", portroot); |
174 |
|
211 |
|
175 |
if (chdir(portvdb) != 0 || (dir = opendir(".")) == NULL) |
212 |
if (chdir(portvdb) != 0 || (dir = opendir(".")) == NULL) |
176 |
return EXIT_FAILURE; |
213 |
errp("could not chdir(ROOT/%s) for installed packages database", portvdb); |
177 |
|
|
|
178 |
if (search_orphans) |
179 |
non_orphans = xmalloc((argc-optind) * sizeof(short)); |
180 |
|
214 |
|
181 |
// For each argument, we store its basename, its dirname, |
215 |
// Try to get $PWD. Must be absolute, with no trailing slash |
182 |
// and the realpath of its dirname. |
216 |
if ((pwd = getenv("PWD")) != NULL && pwd[0] == '/') { |
|
|
217 |
pwd = xstrdup(pwd); |
218 |
if ((pwd[strlen(pwd) - 1] == '/')) |
219 |
pwd[strlen(pwd) - 1] = '\0'; |
220 |
} else |
221 |
pwd = NULL; |
222 |
|
223 |
// Get realpath of $ROOT, with no trailing slash |
224 |
if (portroot[0] == '/') |
225 |
strncpy(tmppath, portroot, _Q_PATH_MAX); |
226 |
else if (pwd != NULL) |
227 |
snprintf(tmppath, _Q_PATH_MAX, "%s/%s", pwd, portroot); |
228 |
else { |
229 |
free(pwd); |
230 |
errp("Could not get absolute path for ROOT (\"%s\"), because of missing or not absolute $PWD", tmppath); |
231 |
} |
232 |
errno = 0; |
233 |
realpath(tmppath, abspath); |
234 |
if (errno != 0) { |
235 |
free(pwd); |
236 |
errp("Could not read real path of ROOT (\"%s\"): %s", tmppath, strerror(errno)); |
237 |
} |
238 |
if (strlen(abspath) == 1) |
239 |
abspath[0] = '\0'; |
240 |
real_root = xstrdup(abspath); |
241 |
real_root_length = strlen(real_root); |
242 |
|
243 |
// Get a copy of $ROOT, with no trailing slash |
244 |
// (this one is just for qfile(...) output) |
245 |
root_prefix = xstrdup(portroot); |
246 |
if (root_prefix[strlen(root_prefix) - 1] == '/') |
247 |
root_prefix[strlen(root_prefix) - 1] = '\0'; |
248 |
|
249 |
// For each argument, we store its basename, its absolute dirname, |
250 |
// and the realpath of its dirname. Dirnames and their realpaths |
251 |
// are stored without their $ROOT prefix, but $ROOT is used when |
252 |
// checking realpaths. |
183 |
basenames = xmalloc((argc-optind) * sizeof(char*)); |
253 |
basenames = xmalloc((argc-optind) * sizeof(char*)); |
184 |
dirnames = xmalloc((argc-optind) * sizeof(char*)); |
254 |
dirnames = xmalloc((argc-optind) * sizeof(char*)); |
185 |
realdirnames = xmalloc((argc-optind) * sizeof(char*)); |
255 |
realdirnames = xmalloc((argc-optind) * sizeof(char*)); |
186 |
if ((pwd = getenv("PWD")) != NULL) { |
256 |
// For optimization of qfile(), we also give it an array of the first char |
187 |
int pwdlen = strlen(pwd); |
257 |
// of each basename. This way we avoid numerous strcmp() calls. |
188 |
if ((pwdlen > 0) && (pwd[pwdlen-1] == '/')) |
258 |
basenames_firstchars = xmalloc((argc-optind) * sizeof(char)); |
189 |
pwd[pwdlen-1] = '\0'; |
259 |
// Finally, if searching for orphans, we need an array to store the results |
190 |
} |
260 |
if (search_orphans) |
|
|
261 |
non_orphans = xmalloc((argc-optind) * sizeof(short)); |
191 |
for (i = 0; i < (argc-optind); ++i) { |
262 |
for (i = 0; i < (argc-optind); ++i) { |
192 |
char tmppath[_Q_PATH_MAX]; |
|
|
193 |
char abspath[_Q_PATH_MAX]; |
194 |
|
195 |
basenames[i] = NULL; |
263 |
basenames[i] = NULL; |
196 |
dirnames[i] = NULL; |
264 |
dirnames[i] = NULL; |
197 |
realdirnames[i] = NULL; |
265 |
realdirnames[i] = NULL; |
198 |
|
266 |
|
199 |
// Record basename, but if it is "." or ".." |
267 |
// Record basename, but if it is ".", ".." or "/" |
200 |
strncpy(tmppath, basename(argv[i+optind]), _Q_PATH_MAX); |
268 |
strncpy(tmppath, basename(argv[i+optind]), _Q_PATH_MAX); |
201 |
if ((strlen(tmppath) > 2) || strncmp(tmppath, "..", strlen(tmppath))) { |
269 |
if ((strlen(tmppath) > 2) || |
|
|
270 |
(strncmp(tmppath, "..", strlen(tmppath)) |
271 |
&& strncmp(tmppath, "/", strlen(tmppath)))) { |
202 |
basenames[i] = xstrdup(tmppath); |
272 |
basenames[i] = xstrdup(tmppath); |
|
|
273 |
basenames_firstchars[i] = basenames[i][0]; |
203 |
// If there is no "/" in the argument, then it's over. |
274 |
// If there is no "/" in the argument, then it's over. |
204 |
// (we are searching a simple file name) |
275 |
// (we are searching a simple file name) |
205 |
if (strchr(argv[i+optind], '/') == NULL) |
276 |
if (strchr(argv[i+optind], '/') == NULL) |
206 |
continue; |
277 |
continue; |
207 |
} |
278 |
} |
208 |
|
279 |
|
209 |
// Make sure we have an absolute path available |
280 |
// Make sure we have an absolute path available (with "realpath(ROOT)" prefix) |
210 |
if (argv[i+optind][0] == '/') |
281 |
if (argv[i+optind][0] == '/') { |
211 |
strncpy(abspath, argv[i+optind], _Q_PATH_MAX); |
282 |
if (assume_root_prefix) |
212 |
else if (pwd != NULL) |
283 |
strncpy(abspath, argv[i+optind], _Q_PATH_MAX); |
213 |
snprintf(abspath, _Q_PATH_MAX, "%s/%s", pwd, argv[i+optind]); |
284 |
else |
214 |
else { |
285 |
snprintf(abspath, _Q_PATH_MAX, "%s%s", real_root, argv[i+optind]); |
215 |
warn("$PWD not found in environment."); |
286 |
} else if (pwd != NULL) { |
216 |
warn("Skipping query item \"%s\".", argv[i+optind]); |
287 |
if (assume_root_prefix) |
217 |
continue; |
288 |
snprintf(abspath, _Q_PATH_MAX, "%s/%s", pwd, argv[i+optind]); |
|
|
289 |
else |
290 |
snprintf(abspath, _Q_PATH_MAX, "%s%s/%s", real_root, pwd, argv[i+optind]); |
291 |
} else { |
292 |
warn("$PWD was not found in environment, or is not an absolute path"); |
293 |
goto skip_query_item; |
218 |
} |
294 |
} |
219 |
|
295 |
|
220 |
if (basenames[i] != NULL) { |
296 |
if (basenames[i] != NULL) { |
221 |
// Get both the dirname and its realpath |
297 |
// Get both the dirname and its realpath. This paths will |
222 |
dirnames[i] = xstrdup(dirname(abspath)); |
298 |
// have no trailing slash, but if it is the only char (ie., |
|
|
299 |
// when searching for "/foobar"). |
300 |
strncpy(tmppath, abspath, _Q_PATH_MAX); |
301 |
strncpy(abspath, dirname(tmppath), _Q_PATH_MAX); |
302 |
if (abspath[real_root_length] == '\0') |
303 |
strncat(abspath, "/", 1); |
304 |
dirnames[i] = xstrdup(abspath + real_root_length); |
223 |
errno = 0; |
305 |
errno = 0; |
224 |
realpath(dirnames[i], tmppath); |
306 |
realpath(abspath, tmppath); |
225 |
if (errno != 0) { |
307 |
if (errno != 0) { |
226 |
if (verbose) { |
308 |
if (verbose) { |
227 |
warn("Could not read real path of \"%s\": %s", dirnames[i], strerror(errno)); |
309 |
warn("Could not read real path of \"%s\": %s", abspath, strerror(errno)); |
228 |
warn("Results for query item \"%s\" may not be accurate.", argv[i+optind]); |
310 |
warn("Results for query item \"%s\" may be inaccurate.", argv[i+optind]); |
229 |
} |
311 |
} |
230 |
} else if (strcmp(dirnames[i], tmppath)) |
312 |
continue; |
231 |
realdirnames[i] = xstrdup(tmppath); |
313 |
} |
|
|
314 |
if (!qfile_is_prefix(tmppath, real_root, real_root_length)) { |
315 |
warn("Real path of \"%s\" is not under ROOT: %s", abspath, tmppath); |
316 |
goto skip_query_item; |
317 |
} |
318 |
if (tmppath[real_root_length] == '\0') |
319 |
strncat(tmppath, "/", 1); |
320 |
if (strcmp(dirnames[i], tmppath + real_root_length)) |
321 |
realdirnames[i] = xstrdup(tmppath + real_root_length); |
232 |
} else { |
322 |
} else { |
233 |
// No basename means we are looking for something like "/foo/bar/.." |
323 |
// No basename means we are looking for something like "/foo/bar/.." |
234 |
// Dirname is meaningless here, we can only get realpath of the full |
324 |
// Dirname is meaningless here, we can only get realpath of the full |
235 |
// path and then split it. |
325 |
// path and then split it. |
236 |
errno = 0; |
326 |
errno = 0; |
237 |
realpath(tmppath, abspath); |
327 |
realpath(abspath, tmppath); |
238 |
if (errno != 0) { |
328 |
if (errno != 0) { |
239 |
warn("Could not read real path of \"%s\": %s", tmppath, strerror(errno)); |
329 |
warn("Could not read real path of \"%s\": %s", abspath, strerror(errno)); |
240 |
warn("Skipping query item \"%s\".", argv[i+optind]); |
330 |
goto skip_query_item; |
241 |
continue; |
331 |
} |
|
|
332 |
if (!qfile_is_prefix(tmppath, real_root, real_root_length)) { |
333 |
warn("Real path of \"%s\" is not under ROOT: %s", abspath, tmppath); |
334 |
goto skip_query_item; |
242 |
} |
335 |
} |
243 |
basenames[i] = xstrdup(basename(tmppath)); |
336 |
strncpy(abspath, tmppath, _Q_PATH_MAX); |
244 |
realdirnames[i] = xstrdup(dirname(tmppath)); |
337 |
basenames[i] = xstrdup(basename(abspath)); |
|
|
338 |
basenames_firstchars[i] = basenames[i][0]; |
339 |
strncpy(abspath, dirname(tmppath), _Q_PATH_MAX); |
340 |
if (tmppath[real_root_length] == '\0') |
341 |
strncat(tmppath, "/", 1); |
342 |
realdirnames[i] = xstrdup(abspath + real_root_length); |
245 |
} |
343 |
} |
|
|
344 |
continue; |
345 |
|
346 |
skip_query_item: |
347 |
--nb_of_queries; |
348 |
warn("Skipping query item \"%s\".", argv[i+optind]); |
349 |
if (basenames[i] != NULL) free(basenames[i]); |
350 |
if (dirnames[i] != NULL) free(dirnames[i]); |
351 |
if (realdirnames[i] != NULL) free(realdirnames[i]); |
352 |
basenames[i] = dirnames[i] = realdirnames[i] = NULL; |
246 |
} |
353 |
} |
247 |
|
354 |
|
248 |
/* open /var/db/pkg */ |
355 |
/* open /var/db/pkg (but if all query items were skipped) */ |
249 |
while ((dentry = q_vdb_get_next_dir(dir))) { |
356 |
while (nb_of_queries && (dentry = q_vdb_get_next_dir(dir))) { |
250 |
xasprintf(&p, "%s%s/%s", portroot, portvdb, dentry->d_name); |
357 |
xasprintf(&p, "%s/%s/%s", real_root, portvdb, dentry->d_name); |
251 |
qfile(p, (argc-optind), basenames, dirnames, realdirnames, non_orphans); |
358 |
qfile(p, (argc-optind), (assume_root_prefix ? root_prefix : NULL), real_root, |
|
|
359 |
basenames_firstchars, basenames, dirnames, realdirnames, non_orphans); |
252 |
free(p); |
360 |
free(p); |
253 |
} |
361 |
} |
254 |
|
362 |
|
Lines 273-278
Link Here
|
273 |
} |
381 |
} |
274 |
free(basenames); free(dirnames); free(realdirnames); |
382 |
free(basenames); free(dirnames); free(realdirnames); |
275 |
|
383 |
|
|
|
384 |
free(basenames_firstchars); |
385 |
|
386 |
if (pwd != NULL) |
387 |
free(pwd); |
388 |
|
389 |
free(real_root); free(root_prefix); |
390 |
|
276 |
return (found ? EXIT_SUCCESS : EXIT_FAILURE); |
391 |
return (found ? EXIT_SUCCESS : EXIT_FAILURE); |
277 |
} |
392 |
} |
278 |
|
393 |
|