1 /* 2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <ctype.h> 8 #include <errno.h> 9 #include <getopt.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <time.h> 14 15 #include <package/hpkg/PackageContentHandler.h> 16 #include <package/hpkg/PackageEntry.h> 17 #include <package/hpkg/PackageEntryAttribute.h> 18 #include <package/hpkg/PackageInfoAttributeValue.h> 19 #include <package/hpkg/PackageReader.h> 20 #include <package/hpkg/StandardErrorOutput.h> 21 22 #include <package/PackageInfo.h> 23 24 #include "package.h" 25 26 27 using namespace BPackageKit::BHPKG; 28 using namespace BPackageKit; 29 30 31 struct PackageContentListHandler : BPackageContentHandler { 32 PackageContentListHandler(bool listAttributes) 33 : 34 fLevel(0), 35 fListAttribute(listAttributes) 36 { 37 } 38 39 virtual status_t HandleEntry(BPackageEntry* entry) 40 { 41 fLevel++; 42 43 int indentation = (fLevel - 1) * 2; 44 printf("%*s", indentation, ""); 45 46 // name and size 47 printf("%-*s", indentation < 32 ? 32 - indentation : 0, entry->Name()); 48 printf(" %8llu", (unsigned long long)entry->Data().UncompressedSize()); 49 50 // time 51 struct tm* time = localtime(&entry->ModifiedTime().tv_sec); 52 printf(" %04d-%02d-%02d %02d:%02d:%02d", 53 1900 + time->tm_year, time->tm_mon + 1, time->tm_mday, 54 time->tm_hour, time->tm_min, time->tm_sec); 55 56 // file type 57 mode_t mode = entry->Mode(); 58 if (S_ISREG(mode)) 59 printf(" -"); 60 else if (S_ISDIR(mode)) 61 printf(" d"); 62 else if (S_ISLNK(mode)) 63 printf(" l"); 64 else 65 printf(" ?"); 66 67 // permissions 68 char buffer[4]; 69 printf("%s", _PermissionString(buffer, mode >> 6, 70 (mode & S_ISUID) != 0)); 71 printf("%s", _PermissionString(buffer, mode >> 3, 72 (mode & S_ISGID) != 0)); 73 printf("%s", _PermissionString(buffer, mode, false)); 74 75 // print the symlink path 76 if (S_ISLNK(mode)) 77 printf(" -> %s", entry->SymlinkPath()); 78 79 printf("\n"); 80 return B_OK; 81 } 82 83 virtual status_t HandleEntryAttribute(BPackageEntry* entry, 84 BPackageEntryAttribute* attribute) 85 { 86 if (!fListAttribute) 87 return B_OK; 88 89 int indentation = fLevel * 2; 90 printf("%*s<", indentation, ""); 91 printf("%-*s %8llu", indentation < 31 ? 31 - indentation : 0, 92 attribute->Name(), 93 (unsigned long long)attribute->Data().UncompressedSize()); 94 95 uint32 type = attribute->Type(); 96 if (isprint(type & 0xff) && isprint((type >> 8) & 0xff) 97 && isprint((type >> 16) & 0xff) && isprint(type >> 24)) { 98 printf(" '%c%c%c%c'", int(type >> 24), int((type >> 16) & 0xff), 99 int((type >> 8) & 0xff), int(type & 0xff)); 100 } else 101 printf(" %#" B_PRIx32, type); 102 103 printf(">\n"); 104 return B_OK; 105 } 106 107 virtual status_t HandleEntryDone(BPackageEntry* entry) 108 { 109 fLevel--; 110 return B_OK; 111 } 112 113 virtual status_t HandlePackageAttribute( 114 const BPackageInfoAttributeValue& value) 115 { 116 switch (value.attributeID) { 117 case B_PACKAGE_INFO_NAME: 118 printf("package-attributes:\n"); 119 printf("\tname: %s\n", value.string); 120 break; 121 122 case B_PACKAGE_INFO_SUMMARY: 123 printf("\tsummary: %s\n", value.string); 124 break; 125 126 case B_PACKAGE_INFO_DESCRIPTION: 127 printf("\tdescription: %s\n", value.string); 128 break; 129 130 case B_PACKAGE_INFO_VENDOR: 131 printf("\tvendor: %s\n", value.string); 132 break; 133 134 case B_PACKAGE_INFO_PACKAGER: 135 printf("\tpackager: %s\n", value.string); 136 break; 137 138 case B_PACKAGE_INFO_FLAGS: 139 if (value.unsignedInt == 0) 140 break; 141 printf("\tflags:\n"); 142 if ((value.unsignedInt & B_PACKAGE_FLAG_APPROVE_LICENSE) != 0) 143 printf("\t\tapprove_license\n"); 144 if ((value.unsignedInt & B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0) 145 printf("\t\tsystem_package\n"); 146 break; 147 148 case B_PACKAGE_INFO_ARCHITECTURE: 149 printf("\tarchitecture: %s\n", 150 BPackageInfo::kArchitectureNames[value.unsignedInt]); 151 break; 152 153 case B_PACKAGE_INFO_VERSION: 154 printf("\tversion: "); 155 _PrintPackageVersion(value.version); 156 printf("\n"); 157 break; 158 159 case B_PACKAGE_INFO_COPYRIGHTS: 160 printf("\tcopyright: %s\n", value.string); 161 break; 162 163 case B_PACKAGE_INFO_LICENSES: 164 printf("\tlicense: %s\n", value.string); 165 break; 166 167 case B_PACKAGE_INFO_URLS: 168 printf("\tURL: %s\n", value.string); 169 break; 170 171 case B_PACKAGE_INFO_SOURCE_URLS: 172 printf("\tsource URL: %s\n", value.string); 173 break; 174 175 case B_PACKAGE_INFO_PROVIDES: 176 printf("\tprovides: %s", value.resolvable.name); 177 if (value.resolvable.haveVersion) { 178 printf(" = "); 179 _PrintPackageVersion(value.resolvable.version); 180 } 181 if (value.resolvable.haveCompatibleVersion) { 182 printf(" (compatible >= "); 183 _PrintPackageVersion(value.resolvable.compatibleVersion); 184 printf(")"); 185 } 186 printf("\n"); 187 break; 188 189 case B_PACKAGE_INFO_REQUIRES: 190 printf("\trequires: %s", value.resolvableExpression.name); 191 if (value.resolvableExpression.haveOpAndVersion) { 192 printf(" %s ", BPackageResolvableExpression::kOperatorNames[ 193 value.resolvableExpression.op]); 194 _PrintPackageVersion(value.resolvableExpression.version); 195 } 196 printf("\n"); 197 break; 198 199 case B_PACKAGE_INFO_SUPPLEMENTS: 200 printf("\tsupplements: %s", value.resolvableExpression.name); 201 if (value.resolvableExpression.haveOpAndVersion) { 202 printf(" %s ", BPackageResolvableExpression::kOperatorNames[ 203 value.resolvableExpression.op]); 204 _PrintPackageVersion(value.resolvableExpression.version); 205 } 206 printf("\n"); 207 break; 208 209 case B_PACKAGE_INFO_CONFLICTS: 210 printf("\tconflicts: %s", value.resolvableExpression.name); 211 if (value.resolvableExpression.haveOpAndVersion) { 212 printf(" %s ", BPackageResolvableExpression::kOperatorNames[ 213 value.resolvableExpression.op]); 214 _PrintPackageVersion(value.resolvableExpression.version); 215 } 216 printf("\n"); 217 break; 218 219 case B_PACKAGE_INFO_FRESHENS: 220 printf("\tfreshens: %s", value.resolvableExpression.name); 221 if (value.resolvableExpression.haveOpAndVersion) { 222 printf(" %s ", BPackageResolvableExpression::kOperatorNames[ 223 value.resolvableExpression.op]); 224 _PrintPackageVersion(value.resolvableExpression.version); 225 } 226 printf("\n"); 227 break; 228 229 case B_PACKAGE_INFO_REPLACES: 230 printf("\treplaces: %s\n", value.string); 231 break; 232 233 case B_PACKAGE_INFO_INSTALL_PATH: 234 printf("\tinstall path: %s\n", value.string); 235 break; 236 237 default: 238 printf( 239 "*** Invalid package attribute section: unexpected " 240 "package attribute id %d encountered\n", value.attributeID); 241 return B_BAD_DATA; 242 } 243 244 return B_OK; 245 } 246 247 virtual void HandleErrorOccurred() 248 { 249 } 250 251 private: 252 static const char* _PermissionString(char* buffer, uint32 mode, bool sticky) 253 { 254 buffer[0] = (mode & 0x4) != 0 ? 'r' : '-'; 255 buffer[1] = (mode & 0x2) != 0 ? 'w' : '-'; 256 257 if ((mode & 0x1) != 0) 258 buffer[2] = sticky ? 's' : 'x'; 259 else 260 buffer[2] = '-'; 261 262 buffer[3] = '\0'; 263 return buffer; 264 } 265 266 static void _PrintPackageVersion(const BPackageVersionData& version) 267 { 268 printf("%s", BPackageVersion(version).ToString().String()); 269 } 270 271 private: 272 int fLevel; 273 bool fListAttribute; 274 }; 275 276 277 struct PackageContentListPathsHandler : BPackageContentHandler { 278 PackageContentListPathsHandler() 279 : 280 fPathComponents() 281 { 282 } 283 284 virtual status_t HandleEntry(BPackageEntry* entry) 285 { 286 fPathComponents.Add(entry->Name()); 287 printf("%s\n", fPathComponents.Join("/").String()); 288 return B_OK; 289 } 290 291 virtual status_t HandleEntryAttribute(BPackageEntry* entry, 292 BPackageEntryAttribute* attribute) 293 { 294 return B_OK; 295 } 296 297 virtual status_t HandleEntryDone(BPackageEntry* entry) 298 { 299 fPathComponents.Remove(fPathComponents.CountStrings() - 1); 300 return B_OK; 301 } 302 303 virtual status_t HandlePackageAttribute( 304 const BPackageInfoAttributeValue& value) 305 { 306 return B_OK; 307 } 308 309 virtual void HandleErrorOccurred() 310 { 311 } 312 313 private: 314 BStringList fPathComponents; 315 }; 316 317 318 int 319 command_list(int argc, const char* const* argv) 320 { 321 bool listAttributes = false; 322 bool filePathsOnly = false; 323 324 while (true) { 325 static struct option sLongOptions[] = { 326 { "help", no_argument, 0, 'h' }, 327 { 0, 0, 0, 0 } 328 }; 329 330 opterr = 0; // don't print errors 331 int c = getopt_long(argc, (char**)argv, "+hap", sLongOptions, NULL); 332 if (c == -1) 333 break; 334 335 switch (c) { 336 case 'a': 337 listAttributes = true; 338 break; 339 340 case 'h': 341 print_usage_and_exit(false); 342 break; 343 344 case 'p': 345 filePathsOnly = true; 346 break; 347 348 default: 349 print_usage_and_exit(true); 350 break; 351 } 352 } 353 354 // One argument should remain -- the package file name. 355 if (optind + 1 != argc) 356 print_usage_and_exit(true); 357 358 const char* packageFileName = argv[optind++]; 359 360 // open package 361 BStandardErrorOutput errorOutput; 362 BPackageReader packageReader(&errorOutput); 363 status_t error = packageReader.Init(packageFileName); 364 if (error != B_OK) 365 return 1; 366 367 // list 368 if (filePathsOnly) { 369 PackageContentListPathsHandler handler; 370 error = packageReader.ParseContent(&handler); 371 } else { 372 PackageContentListHandler handler(listAttributes); 373 error = packageReader.ParseContent(&handler); 374 } 375 if (error != B_OK) 376 return 1; 377 378 return 0; 379 } 380