pull.c 29.9 KB
Newer Older
1
/*  This file is part of "reprepro"
2
 *  Copyright (C) 2006,2007,2016 Bernhard R. Link
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02111-1301  USA
 */
#include <config.h>

#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "error.h"
Bernhard Link's avatar
Bernhard Link committed
25
#include "ignore.h"
26 27 28 29 30 31
#include "mprintf.h"
#include "strlist.h"
#include "names.h"
#include "pull.h"
#include "upgradelist.h"
#include "distribution.h"
32
#include "tracking.h"
33
#include "termdecide.h"
34
#include "filterlist.h"
Bernhard Link's avatar
Bernhard Link committed
35
#include "log.h"
Bernhard Link's avatar
Bernhard Link committed
36
#include "configparser.h"
37
#include "package.h"
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

/***************************************************************************
 * step one:                                                               *
 * parse CONFDIR/pull to get pull information saved in                     *
 * pull_rule structs                                                    *
 **************************************************************************/

/* the data for some upstream part to get pull from, some
 * some fields can be NULL or empty */
struct pull_rule {
	struct pull_rule *next;
	//e.g. "Name: woody"
	char *name;
	//e.g. "From: woody"
	char *from;
53
	//e.g. "Architectures: i386 sparc mips" (not set means all)
54 55
	struct atomlist architectures_from;
	struct atomlist architectures_into;
56 57
	bool architectures_set;
	//e.g. "Components: main contrib" (not set means all)
58
	struct atomlist components;
59 60
	bool components_set;
	//e.g. "UDebComponents: main" // (not set means all)
61
	struct atomlist udebcomponents;
62
	bool udebcomponents_set;
63 64 65
	// NULL means no condition
	/*@null@*/term *includecondition;
	struct filterlist filterlist;
Bernhard Link's avatar
Bernhard Link committed
66
	struct filterlist filtersrclist;
67 68
	/*----only set after _addsourcedistribution----*/
	/*@NULL@*/ struct distribution *distribution;
69
	bool used;
70 71 72
};

static void pull_rule_free(/*@only@*/struct pull_rule *pull) {
73
	if (pull == NULL)
74 75 76
		return;
	free(pull->name);
	free(pull->from);
77 78 79 80
	atomlist_done(&pull->architectures_from);
	atomlist_done(&pull->architectures_into);
	atomlist_done(&pull->components);
	atomlist_done(&pull->udebcomponents);
81 82
	term_free(pull->includecondition);
	filterlist_release(&pull->filterlist);
Bernhard Link's avatar
Bernhard Link committed
83
	filterlist_release(&pull->filtersrclist);
84 85 86 87
	free(pull);
}

void pull_freerules(struct pull_rule *p) {
88
	while (p != NULL) {
89 90 91 92 93 94 95 96
		struct pull_rule *rule;

		rule = p;
		p = rule->next;
		pull_rule_free(rule);
	}
}

Bernhard Link's avatar
Bernhard Link committed
97 98 99
CFlinkedlistinit(pull_rule)
CFvalueSETPROC(pull_rule, name)
CFvalueSETPROC(pull_rule, from)
100 101
CFatomlistSETPROC(pull_rule, components, at_component)
CFatomlistSETPROC(pull_rule, udebcomponents, at_component)
Bernhard Link's avatar
Bernhard Link committed
102
CFfilterlistSETPROC(pull_rule, filterlist)
Bernhard Link's avatar
Bernhard Link committed
103
CFfilterlistSETPROC(pull_rule, filtersrclist)
Bernhard Link's avatar
Bernhard Link committed
104 105
CFtermSETPROC(pull_rule, includecondition)

106 107 108 109 110
CFUSETPROC(pull_rule, architectures) {
	CFSETPROCVAR(pull_rule, this);
	retvalue r;

	this->architectures_set = true;
111 112
	r = config_getsplitatoms(iter, "Architectures",
			at_architecture,
113 114
			&this->architectures_from,
			&this->architectures_into);
115
	if (r == RET_NOTHING) {
116 117 118 119 120 121 122 123 124
		fprintf(stderr,
"Warning parsing %s, line %u: an empty Architectures field\n"
"causes the whole rule to do nothing.\n",
				config_filename(iter),
				config_markerline(iter));
	}
	return r;
}

Bernhard Link's avatar
Bernhard Link committed
125 126 127 128 129 130 131
static const struct configfield pullconfigfields[] = {
	CFr("Name", pull_rule, name),
	CFr("From", pull_rule, from),
	CF("Architectures", pull_rule, architectures),
	CF("Components", pull_rule, components),
	CF("UDebComponents", pull_rule, udebcomponents),
	CF("FilterFormula", pull_rule, includecondition),
Bernhard Link's avatar
Bernhard Link committed
132
	CF("FilterSrcList", pull_rule, filtersrclist),
Bernhard Link's avatar
Bernhard Link committed
133
	CF("FilterList", pull_rule, filterlist)
134 135
};

