xref: /haiku/src/kits/package/DaemonClient.cpp (revision a5a3b2d9a3d95cbae71eaf371708c73a1780ac0d)
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/DaemonClient.h>
11 
12 #include <time.h>
13 
14 #include <Directory.h>
15 #include <Entry.h>
16 #include <package/CommitTransactionResult.h>
17 #include <package/InstallationLocationInfo.h>
18 #include <package/PackageInfo.h>
19 
20 #include <package/ActivationTransaction.h>
21 #include <package/PackagesDirectoryDefs.h>
22 
23 
24 namespace BPackageKit {
25 namespace BPrivate {
26 
27 
28 BDaemonClient::BDaemonClient()
29 	:
30 	fDaemonMessenger()
31 {
32 }
33 
34 
35 BDaemonClient::~BDaemonClient()
36 {
37 }
38 
39 
40 status_t
41 BDaemonClient::GetInstallationLocationInfo(
42 	BPackageInstallationLocation location, BInstallationLocationInfo& _info)
43 {
44 	status_t error = _InitMessenger();
45 	if (error != B_OK)
46 		return error;
47 
48 	// send the request
49 	BMessage request(B_MESSAGE_GET_INSTALLATION_LOCATION_INFO);
50 	error = request.AddInt32("location", location);
51 	if (error != B_OK)
52 		return error;
53 
54 	BMessage reply;
55 	fDaemonMessenger.SendMessage(&request, &reply);
56 	if (reply.what != B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY)
57 		return B_ERROR;
58 
59 	// extract the location info
60 	int32 baseDirectoryDevice;
61 	int64 baseDirectoryNode;
62 	int32 packagesDirectoryDevice;
63 	int64 packagesDirectoryNode;
64 	int64 changeCount;
65 	BPackageInfoSet latestActivePackages;
66 	BPackageInfoSet latestInactivePackages;
67 	if ((error = reply.FindInt32("base directory device", &baseDirectoryDevice))
68 			!= B_OK
69 		|| (error = reply.FindInt64("base directory node", &baseDirectoryNode))
70 			!= B_OK
71 		|| (error = reply.FindInt32("packages directory device",
72 			&packagesDirectoryDevice)) != B_OK
73 		|| (error = reply.FindInt64("packages directory node",
74 			&packagesDirectoryNode)) != B_OK
75 		|| (error = _ExtractPackageInfoSet(reply, "latest active packages",
76 			latestActivePackages)) != B_OK
77 		|| (error = _ExtractPackageInfoSet(reply, "latest inactive packages",
78 			latestInactivePackages)) != B_OK
79 		|| (error = reply.FindInt64("change count", &changeCount)) != B_OK) {
80 		return error;
81 	}
82 
83 	BPackageInfoSet currentlyActivePackages;
84 	error = _ExtractPackageInfoSet(reply, "currently active packages",
85 		currentlyActivePackages);
86 	if (error != B_OK && error != B_NAME_NOT_FOUND)
87 		return error;
88 
89 	BString oldStateName;
90 	error = reply.FindString("old state", &oldStateName);
91 	if (error != B_OK && error != B_NAME_NOT_FOUND)
92 		return error;
93 
94 	_info.Unset();
95 	_info.SetLocation(location);
96 	_info.SetBaseDirectoryRef(node_ref(baseDirectoryDevice, baseDirectoryNode));
97 	_info.SetPackagesDirectoryRef(
98 		node_ref(packagesDirectoryDevice, packagesDirectoryNode));
99 	_info.SetLatestActivePackageInfos(latestActivePackages);
100 	_info.SetLatestInactivePackageInfos(latestInactivePackages);
101 	_info.SetCurrentlyActivePackageInfos(currentlyActivePackages);
102 	_info.SetOldStateName(oldStateName);
103 	_info.SetChangeCount(changeCount);
104 
105 	return B_OK;
106 }
107 
108 
109 status_t
110 BDaemonClient::CommitTransaction(const BActivationTransaction& transaction,
111 	BCommitTransactionResult& _result)
112 {
113 	if (transaction.InitCheck() != B_OK)
114 		return B_BAD_VALUE;
115 
116 	status_t error = _InitMessenger();
117 	if (error != B_OK)
118 		return error;
119 
120 	// send the request
121 	BMessage request(B_MESSAGE_COMMIT_TRANSACTION);
122 	error = transaction.Archive(&request);
123 	if (error != B_OK)
124 		return error;
125 
126 	BMessage reply;
127 	fDaemonMessenger.SendMessage(&request, &reply);
128 	if (reply.what != B_MESSAGE_COMMIT_TRANSACTION_REPLY)
129 		return B_ERROR;
130 
131 	// extract the result
132 	return _result.ExtractFromMessage(reply);
133 }
134 
135 
136 status_t
137 BDaemonClient::CreateTransaction(BPackageInstallationLocation location,
138 	BActivationTransaction& _transaction, BDirectory& _transactionDirectory)
139 {
140 	// get an info for the location
141 	BInstallationLocationInfo info;
142 	status_t error = GetInstallationLocationInfo(location, info);
143 	if (error != B_OK)
144 		return error;
145 
146 	// open admin directory
147 	entry_ref entryRef;
148 	entryRef.device = info.PackagesDirectoryRef().device;
149 	entryRef.directory = info.PackagesDirectoryRef().node;
150 	error = entryRef.set_name(PACKAGES_DIRECTORY_ADMIN_DIRECTORY);
151 	if (error != B_OK)
152 		return error;
153 
154 	BDirectory adminDirectory;
155 	error = adminDirectory.SetTo(&entryRef);
156 	if (error != B_OK)
157 		return error;
158 
159 	// create a transaction directory
160 	int uniqueId = 1;
161 	BString directoryName;
162 	for (;; uniqueId++) {
163 		directoryName.SetToFormat("transaction-%d", uniqueId);
164 		if (directoryName.IsEmpty())
165 			return B_NO_MEMORY;
166 
167 		error = adminDirectory.CreateDirectory(directoryName,
168 			&_transactionDirectory);
169 		if (error == B_OK)
170 			break;
171 		if (error != B_FILE_EXISTS)
172 			return error;
173 	}
174 
175 	// init the transaction
176 	error = _transaction.SetTo(location, info.ChangeCount(), directoryName);
177 	if (error != B_OK) {
178 		BEntry entry;
179 		_transactionDirectory.GetEntry(&entry);
180 		_transactionDirectory.Unset();
181 		if (entry.InitCheck() == B_OK)
182 			entry.Remove();
183 		return error;
184 	}
185 
186 	return B_OK;
187 }
188 
189 
190 status_t
191 BDaemonClient::_InitMessenger()
192 {
193 	if (fDaemonMessenger.IsValid())
194 		return B_OK;
195 
196 		// get the package daemon's address
197 	status_t error;
198 	fDaemonMessenger = BMessenger(B_PACKAGE_DAEMON_APP_SIGNATURE, -1, &error);
199 	return error;
200 }
201 
202 
203 status_t
204 BDaemonClient::_ExtractPackageInfoSet(const BMessage& message,
205 	const char* field, BPackageInfoSet& _infos)
206 {
207 	// get the number of items
208 	type_code type;
209 	int32 count;
210 	if (message.GetInfo(field, &type, &count) != B_OK) {
211 		// the field is missing
212 		return B_OK;
213 	}
214 	if (type != B_MESSAGE_TYPE)
215 		return B_BAD_DATA;
216 
217 	for (int32 i = 0; i < count; i++) {
218 		BMessage archive;
219 		status_t error = message.FindMessage(field, i, &archive);
220 		if (error != B_OK)
221 			return error;
222 
223 		BPackageInfo info(&archive, &error);
224 		if (error != B_OK)
225 			return error;
226 
227 		error = _infos.AddInfo(info);
228 		if (error != B_OK)
229 			return error;
230 	}
231 
232 	return B_OK;
233 }
234 
235 
236 }	// namespace BPrivate
237 }	// namespace BPackageKit
238