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 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 121 status_t 122 BDaemonClient::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 148 status_t 149 BDaemonClient::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 202 status_t 203 BDaemonClient::_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 215 status_t 216 BDaemonClient::_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