vfs: check userland buffers before reading them.
[haiku.git] / src / bin / findpaths.cpp
blob0bf795052cad8b5faae79a87f92de1d1e17a8cea
1 /*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <getopt.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include <package/PackageResolvableExpression.h>
13 #include <package/manager/Exceptions.h>
14 #include <Path.h>
15 #include <PathFinder.h>
16 #include <StringList.h>
19 using namespace BPackageKit::BManager::BPrivate;
22 extern const char* __progname;
23 const char* kCommandName = __progname;
26 struct DirectoryConstantEntry {
27 const char* string;
28 path_base_directory constant;
29 const char* description;
32 #define DEFINE_CONSTANT(constant, description) \
33 { #constant, constant, description }
35 static const DirectoryConstantEntry kDirectoryConstants[] = {
36 DEFINE_CONSTANT(B_FIND_PATH_INSTALLATION_LOCATION_DIRECTORY,
37 "the installation location"),
38 DEFINE_CONSTANT(B_FIND_PATH_ADD_ONS_DIRECTORY,
39 "the add-ons directory"),
40 DEFINE_CONSTANT(B_FIND_PATH_APPS_DIRECTORY,
41 "the applications directory"),
42 DEFINE_CONSTANT(B_FIND_PATH_BIN_DIRECTORY,
43 "the command line programs directory"),
44 DEFINE_CONSTANT(B_FIND_PATH_BOOT_DIRECTORY,
45 "the boot data directory"),
46 DEFINE_CONSTANT(B_FIND_PATH_CACHE_DIRECTORY,
47 "the cache directory"),
48 DEFINE_CONSTANT(B_FIND_PATH_DATA_DIRECTORY,
49 "the data directory"),
50 DEFINE_CONSTANT(B_FIND_PATH_DEVELOP_DIRECTORY,
51 "the develop directory"),
52 DEFINE_CONSTANT(B_FIND_PATH_DEVELOP_LIB_DIRECTORY,
53 "the development libraries directory"),
54 DEFINE_CONSTANT(B_FIND_PATH_DOCUMENTATION_DIRECTORY,
55 "the documentation directory"),
56 DEFINE_CONSTANT(B_FIND_PATH_ETC_DIRECTORY,
57 "the Unix etc directory (global settings)"),
58 DEFINE_CONSTANT(B_FIND_PATH_FONTS_DIRECTORY,
59 "the fonts directory"),
60 DEFINE_CONSTANT(B_FIND_PATH_HEADERS_DIRECTORY,
61 "the development headers directory"),
62 DEFINE_CONSTANT(B_FIND_PATH_LIB_DIRECTORY,
63 "the libraries directory"),
64 DEFINE_CONSTANT(B_FIND_PATH_LOG_DIRECTORY,
65 "the logging directory"),
66 DEFINE_CONSTANT(B_FIND_PATH_MEDIA_NODES_DIRECTORY,
67 "the media node add-ons directory"),
68 DEFINE_CONSTANT(B_FIND_PATH_PACKAGES_DIRECTORY,
69 "the packages directory"),
70 DEFINE_CONSTANT(B_FIND_PATH_PREFERENCES_DIRECTORY,
71 "the preference applications directory"),
72 DEFINE_CONSTANT(B_FIND_PATH_SERVERS_DIRECTORY,
73 "the server programs directory"),
74 DEFINE_CONSTANT(B_FIND_PATH_SETTINGS_DIRECTORY,
75 "the global settings directory"),
76 DEFINE_CONSTANT(B_FIND_PATH_SOUNDS_DIRECTORY,
77 "the sound files directory"),
78 DEFINE_CONSTANT(B_FIND_PATH_SPOOL_DIRECTORY,
79 "the (mail) spool directory"),
80 DEFINE_CONSTANT(B_FIND_PATH_TRANSLATORS_DIRECTORY,
81 "the translator add-ons directory"),
82 DEFINE_CONSTANT(B_FIND_PATH_VAR_DIRECTORY,
83 "the Unix var directory (global writable data)"),
84 DEFINE_CONSTANT(B_FIND_PATH_PACKAGE_PATH,
85 "the path of the package the file specified via -p belongs to"),
88 static const size_t kDirectoryConstantCount
89 = sizeof(kDirectoryConstants) / sizeof(kDirectoryConstants[0]);
92 static const char* kUsage =
93 "Usage: %s [ <options> ] [ <kind> [<subpath>] ]\n"
94 "Prints paths specified by directory constant <kind>. <subpath>, if\n"
95 "specified, is appended to each path. By default a path is printed for\n"
96 "each existing installation location (one per line); the options can\n"
97 "modify this behavior.\n"
98 "\n"
99 "Options:\n"
100 " -a <architecture>\n"
101 " If the path(s) specified by <kind> are architecture specific, use\n"
102 " architecture <architecture>. If not specified, the primary\n"
103 " architecture is used, unless the -p/--path option is specified, in\n"
104 " which case the architecture associated with the given <path> is\n"
105 " used.\n"
106 " -c <separator>\n"
107 " Concatenate the resulting paths, separated only by <separator>,\n"
108 " instead of printing a path per line.\n"
109 " -d, --dependency <dependency>\n"
110 " Modifies the behavior of the -p option. Use the installation "
111 "location\n"
112 " where the dependency <dependency> of the package that the entry\n"
113 " referred to by <path> belongs to is installed.\n"
114 " -e, --existing\n"
115 " Print only paths that refer to existing entries.\n"
116 " -h, --help\n"
117 " Print this usage info.\n"
118 " -l, --list\n"
119 " Print a list of the possible constants for the <kind> parameter.\n"
120 " -p, --path <path>\n"
121 " Print only one path, the one for the installation location that\n"
122 " contains the path <path>.\n"
123 " -r, --resolvable <expression>\n"
124 " Print only one path, the one for the installation location for the\n"
125 " package providing the resolvable matching the expression\n"
126 " <expression>. The expressions can be a simple resolvable name or\n"
127 " a resolvable name with operator and version (e.g.\n"
128 " \"cmd:perl >= 5\"; must be one argument).\n"
129 " -R, --reverse\n"
130 " Print paths in reverse order, i.e. from most general to most\n"
131 " specific.\n"
135 static void
136 print_usage_and_exit(bool error)
138 fprintf(error ? stderr : stdout, kUsage, kCommandName);
139 exit(error ? 1 : 0);
144 main(int argc, const char* const* argv)
146 const char* architecture = NULL;
147 const char* dependency = NULL;
148 const char* referencePath = NULL;
149 const char* resolvable = NULL;
150 bool existingOnly = false;
151 bool reverseOrder = false;
152 const char* separator = NULL;
154 while (true) {
155 static struct option sLongOptions[] = {
156 { "architecture", required_argument, 0, 'a' },
157 { "dependency", required_argument, 0, 'd' },
158 { "help", no_argument, 0, 'h' },
159 { "list", no_argument, 0, 'l' },
160 { "path", required_argument, 0, 'p' },
161 { "resolvable", required_argument, 0, 'pr' },
162 { "reverse", no_argument, 0, 'R' },
163 { 0, 0, 0, 0 }
166 opterr = 0; // don't print errors
167 int c = getopt_long(argc, (char**)argv, "+a:c:d:ehlp:r:R",
168 sLongOptions, NULL);
169 if (c == -1)
170 break;
172 switch (c) {
173 case 'a':
174 architecture = optarg;
175 break;
177 case 'c':
178 separator = optarg;
179 break;
181 case 'd':
182 dependency = optarg;
183 break;
185 case 'e':
186 existingOnly = true;
187 break;
189 case 'h':
190 print_usage_and_exit(false);
191 break;
193 case 'l':
194 for (size_t i = 0; i < kDirectoryConstantCount; i++) {
195 const DirectoryConstantEntry& entry
196 = kDirectoryConstants[i];
197 printf("%s\n - %s\n", entry.string, entry.description);
199 exit(0);
201 case 'p':
202 referencePath = optarg;
203 break;
205 case 'r':
206 resolvable = optarg;
207 break;
209 case 'R':
210 reverseOrder = true;
211 break;
213 default:
214 print_usage_and_exit(true);
215 break;
219 // The remaining arguments are the kind constant and optionally the subpath.
220 if (optind >= argc || optind + 2 < argc)
221 print_usage_and_exit(true);
223 const char* kindConstant = argv[optind++];
225 const char* subPath = NULL;
226 if (optind < argc)
227 subPath = argv[optind++];
229 // only one of path or resolvable may be specified
230 if (referencePath != NULL && resolvable != NULL)
231 print_usage_and_exit(true);
233 // resolve the directory constant
234 path_base_directory baseDirectory = B_FIND_PATH_IMAGE_PATH;
235 bool found = false;
236 for (size_t i = 0; i < kDirectoryConstantCount; i++) {
237 const DirectoryConstantEntry& entry = kDirectoryConstants[i];
238 if (strcmp(kindConstant, entry.string) == 0) {
239 found = true;
240 baseDirectory = entry.constant;
241 break;
245 if (!found) {
246 fprintf(stderr, "Error: Unsupported directory constant \"%s\".\n",
247 kindConstant);
248 exit(1);
251 if (referencePath != NULL || resolvable != NULL) {
252 try {
253 BPathFinder pathFinder;
254 if (referencePath != NULL) {
255 pathFinder.SetTo(referencePath, dependency);
256 } else {
257 pathFinder.SetTo(
258 BPackageKit::BPackageResolvableExpression(resolvable),
259 dependency);
262 BPath path;
263 status_t error = pathFinder.FindPath(architecture, baseDirectory,
264 subPath, existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, path);
265 if (error != B_OK) {
266 fprintf(stderr, "Error: Failed to find path: %s\n",
267 strerror(error));
268 exit(1);
271 printf("%s\n", path.Path());
272 } catch(BFatalErrorException& exception) {
273 if (!exception.Details().IsEmpty())
274 fprintf(stderr, "%s", exception.Details().String());
275 if (exception.Error() == B_OK) {
276 fprintf(stderr, "Error: %s\n", exception.Message().String());
277 } else {
278 fprintf(stderr, "Error: %s: %s\n", exception.Message().String(),
279 strerror(exception.Error()));
281 return 1;
283 } else {
284 BStringList paths;
285 status_t error = BPathFinder::FindPaths(architecture, baseDirectory,
286 subPath, existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, paths);
287 if (error != B_OK) {
288 fprintf(stderr, "Error: Failed to find paths: %s\n",
289 strerror(error));
290 exit(1);
293 int32 count = paths.CountStrings();
294 if (reverseOrder) {
295 for (int32 i = 0; i < count / 2; i++)
296 paths.Swap(i, count - i - 1);
299 if (separator != NULL) {
300 BString result = paths.Join(separator);
301 if (result.IsEmpty()) {
302 fprintf(stderr, "Error: Out of memory!\n");
303 exit(1);
305 printf("%s\n", result.String());
306 } else {
307 for (int32 i = 0; i < count; i++)
308 printf("%s\n", paths.StringAt(i).String());
312 return 0;