136
retvalue pull_getrules(struct pull_rule **rules) {
137 138 139
	struct pull_rule *pull = NULL;
	retvalue r;

140
	r = configfile_parse("pulls", IGNORABLE(unknownfield),
Bernhard Link's avatar
Bernhard Link committed
141
			configparser_pull_rule_init, linkedlistfinish,
142
			"pull rule",
Bernhard Link's avatar
Bernhard Link committed
143
			pullconfigfields, ARRAYCOUNT(pullconfigfields), &pull);
144
	if (RET_IS_OK(r))
145
		*rules = pull;
146 147
	else if (r == RET_NOTHING) {
		assert (pull == NULL);
148 149
		*rules = NULL;
		r = RET_OK;
Bernhard Link's avatar
Bernhard Link committed
150 151 152
	} else {
		// TODO special handle unknownfield
		pull_freerules(pull);
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
	}
	return r;
}

/***************************************************************************
 * step two:                                                               *
 * create pull_distribution structs to hold all additional information for *
 * a distribution                                                          *
 **************************************************************************/

struct pull_target;
static void pull_freetargets(struct pull_target *targets);

struct pull_distribution {
	struct pull_distribution *next;
	/*@dependant@*/struct distribution *distribution;
	struct pull_target *targets;
	/*@dependant@*/struct pull_rule *rules[];
};

void pull_freedistributions(struct pull_distribution *d) {
174
	while (d != NULL) {
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
		struct pull_distribution *next;

		next = d->next;
		pull_freetargets(d->targets);
		free(d);
		d = next;
	}
}

static retvalue pull_initdistribution(struct pull_distribution **pp,
		struct distribution *distribution,
		struct pull_rule *rules) {
	struct pull_distribution *p;
	int i;

	assert(distribution != NULL);
191
	if (distribution->pulls.count == 0)
192 193 194 195
		return RET_NOTHING;

	p = malloc(sizeof(struct pull_distribution)+
		sizeof(struct pull_rules *)*distribution->pulls.count);
196
	if (FAILEDTOALLOC(p))
197 198 199 200
		return RET_ERROR_OOM;
	p->next = NULL;
	p->distribution = distribution;
	p->targets = NULL;
201
	for (i = 0 ; i < distribution->pulls.count ; i++) {
202
		const char *name = distribution->pulls.values[i];
203
		if (strcmp(name, "-") == 0) {
204 205 206
			p->rules[i] = NULL;
		} else {
			struct pull_rule *rule = rules;
207
			while (rule && strcmp(rule->name, name) != 0)
208
				rule = rule->next;
209
			if (rule == NULL) {
210
				fprintf(stderr,
Bernhard Link's avatar
Bernhard Link committed
211
"Error: Unknown pull rule '%s' in distribution '%s'!\n",
212
						name, distribution->codename);
213
				free(p);
214 215 216
				return RET_ERROR_MISSING;
			}
			p->rules[i] = rule;
217
			rule->used = true;
218 219 220 221 222 223 224 225 226 227 228 229 230
		}
	}
	*pp = p;
	return RET_OK;
}

static retvalue pull_init(struct pull_distribution **pulls,
		struct pull_rule *rules,
		struct distribution *distributions) {
	struct pull_distribution *p = NULL, **pp = &p;
	struct distribution *d;
	retvalue r;

231 232
	for (d = distributions ; d != NULL ; d = d->next) {
		if (!d->selected)
233
			continue;
234
		r = pull_initdistribution(pp, d, rules);
235
		if (RET_WAS_ERROR(r)) {
236 237 238
			pull_freedistributions(p);
			return r;
		}
239 240
		if (RET_IS_OK(r)) {
			assert (*pp != NULL);
241 242 243 244 245 246 247 248 249 250 251 252
			pp = &(*pp)->next;
		}
	}
	*pulls = p;
	return RET_OK;
}

/***************************************************************************
 * step three:                                                             *
 * load the config of the distributions mentioned in the rules             *
 **************************************************************************/

253
static retvalue pull_loadsourcedistributions(struct distribution *alldistributions, struct pull_rule *rules) {
254 255 256
	struct pull_rule *rule;
	struct distribution *d;

257 258 259 260
	for (rule = rules ; rule != NULL ; rule = rule->next) {
		if (rule->used && rule->distribution == NULL) {
			for (d = alldistributions ; d != NULL ; d = d->next) {
				if (strcmp(d->codename, rule->from) == 0) {
261
					rule->distribution = d;
262 263 264
					break;
				}
			}
265 266 267
			if (d == NULL) {
				fprintf(stderr,
"Error: Unknown distribution '%s' referenced in pull rule '%s'\n",
268 269 270
						rule->from, rule->name);
				return RET_ERROR_MISSING;
			}
271
		}
272
	}
273
	return RET_OK;
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
}

/***************************************************************************
 * step four:                                                              *
 * create pull_targets and pull_sources                                    *
 **************************************************************************/

