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 ; 126 127 128 static void 129 print_usage_and_exit(bool error) 130 { 131 fprintf(error ? stderr : stdout, kUsage, kCommandName); 132 exit(error ? 1 : 0); 133 } 134 135 136 int 137 main(int argc, const char* const* argv) 138 { 139 const char* architecture = NULL; 140 const char* dependency = NULL; 141 const char* referencePath = NULL; 142 const char* resolvable = NULL; 143 bool existingOnly = false; 144 const char* separator = NULL; 145 146 while (true) { 147 static struct option sLongOptions[] = { 148 { "architecture", required_argument, 0, 'a' }, 149 { "dependency", required_argument, 0, 'd' }, 150 { "help", no_argument, 0, 'h' }, 151 { "path", required_argument, 0, 'p' }, 152 { "resolvable", required_argument, 0, 'pr' }, 153 { 0, 0, 0, 0 } 154 }; 155 156 opterr = 0; // don't print errors 157 int c = getopt_long(argc, (char**)argv, "+a:c:d:ehlp:r:", 158 sLongOptions, NULL); 159 if (c == -1) 160 break; 161 162 switch (c) { 163 case 'a': 164 architecture = optarg; 165 break; 166 167 case 'c': 168 separator = optarg; 169 break; 170 171 case 'd': 172 dependency = optarg; 173 break; 174 175 case 'e': 176 existingOnly = true; 177 break; 178 179 case 'h': 180 print_usage_and_exit(false); 181 break; 182 183 case 'l': 184 for (size_t i = 0; i < kDirectoryConstantCount; i++) { 185 const DirectoryConstantEntry& entry 186 = kDirectoryConstants[i]; 187 printf("%s\n - %s\n", entry.string, entry.description); 188 } 189 exit(0); 190 191 case 'p': 192 referencePath = optarg; 193 break; 194 195 case 'r': 196 resolvable = optarg; 197 break; 198 199 default: 200 print_usage_and_exit(true); 201 break; 202 } 203 } 204 205 // The remaining arguments are the kind constant and optionally the subpath. 206 if (optind >= argc || optind + 2 < argc) 207 print_usage_and_exit(true); 208 209 const char* kindConstant = argv[optind++]; 210 211 const char* subPath = NULL; 212 if (optind >= argc) 213 subPath = argv[optind++]; 214 215 // only one of path or resolvable may be specified 216 if (referencePath != NULL && resolvable != NULL) 217 print_usage_and_exit(true); 218 219 // resolve the directory constant 220 path_base_directory baseDirectory = B_FIND_PATH_IMAGE_PATH; 221 bool found = false; 222 for (size_t i = 0; i < kDirectoryConstantCount; i++) { 223 const DirectoryConstantEntry& entry = kDirectoryConstants[i]; 224 if (strcmp(kindConstant, entry.string) == 0) { 225 found = true; 226 baseDirectory = entry.constant; 227 break; 228 } 229 } 230 231 if (!found) { 232 fprintf(stderr, "Error: Unsupported directory constant \"%s\".\n", 233 kindConstant); 234 exit(1); 235 } 236 237 if (referencePath != NULL || resolvable != NULL) { 238 BPathFinder pathFinder; 239 if (referencePath != NULL) { 240 pathFinder.SetTo(referencePath, dependency); 241 } else { 242 pathFinder.SetTo( 243 BPackageKit::BPackageResolvableExpression(resolvable), 244 dependency); 245 } 246 247 BPath path; 248 status_t error =pathFinder.FindPath(architecture, baseDirectory, 249 subPath, existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, path); 250 if (error != B_OK) { 251 fprintf(stderr, "Error: Failed to find path: %s\n", 252 strerror(error)); 253 exit(1); 254 } 255 256 printf("%s\n", path.Path()); 257 } else { 258 BStringList paths; 259 status_t error = BPathFinder::FindPaths(architecture, baseDirectory, 260 subPath, existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, paths); 261 if (error != B_OK) { 262 fprintf(stderr, "Error: Failed to find paths: %s\n", 263 strerror(error)); 264 exit(1); 265 } 266 267 if (separator != NULL) { 268 BString result = paths.Join(separator); 269 if (result.IsEmpty()) { 270 fprintf(stderr, "Error: Out of memory!\n"); 271 exit(1); 272 } 273 printf("%s\n", result.String()); 274 } else { 275 int32 count = paths.CountStrings(); 276 for (int32 i = 0; i < count; i++) 277 printf("%s\n", paths.StringAt(i).String()); 278 } 279 } 280 281 return 0; 282 } 283