xref: /haiku/src/kits/package/CommitTransactionResult.cpp (revision a5061ecec55353a5f394759473f1fd6df04890da)
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 
17 namespace BPackageKit {
18 
19 
20 // #pragma mark - BTransactionIssue
21 
22 
23 BTransactionIssue::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 
35 BTransactionIssue::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 
49 BTransactionIssue::BTransactionIssue(const BTransactionIssue& other)
50 {
51 	*this = other;
52 }
53 
54 
55 BTransactionIssue::~BTransactionIssue()
56 {
57 }
58 
59 
60 BTransactionIssue::BType
61 BTransactionIssue::Type() const
62 {
63 	return fType;
64 }
65 
66 
67 const BString&
68 BTransactionIssue::PackageName() const
69 {
70 	return fPackageName;
71 }
72 
73 
74 const BString&
75 BTransactionIssue::Path1() const
76 {
77 	return fPath1;
78 }
79 
80 
81 const BString&
82 BTransactionIssue::Path2() const
83 {
84 	return fPath2;
85 }
86 
87 
88 status_t
89 BTransactionIssue::SystemError() const
90 {
91 	return fSystemError;
92 }
93 
94 
95 int
96 BTransactionIssue::ExitCode() const
97 {
98 	return fExitCode;
99 }
100 
101 
102 BString
103 BTransactionIssue::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 
188 status_t
189 BTransactionIssue::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 
206 status_t
207 BTransactionIssue::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 
230 BTransactionIssue&
231 BTransactionIssue::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 
247 BCommitTransactionResult::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 
262 BCommitTransactionResult::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 
277 BCommitTransactionResult::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 
294 BCommitTransactionResult::~BCommitTransactionResult()
295 {
296 }
297 
298 
299 void
300 BCommitTransactionResult::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 
314 int32
315 BCommitTransactionResult::CountIssues() const
316 {
317 	return fIssues.CountItems();
318 }
319 
320 
321 const BTransactionIssue*
322 BCommitTransactionResult::IssueAt(int32 index) const
323 {
324 	if (index < 0 || index >= CountIssues())
325 		return NULL;
326 	return fIssues.ItemAt(index);
327 }
328 
329 
330 bool
331 BCommitTransactionResult::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 
342 BTransactionError
343 BCommitTransactionResult::Error() const
344 {
345 	return fError > 0 ? (BTransactionError)fError : B_TRANSACTION_OK;
346 }
347 
348 
349 void
350 BCommitTransactionResult::SetError(BTransactionError error)
351 {
352 	fError = error;
353 }
354 
355 
356 status_t
357 BCommitTransactionResult::SystemError() const
358 {
359 	return fSystemError;
360 }
361 
362 
363 void
364 BCommitTransactionResult::SetSystemError(status_t error)
365 {
366 	fSystemError = error;
367 }
368 
369 
370 const BString&
371 BCommitTransactionResult::ErrorPackage() const
372 {
373 	return fErrorPackage;
374 }
375 
376 
377 void
378 BCommitTransactionResult::SetErrorPackage(const BString& packageName)
379 {
380 	fErrorPackage = packageName;
381 }
382 
383 
384 BString
385 BCommitTransactionResult::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 
511 const BString&
512 BCommitTransactionResult::Path1() const
513 {
514 	return fPath1;
515 }
516 
517 
518 void
519 BCommitTransactionResult::SetPath1(const BString& path)
520 {
521 	fPath1 = path;
522 }
523 
524 
525 const BString&
526 BCommitTransactionResult::Path2() const
527 {
528 	return fPath2;
529 }
530 
531 
532 void
533 BCommitTransactionResult::SetPath2(const BString& path)
534 {
535 	fPath2 = path;
536 }
537 
538 
539 const BString&
540 BCommitTransactionResult::String1() const
541 {
542 	return fString1;
543 }
544 
545 
546 void
547 BCommitTransactionResult::SetString1(const BString& string)
548 {
549 	fString1 = string;
550 }
551 
552 
553 const BString&
554 BCommitTransactionResult::String2() const
555 {
556 	return fString2;
557 }
558 
559 
560 void
561 BCommitTransactionResult::SetString2(const BString& string)
562 {
563 	fString2 = string;
564 }
565 
566 
567 const BString&
568 BCommitTransactionResult::OldStateDirectory() const
569 {
570 	return fOldStateDirectory;
571 }
572 
573 
574 void
575 BCommitTransactionResult::SetOldStateDirectory(const BString& directory)
576 {
577 	fOldStateDirectory = directory;
578 }
579 
580 
581 status_t
582 BCommitTransactionResult::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 
612 status_t
613 BCommitTransactionResult::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 
651 BCommitTransactionResult&
652 BCommitTransactionResult::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