struct pull_source {
	struct pull_source *next;
	/* NULL, if this is a delete rule */
	struct target *source;
	struct pull_rule *rule;
};
struct pull_target {
	/*@null@*/struct pull_target *next;
	/*@null@*/struct pull_source *sources;
	/*@dependent@*/struct target *target;
	/*@null@*/struct upgradelist *upgradelist;
};

static void pull_freetargets(struct pull_target *targets) {
295
	while (targets != NULL) {
296 297
		struct pull_target *target = targets;
		targets = target->next;
298
		while (target->sources != NULL) {
299 300 301 302 303 304 305 306 307 308 309
			struct pull_source *source = target->sources;
			target->sources = source->next;
			free(source);
		}
		free(target);
	}
}

static retvalue pull_createsource(struct pull_rule *rule,
		struct target *target,
		struct pull_source ***s) {
310 311
	const struct atomlist *c;
	const struct atomlist *a_from, *a_into;
312 313
	int ai;

314 315
	assert (rule != NULL);
	assert (rule->distribution != NULL);
316

317
	if (rule->architectures_set) {
318 319 320 321 322 323
		a_from = &rule->architectures_from;
		a_into = &rule->architectures_into;
	} else {
		a_from = &rule->distribution->architectures;
		a_into = &rule->distribution->architectures;
	}
324 325
	if (target->packagetype == pt_udeb)  {
		if (rule->udebcomponents_set)
326 327 328 329
			c = &rule->udebcomponents;
		else
			c = &rule->distribution->udebcomponents;
	} else {
330
		if (rule->components_set)
331 332 333 334 335
			c = &rule->components;
		else
			c = &rule->distribution->components;
	}

336
	if (!atomlist_in(c, target->component))
337 338
		return RET_NOTHING;

339
	for (ai = 0 ; ai < a_into->count ; ai++) {
340
		struct pull_source *source;
341

342
		if (a_into->atoms[ai] != target->architecture)
343 344
			continue;

345 346
		source = NEW(struct pull_source);
		if (FAILEDTOALLOC(source))
347 348 349 350 351
			return RET_ERROR_OOM;

		source->next = NULL;
		source->rule = rule;
		source->source = distribution_getpart(rule->distribution,
352
				target->component,
353
				a_from->atoms[ai],
354
				target->packagetype);
355 356 357 358 359 360 361 362 363
		**s = source;
		*s = &source->next;
	}
	return RET_OK;
}

static retvalue pull_createdelete(struct pull_source ***s) {
	struct pull_source *source;

364 365
	source = NEW(struct pull_source);
	if (FAILEDTOALLOC(source))
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
		return RET_ERROR_OOM;

	source->next =  NULL;
	source->rule = NULL;
	source->source = NULL;
	**s = source;
	*s = &source->next;
	return RET_OK;
}

static retvalue generatepulltarget(struct pull_distribution *pd, struct target *target) {
	struct pull_source **s;
	struct pull_target *pt;
	retvalue r;
	int i;

382 383
	pt = NEW(struct pull_target);
	if (FAILEDTOALLOC(pt))
384 385 386 387 388 389 390 391
		return RET_ERROR_OOM;
	pt->target = target;
	pt->next = pd->targets;
	pt->upgradelist = NULL;
	pt->sources = NULL;
	s = &pt->sources;
	pd->targets = pt;

392
	for (i = 0 ; i < pd->distribution->pulls.count ; i++) {
393 394
		struct pull_rule *rule = pd->rules[i];

395
		if (rule == NULL)
396 397 398
			r = pull_createdelete(&s);
		else
			r = pull_createsource(rule, target, &s);
399
		if (RET_WAS_ERROR(r))
400 401 402 403 404 405
			return r;
	}

	return RET_OK;
}

406
static retvalue pull_generatetargets(struct pull_distribution *pull_distributions, const struct atomlist *components, const struct atomlist *architectures, const struct atomlist *packagetypes) {
407 408 409 410
	struct pull_distribution *pd;
	struct target *target;
	retvalue r;

411 412
	for (pd = pull_distributions ; pd != NULL ; pd = pd->next) {
		for (target = pd->distribution->targets ; target != NULL ;
413 414
				target = target->next) {

415 416 417
			if (!target_matches(target, components, architectures, packagetypes))
				continue;

418 419
			r = generatepulltarget(pd, target);
			if (RET_WAS_ERROR(r))
420 421 422 423 424 425
				return r;
		}
	}
	return RET_OK;
}

426 427 428 429
/***************************************************************************
 * Some checking to be able to warn against typos                          *
 **************************************************************************/

430 431 432 433
static bool *preparefoundlist(const struct atomlist *list) {
	bool *found;
	int i, j;

434 435
	found = nzNEW(list->count, bool);
	if (FAILEDTOALLOC(found))
436
		return found;
437 438
	for (i = 0 ; i < list->count ; i++) {
		if (found[i])
439
			continue;
440 441
		for (j = i + 1 ; j < list->count ; j++)
			if (list->atoms[i] == list->atoms[j])
442 443 444 445 446 447 448
				found[j] = true;
	}
	return found;
}


