Implement a RRDP_CLEAR message that instructs the parent to cleanup
authorclaudio <claudio@openbsd.org>
Thu, 13 Jan 2022 13:18:41 +0000 (13:18 +0000)
committerclaudio <claudio@openbsd.org>
Thu, 13 Jan 2022 13:18:41 +0000 (13:18 +0000)
the rrdp directory. This is used before a snapshot download to ensure
that the snapshot is applied to a clean repo.
Similar cleanup happens if the transfer fails. In that case remove the
temp directory contents only.
This uses a new function remove_contents() to remove everything below
a base directory (a bit like rm -r X/*).
OK tb@

usr.sbin/rpki-client/extern.h
usr.sbin/rpki-client/main.c
usr.sbin/rpki-client/repo.c
usr.sbin/rpki-client/rrdp.c

index 737aa45..c69fb03 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: extern.h,v 1.101 2022/01/11 13:06:07 claudio Exp $ */
+/*     $OpenBSD: extern.h,v 1.102 2022/01/13 13:18:41 claudio Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -309,10 +309,11 @@ enum rrdp_msg {
        RRDP_START,
        RRDP_SESSION,
        RRDP_FILE,
+       RRDP_CLEAR,
        RRDP_END,
        RRDP_HTTP_REQ,
        RRDP_HTTP_INI,
-       RRDP_HTTP_FIN
+       RRDP_HTTP_FIN,
 };
 
 /*
@@ -501,6 +502,7 @@ void                 proc_rrdp(int);
 
 /* Repository handling */
 int             filepath_add(struct filepath_tree *, char *);
+void            rrdp_clear(unsigned int);
 void            rrdp_save_state(unsigned int, struct rrdp_session *);
 int             rrdp_handle_file(unsigned int, enum publish_type, char *,
                    char *, size_t, char *, size_t);
index 1a976d8..e8084bc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: main.c,v 1.174 2022/01/13 11:50:29 claudio Exp $ */
+/*     $OpenBSD: main.c,v 1.175 2022/01/13 13:18:41 claudio Exp $ */
 /*
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -632,6 +632,9 @@ rrdp_process(struct ibuf *b)
                free(uri);
                free(data);
                break;
+       case RRDP_CLEAR:
+               rrdp_clear(id);
+               break;
        default:
                errx(1, "unexpected rrdp response");
        }
index 5451021..6bd584d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: repo.c,v 1.21 2022/01/13 11:47:44 claudio Exp $ */
+/*     $OpenBSD: repo.c,v 1.22 2022/01/13 13:18:41 claudio Exp $ */
 /*
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -106,6 +106,7 @@ static SLIST_HEAD(, repo)   repos = SLIST_HEAD_INITIALIZER(repos);
 unsigned int           repoid;
 
 static struct rsyncrepo        *rsync_get(const char *, int);
+static void             remove_contents(char *);
 
 /*
  * Database of all file path accessed during a run.
@@ -787,6 +788,23 @@ fail:
        free(file);
 }
 
+/*
+ * Remove RRDP repo and start over.
+ */
+void
+rrdp_clear(unsigned int id)
+{
+       struct rrdprepo *rr;
+
+       rr = rrdp_find(id);
+       if (rr == NULL)
+               errx(1, "non-existant rrdp repo %u", id);
+
+       /* remove rrdp repository contents */
+       remove_contents(rr->basedir);
+       remove_contents(rr->temp);
+}
+
 /*
  * Write a file into the temporary RRDP dir but only after checking
  * its hash (if required). The function also makes sure that the file
@@ -932,24 +950,6 @@ fail:
        return 0;
 }
 
-static void
-rrdp_clean_temp(struct rrdprepo *rr)
-{
-       struct filepath *fp, *nfp;
-       char *fn;
-
-       filepath_free(&rr->deleted);
-
-       RB_FOREACH_SAFE(fp, filepath_tree, &rr->added, nfp) {
-               if ((fn = rrdp_filename(rr, fp->file, 1)) != NULL) {
-                       if (unlink(fn) == -1)
-                               warn("unlink %s", fn);
-                       free(fn);
-               }
-               filepath_put(&rr->added, fp);
-       }
-}
-
 /*
  * RSYNC sync finished, either with or without success.
  */
@@ -981,10 +981,10 @@ rsync_finish(unsigned int id, int ok)
        rr = rsync_find(id);
        if (rr == NULL)
                errx(1, "unknown rsync repo %u", id);
-
        /* repository changed state already, ignore request */
        if (rr->state != REPO_LOADING)
                return;
+
        if (ok) {
                logx("%s: loaded from network", rr->basedir);
                stats.rsync_repos++;
@@ -1016,15 +1016,15 @@ rrdp_finish(unsigned int id, int ok)
 
        if (ok && rrdp_merge_repo(rr)) {
                logx("%s: loaded from network", rr->notifyuri);
-               rr->state = REPO_DONE;
                stats.rrdp_repos++;
+               rr->state = REPO_DONE;
                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);
+               stats.rrdp_fails++;
+               rr->state = REPO_FAILED;
+               remove_contents(rr->temp);
                repo_done(rr, 0);
        }
 }
