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