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 { 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; 64 } 65 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; 71 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; 94 } 95 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; 101 102 BString oldStateName; 103 error = reply.FindString("old state", &oldStateName); 104 if (error != B_OK && error != B_NAME_NOT_FOUND) 105 return error; 106 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); 117 118 return B_OK; 119 } 120 121 122 status_t 123 BDaemonClient::CommitTransaction(const BActivationTransaction& transaction, 124 BCommitTransactionResult& _result) 125 { 126 if (transaction.InitCheck() != B_OK) 127 return B_BAD_VALUE; 128 129 status_t error = _InitMessenger(); 130 if (error != B_OK) 131 return error; 132 133 // send the request 134 BMessage request(B_MESSAGE_COMMIT_TRANSACTION); 135 error = transaction.Archive(&request); 136 if (error != B_OK) 137 return error; 138 139 BMessage reply; 140 fDaemonMessenger.SendMessage(&request, &reply); 141 if (reply.what != B_MESSAGE_COMMIT_TRANSACTION_REPLY) 142 return B_ERROR; 143 144 // extract the result 145 return _result.ExtractFromMessage(reply); 146 } 147 148 149 status_t 150 BDaemonClient::CreateTransaction(BPackageInstallationLocation location, 151 BActivationTransaction& _transaction, BDirectory& _transactionDirectory) 152 { 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; 158 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; 166 167 BDirectory adminDirectory; 168 error = adminDirectory.SetTo(&entryRef); 169 if (error != B_OK) 170 return error; 171 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; 179 180 error = adminDirectory.CreateDirectory(directoryName, 181 &_transactionDirectory); 182 if (error == B_OK) 183 break; 184 if (error != B_FILE_EXISTS) 185 return error; 186 } 187 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; 197 } 198 199 return B_OK; 200 } 201 202 203 status_t 204 BDaemonClient::_InitMessenger() 205 { 206 if (fDaemonMessenger.IsValid()) 207 return B_OK; 208 209 // get the package daemon's address 210 status_t error; 211 fDaemonMessenger = BMessenger(B_PACKAGE_DAEMON_APP_SIGNATURE, -1, &error); 212 return error; 213 } 214 215 216 status_t 217 BDaemonClient::_ExtractPackageInfoSet(const BMessage& message, 218 const char* field, BPackageInfoSet& _infos) 219 { 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; 226 } 227 if (type != B_MESSAGE_TYPE) 228 return B_BAD_DATA; 229 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; 235 236 BPackageInfo info(&archive, &error); 237 if (error != B_OK) 238 return error; 239 240 error = _infos.AddInfo(info); 241 if (error != B_OK) 242 return error; 243 } 244 245 return B_OK; 246 } 247 248 249 } // namespace BPrivate 250 } // namespace BPackageKit 251