xref: /haiku/src/kits/package/PackageRoster.cpp (revision 9e15c9f153c5ffff9ad51b95b581326eb579b0fd)
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 
45 BPackageRoster::BPackageRoster()
46 {
47 }
48 
49 
50 BPackageRoster::~BPackageRoster()
51 {
52 }
53 
54 
55 bool
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
77 BPackageRoster::GetCommonRepositoryConfigPath(BPath* path, bool create) const
78 {
79 	return _GetRepositoryPath(path, create, B_SYSTEM_SETTINGS_DIRECTORY);
80 }
81 
82 
83 status_t
84 BPackageRoster::GetUserRepositoryConfigPath(BPath* path, bool create) const
85 {
86 	return _GetRepositoryPath(path, create, B_USER_SETTINGS_DIRECTORY);
87 }
88 
89 
90 status_t
91 BPackageRoster::GetCommonRepositoryCachePath(BPath* path, bool create) const
92 {
93 	return _GetRepositoryPath(path, create, B_SYSTEM_CACHE_DIRECTORY);
94 }
95 
96 
97 status_t
98 BPackageRoster::GetUserRepositoryCachePath(BPath* path, bool create) const
99 {
100 	return _GetRepositoryPath(path, create, B_USER_CACHE_DIRECTORY);
101 }
102 
103 
104 status_t
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
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
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
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
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
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
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
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
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
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
352 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
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