static inline void markasused(const struct strlist *pulls, const char *rulename, const struct atomlist *needed, const struct atomlist *have, bool *found) {
449 450
	int i, j, o;

451 452
	for (i = 0 ; i < pulls->count ; i++) {
		if (strcmp(pulls->values[i], rulename) != 0)
453
			continue;
454
		for (j = 0 ; j < have->count ; j++) {
455
			o = atomlist_ofs(needed, have->atoms[j]);
456
			if (o >= 0)
457 458 459 460 461
				found[o] = true;
		}
	}
}

462
static void checkifarchitectureisused(const struct atomlist *architectures, const struct distribution *alldistributions, const struct pull_rule *rule, const char *action) {
463 464 465 466
	bool *found;
	const struct distribution *d;
	int i;

467 468
	assert (rule != NULL);
	if (architectures->count == 0)
469
		return;
470
	found = preparefoundlist(architectures);
471
	if (found == NULL)
472
		return;
473
	for (d = alldistributions ; d != NULL ; d = d->next) {
474 475 476 477
		markasused(&d->pulls, rule->name,
				architectures, &d->architectures,
				found);
	}
478 479
	for (i = 0 ; i < architectures->count ; i++) {
		if (found[i])
480 481 482 483 484 485
			continue;
		fprintf(stderr,
"Warning: pull rule '%s' wants to %s architecture '%s',\n"
"but no distribution using this has such an architecture.\n"
"(This will simply be ignored and is not even checked when using --fast).\n",
				rule->name, action,
486
				atoms_architectures[architectures->atoms[i]]);
487 488 489 490 491
	}
	free(found);
	return;
}

492
static void checkifcomponentisused(const struct atomlist *components, const struct distribution *alldistributions, const struct pull_rule *rule, const char *action) {
493 494 495 496
	bool *found;
	const struct distribution *d;
	int i;

497 498
	assert (rule != NULL);
	if (components->count == 0)
499
		return;
500
	found = preparefoundlist(components);
501
	if (found == NULL)
502
		return;
503
	for (d = alldistributions ; d != NULL ; d = d->next) {
504 505 506 507
		markasused(&d->pulls, rule->name,
				components, &d->components,
				found);
	}
508 509
	for (i = 0 ; i < components->count ; i++) {
		if (found[i])
510 511 512 513 514 515
			continue;
		fprintf(stderr,
"Warning: pull rule '%s' wants to %s component '%s',\n"
"but no distribution using this has such an component.\n"
"(This will simply be ignored and is not even checked when using --fast).\n",
				rule->name, action,
516
				atoms_components[components->atoms[i]]);
517 518 519 520 521
	}
	free(found);
	return;
}

522
static void checkifudebcomponentisused(const struct atomlist *udebcomponents, const struct distribution *alldistributions, const struct pull_rule *rule, const char *action) {
523 524 525 526
	bool *found;
	const struct distribution *d;
	int i;

527 528
	assert (rule != NULL);
	if (udebcomponents->count == 0)
529
		return;
530
	found = preparefoundlist(udebcomponents);
531
	if (found == NULL)
532
		return;
533
	for (d = alldistributions ; d != NULL ; d = d->next) {
534 535 536 537
		markasused(&d->pulls, rule->name,
				udebcomponents, &d->udebcomponents,
				found);
	}
538 539
	for (i = 0 ; i < udebcomponents->count ; i++) {
		if (found[i])
540 541 542 543 544 545
			continue;
		fprintf(stderr,
"Warning: pull rule '%s' wants to %s udeb component '%s',\n"
"but no distribution using this has such an udeb component.\n"
"(This will simply be ignored and is not even checked when using --fast).\n",
				rule->name, action,
546
				atoms_components[udebcomponents->atoms[i]]);
547 548 549 550 551
	}
	free(found);
	return;
}

552
static void checksubset(const struct atomlist *needed, const struct atomlist *have, const char *rulename, const char *from, const char *what, const char **atoms) {
553 554
	int i, j;

555
	for (i = 0 ; i < needed->count ; i++) {
556
		atom_t value = needed->atoms[i];
557

558 559
		for (j = 0 ; j < i ; j++) {
			if (value == needed->atoms[j])
560 561
				break;
		}
562
		if (j < i)
563 564
			continue;

565
		if (!atomlist_in(have, value)) {
566 567 568 569
			fprintf(stderr,
"Warning: pull rule '%s' wants to get something from %s '%s',\n"
"but there is no such %s in distribution '%s'.\n"
"(This will simply be ignored and is not even checked when using --fast).\n",
570 571
					rulename, what,
					atoms[value], what, from);
572 573 574 575 576
		}
	}
}

