-/* $OpenBSD: repo.c,v 1.17 2021/12/22 09:35:14 claudio Exp $ */
+/* $OpenBSD: repo.c,v 1.18 2021/12/29 11:35:23 claudio Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
};
SLIST_HEAD(, tarepo) tarepos = SLIST_HEAD_INITIALIZER(tarepos);
-struct repo {
+struct repo {
SLIST_ENTRY(repo) entry;
char *repouri;
char *notifyuri;
/* counter for unique repo id */
unsigned int repoid;
+static struct rsyncrepo *rsync_get(const char *, int);
+
/*
* Database of all file path accessed during a run.
*/
return 0;
}
+/*
+ * Return the state of a repository.
+ */
+static enum repo_state
+repo_state(struct repo *rp)
+{
+ if (rp->ta)
+ return rp->ta->state;
+ if (rp->rsync)
+ return rp->rsync->state;
+ if (rp->rrdp)
+ return rp->rrdp->state;
+ errx(1, "%s: bad repo", rp->repouri);
+}
+
+/*
+ * Function called once a repository is done with the sync. Either
+ * successfully or after failure.
+ */
+static void
+repo_done(const void *vp, int ok)
+{
+ struct repo *rp;
+
+ SLIST_FOREACH(rp, &repos, entry) {
+ if (vp == rp->ta)
+ entityq_flush(&rp->queue, rp);
+ if (vp == rp->rsync)
+ entityq_flush(&rp->queue, rp);
+ if (vp == rp->rrdp) {
+ if (!ok) {
+ /* try to fall back to rsync */
+ rp->rrdp = NULL;
+ rp->rsync = rsync_get(rp->repouri, 0);
+ /* need to check if it was already loaded */
+ if (repo_state(rp) != REPO_LOADING)
+ entityq_flush(&rp->queue, rp);
+ } else
+ entityq_flush(&rp->queue, rp);
+ }
+ }
+}
+
/*
* Build TA file name based on the repo info.
* If temp is set add Xs for mkostemp.
}
if (tr->uriidx >= tr->urisz) {
- struct repo *rp;
-
tr->state = REPO_FAILED;
logx("ta/%s: fallback to cache", tr->descr);
- SLIST_FOREACH(rp, &repos, entry)
- if (rp->ta == tr)
- entityq_flush(&rp->queue, rp);
+ repo_done(tr, 0);
return;
}
tal->uri = NULL;
if (noop) {
- tr->state = REPO_DONE;
+ tr->state = REPO_FAILED;
logx("ta/%s: using cache", tr->descr);
- /* there is nothing in the queue so no need to flush */
+ repo_done(tr, 0);
} else {
/* try to create base directory */
if (mkpath(tr->basedir) == -1)
rr->basedir = repo_dir(repo, "rsync", 0);
if (noop || nofetch) {
- rr->state = REPO_DONE;
+ rr->state = REPO_FAILED;
logx("%s: using cache", rr->basedir);
- /* there is nothing in the queue so no need to flush */
+ repo_done(rr, 0);
} else {
/* create base directory */
if (mkpath(rr->basedir) == -1) {
RB_INIT(&rr->deleted);
if (noop || nofetch) {
- rr->state = REPO_DONE;
+ rr->state = REPO_FAILED;
logx("%s: using cache", rr->notifyuri);
- /* there is nothing in the queue so no need to flush */
+ repo_done(rr, 0);
} else {
/* create base directory */
if (mkpath(rr->basedir) == -1) {
return rp;
}
-/*
- * Return the state of a repository.
- */
-static enum repo_state
-repo_state(struct repo *rp)
-{
- if (rp->ta)
- return rp->ta->state;
- if (rp->rrdp)
- return rp->rrdp->state;
- if (rp->rsync)
- return rp->rsync->state;
- errx(1, "%s: bad repo", rp->repouri);
-}
-
/*
* Parse the RRDP state file if it exists and set the session struct
* based on that information.
{
struct rsyncrepo *rr;
struct tarepo *tr;
- struct repo *rp;
tr = ta_find(id);
if (tr != NULL) {
logx("ta/%s: loaded from network", tr->descr);
stats.rsync_repos++;
tr->state = REPO_DONE;
+ repo_done(tr, 1);
} else {
logx("ta/%s: load from network failed", tr->descr);
stats.rsync_fails++;
tr->uriidx++;
ta_fetch(tr);
- return;
}
- SLIST_FOREACH(rp, &repos, entry)
- if (rp->ta == tr)
- entityq_flush(&rp->queue, rp);
-
return;
}
rr->state = REPO_FAILED;
}
- SLIST_FOREACH(rp, &repos, entry)
- if (rp->rsync == rr)
- entityq_flush(&rp->queue, rp);
+ repo_done(rr, ok);
}
/*
rrdp_finish(unsigned int id, int ok)
{
struct rrdprepo *rr;
- struct repo *rp;
rr = rrdp_find(id);
if (rr == NULL)
logx("%s: loaded from network", rr->notifyuri);
rr->state = REPO_DONE;
stats.rrdp_repos++;
- SLIST_FOREACH(rp, &repos, entry)
- if (rp->rrdp == rr)
- entityq_flush(&rp->queue, rp);
- } else if (!ok) {
+ repo_done(rr, ok);
+ } else {
rrdp_clean_temp(rr);
stats.rrdp_fails++;
rr->state = REPO_FAILED;
logx("%s: load from network failed, fallback to rsync",
rr->notifyuri);
- SLIST_FOREACH(rp, &repos, entry)
- if (rp->rrdp == rr) {
- rp->rrdp = NULL;
- rp->rsync = rsync_get(rp->repouri, 0);
- /* need to check if it was already loaded */
- if (repo_state(rp) != REPO_LOADING)
- entityq_flush(&rp->queue, rp);
- }
- } else {
- rrdp_clean_temp(rr);
- stats.rrdp_fails++;
- rr->state = REPO_FAILED;
- logx("%s: load from network failed", rr->notifyuri);
- SLIST_FOREACH(rp, &repos, entry)
- if (rp->rrdp == rr)
- entityq_flush(&rp->queue, rp);
+ repo_done(rr, 0);
}
}
http_finish(unsigned int id, enum http_result res, const char *last_mod)
{
struct tarepo *tr;
- struct repo *rp;
tr = ta_find(id);
if (tr == NULL) {
logx("ta/%s: loaded from network", tr->descr);
tr->state = REPO_DONE;
stats.http_repos++;
+ repo_done(tr, 1);
} else {
if (unlink(tr->temp) == -1 && errno != ENOENT)
warn("unlink %s", tr->temp);
tr->uriidx++;
logx("ta/%s: load from network failed", tr->descr);
ta_fetch(tr);
- return;
}
-
- SLIST_FOREACH(rp, &repos, entry)
- if (rp->ta == tr)
- entityq_flush(&rp->queue, rp);
}
* Look up a repository, queueing it for discovery if not found.
*/
struct repo *
-repo_lookup(int id, const char *uri, const char *notify)
+repo_lookup(int talid, const char *uri, const char *notify)
{
struct repo *rp;
char *repouri;
return rp;
}
- rp = repo_alloc(id);
+ rp = repo_alloc(talid);
rp->repouri = repouri;
if (notify != NULL)
if ((rp->notifyuri = strdup(notify)) == NULL)
err(1, NULL);
- if (++talrepocnt[id] >= MAX_REPO_PER_TAL) {
- if (talrepocnt[id] == MAX_REPO_PER_TAL)
- warnx("too many repositories under %s", tals[id]);
+ if (++talrepocnt[talid] >= MAX_REPO_PER_TAL) {
+ if (talrepocnt[talid] == MAX_REPO_PER_TAL)
+ warnx("too many repositories under %s", tals[talid]);
nofetch = 1;
}