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