static void searchunused(const struct distribution *alldistributions, const struct pull_rule *rule) {
577
	if (rule->distribution != NULL) {
578 579 580
		// TODO: move this part of the checks into parsing?
		checksubset(&rule->architectures_from,
				&rule->distribution->architectures,
581 582
				rule->name, rule->from, "architecture",
				atoms_architectures);
583 584
		checksubset(&rule->components,
				&rule->distribution->components,
585 586
				rule->name, rule->from, "component",
				atoms_components);
587 588
		checksubset(&rule->udebcomponents,
				&rule->distribution->udebcomponents,
589 590
				rule->name, rule->from, "udeb component",
				atoms_components);
591 592
	}

593 594
	if (rule->distribution == NULL) {
		assert (strcmp(rule->from, "*") == 0);
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
		checkifarchitectureisused(&rule->architectures_from,
				alldistributions, rule, "get something from");
		/* no need to check component and udebcomponent, as those
		 * are the same with the others */
	}
	checkifarchitectureisused(&rule->architectures_into,
			alldistributions, rule, "put something into");
	checkifcomponentisused(&rule->components,
			alldistributions, rule, "put something into");
	checkifudebcomponentisused(&rule->udebcomponents,
			alldistributions, rule, "put something into");
}

static void pull_searchunused(const struct distribution *alldistributions, struct pull_rule *pull_rules) {
	struct pull_rule *rule;

611 612
	for (rule = pull_rules ; rule != NULL ; rule = rule->next) {
		if (!rule->used)
613 614 615 616 617 618
			continue;

		searchunused(alldistributions, rule);
	}
}

619 620 621 622
/***************************************************************************
 * combination of the steps two, three and four                            *
 **************************************************************************/

623
retvalue pull_prepare(struct distribution *alldistributions, struct pull_rule *rules, bool fast, const struct atomlist *components, const struct atomlist *architectures, const struct atomlist *types, struct pull_distribution **pd) {
624 625 626
	struct pull_distribution *pulls;
	retvalue r;

627
	r = pull_init(&pulls, rules, alldistributions);
628
	if (RET_WAS_ERROR(r))
629 630
		return r;

631
	r = pull_loadsourcedistributions(alldistributions, rules);
632
	if (RET_WAS_ERROR(r)) {
633 634 635
		pull_freedistributions(pulls);
		return r;
	}
636
	if (!fast)
637 638
		pull_searchunused(alldistributions, rules);

639
	r = pull_generatetargets(pulls, components, architectures, types);
640
	if (RET_WAS_ERROR(r)) {
641 642 643 644 645 646 647 648 649 650 651 652
		pull_freedistributions(pulls);
		return r;
	}
	*pd = pulls;
	return RET_OK;
}

/***************************************************************************
 * step five:                                                              *
 * decide what gets pulled                                                 *
 **************************************************************************/

