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