xref: /haiku/src/bin/findpaths.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
1 /*
2  * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <getopt.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <package/PackageResolvableExpression.h>
13 #include <package/manager/Exceptions.h>
14 #include <Path.h>
15 #include <PathFinder.h>
16 #include <StringList.h>
17 
18 
19 using namespace BPackageKit::BManager::BPrivate;
20 
21 
22 extern const char* __progname;
23 const char* kCommandName = __progname;
24 
25 
26 struct DirectoryConstantEntry {
27 	const char*			string;
28 	path_base_directory	constant;
29 	const char*			description;
30 };
31 
32 #define DEFINE_CONSTANT(constant, description)	\
33 	{ #constant, constant, description }
34 
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"),
86 };
87 
88 static const size_t kDirectoryConstantCount
89 	= sizeof(kDirectoryConstants) / sizeof(kDirectoryConstants[0]);
90 
91 
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"
132 ;
133 
134 
135 static void
136 print_usage_and_exit(bool error)
137 {
138     fprintf(error ? stderr : stdout, kUsage, kCommandName);
139     exit(error ? 1 : 0);
140 }
141 
142 
143 int
144 main(int argc, const char* const* argv)
145 {
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;
153 
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 }
164 		};
165 
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;
171 
172 		switch (c) {
173 			case 'a':
174 				architecture = optarg;
175 				break;
176 
177 			case 'c':
178 				separator = optarg;
179 				break;
180 
181 			case 'd':
182 				dependency = optarg;
183 				break;
184 
185 			case 'e':
186 				existingOnly = true;
187 				break;
188 
189 			case 'h':
190 				print_usage_and_exit(false);
191 				break;
192 
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);
198 				}
199 				exit(0);
200 
201 			case 'p':
202 				referencePath = optarg;
203 				break;
204 
205 			case 'r':
206 				resolvable = optarg;
207 				break;
208 
209 			case 'R':
210 				reverseOrder = true;
211 				break;
212 
213 			default:
214 				print_usage_and_exit(true);
215 				break;
216 		}
217 	}
218 
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);
222 
223 	const char* kindConstant = argv[optind++];
224 
225 	const char* subPath = NULL;
226 	if (optind < argc)
227 		subPath = argv[optind++];
228 
229 	// only one of path or resolvable may be specified
230 	if (referencePath != NULL && resolvable != NULL)
231 		print_usage_and_exit(true);
232 
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;
242 		}
243 	}
244 
245 	if (!found) {
246 		fprintf(stderr, "Error: Unsupported directory constant \"%s\".\n",
247 			kindConstant);
248 		exit(1);
249 	}
250 
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);
260 			}
261 
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);
269 			}
270 
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()));
280 			}
281 			return 1;
282 		}
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);
291 		}
292 
293 		int32 count = paths.CountStrings();
294 		if (reverseOrder) {
295 			for (int32 i = 0; i < count / 2; i++)
296 				paths.Swap(i, count - i - 1);
297 		}
298 
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);
304 			}
305 			printf("%s\n", result.String());
306 		} else {
307 			for (int32 i = 0; i < count; i++)
308 				printf("%s\n", paths.StringAt(i).String());
309 		}
310 	}
311 
312 	return 0;
313 }
314