653
static upgrade_decision ud_decide_by_rule(void *privdata, struct target *target, struct package *new, /*@null@*/const char *old_version) {
654
	struct pull_rule *rule = privdata;
655
	upgrade_decision decision = UD_UPGRADE;
656
	retvalue r;
Bernhard Link's avatar
Bernhard Link committed
657 658
	struct filterlist *fl;
	const char *n, *v;
659
	bool cmdline_still_undecided;
Bernhard Link's avatar
Bernhard Link committed
660 661

	if (target->packagetype == pt_dsc) {
662 663
		assert (strcmp(new->name, new->source) == 0);
		assert (strcmp(new->version, new->sourceversion) == 0);
Bernhard Link's avatar
Bernhard Link committed
664 665 666 667
		if (rule->filtersrclist.set)
			fl = &rule->filtersrclist;
		else
			fl = &rule->filterlist;
668 669
		n = new->name;
		v = new->version;
Bernhard Link's avatar
Bernhard Link committed
670 671 672
	} else {
		if (rule->filterlist.set) {
			fl = &rule->filterlist;
673 674
			n = new->name;
			v = new->version;
Bernhard Link's avatar
Bernhard Link committed
675 676
		} else {
			fl = &rule->filtersrclist;
677 678
			n = new->source;
			v = new->sourceversion;
Bernhard Link's avatar
Bernhard Link committed
679 680
		}
	}
681

Bernhard Link's avatar
Bernhard Link committed
682
	switch (filterlist_find(n, v, fl)) {
683 684 685
		case flt_deinstall:
		case flt_purge:
			return UD_NO;
686 687
		case flt_warning:
			return UD_LOUDNO;
688 689 690
		case flt_supersede:
			decision = UD_SUPERSEDE;
			break;
691
		case flt_hold:
692 693
			decision = UD_HOLD;
			break;
694 695
		case flt_error:
			/* cannot yet be handled! */
Bernhard Link's avatar
Bernhard Link committed
696
			fprintf(stderr,
697
"Package name marked to be unexpected('error'): '%s'!\n", new->name);
698
			return UD_ERROR;
699
		case flt_upgradeonly:
700
			if (old_version == NULL)
701 702
				return UD_NO;
			break;
703 704
		case flt_install:
			break;
705 706 707 708 709 710 711
		case flt_unchanged:
		case flt_auto_hold:
			assert (false);
			break;
	}

	cmdline_still_undecided = false;
712
	switch (filterlist_find(new->source, new->sourceversion,
713 714 715 716 717 718 719 720 721 722 723 724 725
				&cmdline_src_filter)) {
		case flt_deinstall:
		case flt_purge:
			return UD_NO;
		case flt_warning:
			return UD_LOUDNO;
		case flt_auto_hold:
			cmdline_still_undecided = true;
			decision = UD_HOLD;
			break;
		case flt_hold:
			decision = UD_HOLD;
			break;
726 727 728
		case flt_supersede:
			decision = UD_SUPERSEDE;
			break;
729 730 731
		case flt_error:
			/* cannot yet be handled! */
			fprintf(stderr,
732
"Package name marked to be unexpected('error'): '%s'!\n", new->name);
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
			return UD_ERROR;
		case flt_upgradeonly:
			if (old_version == NULL)
				return UD_NO;
			break;
		case flt_install:
			decision = UD_UPGRADE;
			break;
		case flt_unchanged:
			cmdline_still_undecided = true;
			break;
	}


	if (target->packagetype != pt_dsc) {
748
		switch (filterlist_find(new->name, new->version,
749 750 751 752 753 754 755 756 757
					&cmdline_bin_filter)) {
			case flt_deinstall:
			case flt_purge:
				return UD_NO;
			case flt_warning:
				return UD_LOUDNO;
			case flt_hold:
				decision = UD_HOLD;
				break;
758 759 760
			case flt_supersede:
				decision = UD_SUPERSEDE;
				break;
761 762 763
			case flt_error:
				/* cannot yet be handled! */
				fprintf(stderr,
764
"Package name marked to be unexpected('error'): '%s'!\n", new->name);
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
				return UD_ERROR;
			case flt_upgradeonly:
				if (old_version == NULL)
					return UD_NO;
				break;
			case flt_install:
				decision = UD_UPGRADE;
				break;
			case flt_unchanged:
				break;
			case flt_auto_hold:
				/* hold only if it was not in the src-filter */
				if (cmdline_still_undecided)
					decision = UD_HOLD;
				break;
		}
	} else if (cmdline_bin_filter.defaulttype == flt_auto_hold) {
		if (cmdline_still_undecided)
			decision = UD_HOLD;
784 785
	}

786
	/* formula tested last as it is the most expensive */
787
	if (rule->includecondition != NULL) {
788
		r = term_decidepackage(rule->includecondition, new, target);
789
		if (RET_WAS_ERROR(r))
790
			return UD_ERROR;
791
		if (r == RET_NOTHING) {
792 793 794 795
			return UD_NO;
		}
	}

796
	return decision;
797 798
}

799
static inline retvalue pull_searchformissing(/*@null@*/FILE *out, struct pull_target *p) {
800
	struct pull_source *source;
801
	retvalue result, r;
802

803 804
	if (verbose > 2 && out != NULL)
		fprintf(out, "  pulling into '%s'\n", p->target->identifier);
805
	assert(p->upgradelist == NULL);
806
	r = upgradelist_initialize(&p->upgradelist, p->target);
807
	if (RET_WAS_ERROR(r))
808 809 810 811
		return r;

	result = RET_NOTHING;

812
	for (source=p->sources ; source != NULL ; source=source->next) {
813

814 815 816 817
		if (source->rule == NULL) {
			if (verbose > 4 && out != NULL)
				fprintf(out,
"  marking everything to be deleted\n");
818
			r = upgradelist_deleteall(p->upgradelist);
819 820
			RET_UPDATE(result, r);
			if (RET_WAS_ERROR(r))
821 822 823 824
				return result;
			continue;
		}

825 826
		if (verbose > 4 && out != NULL)
			fprintf(out, "  looking what to get from '%s'\n",
827
					source->source->identifier);
828 829
		r = upgradelist_pull(p->upgradelist, source->source,
				ud_decide_by_rule, source->rule, source);
830 831
		RET_UPDATE(result, r);
		if (RET_WAS_ERROR(r))
832 833 834 835 836 837
			return result;
	}

	return result;
}

838
static retvalue pull_search(/*@null@*/FILE *out, struct pull_distribution *d) {
839
	retvalue result, r;
840 841 842
	struct pull_target *u;

	result = RET_NOTHING;
843
	for (u=d->targets ; u != NULL ; u=u->next) {
844
		r = pull_searchformissing(out, u);
845 846
		RET_UPDATE(result, r);
		if (RET_WAS_ERROR(r))
847 848 849 850 851
			break;
	}
	return result;
}

Bernhard Link's avatar
Bernhard Link committed
852 853 854
static bool pull_isbigdelete(struct pull_distribution *d) {
	struct pull_target *u, *v;

855 856
	for (u = d->targets ; u != NULL ; u=u->next) {
		if (upgradelist_isbigdelete(u->upgradelist)) {
Bernhard Link's avatar
Bernhard Link committed
857
			d->distribution->omitted = true;
858
			for (v = d->targets ; v != NULL ; v = v->next) {
Bernhard Link's avatar
Bernhard Link committed
859 860 861 862 863 864 865 866 867 868
				upgradelist_free(v->upgradelist);
				v->upgradelist = NULL;
			}
			return true;
		}
	}
	return false;
}


