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