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