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