@@ -1418,3 +1418,48 @@ repo_free(void)
        rrdp_free();
        rsync_free();
 }
+
+static void
+remove_contents(char *base)
+{
+       char *argv[2] = { base, NULL };
+       FTS *fts;
+       FTSENT *e;
+
+       if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT, NULL)) == NULL)
+               err(1, "fts_open");
+       errno = 0;
+       while ((e = fts_read(fts)) != NULL) {
+               switch (e->fts_info) {
+               case FTS_NSOK:
+               case FTS_SL:
+               case FTS_SLNONE:
+                       if (unlink(e->fts_accpath) == -1)
+                               warn("unlink %s", e->fts_path);
+                       break;
+               case FTS_D:
+                       break;
+               case FTS_DP:
+                       /* keep root directory */
+                       if (e->fts_level == FTS_ROOTLEVEL)
+                               break;
+                       if (rmdir(e->fts_accpath) == -1)
+                               warn("rmdir %s", e->fts_path);
+                       break;
+               case FTS_NS:
+               case FTS_ERR:
+                       warnx("fts_read %s: %s", e->fts_path,
+                           strerror(e->fts_errno));
+                       break;
+               default:
+                       warnx("unhandled[%x] %s", e->fts_info,
+                           e->fts_path);
+                       break;
+               }
+               errno = 0;
+       }
+       if (errno)
+               err(1, "fts_read");
+       if (fts_close(fts) == -1)
+               err(1, "fts_close");
+}
index 3ee191f..80c22b9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rrdp.c,v 1.19 2021/12/22 09:35:14 claudio Exp $ */
+/*     $OpenBSD: rrdp.c,v 1.20 2022/01/13 13:18:41 claudio Exp $ */
 /*
  * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
@@ -141,6 +141,21 @@ rrdp_state_send(struct rrdp *s)
        io_close_buffer(&msgq, b);
 }
 
+/*
+ * Inform parent to clear the RRDP repository before start of snapshot.
+ */
+static void
+rrdp_clear_repo(struct rrdp *s)
+{
+       enum rrdp_msg type = RRDP_CLEAR;
+       struct ibuf *b;
+
+       b = io_new_buffer();
+       io_simple_buffer(b, &type, sizeof(type));
+       io_simple_buffer(b, &s->id, sizeof(s->id));
+       io_close_buffer(&msgq, b);
+}
+
 /*
  * Send a blob of data to the main process to store it in the repository.
  */
@@ -246,6 +261,7 @@ rrdp_failed(struct rrdp *s)
                /* fallback to a snapshot as per RFC8182 */
                free_delta_xml(s->dxml);
                s->dxml = NULL;
+               rrdp_clear_repo(s);
                s->sxml = new_snapshot_xml(s->parser, &s->current, s);
                s->task = SNAPSHOT;
                s->state = RRDP_STATE_REQ;
@@ -315,6 +331,7 @@ rrdp_finished(struct rrdp *s)
                                break;
                        case SNAPSHOT:
                                logx("%s: downloading snapshot", s->local);
+                               rrdp_clear_repo(s);
                                s->sxml = new_snapshot_xml(p, &s->current, s);
                                s->state = RRDP_STATE_REQ;
                                break;