xref: /haiku/src/kits/package/solver/libsolv/LibsolvSolver.cpp (revision 36aafa560b2cf96aa39cc753c6dec7f54431d564)
1 /*
2  * Copyright 2013, 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 "LibsolvSolver.h"
11 
12 #include <errno.h>
13 #include <sys/utsname.h>
14 
15 #include <new>
16 
17 #include <solv/policy.h>
18 #include <solv/poolarch.h>
19 #include <solv/repo.h>
20 #include <solv/repo_haiku.h>
21 #include <solv/selection.h>
22 #include <solv/solverdebug.h>
23 
24 #include <package/PackageResolvableExpression.h>
25 #include <package/RepositoryCache.h>
26 #include <package/solver/SolverPackage.h>
27 #include <package/solver/SolverPackageSpecifier.h>
28 #include <package/solver/SolverPackageSpecifierList.h>
29 #include <package/solver/SolverProblem.h>
30 #include <package/solver/SolverRepository.h>
31 #include <package/solver/SolverResult.h>
32 
33 #include <AutoDeleter.h>
34 #include <ObjectList.h>
35 
36 
37 // TODO: libsolv doesn't have any helpful out-of-memory handling. It just just
38 // abort()s. Obviously that isn't good behavior for a library.
39 
40 
41 BSolver*
create_solver()42 BPackageKit::create_solver()
43 {
44 	return new(std::nothrow) LibsolvSolver;
45 }
46 
47 
48 struct LibsolvSolver::SolvQueue : Queue {
SolvQueueLibsolvSolver::SolvQueue49 	SolvQueue()
50 	{
51 		queue_init(this);
52 	}
53 
~SolvQueueLibsolvSolver::SolvQueue54 	~SolvQueue()
55 	{
56 		queue_free(this);
57 	}
58 };
59 
60 
61 struct LibsolvSolver::SolvDataIterator : Dataiterator {
SolvDataIteratorLibsolvSolver::SolvDataIterator62 	SolvDataIterator(Pool* pool, Repo* repo, Id solvableId, Id keyname,
63 		const char* match, int flags)
64 	{
65 		dataiterator_init(this, pool, repo, solvableId, keyname, match, flags);
66 	}
67 
~SolvDataIteratorLibsolvSolver::SolvDataIterator68 	~SolvDataIterator()
69 	{
70 		dataiterator_free(this);
71 	}
72 };
73 
74 
75 struct LibsolvSolver::RepositoryInfo {
RepositoryInfoLibsolvSolver::RepositoryInfo76 	RepositoryInfo(BSolverRepository* repository)
77 		:
78 		fRepository(repository),
79 		fSolvRepo(NULL),
80 		fChangeCount(repository->ChangeCount())
81 	{
82 	}
83 
RepositoryLibsolvSolver::RepositoryInfo84 	BSolverRepository* Repository() const
85 	{
86 		return fRepository;
87 	}
88 
SolvRepoLibsolvSolver::RepositoryInfo89 	Repo* SolvRepo()
90 	{
91 		return fSolvRepo;
92 	}
93 
SetSolvRepoLibsolvSolver::RepositoryInfo94 	void SetSolvRepo(Repo* repo)
95 	{
96 		fSolvRepo = repo;
97 	}
98 
HasChangedLibsolvSolver::RepositoryInfo99 	bool HasChanged() const
100 	{
101 		return fChangeCount != fRepository->ChangeCount() || fSolvRepo == NULL;
102 	}
103 
SetUnchangedLibsolvSolver::RepositoryInfo104 	void SetUnchanged()
105 	{
106 		fChangeCount = fRepository->ChangeCount();
107 	}
108 
109 private:
110 	BSolverRepository*	fRepository;
111 	Repo*				fSolvRepo;
112 	uint64				fChangeCount;
113 };
114 
115 
116 struct LibsolvSolver::Problem : public BSolverProblem {
ProblemLibsolvSolver::Problem117 	Problem(::Id id, BType type, BSolverPackage* sourcePackage,
118 		BSolverPackage* targetPackage,
119 		const BPackageResolvableExpression& dependency)
120 		:
121 		BSolverProblem(type, sourcePackage, targetPackage, dependency),
122 		fId(id),
123 		fSelectedSolution(NULL)
124 	{
125 	}
126 
IdLibsolvSolver::Problem127 	::Id Id() const
128 	{
129 		return fId;
130 	}
131 
SelectedSolutionLibsolvSolver::Problem132 	const Solution* SelectedSolution() const
133 	{
134 		return fSelectedSolution;
135 	}
136 
SetSelectedSolutionLibsolvSolver::Problem137 	void SetSelectedSolution(const Solution* solution)
138 	{
139 		fSelectedSolution = solution;
140 	}
141 
142 private:
143 	::Id			fId;
144 	const Solution*	fSelectedSolution;
145 };
146 
147 
148 struct LibsolvSolver::Solution : public BSolverProblemSolution {
SolutionLibsolvSolver::Solution149 	Solution(::Id id, LibsolvSolver::Problem* problem)
150 		:
151 		BSolverProblemSolution(),
152 		fId(id),
153 		fProblem(problem)
154 	{
155 	}
156 
IdLibsolvSolver::Solution157 	::Id Id() const
158 	{
159 		return fId;
160 	}
161 
ProblemLibsolvSolver::Solution162 	LibsolvSolver::Problem* Problem() const
163 	{
164 		return fProblem;
165 	}
166 
167 private:
168 	::Id					fId;
169 	LibsolvSolver::Problem*	fProblem;
170 };
171 
172 
173 // #pragma mark - LibsolvSolver
174 
175 
LibsolvSolver()176 LibsolvSolver::LibsolvSolver()
177 	:
178 	fPool(NULL),
179 	fSolver(NULL),
180 	fJobs(NULL),
181 	fRepositoryInfos(10, true),
182 	fInstalledRepository(NULL),
183 	fSolvablePackages(),
184 	fPackageSolvables(),
185 	fProblems(10, true),
186 	fDebugLevel(0)
187 {
188 }
189 
190 
~LibsolvSolver()191 LibsolvSolver::~LibsolvSolver()
192 {
193 	_Cleanup();
194 }
195 
196 
197 status_t
Init()198 LibsolvSolver::Init()
199 {
200 	_Cleanup();
201 
202 	// We do all initialization lazily.
203 	return B_OK;
204 }
205 
206 
207 void
SetDebugLevel(int32 level)208 LibsolvSolver::SetDebugLevel(int32 level)
209 {
210 	fDebugLevel = level;
211 
212 	if (fPool != NULL)
213 		pool_setdebuglevel(fPool, fDebugLevel);
214 }
215 
216 
217 status_t
AddRepository(BSolverRepository * repository)218 LibsolvSolver::AddRepository(BSolverRepository* repository)
219 {
220 	if (repository == NULL || repository->InitCheck() != B_OK)
221 		return B_BAD_VALUE;
222 
223 	// If the repository represents installed packages, check, if we already
224 	// have such a repository.
225 	if (repository->IsInstalled() && _InstalledRepository() != NULL)
226 		return B_BAD_VALUE;
227 
228 	// add the repository info
229 	RepositoryInfo* info = new(std::nothrow) RepositoryInfo(repository);
230 	if (info == NULL)
231 		return B_NO_MEMORY;
232 
233 	if (!fRepositoryInfos.AddItem(info)) {
234 		delete info;
235 		return B_NO_MEMORY;
236 	}
237 
238 	return B_OK;
239 }
240 
241 
242 status_t
FindPackages(const char * searchString,uint32 flags,BObjectList<BSolverPackage> & _packages)243 LibsolvSolver::FindPackages(const char* searchString, uint32 flags,
244 	BObjectList<BSolverPackage>& _packages)
245 {
246 	// add repositories to pool
247 	status_t error = _AddRepositories();
248 	if (error != B_OK)
249 		return error;
250 
251 	// create data iterator
252 	int iteratorFlags = SEARCH_SUBSTRING;
253 	if ((flags & B_FIND_CASE_INSENSITIVE) != 0)
254 		iteratorFlags |= SEARCH_NOCASE;
255 
256 	SolvDataIterator iterator(fPool, 0, 0, 0, searchString, iteratorFlags);
257 	SolvQueue selection;
258 
259 	// search package names
260 	if ((flags & B_FIND_IN_NAME) != 0) {
261 		dataiterator_set_keyname(&iterator, SOLVABLE_NAME);
262 		dataiterator_set_search(&iterator, 0, 0);
263 
264 		while (dataiterator_step(&iterator))
265 			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
266 	}
267 
268 	// search package summaries
269 	if ((flags & B_FIND_IN_SUMMARY) != 0) {
270 		dataiterator_set_keyname(&iterator, SOLVABLE_SUMMARY);
271 		dataiterator_set_search(&iterator, 0, 0);
272 
273 		while (dataiterator_step(&iterator))
274 			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
275 	}
276 
277 	// search package description
278 	if ((flags & B_FIND_IN_DESCRIPTION) != 0) {
279 		dataiterator_set_keyname(&iterator, SOLVABLE_DESCRIPTION);
280 		dataiterator_set_search(&iterator, 0, 0);
281 
282 		while (dataiterator_step(&iterator))
283 			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
284 	}
285 
286 	// search package provides
287 	if ((flags & B_FIND_IN_PROVIDES) != 0) {
288 		dataiterator_set_keyname(&iterator, SOLVABLE_PROVIDES);
289 		dataiterator_set_search(&iterator, 0, 0);
290 
291 		while (dataiterator_step(&iterator))
292 			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
293 	}
294 
295 	// search package requires
296 	if ((flags & B_FIND_IN_REQUIRES) != 0) {
297 		dataiterator_set_keyname(&iterator, SOLVABLE_REQUIRES);
298 		dataiterator_set_search(&iterator, 0, 0);
299 
300 		while (dataiterator_step(&iterator))
301 			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
302 	}
303 
304 	return _GetFoundPackages(selection, flags, _packages);
305 }
306 
307 
308 status_t
FindPackages(const BSolverPackageSpecifierList & packages,uint32 flags,BObjectList<BSolverPackage> & _packages,const BSolverPackageSpecifier ** _unmatched)309 LibsolvSolver::FindPackages(const BSolverPackageSpecifierList& packages,
310 	uint32 flags, BObjectList<BSolverPackage>& _packages,
311 	const BSolverPackageSpecifier** _unmatched)
312 {
313 	if (_unmatched != NULL)
314 		*_unmatched = NULL;
315 
316 	if ((flags & B_FIND_INSTALLED_ONLY) != 0 && _InstalledRepository() == NULL)
317 		return B_BAD_VALUE;
318 
319 	// add repositories to pool
320 	status_t error = _AddRepositories();
321 	if (error != B_OK)
322 		return error;
323 
324 	error = _InitJobQueue();
325 	if (error != B_OK)
326 		return error;
327 
328 	// add the package specifies to the job queue
329 	error = _AddSpecifiedPackages(packages, _unmatched,
330 		(flags & B_FIND_INSTALLED_ONLY) != 0 ? SELECTION_INSTALLED_ONLY : 0);
331 	if (error != B_OK)
332 		return error;
333 
334 	return _GetFoundPackages(*fJobs, flags, _packages);
335 }
336 
337 
338 status_t
Install(const BSolverPackageSpecifierList & packages,const BSolverPackageSpecifier ** _unmatched)339 LibsolvSolver::Install(const BSolverPackageSpecifierList& packages,
340 	const BSolverPackageSpecifier** _unmatched)
341 {
342 	if (_unmatched != NULL)
343 		*_unmatched = NULL;
344 
345 	if (packages.IsEmpty())
346 		return B_BAD_VALUE;
347 
348 	// add repositories to pool
349 	status_t error = _AddRepositories();
350 	if (error != B_OK)
351 		return error;
352 
353 	// add the packages to install to the job queue
354 	error = _InitJobQueue();
355 	if (error != B_OK)
356 		return error;
357 
358 	error = _AddSpecifiedPackages(packages, _unmatched, 0);
359 	if (error != B_OK)
360 		return error;
361 
362 	// set jobs' solver mode and solve
363 	_SetJobsSolverMode(SOLVER_INSTALL);
364 
365 	_InitSolver();
366 	return _Solve();
367 }
368 
369 
370 status_t
Uninstall(const BSolverPackageSpecifierList & packages,const BSolverPackageSpecifier ** _unmatched)371 LibsolvSolver::Uninstall(const BSolverPackageSpecifierList& packages,
372 	const BSolverPackageSpecifier** _unmatched)
373 {
374 	if (_unmatched != NULL)
375 		*_unmatched = NULL;
376 
377 	if (_InstalledRepository() == NULL || packages.IsEmpty())
378 		return B_BAD_VALUE;
379 
380 	// add repositories to pool
381 	status_t error = _AddRepositories();
382 	if (error != B_OK)
383 		return error;
384 
385 	// add the packages to uninstall to the job queue
386 	error = _InitJobQueue();
387 	if (error != B_OK)
388 		return error;
389 
390 	error = _AddSpecifiedPackages(packages, _unmatched,
391 		SELECTION_INSTALLED_ONLY);
392 	if (error != B_OK)
393 		return error;
394 
395 	// set jobs' solver mode and solve
396 	_SetJobsSolverMode(SOLVER_ERASE);
397 
398 	_InitSolver();
399 	solver_set_flag(fSolver, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
400 	return _Solve();
401 }
402 
403 
404 status_t
Update(const BSolverPackageSpecifierList & packages,bool installNotYetInstalled,const BSolverPackageSpecifier ** _unmatched)405 LibsolvSolver::Update(const BSolverPackageSpecifierList& packages,
406 	bool installNotYetInstalled, const BSolverPackageSpecifier** _unmatched)
407 {
408 	if (_unmatched != NULL)
409 		*_unmatched = NULL;
410 
411 	// add repositories to pool
412 	status_t error = _AddRepositories();
413 	if (error != B_OK)
414 		return error;
415 
416 	// add the packages to update to the job queue -- if none are specified,
417 	// update all
418 	error = _InitJobQueue();
419 	if (error != B_OK)
420 		return error;
421 
422 	if (packages.IsEmpty()) {
423 		queue_push2(fJobs, SOLVER_SOLVABLE_ALL, 0);
424 	} else {
425 		error = _AddSpecifiedPackages(packages, _unmatched, 0);
426 		if (error != B_OK)
427 			return error;
428 	}
429 
430 	// set jobs' solver mode and solve
431 	_SetJobsSolverMode(SOLVER_UPDATE);
432 
433 	if (installNotYetInstalled) {
434 		for (int i = 0; i < fJobs->count; i += 2) {
435 			// change solver mode to SOLVER_INSTALL for empty update jobs
436 			if (pool_isemptyupdatejob(fPool, fJobs->elements[i],
437 					fJobs->elements[i + 1])) {
438 				fJobs->elements[i] &= ~SOLVER_JOBMASK;
439 				fJobs->elements[i] |= SOLVER_INSTALL;
440 			}
441 		}
442 	}
443 
444 	_InitSolver();
445 	return _Solve();
446 }
447 
448 
449 status_t
FullSync()450 LibsolvSolver::FullSync()
451 {
452 	// add repositories to pool
453 	status_t error = _AddRepositories();
454 	if (error != B_OK)
455 		return error;
456 
457 	// Init the job queue and specify that all packages shall be updated.
458 	error = _InitJobQueue();
459 	if (error != B_OK)
460 		return error;
461 
462 	queue_push2(fJobs, SOLVER_SOLVABLE_ALL, 0);
463 
464 	// set jobs' solver mode and solve
465 	_SetJobsSolverMode(SOLVER_DISTUPGRADE);
466 
467 	_InitSolver();
468 	return _Solve();
469 }
470 
471 
472 status_t
VerifyInstallation(uint32 flags)473 LibsolvSolver::VerifyInstallation(uint32 flags)
474 {
475 	if (_InstalledRepository() == NULL)
476 		return B_BAD_VALUE;
477 
478 	// add repositories to pool
479 	status_t error = _AddRepositories();
480 	if (error != B_OK)
481 		return error;
482 
483 	// add the verify job to the job queue
484 	error = _InitJobQueue();
485 	if (error != B_OK)
486 		return error;
487 
488 	queue_push2(fJobs, SOLVER_SOLVABLE_ALL, 0);
489 
490 	// set jobs' solver mode and solve
491 	_SetJobsSolverMode(SOLVER_VERIFY);
492 
493 	_InitSolver();
494 	if ((flags & B_VERIFY_ALLOW_UNINSTALL) != 0)
495 		solver_set_flag(fSolver, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
496 	return _Solve();
497 }
498 
499 
500 status_t
SelectProblemSolution(BSolverProblem * _problem,const BSolverProblemSolution * _solution)501 LibsolvSolver::SelectProblemSolution(BSolverProblem* _problem,
502 	const BSolverProblemSolution* _solution)
503 {
504 	if (_problem == NULL)
505 		return B_BAD_VALUE;
506 
507 	Problem* problem = static_cast<Problem*>(_problem);
508 	if (_solution == NULL) {
509 		problem->SetSelectedSolution(NULL);
510 		return B_OK;
511 	}
512 
513 	const Solution* solution = static_cast<const Solution*>(_solution);
514 	if (solution->Problem() != problem)
515 		return B_BAD_VALUE;
516 
517 	problem->SetSelectedSolution(solution);
518 	return B_OK;
519 }
520 
521 
522 status_t
SolveAgain()523 LibsolvSolver::SolveAgain()
524 {
525 	if (fSolver == NULL || fJobs == NULL)
526 		return B_BAD_VALUE;
527 
528 	// iterate through all problems and propagate the selected solutions
529 	int32 problemCount = fProblems.CountItems();
530 	for (int32 i = 0; i < problemCount; i++) {
531 		Problem* problem = fProblems.ItemAt(i);
532 		if (const Solution* solution = problem->SelectedSolution())
533 			solver_take_solution(fSolver, problem->Id(), solution->Id(), fJobs);
534 	}
535 
536 	return _Solve();
537 }
538 
539 
540 int32
CountProblems() const541 LibsolvSolver::CountProblems() const
542 {
543 	return fProblems.CountItems();
544 }
545 
546 
547 BSolverProblem*
ProblemAt(int32 index) const548 LibsolvSolver::ProblemAt(int32 index) const
549 {
550 	return fProblems.ItemAt(index);
551 }
552 
553 
554 status_t
GetResult(BSolverResult & _result)555 LibsolvSolver::GetResult(BSolverResult& _result)
556 {
557 	if (fSolver == NULL || HasProblems())
558 		return B_BAD_VALUE;
559 
560 	_result.MakeEmpty();
561 
562 	Transaction* transaction = solver_create_transaction(fSolver);
563 	CObjectDeleter<Transaction, void, transaction_free>
564 		transactionDeleter(transaction);
565 
566 	if (transaction->steps.count == 0)
567 		return B_OK;
568 
569 	transaction_order(transaction, 0);
570 
571 	for (int i = 0; i < transaction->steps.count; i++) {
572 		Id solvableId = transaction->steps.elements[i];
573 		if (fPool->installed
574 			&& fPool->solvables[solvableId].repo == fPool->installed) {
575 			BSolverPackage* package = _GetPackage(solvableId);
576 			if (package == NULL)
577 				return B_ERROR;
578 
579 			if (!_result.AppendElement(
580 					BSolverResultElement(
581 						BSolverResultElement::B_TYPE_UNINSTALL, package))) {
582 				return B_NO_MEMORY;
583 			}
584 		} else {
585 			BSolverPackage* package = _GetPackage(solvableId);
586 			if (package == NULL)
587 				return B_ERROR;
588 
589 			if (!_result.AppendElement(
590 					BSolverResultElement(
591 						BSolverResultElement::B_TYPE_INSTALL, package))) {
592 				return B_NO_MEMORY;
593 			}
594 		}
595 	}
596 
597 	return B_OK;
598 }
599 
600 
601 status_t
_InitPool()602 LibsolvSolver::_InitPool()
603 {
604 	_CleanupPool();
605 
606 	fPool = pool_create();
607 
608 	pool_setdebuglevel(fPool, fDebugLevel);
609 
610 	// Set the system architecture. We use what uname() returns unless we're on
611 	// x86 gcc2.
612 	{
613 		const char* arch;
614 		#ifdef HAIKU_TARGET_PLATFORM_HAIKU
615 			#ifdef __HAIKU_ARCH_X86
616 				#if (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2
617 					arch = "x86_gcc2";
618 				#else
619 					arch = "x86";
620 				#endif
621 			#else
622 				struct utsname info;
623 				if (uname(&info) != 0)
624 					return errno;
625 				arch = info.machine;
626 			#endif
627 		#else
628 			arch = HAIKU_PACKAGING_ARCH;
629 		#endif
630 
631 		pool_setarchpolicy(fPool, arch);
632 	}
633 
634 	return B_OK;
635 }
636 
637 
638 status_t
_InitJobQueue()639 LibsolvSolver::_InitJobQueue()
640 {
641 	_CleanupJobQueue();
642 
643 	fJobs = new(std::nothrow) SolvQueue;
644 	return fJobs != NULL ? B_OK : B_NO_MEMORY;;
645 }
646 
647 
648 void
_InitSolver()649 LibsolvSolver::_InitSolver()
650 {
651 	_CleanupSolver();
652 
653 	fSolver = solver_create(fPool);
654 	solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
655 	solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
656 }
657 
658 
659 void
_Cleanup()660 LibsolvSolver::_Cleanup()
661 {
662 	_CleanupPool();
663 
664 	fInstalledRepository = NULL;
665 	fRepositoryInfos.MakeEmpty();
666 
667 }
668 
669 
670 void
_CleanupPool()671 LibsolvSolver::_CleanupPool()
672 {
673 	// clean up jobs and solver data
674 	_CleanupJobQueue();
675 
676 	// clean up our data structures that depend on/refer to libsolv pool data
677 	fSolvablePackages.clear();
678 	fPackageSolvables.clear();
679 
680 	int32 repositoryCount = fRepositoryInfos.CountItems();
681 	for (int32 i = 0; i < repositoryCount; i++)
682 		fRepositoryInfos.ItemAt(i)->SetSolvRepo(NULL);
683 
684 	// delete the pool
685 	if (fPool != NULL) {
686 		pool_free(fPool);
687 		fPool = NULL;
688 	}
689 }
690 
691 
692 void
_CleanupJobQueue()693 LibsolvSolver::_CleanupJobQueue()
694 {
695 	_CleanupSolver();
696 
697 	delete fJobs;
698 	fJobs = NULL;
699 }
700 
701 
702 void
_CleanupSolver()703 LibsolvSolver::_CleanupSolver()
704 {
705 	fProblems.MakeEmpty();
706 
707 	if (fSolver != NULL) {
708 		solver_free(fSolver);
709 		fSolver = NULL;
710 	}
711 }
712 
713 
714 bool
_HaveRepositoriesChanged() const715 LibsolvSolver::_HaveRepositoriesChanged() const
716 {
717 	int32 repositoryCount = fRepositoryInfos.CountItems();
718 	for (int32 i = 0; i < repositoryCount; i++) {
719 		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
720 		if (repositoryInfo->HasChanged())
721 			return true;
722 	}
723 
724 	return false;
725 }
726 
727 
728 status_t
_AddRepositories()729 LibsolvSolver::_AddRepositories()
730 {
731 	if (fPool != NULL && !_HaveRepositoriesChanged())
732 		return B_OK;
733 
734 	// something has changed -- re-create the pool
735 	status_t error = _InitPool();
736 	if (error != B_OK)
737 		return error;
738 
739 	fInstalledRepository = NULL;
740 
741 	int32 repositoryCount = fRepositoryInfos.CountItems();
742 	for (int32 i = 0; i < repositoryCount; i++) {
743 		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
744 		BSolverRepository* repository = repositoryInfo->Repository();
745 		Repo* repo = repo_create(fPool, repository->Name());
746 		repositoryInfo->SetSolvRepo(repo);
747 
748 		repo->priority = -1 - repository->Priority();
749 		repo->appdata = (void*)repositoryInfo;
750 
751 		int32 packageCount = repository->CountPackages();
752 		for (int32 k = 0; k < packageCount; k++) {
753 			BSolverPackage* package = repository->PackageAt(k);
754 			Id solvableId = repo_add_haiku_package_info(repo, package->Info(),
755 				REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
756 
757 			try {
758 				fSolvablePackages[solvableId] = package;
759 				fPackageSolvables[package] = solvableId;
760 			} catch (std::bad_alloc&) {
761 				return B_NO_MEMORY;
762 			}
763 		}
764 
765 		repo_internalize(repo);
766 
767 		if (repository->IsInstalled()) {
768 			fInstalledRepository = repositoryInfo;
769 			pool_set_installed(fPool, repo);
770 		}
771 
772 		repositoryInfo->SetUnchanged();
773 	}
774 
775 	// create "provides" lookup
776 	pool_createwhatprovides(fPool);
777 
778 	return B_OK;
779 }
780 
781 
782 LibsolvSolver::RepositoryInfo*
_InstalledRepository() const783 LibsolvSolver::_InstalledRepository() const
784 {
785 	int32 repositoryCount = fRepositoryInfos.CountItems();
786 	for (int32 i = 0; i < repositoryCount; i++) {
787 		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
788 		if (repositoryInfo->Repository()->IsInstalled())
789 			return repositoryInfo;
790 	}
791 
792 	return NULL;
793 }
794 
795 
796 LibsolvSolver::RepositoryInfo*
_GetRepositoryInfo(BSolverRepository * repository) const797 LibsolvSolver::_GetRepositoryInfo(BSolverRepository* repository) const
798 {
799 	int32 repositoryCount = fRepositoryInfos.CountItems();
800 	for (int32 i = 0; i < repositoryCount; i++) {
801 		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
802 		if (repository == repositoryInfo->Repository())
803 			return repositoryInfo;
804 	}
805 
806 	return NULL;
807 }
808 
809 
810 BSolverPackage*
_GetPackage(Id solvableId) const811 LibsolvSolver::_GetPackage(Id solvableId) const
812 {
813 	SolvableMap::const_iterator it = fSolvablePackages.find(solvableId);
814 	return it != fSolvablePackages.end() ? it->second : NULL;
815 }
816 
817 
818 Id
_GetSolvable(BSolverPackage * package) const819 LibsolvSolver::_GetSolvable(BSolverPackage* package) const
820 {
821 	PackageMap::const_iterator it = fPackageSolvables.find(package);
822 	return it != fPackageSolvables.end() ? it->second : 0;
823 }
824 
825 
826 status_t
_AddSpecifiedPackages(const BSolverPackageSpecifierList & packages,const BSolverPackageSpecifier ** _unmatched,int additionalFlags)827 LibsolvSolver::_AddSpecifiedPackages(
828 	const BSolverPackageSpecifierList& packages,
829 	const BSolverPackageSpecifier** _unmatched, int additionalFlags)
830 {
831 	int32 packageCount = packages.CountSpecifiers();
832 	for (int32 i = 0; i < packageCount; i++) {
833 		const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
834 		switch (specifier.Type()) {
835 			case BSolverPackageSpecifier::B_UNSPECIFIED:
836 				return B_BAD_VALUE;
837 
838 			case BSolverPackageSpecifier::B_PACKAGE:
839 			{
840 				BSolverPackage* package = specifier.Package();
841 				Id solvableId;
842 				if (package == NULL
843 					|| (solvableId = _GetSolvable(package)) == 0) {
844 					return B_BAD_VALUE;
845 				}
846 
847 				queue_push2(fJobs, SOLVER_SOLVABLE, solvableId);
848 				break;
849 			}
850 
851 			case BSolverPackageSpecifier::B_SELECT_STRING:
852 			{
853 				// find matching packages
854 				SolvQueue matchingPackages;
855 
856 				int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
857 					| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL
858 					| additionalFlags;
859 				/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
860 					specifier.SelectString().String(), flags);
861 				if (matchingPackages.count == 0) {
862 					if (_unmatched != NULL)
863 						*_unmatched = &specifier;
864 					return B_NAME_NOT_FOUND;
865 				}
866 // TODO: We might want to add support for restricting to certain repositories.
867 #if 0
868 				// restrict to the matching repository
869 				if (BSolverRepository* repository = specifier.Repository()) {
870 					RepositoryInfo* repositoryInfo
871 						= _GetRepositoryInfo(repository);
872 					if (repositoryInfo == NULL)
873 						return B_BAD_VALUE;
874 
875 					SolvQueue repoFilter;
876 					queue_push2(&repoFilter,
877 						SOLVER_SOLVABLE_REPO
878 							/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/,
879 						repositoryInfo->SolvRepo()->repoid);
880 
881 					selection_filter(fPool, &matchingPackages, &repoFilter);
882 
883 					if (matchingPackages.count == 0)
884 						return B_NAME_NOT_FOUND;
885 				}
886 #endif
887 
888 				for (int j = 0; j < matchingPackages.count; j++)
889 					queue_push(fJobs, matchingPackages.elements[j]);
890 			}
891 		}
892 	}
893 
894 	return B_OK;
895 }
896 
897 
898 status_t
_AddProblem(Id problemId)899 LibsolvSolver::_AddProblem(Id problemId)
900 {
901 	enum {
902 		NEED_SOURCE		= 0x1,
903 		NEED_TARGET		= 0x2,
904 		NEED_DEPENDENCY	= 0x4
905 	};
906 
907 	Id ruleId = solver_findproblemrule(fSolver, problemId);
908 	Id sourceId;
909 	Id targetId;
910 	Id dependencyId;
911 	BSolverProblem::BType problemType = BSolverProblem::B_UNSPECIFIED;
912 	uint32 needed = 0;
913 
914 	switch (solver_ruleinfo(fSolver, ruleId, &sourceId, &targetId,
915 			&dependencyId)) {
916 		case SOLVER_RULE_DISTUPGRADE:
917 			problemType = BSolverProblem::B_NOT_IN_DISTUPGRADE_REPOSITORY;
918 			needed = NEED_SOURCE;
919 			break;
920 		case SOLVER_RULE_INFARCH:
921 			problemType = BSolverProblem::B_INFERIOR_ARCHITECTURE;
922 			needed = NEED_SOURCE;
923 			break;
924 		case SOLVER_RULE_UPDATE:
925 			problemType = BSolverProblem::B_INSTALLED_PACKAGE_PROBLEM;
926 			needed = NEED_SOURCE;
927 			break;
928 		case SOLVER_RULE_JOB:
929 			problemType = BSolverProblem::B_CONFLICTING_REQUESTS;
930 			break;
931 		case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
932 			problemType = BSolverProblem::B_REQUESTED_RESOLVABLE_NOT_PROVIDED;
933 			needed = NEED_DEPENDENCY;
934 			break;
935 		case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
936 			problemType
937 				= BSolverProblem::B_REQUESTED_RESOLVABLE_PROVIDED_BY_SYSTEM;
938 			needed = NEED_DEPENDENCY;
939 			break;
940 		case SOLVER_RULE_RPM:
941 			problemType = BSolverProblem::B_DEPENDENCY_PROBLEM;
942 			break;
943 		case SOLVER_RULE_RPM_NOT_INSTALLABLE:
944 			problemType = BSolverProblem::B_PACKAGE_NOT_INSTALLABLE;
945 			needed = NEED_SOURCE;
946 			break;
947 		case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
948 			problemType = BSolverProblem::B_DEPENDENCY_NOT_PROVIDED;
949 			needed = NEED_SOURCE | NEED_DEPENDENCY;
950 			break;
951 		case SOLVER_RULE_RPM_SAME_NAME:
952 			problemType = BSolverProblem::B_PACKAGE_NAME_CLASH;
953 			needed = NEED_SOURCE | NEED_TARGET;
954 			break;
955 		case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
956 			problemType = BSolverProblem::B_PACKAGE_CONFLICT;
957 			needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
958 			break;
959 		case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
960 			problemType = BSolverProblem::B_PACKAGE_OBSOLETES_RESOLVABLE;
961 			needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
962 			break;
963 		case SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES:
964 			problemType
965 				= BSolverProblem::B_INSTALLED_PACKAGE_OBSOLETES_RESOLVABLE;
966 			needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
967 			break;
968 		case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES:
969 			problemType
970 				= BSolverProblem::B_PACKAGE_IMPLICITLY_OBSOLETES_RESOLVABLE;
971 			needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
972 			break;
973 		case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
974 			problemType = BSolverProblem::B_DEPENDENCY_NOT_INSTALLABLE;
975 			needed = NEED_SOURCE | NEED_DEPENDENCY;
976 			break;
977 		case SOLVER_RULE_RPM_SELF_CONFLICT:
978 			problemType = BSolverProblem::B_SELF_CONFLICT;
979 			needed = NEED_SOURCE | NEED_DEPENDENCY;
980 			break;
981 		case SOLVER_RULE_UNKNOWN:
982 		case SOLVER_RULE_FEATURE:
983 		case SOLVER_RULE_LEARNT:
984 		case SOLVER_RULE_CHOICE:
985 		case SOLVER_RULE_BEST:
986 			problemType = BSolverProblem::B_UNSPECIFIED;
987 			break;
988 	}
989 
990 	BSolverPackage* sourcePackage = NULL;
991 	if ((needed & NEED_SOURCE) != 0) {
992 		sourcePackage = _GetPackage(sourceId);
993 		if (sourcePackage == NULL)
994 			return B_ERROR;
995 	}
996 
997 	BSolverPackage* targetPackage = NULL;
998 	if ((needed & NEED_TARGET) != 0) {
999 		targetPackage = _GetPackage(targetId);
1000 		if (targetPackage == NULL)
1001 			return B_ERROR;
1002 	}
1003 
1004 	BPackageResolvableExpression dependency;
1005 	if ((needed & NEED_DEPENDENCY) != 0) {
1006 		status_t error = _GetResolvableExpression(dependencyId, dependency);
1007 		if (error != B_OK)
1008 			return error;
1009 	}
1010 
1011 	Problem* problem = new(std::nothrow) Problem(problemId, problemType,
1012 		sourcePackage, targetPackage, dependency);
1013 	if (problem == NULL || !fProblems.AddItem(problem)) {
1014 		delete problem;
1015 		return B_NO_MEMORY;
1016 	}
1017 
1018 	int solutionCount = solver_solution_count(fSolver, problemId);
1019 	for (Id solutionId = 1; solutionId <= solutionCount; solutionId++) {
1020 		status_t error = _AddSolution(problem, solutionId);
1021 		if (error != B_OK)
1022 			return error;
1023 	}
1024 
1025 	return B_OK;
1026 }
1027 
1028 
1029 status_t
_AddSolution(Problem * problem,Id solutionId)1030 LibsolvSolver::_AddSolution(Problem* problem, Id solutionId)
1031 {
1032 	Solution* solution = new(std::nothrow) Solution(solutionId, problem);
1033 	if (solution == NULL || !problem->AppendSolution(solution)) {
1034 		delete solution;
1035 		return B_NO_MEMORY;
1036 	}
1037 
1038 	Id elementId = 0;
1039 	for (;;) {
1040 		Id sourceId;
1041 		Id targetId;
1042 		elementId = solver_next_solutionelement(fSolver, problem->Id(),
1043 			solutionId, elementId, &sourceId, &targetId);
1044 		if (elementId == 0)
1045 			break;
1046 
1047 		status_t error = _AddSolutionElement(solution, sourceId, targetId);
1048 		if (error != B_OK)
1049 			return error;
1050 	}
1051 
1052 	return B_OK;
1053 }
1054 
1055 
1056 status_t
_AddSolutionElement(Solution * solution,Id sourceId,Id targetId)1057 LibsolvSolver::_AddSolutionElement(Solution* solution, Id sourceId, Id targetId)
1058 {
1059 	typedef BSolverProblemSolutionElement Element;
1060 
1061 	if (sourceId == SOLVER_SOLUTION_JOB
1062 		|| sourceId == SOLVER_SOLUTION_POOLJOB) {
1063 		// targetId is an index into the job queue
1064 		if (sourceId == SOLVER_SOLUTION_JOB)
1065 			targetId += fSolver->pooljobcnt;
1066 
1067 		Id how = fSolver->job.elements[targetId - 1];
1068 		Id what = fSolver->job.elements[targetId];
1069 		Id select = how & SOLVER_SELECTMASK;
1070 
1071 		switch (how & SOLVER_JOBMASK) {
1072 			case SOLVER_INSTALL:
1073 				if (select == SOLVER_SOLVABLE && fInstalledRepository != NULL
1074 					&& fPool->solvables[what].repo
1075 						== fInstalledRepository->SolvRepo()) {
1076 					return _AddSolutionElement(solution, Element::B_DONT_KEEP,
1077 						what, 0, NULL);
1078 				}
1079 
1080 				return _AddSolutionElement(solution,
1081 					Element::B_DONT_INSTALL, 0, 0,
1082 					solver_select2str(fPool, select, what));
1083 
1084 			case SOLVER_ERASE:
1085 			{
1086 				if (select == SOLVER_SOLVABLE
1087 					&& (fInstalledRepository == NULL
1088 						|| fPool->solvables[what].repo
1089 							!= fInstalledRepository->SolvRepo())) {
1090 					return _AddSolutionElement(solution,
1091 						Element::B_DONT_FORBID_INSTALLATION, what, 0, NULL);
1092 				}
1093 
1094 				Element::BType type = select == SOLVER_SOLVABLE_PROVIDES
1095 					? Element::B_DONT_DEINSTALL_ALL : Element::B_DONT_DEINSTALL;
1096 				return _AddSolutionElement(solution, type, 0, 0,
1097 					solver_select2str(fPool, select, what));
1098 			}
1099 
1100 			case SOLVER_UPDATE:
1101 				return _AddSolutionElement(solution,
1102 					Element::B_DONT_INSTALL_MOST_RECENT, 0, 0,
1103 					solver_select2str(fPool, select, what));
1104 
1105 			case SOLVER_LOCK:
1106 				return _AddSolutionElement(solution, Element::B_DONT_LOCK, 0, 0,
1107 					solver_select2str(fPool, select, what));
1108 
1109 			default:
1110 				return _AddSolutionElement(solution, Element::B_UNSPECIFIED, 0,
1111 					0, NULL);
1112 		}
1113 	}
1114 
1115 	Solvable* target = targetId != 0 ? fPool->solvables + targetId : NULL;
1116 	bool targetInstalled = target != NULL && fInstalledRepository
1117 		&& target->repo == fInstalledRepository->SolvRepo();
1118 
1119 	if (sourceId == SOLVER_SOLUTION_INFARCH) {
1120 		return _AddSolutionElement(solution,
1121 			targetInstalled
1122 				? Element::B_KEEP_INFERIOR_ARCHITECTURE
1123 				: Element::B_INSTALL_INFERIOR_ARCHITECTURE,
1124 			targetId, 0, NULL);
1125 	}
1126 
1127 	if (sourceId == SOLVER_SOLUTION_DISTUPGRADE) {
1128 		return _AddSolutionElement(solution,
1129 			targetInstalled
1130 				? Element::B_KEEP_EXCLUDED : Element::B_INSTALL_EXCLUDED,
1131 			targetId, 0, NULL);
1132 	}
1133 
1134 	if (sourceId == SOLVER_SOLUTION_BEST) {
1135 		return _AddSolutionElement(solution,
1136 			targetInstalled ? Element::B_KEEP_OLD : Element::B_INSTALL_OLD,
1137 			targetId, 0, NULL);
1138 	}
1139 
1140 	// replace source with target
1141 	Solvable* source = fPool->solvables + sourceId;
1142 	if (target == NULL) {
1143 		return _AddSolutionElement(solution, Element::B_ALLOW_DEINSTALLATION,
1144 			sourceId, 0, NULL);
1145 	}
1146 
1147 	int illegalMask = policy_is_illegal(fSolver, source, target, 0);
1148 	if ((illegalMask & POLICY_ILLEGAL_DOWNGRADE) != 0) {
1149 		status_t error = _AddSolutionElement(solution,
1150 			Element::B_ALLOW_DOWNGRADE, sourceId, targetId, NULL);
1151 		if (error != B_OK)
1152 			return error;
1153 	}
1154 
1155 	if ((illegalMask & POLICY_ILLEGAL_NAMECHANGE) != 0) {
1156 		status_t error = _AddSolutionElement(solution,
1157 			Element::B_ALLOW_NAME_CHANGE, sourceId, targetId, NULL);
1158 		if (error != B_OK)
1159 			return error;
1160 	}
1161 
1162 	if ((illegalMask & POLICY_ILLEGAL_ARCHCHANGE) != 0) {
1163 		status_t error = _AddSolutionElement(solution,
1164 			Element::B_ALLOW_ARCHITECTURE_CHANGE, sourceId, targetId, NULL);
1165 		if (error != B_OK)
1166 			return error;
1167 	}
1168 
1169 	if ((illegalMask & POLICY_ILLEGAL_VENDORCHANGE) != 0) {
1170 		status_t error = _AddSolutionElement(solution,
1171 			Element::B_ALLOW_VENDOR_CHANGE, sourceId, targetId, NULL);
1172 		if (error != B_OK)
1173 			return error;
1174 	}
1175 
1176 	if (illegalMask == 0) {
1177 		return _AddSolutionElement(solution, Element::B_ALLOW_REPLACEMENT,
1178 			sourceId, targetId, NULL);
1179 	}
1180 
1181 	return B_OK;
1182 }
1183 
1184 
1185 status_t
_AddSolutionElement(Solution * solution,BSolverProblemSolutionElement::BType type,Id sourceSolvableId,Id targetSolvableId,const char * selectionString)1186 LibsolvSolver::_AddSolutionElement(Solution* solution,
1187 	BSolverProblemSolutionElement::BType type, Id sourceSolvableId,
1188 	Id targetSolvableId, const char* selectionString)
1189 {
1190 	BSolverPackage* sourcePackage = NULL;
1191 	if (sourceSolvableId != 0) {
1192 		sourcePackage = _GetPackage(sourceSolvableId);
1193 		if (sourcePackage == NULL)
1194 			return B_ERROR;
1195 	}
1196 
1197 	BSolverPackage* targetPackage = NULL;
1198 	if (targetSolvableId != 0) {
1199 		targetPackage = _GetPackage(targetSolvableId);
1200 		if (targetPackage == NULL)
1201 			return B_ERROR;
1202 	}
1203 
1204 	BString selection;
1205 	if (selectionString != NULL && selectionString[0] != '\0') {
1206 		selection = selectionString;
1207 		if (selection.IsEmpty())
1208 			return B_NO_MEMORY;
1209 	}
1210 
1211 	if (!solution->AppendElement(BSolverProblemSolutionElement(
1212 			type, sourcePackage, targetPackage, selection))) {
1213 		return B_NO_MEMORY;
1214 	}
1215 
1216 	return B_OK;
1217 }
1218 
1219 
1220 status_t
_GetResolvableExpression(Id id,BPackageResolvableExpression & _expression) const1221 LibsolvSolver::_GetResolvableExpression(Id id,
1222 	BPackageResolvableExpression& _expression) const
1223 {
1224 	// Try to translate the libsolv ID to a resolvable expression. Generally
1225 	// that doesn't work, since libsolv is more expressive, but all the stuff
1226 	// we feed libsolv we should be able to translate back.
1227 
1228 	if (!ISRELDEP(id)) {
1229 		// just a string
1230 		_expression.SetTo(pool_id2str(fPool, id));
1231 		return B_OK;
1232 	}
1233 
1234 	// a composite -- analyze it
1235 	Reldep* reldep = GETRELDEP(fPool, id);
1236 
1237 	// No support for more than one level, so both name and evr must be strings.
1238 	if (ISRELDEP(reldep->name) || ISRELDEP(reldep->evr))
1239 		return B_NOT_SUPPORTED;
1240 
1241 	const char* name = pool_id2str(fPool, reldep->name);
1242 	const char* versionString = pool_id2str(fPool, reldep->evr);
1243 	if (name == NULL || versionString == NULL)
1244 		return B_NOT_SUPPORTED;
1245 
1246 	// get the operator -- we don't support all libsolv supports
1247 	BPackageResolvableOperator op;
1248 	switch (reldep->flags) {
1249 		case 1:
1250 			op = B_PACKAGE_RESOLVABLE_OP_GREATER;
1251 			break;
1252 		case 2:
1253 			op = B_PACKAGE_RESOLVABLE_OP_EQUAL;
1254 			break;
1255 		case 3:
1256 			op = B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL;
1257 			break;
1258 		case 4:
1259 			op = B_PACKAGE_RESOLVABLE_OP_LESS;
1260 			break;
1261 		case 5:
1262 			op = B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL;
1263 			break;
1264 		case 6:
1265 			op = B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL;
1266 			break;
1267 		default:
1268 			return B_NOT_SUPPORTED;
1269 	}
1270 
1271 	// get the version (cut off the empty epoch)
1272 	if (versionString[0] == ':')
1273 		versionString++;
1274 
1275 	BPackageVersion version;
1276 	status_t error = version.SetTo(versionString, true);
1277 	if (error != B_OK)
1278 		return error == B_BAD_DATA ? B_NOT_SUPPORTED : error;
1279 
1280 	_expression.SetTo(name, op, version);
1281 	return B_OK;
1282 }
1283 
1284 
1285 status_t
_GetFoundPackages(SolvQueue & selection,uint32 flags,BObjectList<BSolverPackage> & _packages)1286 LibsolvSolver::_GetFoundPackages(SolvQueue& selection, uint32 flags,
1287 	BObjectList<BSolverPackage>& _packages)
1288 {
1289 	// get solvables
1290 	SolvQueue solvables;
1291 	selection_solvables(fPool, &selection, &solvables);
1292 
1293 	// get packages
1294 	for (int i = 0; i < solvables.count; i++) {
1295 		BSolverPackage* package = _GetPackage(solvables.elements[i]);
1296 		if (package == NULL)
1297 			return B_ERROR;
1298 
1299 		// TODO: Fix handling of SELECTION_INSTALLED_ONLY in libsolv. Despite
1300 		// passing the flag, we get solvables that aren't installed.
1301 		if ((flags & B_FIND_INSTALLED_ONLY) != 0
1302 			&& package->Repository() != fInstalledRepository->Repository()) {
1303 			continue;
1304 		}
1305 
1306 		if (!_packages.AddItem(package))
1307 			return B_NO_MEMORY;
1308 	}
1309 
1310 	return B_OK;
1311 }
1312 
1313 
1314 status_t
_Solve()1315 LibsolvSolver::_Solve()
1316 {
1317 	if (fJobs == NULL || fSolver == NULL)
1318 		return B_BAD_VALUE;
1319 
1320 	int problemCount = solver_solve(fSolver, fJobs);
1321 
1322 	// get the problems (if any)
1323 	fProblems.MakeEmpty();
1324 
1325 	for (Id problemId = 1; problemId <= problemCount; problemId++) {
1326 		status_t error = _AddProblem(problemId);
1327 		if (error != B_OK)
1328 			return error;
1329 	}
1330 
1331 	return B_OK;
1332 }
1333 
1334 
1335 void
_SetJobsSolverMode(int solverMode)1336 LibsolvSolver::_SetJobsSolverMode(int solverMode)
1337 {
1338 	for (int i = 0; i < fJobs->count; i += 2)
1339 		fJobs->elements[i] |= solverMode;
1340 }
1341