1/* 2 * Copyright 2013-2014, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold <ingo_weinhold@gmx.de> 7 */ 8 9 10#include <package/CommitTransactionResult.h> 11 12#include <Message.h> 13 14//#include <package/DaemonDefs.h> 15 16 17namespace BPackageKit { 18 19 20// #pragma mark - BTransactionIssue 21 22 23BTransactionIssue::BTransactionIssue() 24 : 25 fType(B_WRITABLE_FILE_TYPE_MISMATCH), 26 fPackageName(), 27 fPath1(), 28 fPath2(), 29 fSystemError(B_OK), 30 fExitCode(0) 31{ 32} 33 34 35BTransactionIssue::BTransactionIssue(BType type, const BString& packageName, 36 const BString& path1, const BString& path2, status_t systemError, 37 int exitCode) 38 : 39 fType(type), 40 fPackageName(packageName), 41 fPath1(path1), 42 fPath2(path2), 43 fSystemError(systemError), 44 fExitCode(exitCode) 45{ 46} 47 48 49BTransactionIssue::BTransactionIssue(const BTransactionIssue& other) 50{ 51 *this = other; 52} 53 54 55BTransactionIssue::~BTransactionIssue() 56{ 57} 58 59 60BTransactionIssue::BType 61BTransactionIssue::Type() const 62{ 63 return fType; 64} 65 66 67const BString& 68BTransactionIssue::PackageName() const 69{ 70 return fPackageName; 71} 72 73 74const BString& 75BTransactionIssue::Path1() const 76{ 77 return fPath1; 78} 79 80 81const BString& 82BTransactionIssue::Path2() const 83{ 84 return fPath2; 85} 86 87 88status_t 89BTransactionIssue::SystemError() const 90{ 91 return fSystemError; 92} 93 94 95int 96BTransactionIssue::ExitCode() const 97{ 98 return fExitCode; 99} 100 101 102BString 103BTransactionIssue::ToString() const 104{ 105 const char* messageTemplate = ""; 106 switch (fType) { 107 case B_WRITABLE_FILE_TYPE_MISMATCH: 108 messageTemplate = "\"%path1%\" cannot be updated automatically," 109 " since its type doesn't match the type of \"%path2%\" which it" 110 " is supposed to be updated with." 111 " Please perform the update manually if needed."; 112 break; 113 case B_WRITABLE_FILE_NO_PACKAGE_ATTRIBUTE: 114 messageTemplate = "\"%path1%\" cannot be updated automatically," 115 " since it doesn't have a SYS:PACKAGE attribute." 116 " Please perform the update manually if needed."; 117 break; 118 case B_WRITABLE_FILE_OLD_ORIGINAL_FILE_MISSING: 119 messageTemplate = "\"%path1%\" cannot be updated automatically," 120 " since \"%path2%\" which we need to compare it with is" 121 " missing." 122 " Please perform the update manually if needed."; 123 break; 124 case B_WRITABLE_FILE_OLD_ORIGINAL_FILE_TYPE_MISMATCH: 125 messageTemplate = "\"%path1%\" cannot be updated automatically," 126 " since its type doesn't match the type of \"%path2%\" which we" 127 " need to compare it with." 128 " Please perform the update manually if needed."; 129 break; 130 case B_WRITABLE_FILE_COMPARISON_FAILED: 131 messageTemplate = "\"%path1%\" cannot be updated automatically," 132 " since the comparison with \"%path2%\" failed: %error%." 133 " Please perform the update manually if needed."; 134 break; 135 case B_WRITABLE_FILE_NOT_EQUAL: // !keep old 136 messageTemplate = "\"%path1%\" cannot be updated automatically," 137 " since it was changed manually from previous version" 138 " \"%path2%\"." 139 " Please perform the update manually if needed."; 140 break; 141 case B_WRITABLE_SYMLINK_COMPARISON_FAILED: // !keep old 142 messageTemplate = "Symbolic link \"%path1%\" cannot be updated" 143 " automatically, since the comparison with \"%path2%\" failed:" 144 " %error%." 145 " Please perform the update manually if needed."; 146 break; 147 case B_WRITABLE_SYMLINK_NOT_EQUAL: // !keep old 148 messageTemplate = "Symbolic link \"%path1%\" cannot be updated" 149 " automatically, since it was changed manually from previous" 150 " version \"%path2%\"." 151 " Please perform the update manually if needed."; 152 break; 153 case B_POST_INSTALL_SCRIPT_NOT_FOUND: 154 messageTemplate = "Failed to find post-installation script " 155 " \"%path1%\": %error%."; 156 break; 157 case B_STARTING_POST_INSTALL_SCRIPT_FAILED: 158 messageTemplate = "Failed to run post-installation script " 159 " \"%path1%\": %error%."; 160 break; 161 case B_POST_INSTALL_SCRIPT_FAILED: 162 messageTemplate = "The post-installation script " 163 " \"%path1%\" failed with exit code %exitCode%."; 164 break; 165 case B_PRE_UNINSTALL_SCRIPT_NOT_FOUND: 166 messageTemplate = "Failed to find pre-uninstall script " 167 " \"%path1%\": %error%."; 168 break; 169 case B_STARTING_PRE_UNINSTALL_SCRIPT_FAILED: 170 messageTemplate = "Failed to run pre-uninstall script " 171 " \"%path1%\": %error%."; 172 break; 173 case B_PRE_UNINSTALL_SCRIPT_FAILED: 174 messageTemplate = "The pre-uninstall script " 175 " \"%path1%\" failed with exit code %exitCode%."; 176 break; 177 } 178 179 BString message(messageTemplate); 180 message.ReplaceAll("%path1%", fPath1) 181 .ReplaceAll("%path2%", fPath2) 182 .ReplaceAll("%error%", strerror(fSystemError)) 183 .ReplaceAll("%exitCode%", BString() << fExitCode); 184 return message; 185} 186 187 188status_t 189BTransactionIssue::AddToMessage(BMessage& message) const 190{ 191 status_t error; 192 if ((error = message.AddInt32("type", (int32)fType)) != B_OK 193 || (error = message.AddString("package", fPackageName)) != B_OK 194 || (error = message.AddString("path1", fPath1)) != B_OK 195 || (error = message.AddString("path2", fPath2)) != B_OK 196 || (error = message.AddInt32("system error", (int32)fSystemError)) 197 != B_OK 198 || (error = message.AddInt32("exit code", (int32)fExitCode)) != B_OK) { 199 return error; 200 } 201 202 return B_OK; 203} 204 205 206status_t 207BTransactionIssue::ExtractFromMessage(const BMessage& message) 208{ 209 status_t error; 210 int32 type; 211 int32 systemError; 212 int32 exitCode; 213 if ((error = message.FindInt32("type", &type)) != B_OK 214 || (error = message.FindString("package", &fPackageName)) != B_OK 215 || (error = message.FindString("path1", &fPath1)) != B_OK 216 || (error = message.FindString("path2", &fPath2)) != B_OK 217 || (error = message.FindInt32("system error", &systemError)) != B_OK 218 || (error = message.FindInt32("exit code", &exitCode)) != B_OK) { 219 return error; 220 } 221 222 fType = (BType)type; 223 fSystemError = (status_t)systemError; 224 fExitCode = (int)exitCode; 225 226 return B_OK; 227} 228 229 230BTransactionIssue& 231BTransactionIssue::operator=(const BTransactionIssue& other) 232{ 233 fType = other.fType; 234 fPackageName = other.fPackageName; 235 fPath1 = other.fPath1; 236 fPath2 = other.fPath2; 237 fSystemError = other.fSystemError; 238 fExitCode = other.fExitCode; 239 240 return *this; 241} 242 243 244// #pragma mark - BCommitTransactionResult 245 246 247BCommitTransactionResult::BCommitTransactionResult() 248 : 249 fError(B_TRANSACTION_INTERNAL_ERROR), 250 fSystemError(B_ERROR), 251 fErrorPackage(), 252 fPath1(), 253 fPath2(), 254 fString1(), 255 fString2(), 256 fOldStateDirectory(), 257 fIssues(10, true) 258{ 259} 260 261 262BCommitTransactionResult::BCommitTransactionResult(BTransactionError error) 263 : 264 fError(error), 265 fSystemError(B_ERROR), 266 fErrorPackage(), 267 fPath1(), 268 fPath2(), 269 fString1(), 270 fString2(), 271 fOldStateDirectory(), 272 fIssues(10, true) 273{ 274} 275 276 277BCommitTransactionResult::BCommitTransactionResult( 278 const BCommitTransactionResult& other) 279 : 280 fError(B_TRANSACTION_INTERNAL_ERROR), 281 fSystemError(B_ERROR), 282 fErrorPackage(), 283 fPath1(), 284 fPath2(), 285 fString1(), 286 fString2(), 287 fOldStateDirectory(), 288 fIssues(10, true) 289{ 290 *this = other; 291} 292 293 294BCommitTransactionResult::~BCommitTransactionResult() 295{ 296} 297 298 299void 300BCommitTransactionResult::Unset() 301{ 302 fError = B_TRANSACTION_INTERNAL_ERROR; 303 fSystemError = B_ERROR; 304 fErrorPackage.Truncate(0); 305 fPath1.Truncate(0); 306 fPath2.Truncate(0); 307 fString1.Truncate(0); 308 fString2.Truncate(0); 309 fOldStateDirectory.Truncate(0); 310 fIssues.MakeEmpty(); 311} 312 313 314int32 315BCommitTransactionResult::CountIssues() const 316{ 317 return fIssues.CountItems(); 318} 319 320 321const BTransactionIssue* 322BCommitTransactionResult::IssueAt(int32 index) const 323{ 324 if (index < 0 || index >= CountIssues()) 325 return NULL; 326 return fIssues.ItemAt(index); 327} 328 329 330bool 331BCommitTransactionResult::AddIssue(const BTransactionIssue& issue) 332{ 333 BTransactionIssue* newIssue = new(std::nothrow) BTransactionIssue(issue); 334 if (newIssue == NULL || !fIssues.AddItem(newIssue)) { 335 delete newIssue; 336 return false; 337 } 338 return true; 339} 340 341 342BTransactionError 343BCommitTransactionResult::Error() const 344{ 345 return fError > 0 ? (BTransactionError)fError : B_TRANSACTION_OK; 346} 347 348 349void 350BCommitTransactionResult::SetError(BTransactionError error) 351{ 352 fError = error; 353} 354 355 356status_t 357BCommitTransactionResult::SystemError() const 358{ 359 return fSystemError; 360} 361 362 363void 364BCommitTransactionResult::SetSystemError(status_t error) 365{ 366 fSystemError = error; 367} 368 369 370const BString& 371BCommitTransactionResult::ErrorPackage() const 372{ 373 return fErrorPackage; 374} 375 376 377void 378BCommitTransactionResult::SetErrorPackage(const BString& packageName) 379{ 380 fErrorPackage = packageName; 381} 382 383 384BString 385BCommitTransactionResult::FullErrorMessage() const 386{ 387 if (fError == 0) 388 return "no error"; 389 390 const char* messageTemplate = ""; 391 switch ((BTransactionError)fError) { 392 case B_TRANSACTION_OK: 393 messageTemplate = "Everything went fine."; 394 break; 395 case B_TRANSACTION_NO_MEMORY: 396 messageTemplate = "Out of memory."; 397 break; 398 case B_TRANSACTION_INTERNAL_ERROR: 399 messageTemplate = "An internal error occurred. Specifics can be" 400 " found in the syslog."; 401 break; 402 case B_TRANSACTION_INSTALLATION_LOCATION_BUSY: 403 messageTemplate = "Another package operation is already in" 404 " progress."; 405 break; 406 case B_TRANSACTION_CHANGE_COUNT_MISMATCH: 407 messageTemplate = "The transaction is out of date."; 408 break; 409 case B_TRANSACTION_BAD_REQUEST: 410 messageTemplate = "The requested transaction is invalid."; 411 break; 412 case B_TRANSACTION_NO_SUCH_PACKAGE: 413 messageTemplate = "No such package \"%package%\"."; 414 break; 415 case B_TRANSACTION_PACKAGE_ALREADY_EXISTS: 416 messageTemplate = "The to be activated package \"%package%\" does" 417 " already exist."; 418 break; 419 case B_TRANSACTION_FAILED_TO_GET_ENTRY_PATH: 420 if (fPath1.IsEmpty()) { 421 if (fErrorPackage.IsEmpty()) { 422 messageTemplate = "A file path could not be determined:" 423 "%error%"; 424 } else { 425 messageTemplate = "While processing package \"%package%\"" 426 " a file path could not be determined: %error%"; 427 } 428 } else { 429 if (fErrorPackage.IsEmpty()) { 430 messageTemplate = "The file path for \"%path1%\" could not" 431 " be determined: %error%"; 432 } else { 433 messageTemplate = "While processing package \"%package%\"" 434 " the file path for \"%path1%\" could not be" 435 " determined: %error%"; 436 } 437 } 438 break; 439 case B_TRANSACTION_FAILED_TO_OPEN_DIRECTORY: 440 messageTemplate = "Failed to open directory \"%path1%\": %error%"; 441 break; 442 case B_TRANSACTION_FAILED_TO_CREATE_DIRECTORY: 443 messageTemplate = "Failed to create directory \"%path1%\": %error%"; 444 break; 445 case B_TRANSACTION_FAILED_TO_REMOVE_DIRECTORY: 446 messageTemplate = "Failed to remove directory \"%path1%\": %error%"; 447 break; 448 case B_TRANSACTION_FAILED_TO_MOVE_DIRECTORY: 449 messageTemplate = "Failed to move directory \"%path1%\" to" 450 " \"%path2%\": %error%"; 451 break; 452 case B_TRANSACTION_FAILED_TO_WRITE_ACTIVATION_FILE: 453 messageTemplate = "Failed to write new package activation file" 454 " \"%path1%\": %error%"; 455 break; 456 case B_TRANSACTION_FAILED_TO_READ_PACKAGE_FILE: 457 messageTemplate = "Failed to read package file \"%path1%\":" 458 " %error%"; 459 break; 460 case B_TRANSACTION_FAILED_TO_EXTRACT_PACKAGE_FILE: 461 messageTemplate = "Failed to extract \"%path1%\" from package" 462 " \"%package%\": %error%"; 463 break; 464 case B_TRANSACTION_FAILED_TO_OPEN_FILE: 465 messageTemplate = "Failed to open file \"%path1%\": %error%"; 466 break; 467 case B_TRANSACTION_FAILED_TO_MOVE_FILE: 468 messageTemplate = "Failed to move file \"%path1%\" to \"%path2%\":" 469 " %error%"; 470 break; 471 case B_TRANSACTION_FAILED_TO_COPY_FILE: 472 messageTemplate = "Failed to copy file \"%path1%\" to \"%path2%\":" 473 " %error%"; 474 break; 475 case B_TRANSACTION_FAILED_TO_WRITE_FILE_ATTRIBUTE: 476 messageTemplate = "Failed to write attribute \"%string1%\" of file" 477 " \"%path1%\": %error%"; 478 break; 479 case B_TRANSACTION_FAILED_TO_ACCESS_ENTRY: 480 messageTemplate = "Failed to access entry \"%path1%\": %error%"; 481 break; 482 case B_TRANSACTION_FAILED_TO_ADD_GROUP: 483 messageTemplate = "Failed to add user group \"%string1%\" required" 484 " by package \"%package%\"."; 485 break; 486 case B_TRANSACTION_FAILED_TO_ADD_USER: 487 messageTemplate = "Failed to add user \"%string1%\" required" 488 " by package \"%package%\"."; 489 break; 490 case B_TRANSACTION_FAILED_TO_ADD_USER_TO_GROUP: 491 messageTemplate = "Failed to add user \"%string1%\" to group" 492 " \"%string2%\" as required by package \"%package%\"."; 493 break; 494 case B_TRANSACTION_FAILED_TO_CHANGE_PACKAGE_ACTIVATION: 495 messageTemplate = "Failed to change the package activation in" 496 " packagefs: %error%"; 497 break; 498 } 499 500 BString message(messageTemplate); 501 message.ReplaceAll("%package%", fErrorPackage) 502 .ReplaceAll("%path1%", fPath1) 503 .ReplaceAll("%path2%", fPath2) 504 .ReplaceAll("%string1%", fString1) 505 .ReplaceAll("%string2%", fString2) 506 .ReplaceAll("%error%", strerror(fSystemError)); 507 return message; 508} 509 510 511const BString& 512BCommitTransactionResult::Path1() const 513{ 514 return fPath1; 515} 516 517 518void 519BCommitTransactionResult::SetPath1(const BString& path) 520{ 521 fPath1 = path; 522} 523 524 525const BString& 526BCommitTransactionResult::Path2() const 527{ 528 return fPath2; 529} 530 531 532void 533BCommitTransactionResult::SetPath2(const BString& path) 534{ 535 fPath2 = path; 536} 537 538 539const BString& 540BCommitTransactionResult::String1() const 541{ 542 return fString1; 543} 544 545 546void 547BCommitTransactionResult::SetString1(const BString& string) 548{ 549 fString1 = string; 550} 551 552 553const BString& 554BCommitTransactionResult::String2() const 555{ 556 return fString2; 557} 558 559 560void 561BCommitTransactionResult::SetString2(const BString& string) 562{ 563 fString2 = string; 564} 565 566 567const BString& 568BCommitTransactionResult::OldStateDirectory() const 569{ 570 return fOldStateDirectory; 571} 572 573 574void 575BCommitTransactionResult::SetOldStateDirectory(const BString& directory) 576{ 577 fOldStateDirectory = directory; 578} 579 580 581status_t 582BCommitTransactionResult::AddToMessage(BMessage& message) const 583{ 584 status_t error; 585 if ((error = message.AddInt32("error", (int32)fError)) != B_OK 586 || (error = message.AddInt32("system error", (int32)fSystemError)) 587 != B_OK 588 || (error = message.AddString("error package", fErrorPackage)) != B_OK 589 || (error = message.AddString("path1", fPath1)) != B_OK 590 || (error = message.AddString("path2", fPath2)) != B_OK 591 || (error = message.AddString("string1", fString1)) != B_OK 592 || (error = message.AddString("string2", fString2)) != B_OK 593 || (error = message.AddString("old state", fOldStateDirectory)) 594 != B_OK) { 595 return error; 596 } 597 598 int32 count = fIssues.CountItems(); 599 for (int32 i = 0; i < count; i++) { 600 const BTransactionIssue* issue = fIssues.ItemAt(i); 601 BMessage issueMessage; 602 if ((error = issue->AddToMessage(issueMessage)) != B_OK 603 || (error = message.AddMessage("issues", &issueMessage)) != B_OK) { 604 return error; 605 } 606 } 607 608 return B_OK; 609} 610 611 612status_t 613BCommitTransactionResult::ExtractFromMessage(const BMessage& message) 614{ 615 Unset(); 616 617 int32 resultError; 618 int32 systemError; 619 status_t error; 620 if ((error = message.FindInt32("error", &resultError)) != B_OK 621 || (error = message.FindInt32("system error", &systemError)) != B_OK 622 || (error = message.FindString("error package", &fErrorPackage)) != B_OK 623 || (error = message.FindString("path1", &fPath1)) != B_OK 624 || (error = message.FindString("path2", &fPath2)) != B_OK 625 || (error = message.FindString("string1", &fString1)) != B_OK 626 || (error = message.FindString("string2", &fString2)) != B_OK 627 || (error = message.FindString("old state", &fOldStateDirectory)) 628 != B_OK) { 629 return error; 630 } 631 632 fError = (BTransactionError)resultError; 633 fSystemError = (status_t)systemError; 634 635 BMessage issueMessage; 636 for (int32 i = 0; message.FindMessage("issues", i, &issueMessage) == B_OK; 637 i++) { 638 BTransactionIssue issue; 639 error = issue.ExtractFromMessage(issueMessage); 640 if (error != B_OK) 641 return error; 642 643 if (!AddIssue(issue)) 644 return B_NO_MEMORY; 645 } 646 647 return B_OK; 648} 649 650 651BCommitTransactionResult& 652BCommitTransactionResult::operator=(const BCommitTransactionResult& other) 653{ 654 Unset(); 655 656 fError = other.fError; 657 fSystemError = other.fSystemError; 658 fErrorPackage = other.fErrorPackage; 659 fPath1 = other.fPath1; 660 fPath2 = other.fPath2; 661 fString1 = other.fString1; 662 fString2 = other.fString2; 663 fOldStateDirectory = other.fOldStateDirectory; 664 665 for (int32 i = 0; const BTransactionIssue* issue = other.fIssues.ItemAt(i); 666 i++) { 667 AddIssue(*issue); 668 } 669 670 return *this; 671} 672 673 674} // namespace BPackageKit 675