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