vfs: check userland buffers before reading them.
[haiku.git] / src / kits / package / DaemonClient.cpp
blob7a9ca039905b0afa48439656249237b4abba6fb5
1 /*
2 * Copyright 2013-2014, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold <ingo_weinhold@gmx.de>
7 */
10 #include <package/DaemonClient.h>
12 #include <time.h>
14 #include <Directory.h>
15 #include <Entry.h>
16 #include <package/CommitTransactionResult.h>
17 #include <package/InstallationLocationInfo.h>
18 #include <package/PackageInfo.h>
20 #include <package/ActivationTransaction.h>
21 #include <package/PackagesDirectoryDefs.h>
24 namespace BPackageKit {
25 namespace BPrivate {
28 BDaemonClient::BDaemonClient()
30 fDaemonMessenger()
35 BDaemonClient::~BDaemonClient()
40 status_t
41 BDaemonClient::GetInstallationLocationInfo(
42 BPackageInstallationLocation location, BInstallationLocationInfo& _info)
44 status_t error = _InitMessenger();
45 if (error != B_OK)
46 return error;
48 BMessage request(B_MESSAGE_GET_INSTALLATION_LOCATION_INFO);
49 error = request.AddInt32("location", location);
50 if (error != B_OK)
51 return error;
53 // Get our filesystem root node. If we are in a chroot this is not the same
54 // as the package_daemon root node, so we must provide it.
55 struct stat st;
56 if (stat("/boot", &st) == 0)
58 error = request.AddInt32("volume", st.st_dev);
59 if (error != B_OK)
60 return error;
61 error = request.AddInt64("root", st.st_ino);
62 if (error != B_OK)
63 return error;
66 // send the request
67 BMessage reply;
68 fDaemonMessenger.SendMessage(&request, &reply);
69 if (reply.what != B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY)
70 return B_ERROR;
72 // extract the location info
73 int32 baseDirectoryDevice;
74 int64 baseDirectoryNode;
75 int32 packagesDirectoryDevice;
76 int64 packagesDirectoryNode;
77 int64 changeCount;
78 BPackageInfoSet latestActivePackages;
79 BPackageInfoSet latestInactivePackages;
80 if ((error = reply.FindInt32("base directory device", &baseDirectoryDevice))
81 != B_OK
82 || (error = reply.FindInt64("base directory node", &baseDirectoryNode))
83 != B_OK
84 || (error = reply.FindInt32("packages directory device",
85 &packagesDirectoryDevice)) != B_OK
86 || (error = reply.FindInt64("packages directory node",
87 &packagesDirectoryNode)) != B_OK
88 || (error = _ExtractPackageInfoSet(reply, "latest active packages",
89 latestActivePackages)) != B_OK
90 || (error = _ExtractPackageInfoSet(reply, "latest inactive packages",
91 latestInactivePackages)) != B_OK
92 || (error = reply.FindInt64("change count", &changeCount)) != B_OK) {
93 return error;
96 BPackageInfoSet currentlyActivePackages;
97 error = _ExtractPackageInfoSet(reply, "currently active packages",
98 currentlyActivePackages);
99 if (error != B_OK && error != B_NAME_NOT_FOUND)
100 return error;
102 BString oldStateName;
103 error = reply.FindString("old state", &oldStateName);
104 if (error != B_OK && error != B_NAME_NOT_FOUND)
105 return error;
107 _info.Unset();
108 _info.SetLocation(location);
109 _info.SetBaseDirectoryRef(node_ref(baseDirectoryDevice, baseDirectoryNode));
110 _info.SetPackagesDirectoryRef(
111 node_ref(packagesDirectoryDevice, packagesDirectoryNode));
112 _info.SetLatestActivePackageInfos(latestActivePackages);
113 _info.SetLatestInactivePackageInfos(latestInactivePackages);
114 _info.SetCurrentlyActivePackageInfos(currentlyActivePackages);
115 _info.SetOldStateName(oldStateName);
116 _info.SetChangeCount(changeCount);
118 return B_OK;
122 status_t
123 BDaemonClient::CommitTransaction(const BActivationTransaction& transaction,
124 BCommitTransactionResult& _result)
126 if (transaction.InitCheck() != B_OK)
127 return B_BAD_VALUE;
129 status_t error = _InitMessenger();
130 if (error != B_OK)
131 return error;
133 // send the request
134 BMessage request(B_MESSAGE_COMMIT_TRANSACTION);
135 error = transaction.Archive(&request);
136 if (error != B_OK)
137 return error;
139 BMessage reply;
140 fDaemonMessenger.SendMessage(&request, &reply);
141 if (reply.what != B_MESSAGE_COMMIT_TRANSACTION_REPLY)
142 return B_ERROR;
144 // extract the result
145 return _result.ExtractFromMessage(reply);
149 status_t
150 BDaemonClient::CreateTransaction(BPackageInstallationLocation location,
151 BActivationTransaction& _transaction, BDirectory& _transactionDirectory)
153 // get an info for the location
154 BInstallationLocationInfo info;
155 status_t error = GetInstallationLocationInfo(location, info);
156 if (error != B_OK)
157 return error;
159 // open admin directory
160 entry_ref entryRef;
161 entryRef.device = info.PackagesDirectoryRef().device;
162 entryRef.directory = info.PackagesDirectoryRef().node;
163 error = entryRef.set_name(PACKAGES_DIRECTORY_ADMIN_DIRECTORY);
164 if (error != B_OK)
165 return error;
167 BDirectory adminDirectory;
168 error = adminDirectory.SetTo(&entryRef);
169 if (error != B_OK)
170 return error;
172 // create a transaction directory
173 int uniqueId = 1;
174 BString directoryName;
175 for (;; uniqueId++) {
176 directoryName.SetToFormat("transaction-%d", uniqueId);
177 if (directoryName.IsEmpty())
178 return B_NO_MEMORY;
180 error = adminDirectory.CreateDirectory(directoryName,
181 &_transactionDirectory);
182 if (error == B_OK)
183 break;
184 if (error != B_FILE_EXISTS)
185 return error;
188 // init the transaction
189 error = _transaction.SetTo(location, info.ChangeCount(), directoryName);
190 if (error != B_OK) {
191 BEntry entry;
192 _transactionDirectory.GetEntry(&entry);
193 _transactionDirectory.Unset();
194 if (entry.InitCheck() == B_OK)
195 entry.Remove();
196 return error;
199 return B_OK;
203 status_t
204 BDaemonClient::_InitMessenger()
206 if (fDaemonMessenger.IsValid())
207 return B_OK;
209 // get the package daemon's address
210 status_t error;
211 fDaemonMessenger = BMessenger(B_PACKAGE_DAEMON_APP_SIGNATURE, -1, &error);
212 return error;
216 status_t
217 BDaemonClient::_ExtractPackageInfoSet(const BMessage& message,
218 const char* field, BPackageInfoSet& _infos)
220 // get the number of items
221 type_code type;
222 int32 count;
223 if (message.GetInfo(field, &type, &count) != B_OK) {
224 // the field is missing
225 return B_OK;
227 if (type != B_MESSAGE_TYPE)
228 return B_BAD_DATA;
230 for (int32 i = 0; i < count; i++) {
231 BMessage archive;
232 status_t error = message.FindMessage(field, i, &archive);
233 if (error != B_OK)
234 return error;
236 BPackageInfo info(&archive, &error);
237 if (error != B_OK)
238 return error;
240 error = _infos.AddInfo(info);
241 if (error != B_OK)
242 return error;
245 return B_OK;
249 } // namespace BPrivate
250 } // namespace BPackageKit