869 870 871 872 873 874 875
static void pull_from_callback(void *privdata, const char **rule_p, const char **from_p) {
	struct pull_source *source = privdata;

	*rule_p = source->rule->name;
	*from_p = source->rule->from;
}

876
static retvalue pull_install(struct pull_distribution *distribution) {
877
	retvalue result, r;
878
	struct pull_target *u;
879
	struct distribution *d = distribution->distribution;
880

881
	assert (logger_isprepared(d->logger));
Bernhard Link's avatar
Bernhard Link committed
882

883
	result = RET_NOTHING;
884
	for (u=distribution->targets ; u != NULL ; u=u->next) {
885
		r = upgradelist_install(u->upgradelist, d->logger,
886
				false, pull_from_callback);
887
		RET_UPDATE(d->status, r);
888
		RET_UPDATE(result, r);
889 890
		upgradelist_free(u->upgradelist);
		u->upgradelist = NULL;
891
		if (RET_WAS_ERROR(r))
892 893
			break;
	}
894
	if (RET_IS_OK(result) && d->tracking != dt_NONE) {
895
		r = tracking_retrack(d, false);
896 897
		RET_ENDUPDATE(result, r);
	}
898 899 900
	return result;
}

901 902 903
static void pull_dumppackage(const char *packagename, /*@null@*/const char *oldversion, /*@null@*/const char *newversion, /*@null@*/const char *bestcandidate, /*@null@*/const struct strlist *newfilekeys, /*@null@*/const char *newcontrol, void *privdata) {
	struct pull_source *source = privdata;

904 905
	if (newversion == NULL) {
		if (oldversion != NULL && bestcandidate != NULL) {
906 907 908
			printf("'%s': '%s' will be deleted"
					" (best new: '%s')\n",
					packagename, oldversion, bestcandidate);
909
		} else if (oldversion != NULL) {
910
			printf("'%s': '%s' will be deleted"
911
					" (no longer available or superseded)\n",
912 913 914 915 916
					packagename, oldversion);
		} else {
			printf("'%s': will NOT be added as '%s'\n",
					packagename, bestcandidate);
		}
917 918 919
	} else if (newversion == oldversion) {
		if (bestcandidate != NULL) {
			if (verbose > 1)
920 921 922 923 924
				printf("'%s': '%s' will be kept"
						" (best new: '%s')\n",
						packagename, oldversion,
						bestcandidate);
		} else {
925
			if (verbose > 0)
926 927 928 929 930 931 932
				printf("'%s': '%s' will be kept"
						" (unavailable for reload)\n",
						packagename, oldversion);
		}
	} else {
		const char *via = source->rule->name;

933 934 935
		assert (newfilekeys != NULL);
		assert (newcontrol != NULL);
		if (oldversion != NULL)
936 937 938 939 940 941 942 943 944
			(void)printf("'%s': '%s' will be upgraded"
					" to '%s' (from '%s'):\n files needed: ",
					packagename, oldversion,
					newversion, via);
		else
			(void)printf("'%s': newly installed"
					" as '%s' (from '%s'):\n files needed: ",
					packagename, newversion, via);
		(void)strlist_fprint(stdout, newfilekeys);
945
		if (verbose > 2)
946 947 948 949 950 951 952
			(void)printf("\n installing as: '%s'\n",
					newcontrol);
		else
			(void)putchar('\n');
	}
}

953 954 955
static void pull_dump(struct pull_distribution *distribution) {
	struct pull_target *u;

956 957
	for (u=distribution->targets ; u != NULL ; u=u->next) {
		if (u->upgradelist == NULL)
958
			continue;
959 960 961 962 963 964 965 966 967 968
		printf("Updates needed for '%s':\n", u->target->identifier);
		upgradelist_dump(u->upgradelist, pull_dumppackage);
		upgradelist_free(u->upgradelist);
		u->upgradelist = NULL;
	}
}

static void pull_dumplistpackage(const char *packagename, /*@null@*/const char *oldversion, /*@null@*/const char *newversion, /*@null@*/const char *bestcandidate, /*@null@*/const struct strlist *newfilekeys, /*@null@*/const char *newcontrol, void *privdata) {
	struct pull_source *source = privdata;

969 970
	if (newversion == NULL) {
		if (oldversion == NULL)
971 972
			return;
		printf("delete '%s' '%s'\n", packagename, oldversion);
973 974
	} else if (newversion == oldversion) {
		if (bestcandidate != NULL)
975 976 977 978 979 980 981 982
			printf("keep '%s' '%s' '%s'\n", packagename,
					oldversion, bestcandidate);
		else
			printf("keep '%s' '%s' unavailable\n", packagename,
					oldversion);
	} else {
		const char *via = source->rule->name;

983 984 985
		assert (newfilekeys != NULL);
		assert (newcontrol != NULL);
		if (oldversion != NULL)
986 987 988 989 990 991 992 993 994 995 996 997
			(void)printf("update '%s' '%s' '%s' '%s'\n",
					packagename, oldversion,
					newversion, via);
		else
			(void)printf("add '%s' - '%s' '%s'\n",
					packagename, newversion, via);
	}
}

