1 /*
2 * Copyright 2011-2014, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Oliver Tappe <zooey@hirschkaefer.de>
7 */
8
9
10 #include <package/PackageRoster.h>
11
12 #include <errno.h>
13 #include <sys/stat.h>
14
15 #include <Directory.h>
16 #include <Entry.h>
17 #include <Messenger.h>
18 #include <Path.h>
19 #include <String.h>
20 #include <StringList.h>
21
22 #include <package/InstallationLocationInfo.h>
23 #include <package/PackageInfo.h>
24 #include <package/PackageInfoContentHandler.h>
25 #include <package/PackageInfoSet.h>
26 #include <package/RepositoryCache.h>
27 #include <package/RepositoryConfig.h>
28
29 #include <package/hpkg/PackageReader.h>
30
31
32 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
33 # include <package/DaemonClient.h>
34 # include <RegistrarDefs.h>
35 # include <RosterPrivate.h>
36 #endif
37
38
39 namespace BPackageKit {
40
41
42 using namespace BHPKG;
43
44
BPackageRoster()45 BPackageRoster::BPackageRoster()
46 {
47 }
48
49
~BPackageRoster()50 BPackageRoster::~BPackageRoster()
51 {
52 }
53
54
55 bool
IsRebootNeeded()56 BPackageRoster::IsRebootNeeded()
57 {
58 BInstallationLocationInfo info;
59
60 // We get information on the system package installation location.
61 // If we fail, we just have to assume a reboot is not needed.
62 if (GetInstallationLocationInfo(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM,
63 info) != B_OK)
64 return false;
65
66 // CurrentlyActivePackageInfos() will return 0 if no packages need to be
67 // activated with a reboot. Otherwise, the method will return the total
68 // number of packages in the system package directory.
69 if (info.CurrentlyActivePackageInfos().CountInfos() != 0)
70 return true;
71
72 return false;
73 }
74
75
76 status_t
GetCommonRepositoryConfigPath(BPath * path,bool create) const77 BPackageRoster::GetCommonRepositoryConfigPath(BPath* path, bool create) const
78 {
79 return _GetRepositoryPath(path, create, B_SYSTEM_SETTINGS_DIRECTORY);
80 }
81
82
83 status_t
GetUserRepositoryConfigPath(BPath * path,bool create) const84 BPackageRoster::GetUserRepositoryConfigPath(BPath* path, bool create) const
85 {
86 return _GetRepositoryPath(path, create, B_USER_SETTINGS_DIRECTORY);
87 }
88
89
90 status_t
GetCommonRepositoryCachePath(BPath * path,bool create) const91 BPackageRoster::GetCommonRepositoryCachePath(BPath* path, bool create) const
92 {
93 return _GetRepositoryPath(path, create, B_SYSTEM_CACHE_DIRECTORY);
94 }
95
96
97 status_t
GetUserRepositoryCachePath(BPath * path,bool create) const98 BPackageRoster::GetUserRepositoryCachePath(BPath* path, bool create) const
99 {
100 return _GetRepositoryPath(path, create, B_USER_CACHE_DIRECTORY);
101 }
102
103
104 status_t
VisitCommonRepositoryConfigs(BRepositoryConfigVisitor & visitor)105 BPackageRoster::VisitCommonRepositoryConfigs(BRepositoryConfigVisitor& visitor)
106 {
107 BPath commonRepositoryConfigPath;
108 status_t result
109 = GetCommonRepositoryConfigPath(&commonRepositoryConfigPath);
110 if (result != B_OK)
111 return result;
112
113 return _VisitRepositoryConfigs(commonRepositoryConfigPath, visitor);
114 }
115
116
117 status_t
VisitUserRepositoryConfigs(BRepositoryConfigVisitor & visitor)118 BPackageRoster::VisitUserRepositoryConfigs(BRepositoryConfigVisitor& visitor)
119 {
120 BPath userRepositoryConfigPath;
121 status_t result = GetUserRepositoryConfigPath(&userRepositoryConfigPath);
122 if (result != B_OK)
123 return result;
124
125 return _VisitRepositoryConfigs(userRepositoryConfigPath, visitor);
126 }
127
128
129 status_t
GetRepositoryNames(BStringList & names)130 BPackageRoster::GetRepositoryNames(BStringList& names)
131 {
132 struct RepositoryNameCollector : public BRepositoryConfigVisitor {
133 RepositoryNameCollector(BStringList& _names)
134 : names(_names)
135 {
136 }
137 status_t operator()(const BEntry& entry)
138 {
139 char name[B_FILE_NAME_LENGTH];
140 status_t result = entry.GetName(name);
141 if (result != B_OK)
142 return result;
143 int32 count = names.CountStrings();
144 for (int i = 0; i < count; ++i) {
145 if (names.StringAt(i).Compare(name) == 0)
146 return B_OK;
147 }
148 names.Add(name);
149 return B_OK;
150 }
151 BStringList& names;
152 };
153 RepositoryNameCollector repositoryNameCollector(names);
154 status_t result = VisitUserRepositoryConfigs(repositoryNameCollector);
155 if (result != B_OK)
156 return result;
157
158 return VisitCommonRepositoryConfigs(repositoryNameCollector);
159 }
160
161
162 status_t
GetRepositoryCache(const BString & name,BRepositoryCache * repositoryCache)163 BPackageRoster::GetRepositoryCache(const BString& name,
164 BRepositoryCache* repositoryCache)
165 {
166 if (repositoryCache == NULL)
167 return B_BAD_VALUE;
168
169 // user path has higher precedence than common path
170 BPath path;
171 status_t result = GetUserRepositoryCachePath(&path);
172 if (result != B_OK)
173 return result;
174 path.Append(name.String());
175
176 BEntry repoCacheEntry(path.Path());
177 if (repoCacheEntry.Exists())
178 return repositoryCache->SetTo(repoCacheEntry);
179
180 if ((result = GetCommonRepositoryCachePath(&path, true)) != B_OK)
181 return result;
182 path.Append(name.String());
183
184 result = repoCacheEntry.SetTo(path.Path());
185 if (result != B_OK)
186 return result;
187 return repositoryCache->SetTo(repoCacheEntry);
188 }
189
190
191 status_t
GetRepositoryConfig(const BString & name,BRepositoryConfig * repositoryConfig)192 BPackageRoster::GetRepositoryConfig(const BString& name,
193 BRepositoryConfig* repositoryConfig)
194 {
195 if (repositoryConfig == NULL)
196 return B_BAD_VALUE;
197
198 // user path has higher precedence than common path
199 BPath path;
200 status_t result = GetUserRepositoryConfigPath(&path);
201 if (result != B_OK)
202 return result;
203 path.Append(name.String());
204
205 BEntry repoConfigEntry(path.Path());
206 if (repoConfigEntry.Exists())
207 return repositoryConfig->SetTo(repoConfigEntry);
208
209 if ((result = GetCommonRepositoryConfigPath(&path, true)) != B_OK)
210 return result;
211 path.Append(name.String());
212
213 result = repoConfigEntry.SetTo(path.Path());
214 if (result != B_OK)
215 return result;
216 return repositoryConfig->SetTo(repoConfigEntry);
217 }
218
219
220 status_t
GetInstallationLocationInfo(BPackageInstallationLocation location,BInstallationLocationInfo & _info)221 BPackageRoster::GetInstallationLocationInfo(
222 BPackageInstallationLocation location, BInstallationLocationInfo& _info)
223 {
224 // This method makes sense only on an installed Haiku, but not for the build
225 // tools.
226 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
227 return BPackageKit::BPrivate::BDaemonClient().GetInstallationLocationInfo(
228 location, _info);
229 #else
230 return B_NOT_SUPPORTED;
231 #endif
232 }
233
234
235 status_t
GetActivePackages(BPackageInstallationLocation location,BPackageInfoSet & packageInfos)236 BPackageRoster::GetActivePackages(BPackageInstallationLocation location,
237 BPackageInfoSet& packageInfos)
238 {
239 // This method makes sense only on an installed Haiku, but not for the build
240 // tools.
241 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
242 BInstallationLocationInfo info;
243 status_t error = GetInstallationLocationInfo(location, info);
244 if (error != B_OK)
245 return error;
246
247 packageInfos = info.LatestActivePackageInfos();
248 return B_OK;
249 #else
250 return B_NOT_SUPPORTED;
251 #endif
252 }
253
254
255 status_t
IsPackageActive(BPackageInstallationLocation location,const BPackageInfo info,bool * active)256 BPackageRoster::IsPackageActive(BPackageInstallationLocation location,
257 const BPackageInfo info, bool* active)
258 {
259 // This method makes sense only on an installed Haiku, but not for the build
260 // tools.
261 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
262 BPackageInfoSet packageInfos;
263 status_t error = GetActivePackages(location, packageInfos);
264 if (error != B_OK)
265 return error;
266
267 BRepositoryCache::Iterator it = packageInfos.GetIterator();
268 while (const BPackageInfo* packageInfo = it.Next()) {
269 if (info.Name() == packageInfo->Name() &&
270 info.Version().Compare(packageInfo->Version()) == 0) {
271 *active = true;
272 break;
273 }
274 }
275
276 return B_OK;
277 #else
278 return B_NOT_SUPPORTED;
279 #endif
280 }
281
282
283 status_t
StartWatching(const BMessenger & target,uint32 eventMask)284 BPackageRoster::StartWatching(const BMessenger& target, uint32 eventMask)
285 {
286 // This method makes sense only on an installed Haiku, but not for the build
287 // tools.
288 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
289 // compose the registrar request
290 BMessage request(::BPrivate::B_REG_PACKAGE_START_WATCHING);
291 status_t error;
292 if ((error = request.AddMessenger("target", target)) != B_OK
293 || (error = request.AddUInt32("events", eventMask)) != B_OK) {
294 return error;
295 }
296
297 // send it
298 BMessage reply;
299 error = BRoster::Private().SendTo(&request, &reply, false);
300 if (error != B_OK)
301 return error;
302
303 // get result
304 if (reply.what != ::BPrivate::B_REG_SUCCESS) {
305 int32 result;
306 if (reply.FindInt32("error", &result) != B_OK)
307 result = B_ERROR;
308 return (status_t)error;
309 }
310
311 return B_OK;
312 #else
313 return B_NOT_SUPPORTED;
314 #endif
315 }
316
317
318 status_t
StopWatching(const BMessenger & target)319 BPackageRoster::StopWatching(const BMessenger& target)
320 {
321 // This method makes sense only on an installed Haiku, but not for the build
322 // tools.
323 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
324 // compose the registrar request
325 BMessage request(::BPrivate::B_REG_PACKAGE_STOP_WATCHING);
326 status_t error = request.AddMessenger("target", target);
327 if (error != B_OK)
328 return error;
329
330 // send it
331 BMessage reply;
332 error = BRoster::Private().SendTo(&request, &reply, false);
333 if (error != B_OK)
334 return error;
335
336 // get result
337 if (reply.what != ::BPrivate::B_REG_SUCCESS) {
338 int32 result;
339 if (reply.FindInt32("error", &result) != B_OK)
340 result = B_ERROR;
341 return (status_t)error;
342 }
343
344 return B_OK;
345 #else
346 return B_NOT_SUPPORTED;
347 #endif
348 }
349
350
351 status_t
_GetRepositoryPath(BPath * path,bool create,directory_which whichDir) const352 BPackageRoster::_GetRepositoryPath(BPath* path, bool create,
353 directory_which whichDir) const
354 {
355 if (path == NULL)
356 return B_BAD_VALUE;
357
358 status_t result = find_directory(whichDir, path);
359 if (result != B_OK)
360 return result;
361 if ((result = path->Append("package-repositories")) != B_OK)
362 return result;
363
364 if (create) {
365 BEntry entry(path->Path(), true);
366 if (!entry.Exists()) {
367 if (mkdir(path->Path(), 0755) != 0)
368 return errno;
369 }
370 }
371
372 return B_OK;
373 }
374
375
376 status_t
_VisitRepositoryConfigs(const BPath & path,BRepositoryConfigVisitor & visitor)377 BPackageRoster::_VisitRepositoryConfigs(const BPath& path,
378 BRepositoryConfigVisitor& visitor)
379 {
380 BDirectory directory(path.Path());
381 status_t result = directory.InitCheck();
382 if (result == B_ENTRY_NOT_FOUND)
383 return B_OK;
384 if (result != B_OK)
385 return result;
386
387 BEntry entry;
388 while (directory.GetNextEntry(&entry, true) == B_OK) {
389 if ((result = visitor(entry)) != B_OK)
390 return result;
391 }
392
393 return B_OK;
394 }
395
396
397 } // namespace BPackageKit
398