static void pull_dumplist(struct pull_distribution *distribution) {
	struct pull_target *u;

998 999
	for (u=distribution->targets ; u != NULL ; u=u->next) {
		if (u->upgradelist == NULL)
1000 1001 1002
			continue;
		printf("Updates needed for '%s':\n", u->target->identifier);
		upgradelist_dump(u->upgradelist, pull_dumplistpackage);
1003 1004
		upgradelist_free(u->upgradelist);
		u->upgradelist = NULL;
1005 1006 1007
	}
}

1008
retvalue pull_update(struct pull_distribution *distributions) {
1009
	retvalue result, r;
1010 1011
	struct pull_distribution *d;

1012
	for (d=distributions ; d != NULL ; d=d->next) {
Bernhard Link's avatar
Bernhard Link committed
1013
		r = distribution_prepareforwriting(d->distribution);
1014
		if (RET_WAS_ERROR(r))
Bernhard Link's avatar
Bernhard Link committed
1015
			return r;
1016
		r = distribution_loadalloverrides(d->distribution);
1017
		if (RET_WAS_ERROR(r))
1018
			return r;
Bernhard Link's avatar
Bernhard Link committed
1019 1020
	}

1021
	if (verbose >= 0)
1022
		printf("Calculating packages to pull...\n");
1023 1024 1025

	result = RET_NOTHING;

1026
	for (d=distributions ; d != NULL ; d=d->next) {
1027
		r = pull_search(stdout, d);
1028 1029
		RET_UPDATE(result, r);
		if (RET_WAS_ERROR(r))
1030 1031 1032
			break;
		// TODO: make already here sure the files are ready?
	}
1033 1034
	if (RET_WAS_ERROR(result)) {
		for (d=distributions ; d != NULL ; d=d->next) {
1035
			struct pull_target *u;
1036
			for (u=d->targets ; u != NULL ; u=u->next) {
1037 1038 1039 1040
				upgradelist_free(u->upgradelist);
				u->upgradelist = NULL;
			}
		}
1041 1042
		return result;
	}
1043
	if (verbose >= 0)
1044
		printf("Installing (and possibly deleting) packages...\n");
1045

1046 1047 1048
	for (d=distributions ; d != NULL ; d=d->next) {
		if (global.onlysmalldeletes) {
			if (pull_isbigdelete(d)) {
Bernhard Link's avatar
Bernhard Link committed
1049 1050 1051 1052 1053 1054
				fprintf(stderr,
"Not processing '%s' because of --onlysmalldeletes\n",
						d->distribution->codename);
				continue;
			}
		}
1055
		r = pull_install(d);
1056 1057
		RET_UPDATE(result, r);
		if (RET_WAS_ERROR(r))
1058 1059
			break;
	}
1060
	logger_wait();
1061 1062 1063 1064

	return result;
}

1065
retvalue pull_checkupdate(struct pull_distribution *distributions) {
1066
	struct pull_distribution *d;
1067
	retvalue result, r;
1068

1069
	for (d=distributions ; d != NULL ; d=d->next) {
1070
		r = distribution_loadalloverrides(d->distribution);
1071
		if (RET_WAS_ERROR(r))
1072 1073 1074
			return r;
	}

1075 1076
	if (verbose >= 0)
		fprintf(stderr, "Calculating packages to get...\n");
1077 1078 1079

	result = RET_NOTHING;

1080
	for (d=distributions ; d != NULL ; d=d->next) {
1081
		r = pull_search(stderr, d);
1082 1083
		RET_UPDATE(result, r);
		if (RET_WAS_ERROR(r))
1084 1085 1086 1087 1088 1089 1090
			break;
		pull_dump(d);
	}

	return result;
}

1091
retvalue pull_dumpupdate(struct pull_distribution *distributions) {
1092
	struct pull_distribution *d;
1093
	retvalue result, r;
1094

1095
	for (d=distributions ; d != NULL ; d=d->next) {
1096
		r = distribution_loadalloverrides(d->distribution);
1097
		if (RET_WAS_ERROR(r))
1098 1099 1100
			return r;
	}

1101 1102
	result = RET_NOTHING;

1103
	for (d=distributions ; d != NULL ; d=d->next) {
1104
		r = pull_search(NULL, d);
1105 1106
		RET_UPDATE(result, r);
		if (RET_WAS_ERROR(r))
1107 1108 1109 1110 1111 1112
			break;
		pull_dumplist(d);
	}

	return result;
}