1 /* $OpenBSD: repo.c,v 1.45 2023/05/16 17:01:31 claudio Exp $ */ 2 /* 3 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> 4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/queue.h> 20 #include <sys/tree.h> 21 #include <sys/types.h> 22 #include <sys/stat.h> 23 24 #include <assert.h> 25 #include <err.h> 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <fts.h> 29 #include <limits.h> 30 #include <poll.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <unistd.h> 35 36 #include <imsg.h> 37 38 #include "extern.h" 39 40 extern struct stats stats; 41 extern int noop; 42 extern int rrdpon; 43 extern int repo_timeout; 44 extern time_t deadline; 45 int nofetch; 46 47 enum repo_state { 48 REPO_LOADING = 0, 49 REPO_DONE = 1, 50 REPO_FAILED = -1, 51 }; 52 53 /* 54 * A ta, rsync or rrdp repository. 55 * Depending on what is needed the generic repository is backed by 56 * a ta, rsync or rrdp repository. Multiple repositories can use the 57 * same backend. 58 */ 59 struct rrdprepo { 60 SLIST_ENTRY(rrdprepo) entry; 61 char *notifyuri; 62 char *basedir; 63 struct filepath_tree deleted; 64 unsigned int id; 65 enum repo_state state; 66 }; 67 static SLIST_HEAD(, rrdprepo) rrdprepos = SLIST_HEAD_INITIALIZER(rrdprepos); 68 69 struct rsyncrepo { 70 SLIST_ENTRY(rsyncrepo) entry; 71 char *repouri; 72 char *basedir; 73 unsigned int id; 74 enum repo_state state; 75 }; 76 static SLIST_HEAD(, rsyncrepo) rsyncrepos = SLIST_HEAD_INITIALIZER(rsyncrepos); 77 78 struct tarepo { 79 SLIST_ENTRY(tarepo) entry; 80 char *descr; 81 char *basedir; 82 char *temp; 83 char **uri; 84 size_t urisz; 85 size_t uriidx; 86 unsigned int id; 87 enum repo_state state; 88 }; 89 static SLIST_HEAD(, tarepo) tarepos = SLIST_HEAD_INITIALIZER(tarepos); 90 91 struct repo { 92 SLIST_ENTRY(repo) entry; 93 char *repouri; 94 char *notifyuri; 95 char *basedir; 96 const struct rrdprepo *rrdp; 97 const struct rsyncrepo *rsync; 98 const struct tarepo *ta; 99 struct entityq queue; /* files waiting for repo */ 100 struct repotalstats stats[TALSZ_MAX]; 101 struct repostats repostats; 102 struct timespec start_time; 103 time_t alarm; /* sync timeout */ 104 int talid; 105 int stats_used[TALSZ_MAX]; 106 unsigned int id; /* identifier */ 107 }; 108 static SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos); 109 110 /* counter for unique repo id */ 111 unsigned int repoid; 112 113 static struct rsyncrepo *rsync_get(const char *, const char *); 114 static void remove_contents(char *); 115 116 /* 117 * Database of all file path accessed during a run. 118 */ 119 struct filepath { 120 RB_ENTRY(filepath) entry; 121 char *file; 122 }; 123 124 static inline int 125 filepathcmp(struct filepath *a, struct filepath *b) 126 { 127 return strcmp(a->file, b->file); 128 } 129 130 RB_PROTOTYPE(filepath_tree, filepath, entry, filepathcmp); 131 132 /* 133 * Functions to lookup which files have been accessed during computation. 134 */ 135 int 136 filepath_add(struct filepath_tree *tree, char *file) 137 { 138 struct filepath *fp; 139 140 if ((fp = malloc(sizeof(*fp))) == NULL) 141 err(1, NULL); 142 if ((fp->file = strdup(file)) == NULL) 143 err(1, NULL); 144 145 if (RB_INSERT(filepath_tree, tree, fp) != NULL) { 146 /* already in the tree */ 147 free(fp->file); 148 free(fp); 149 return 0; 150 } 151 152 return 1; 153 } 154 155 /* 156 * Lookup a file path in the tree and return the object if found or NULL. 157 */ 158 static struct filepath * 159 filepath_find(struct filepath_tree *tree, char *file) 160 { 161 struct filepath needle = { .file = file }; 162 163 return RB_FIND(filepath_tree, tree, &needle); 164 } 165 166 /* 167 * Returns true if file exists in the tree. 168 */ 169 static int 170 filepath_exists(struct filepath_tree *tree, char *file) 171 { 172 return filepath_find(tree, file) != NULL; 173 } 174 175 /* 176 * Remove entry from tree and free it. 177 */ 178 static void 179 filepath_put(struct filepath_tree *tree, struct filepath *fp) 180 { 181 RB_REMOVE(filepath_tree, tree, fp); 182 free((void *)fp->file); 183 free(fp); 184 } 185 186 /* 187 * Free all elements of a filepath tree. 188 */ 189 static void 190 filepath_free(struct filepath_tree *tree) 191 { 192 struct filepath *fp, *nfp; 193 194 RB_FOREACH_SAFE(fp, filepath_tree, tree, nfp) 195 filepath_put(tree, fp); 196 } 197 198 RB_GENERATE(filepath_tree, filepath, entry, filepathcmp); 199 200 /* 201 * Function to hash a string into a unique directory name. 202 * Returned hash needs to be freed. 203 */ 204 static char * 205 hash_dir(const char *uri) 206 { 207 unsigned char m[SHA256_DIGEST_LENGTH]; 208 209 SHA256(uri, strlen(uri), m); 210 return hex_encode(m, sizeof(m)); 211 } 212 213 /* 214 * Function to build the directory name based on URI and a directory 215 * as prefix. Skip the proto:// in URI but keep everything else. 216 */ 217 static char * 218 repo_dir(const char *uri, const char *dir, int hash) 219 { 220 const char *local; 221 char *out, *hdir = NULL; 222 223 if (hash) { 224 local = hdir = hash_dir(uri); 225 } else { 226 local = strchr(uri, ':'); 227 if (local != NULL) 228 local += strlen("://"); 229 else 230 local = uri; 231 } 232 233 if (dir == NULL) { 234 if ((out = strdup(local)) == NULL) 235 err(1, NULL); 236 } else { 237 if (asprintf(&out, "%s/%s", dir, local) == -1) 238 err(1, NULL); 239 } 240 241 free(hdir); 242 return out; 243 } 244 245 /* 246 * Function to create all missing directories to a path. 247 * This functions alters the path temporarily. 248 */ 249 static int 250 repo_mkpath(int fd, char *file) 251 { 252 char *slash; 253 254 /* build directory hierarchy */ 255 slash = strrchr(file, '/'); 256 assert(slash != NULL); 257 *slash = '\0'; 258 if (mkpathat(fd, file) == -1) { 259 warn("mkpath %s", file); 260 return -1; 261 } 262 *slash = '/'; 263 return 0; 264 } 265 266 /* 267 * Return the state of a repository. 268 */ 269 static enum repo_state 270 repo_state(const struct repo *rp) 271 { 272 if (rp->ta) 273 return rp->ta->state; 274 if (rp->rsync) 275 return rp->rsync->state; 276 if (rp->rrdp) 277 return rp->rrdp->state; 278 /* No backend so sync is by definition done. */ 279 return REPO_DONE; 280 } 281 282 /* 283 * Function called once a repository is done with the sync. Either 284 * successfully or after failure. 285 */ 286 static void 287 repo_done(const void *vp, int ok) 288 { 289 struct repo *rp; 290 struct timespec flush_time; 291 292 SLIST_FOREACH(rp, &repos, entry) { 293 if (vp != rp->ta && vp != rp->rsync && vp != rp->rrdp) 294 continue; 295 296 /* for rrdp try to fall back to rsync */ 297 if (vp == rp->rrdp && !ok && !nofetch) { 298 rp->rrdp = NULL; 299 rp->rsync = rsync_get(rp->repouri, rp->basedir); 300 /* need to check if it was already loaded */ 301 if (repo_state(rp) == REPO_LOADING) 302 continue; 303 } 304 305 entityq_flush(&rp->queue, rp); 306 clock_gettime(CLOCK_MONOTONIC, &flush_time); 307 timespecsub(&flush_time, &rp->start_time, 308 &rp->repostats.sync_time); 309 } 310 } 311 312 /* 313 * Build TA file name based on the repo info. 314 * If temp is set add Xs for mkostemp. 315 */ 316 static char * 317 ta_filename(const struct tarepo *tr, int temp) 318 { 319 const char *file; 320 char *nfile; 321 322 /* does not matter which URI, all end with same filename */ 323 file = strrchr(tr->uri[0], '/'); 324 assert(file); 325 326 if (asprintf(&nfile, "%s%s%s", tr->basedir, file, 327 temp ? ".XXXXXXXX" : "") == -1) 328 err(1, NULL); 329 330 return nfile; 331 } 332 333 static void 334 ta_fetch(struct tarepo *tr) 335 { 336 if (!rrdpon) { 337 for (; tr->uriidx < tr->urisz; tr->uriidx++) { 338 if (strncasecmp(tr->uri[tr->uriidx], 339 "rsync://", 8) == 0) 340 break; 341 } 342 } 343 344 if (tr->uriidx >= tr->urisz) { 345 tr->state = REPO_FAILED; 346 logx("ta/%s: fallback to cache", tr->descr); 347 348 repo_done(tr, 0); 349 return; 350 } 351 352 logx("ta/%s: pulling from %s", tr->descr, tr->uri[tr->uriidx]); 353 354 if (strncasecmp(tr->uri[tr->uriidx], "rsync://", 8) == 0) { 355 /* 356 * Create destination location. 357 * Build up the tree to this point. 358 */ 359 rsync_fetch(tr->id, tr->uri[tr->uriidx], tr->basedir, NULL); 360 } else { 361 int fd; 362 363 tr->temp = ta_filename(tr, 1); 364 fd = mkostemp(tr->temp, O_CLOEXEC); 365 if (fd == -1) { 366 warn("mkostemp: %s", tr->temp); 367 http_finish(tr->id, HTTP_FAILED, NULL); 368 return; 369 } 370 if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) 371 warn("fchmod: %s", tr->temp); 372 373 http_fetch(tr->id, tr->uri[tr->uriidx], NULL, fd); 374 } 375 } 376 377 static struct tarepo * 378 ta_get(struct tal *tal) 379 { 380 struct tarepo *tr; 381 382 /* no need to look for possible other repo */ 383 384 if ((tr = calloc(1, sizeof(*tr))) == NULL) 385 err(1, NULL); 386 tr->id = ++repoid; 387 SLIST_INSERT_HEAD(&tarepos, tr, entry); 388 389 if ((tr->descr = strdup(tal->descr)) == NULL) 390 err(1, NULL); 391 tr->basedir = repo_dir(tal->descr, "ta", 0); 392 393 /* steal URI information from TAL */ 394 tr->urisz = tal->urisz; 395 tr->uri = tal->uri; 396 tal->urisz = 0; 397 tal->uri = NULL; 398 399 ta_fetch(tr); 400 401 return tr; 402 } 403 404 static struct tarepo * 405 ta_find(unsigned int id) 406 { 407 struct tarepo *tr; 408 409 SLIST_FOREACH(tr, &tarepos, entry) 410 if (id == tr->id) 411 break; 412 return tr; 413 } 414 415 static void 416 ta_free(void) 417 { 418 struct tarepo *tr; 419 420 while ((tr = SLIST_FIRST(&tarepos)) != NULL) { 421 SLIST_REMOVE_HEAD(&tarepos, entry); 422 free(tr->descr); 423 free(tr->basedir); 424 free(tr->temp); 425 free(tr->uri); 426 free(tr); 427 } 428 } 429 430 static struct rsyncrepo * 431 rsync_get(const char *uri, const char *validdir) 432 { 433 struct rsyncrepo *rr; 434 char *repo; 435 436 if ((repo = rsync_base_uri(uri)) == NULL) 437 errx(1, "bad caRepository URI: %s", uri); 438 439 SLIST_FOREACH(rr, &rsyncrepos, entry) 440 if (strcmp(rr->repouri, repo) == 0) { 441 free(repo); 442 return rr; 443 } 444 445 if ((rr = calloc(1, sizeof(*rr))) == NULL) 446 err(1, NULL); 447 448 rr->id = ++repoid; 449 SLIST_INSERT_HEAD(&rsyncrepos, rr, entry); 450 451 rr->repouri = repo; 452 rr->basedir = repo_dir(repo, ".rsync", 0); 453 454 /* create base directory */ 455 if (mkpath(rr->basedir) == -1) { 456 warn("mkpath %s", rr->basedir); 457 rsync_finish(rr->id, 0); 458 return rr; 459 } 460 461 logx("%s: pulling from %s", rr->basedir, rr->repouri); 462 rsync_fetch(rr->id, rr->repouri, rr->basedir, validdir); 463 464 return rr; 465 } 466 467 static struct rsyncrepo * 468 rsync_find(unsigned int id) 469 { 470 struct rsyncrepo *rr; 471 472 SLIST_FOREACH(rr, &rsyncrepos, entry) 473 if (id == rr->id) 474 break; 475 return rr; 476 } 477 478 static void 479 rsync_free(void) 480 { 481 struct rsyncrepo *rr; 482 483 while ((rr = SLIST_FIRST(&rsyncrepos)) != NULL) { 484 SLIST_REMOVE_HEAD(&rsyncrepos, entry); 485 free(rr->repouri); 486 free(rr->basedir); 487 free(rr); 488 } 489 } 490 491 /* 492 * Build local file name base on the URI and the rrdprepo info. 493 */ 494 static char * 495 rrdp_filename(const struct rrdprepo *rr, const char *uri, int valid) 496 { 497 char *nfile; 498 const char *dir = rr->basedir; 499 500 if (!valid_uri(uri, strlen(uri), "rsync://")) 501 errx(1, "%s: bad URI %s", rr->basedir, uri); 502 uri += strlen("rsync://"); /* skip proto */ 503 if (valid) { 504 if ((nfile = strdup(uri)) == NULL) 505 err(1, NULL); 506 } else { 507 if (asprintf(&nfile, "%s/%s", dir, uri) == -1) 508 err(1, NULL); 509 } 510 return nfile; 511 } 512 513 /* 514 * Build RRDP state file name based on the repo info. 515 * If temp is set add Xs for mkostemp. 516 */ 517 static char * 518 rrdp_state_filename(const struct rrdprepo *rr, int temp) 519 { 520 char *nfile; 521 522 if (asprintf(&nfile, "%s/.state%s", rr->basedir, 523 temp ? ".XXXXXXXX" : "") == -1) 524 err(1, NULL); 525 526 return nfile; 527 } 528 529 static struct rrdprepo * 530 rrdp_find(unsigned int id) 531 { 532 struct rrdprepo *rr; 533 534 SLIST_FOREACH(rr, &rrdprepos, entry) 535 if (id == rr->id) 536 break; 537 return rr; 538 } 539 540 static void 541 rrdp_free(void) 542 { 543 struct rrdprepo *rr; 544 545 while ((rr = SLIST_FIRST(&rrdprepos)) != NULL) { 546 SLIST_REMOVE_HEAD(&rrdprepos, entry); 547 548 free(rr->notifyuri); 549 free(rr->basedir); 550 551 filepath_free(&rr->deleted); 552 553 free(rr); 554 } 555 } 556 557 /* 558 * Check if a directory is an active rrdp repository. 559 * Returns 1 if found else 0. 560 */ 561 static struct repo * 562 repo_rrdp_bypath(const char *dir) 563 { 564 struct repo *rp; 565 566 SLIST_FOREACH(rp, &repos, entry) { 567 if (rp->rrdp == NULL) 568 continue; 569 if (strcmp(dir, rp->rrdp->basedir) == 0) 570 return rp; 571 } 572 return NULL; 573 } 574 575 /* 576 * Check if the URI is actually covered by one of the repositories 577 * that depend on this RRDP repository. 578 * Returns 1 if the URI is valid, 0 if no repouri matches the URI. 579 */ 580 static int 581 rrdp_uri_valid(struct rrdprepo *rr, const char *uri) 582 { 583 struct repo *rp; 584 585 SLIST_FOREACH(rp, &repos, entry) { 586 if (rp->rrdp != rr) 587 continue; 588 if (strncmp(uri, rp->repouri, strlen(rp->repouri)) == 0) 589 return 1; 590 } 591 return 0; 592 } 593 594 /* 595 * Allocate and insert a new repository. 596 */ 597 static struct repo * 598 repo_alloc(int talid) 599 { 600 struct repo *rp; 601 602 if ((rp = calloc(1, sizeof(*rp))) == NULL) 603 err(1, NULL); 604 605 rp->id = ++repoid; 606 rp->talid = talid; 607 rp->alarm = getmonotime() + repo_timeout; 608 TAILQ_INIT(&rp->queue); 609 SLIST_INSERT_HEAD(&repos, rp, entry); 610 clock_gettime(CLOCK_MONOTONIC, &rp->start_time); 611 612 stats.repos++; 613 return rp; 614 } 615 616 /* 617 * Parse the RRDP state file if it exists and set the session struct 618 * based on that information. 619 */ 620 static void 621 rrdp_parse_state(const struct rrdprepo *rr, struct rrdp_session *state) 622 { 623 FILE *f; 624 int fd, ln = 0; 625 const char *errstr; 626 char *line = NULL, *file; 627 size_t len = 0; 628 ssize_t n; 629 630 file = rrdp_state_filename(rr, 0); 631 if ((fd = open(file, O_RDONLY)) == -1) { 632 if (errno != ENOENT) 633 warn("%s: open state file", rr->basedir); 634 free(file); 635 return; 636 } 637 free(file); 638 f = fdopen(fd, "r"); 639 if (f == NULL) 640 err(1, "fdopen"); 641 642 while ((n = getline(&line, &len, f)) != -1) { 643 if (line[n - 1] == '\n') 644 line[n - 1] = '\0'; 645 switch (ln) { 646 case 0: 647 if ((state->session_id = strdup(line)) == NULL) 648 err(1, NULL); 649 break; 650 case 1: 651 state->serial = strtonum(line, 1, LLONG_MAX, &errstr); 652 if (errstr) 653 goto fail; 654 break; 655 case 2: 656 if ((state->last_mod = strdup(line)) == NULL) 657 err(1, NULL); 658 break; 659 default: 660 goto fail; 661 } 662 ln++; 663 } 664 665 free(line); 666 if (ferror(f)) 667 goto fail; 668 fclose(f); 669 return; 670 671 fail: 672 warnx("%s: troubles reading state file", rr->basedir); 673 fclose(f); 674 free(state->session_id); 675 free(state->last_mod); 676 memset(state, 0, sizeof(*state)); 677 } 678 679 /* 680 * Carefully write the RRDP session state file back. 681 */ 682 void 683 rrdp_save_state(unsigned int id, struct rrdp_session *state) 684 { 685 struct rrdprepo *rr; 686 char *temp, *file; 687 FILE *f; 688 int fd; 689 690 rr = rrdp_find(id); 691 if (rr == NULL) 692 errx(1, "non-existent rrdp repo %u", id); 693 694 file = rrdp_state_filename(rr, 0); 695 temp = rrdp_state_filename(rr, 1); 696 697 if ((fd = mkostemp(temp, O_CLOEXEC)) == -1) { 698 warn("mkostemp %s", temp); 699 goto fail; 700 } 701 (void)fchmod(fd, 0644); 702 f = fdopen(fd, "w"); 703 if (f == NULL) 704 err(1, "fdopen"); 705 706 /* write session state file out */ 707 if (fprintf(f, "%s\n%lld\n", state->session_id, 708 state->serial) < 0) { 709 fclose(f); 710 goto fail; 711 } 712 if (state->last_mod != NULL) { 713 if (fprintf(f, "%s\n", state->last_mod) < 0) { 714 fclose(f); 715 goto fail; 716 } 717 } 718 if (fclose(f) != 0) 719 goto fail; 720 721 if (rename(temp, file) == -1) 722 warn("%s: rename state file", rr->basedir); 723 724 free(temp); 725 free(file); 726 return; 727 728 fail: 729 warnx("%s: failed to save state", rr->basedir); 730 unlink(temp); 731 free(temp); 732 free(file); 733 } 734 735 static struct rrdprepo * 736 rrdp_get(const char *uri) 737 { 738 struct rrdp_session state = { 0 }; 739 struct rrdprepo *rr; 740 741 SLIST_FOREACH(rr, &rrdprepos, entry) 742 if (strcmp(rr->notifyuri, uri) == 0) { 743 if (rr->state == REPO_FAILED) 744 return NULL; 745 return rr; 746 } 747 748 if ((rr = calloc(1, sizeof(*rr))) == NULL) 749 err(1, NULL); 750 751 rr->id = ++repoid; 752 SLIST_INSERT_HEAD(&rrdprepos, rr, entry); 753 754 if ((rr->notifyuri = strdup(uri)) == NULL) 755 err(1, NULL); 756 rr->basedir = repo_dir(uri, ".rrdp", 1); 757 758 RB_INIT(&rr->deleted); 759 760 /* create base directory */ 761 if (mkpath(rr->basedir) == -1) { 762 warn("mkpath %s", rr->basedir); 763 rrdp_finish(rr->id, 0); 764 return rr; 765 } 766 767 /* parse state and start the sync */ 768 rrdp_parse_state(rr, &state); 769 rrdp_fetch(rr->id, rr->notifyuri, rr->notifyuri, &state); 770 free(state.session_id); 771 free(state.last_mod); 772 773 logx("%s: pulling from %s", rr->notifyuri, "network"); 774 775 return rr; 776 } 777 778 /* 779 * Remove RRDP repo and start over. 780 */ 781 void 782 rrdp_clear(unsigned int id) 783 { 784 struct rrdprepo *rr; 785 786 rr = rrdp_find(id); 787 if (rr == NULL) 788 errx(1, "non-existent rrdp repo %u", id); 789 790 /* remove rrdp repository contents */ 791 remove_contents(rr->basedir); 792 } 793 794 /* 795 * Write a file into the temporary RRDP dir but only after checking 796 * its hash (if required). The function also makes sure that the file 797 * tracking is properly adjusted. 798 * Returns 1 on success, 0 if the repo is corrupt, -1 on IO error 799 */ 800 int 801 rrdp_handle_file(unsigned int id, enum publish_type pt, char *uri, 802 char *hash, size_t hlen, char *data, size_t dlen) 803 { 804 struct rrdprepo *rr; 805 struct filepath *fp; 806 ssize_t s; 807 char *fn = NULL; 808 int fd = -1, try = 0; 809 int flags; 810 811 rr = rrdp_find(id); 812 if (rr == NULL) 813 errx(1, "non-existent rrdp repo %u", id); 814 if (rr->state == REPO_FAILED) 815 return -1; 816 817 /* check hash of original file for updates and deletes */ 818 if (pt == PUB_UPD || pt == PUB_DEL) { 819 if (filepath_exists(&rr->deleted, uri)) { 820 warnx("%s: already deleted", uri); 821 return 0; 822 } 823 /* try to open file first in rrdp then in valid repo */ 824 do { 825 free(fn); 826 if ((fn = rrdp_filename(rr, uri, try++)) == NULL) 827 return 0; 828 fd = open(fn, O_RDONLY); 829 } while (fd == -1 && try < 2); 830 831 if (!valid_filehash(fd, hash, hlen)) { 832 warnx("%s: bad file digest for %s", rr->notifyuri, fn); 833 free(fn); 834 return 0; 835 } 836 free(fn); 837 } 838 839 /* write new content or mark uri as deleted. */ 840 if (pt == PUB_DEL) { 841 filepath_add(&rr->deleted, uri); 842 } else { 843 fp = filepath_find(&rr->deleted, uri); 844 if (fp != NULL) 845 filepath_put(&rr->deleted, fp); 846 847 /* add new file to rrdp dir */ 848 if ((fn = rrdp_filename(rr, uri, 0)) == NULL) 849 return 0; 850 851 if (repo_mkpath(AT_FDCWD, fn) == -1) 852 goto fail; 853 854 flags = O_WRONLY|O_CREAT|O_TRUNC; 855 if (pt == PUB_ADD) 856 flags |= O_EXCL; 857 fd = open(fn, flags, 0644); 858 if (fd == -1) { 859 if (errno == EEXIST) { 860 warnx("%s: duplicate publish element for %s", 861 rr->notifyuri, fn); 862 free(fn); 863 return 0; 864 } 865 warn("open %s", fn); 866 goto fail; 867 } 868 869 if ((s = write(fd, data, dlen)) == -1) { 870 warn("write %s", fn); 871 goto fail; 872 } 873 close(fd); 874 if ((size_t)s != dlen) /* impossible */ 875 errx(1, "short write %s", fn); 876 free(fn); 877 } 878 879 return 1; 880 881 fail: 882 rr->state = REPO_FAILED; 883 if (fd != -1) 884 close(fd); 885 free(fn); 886 return -1; 887 } 888 889 /* 890 * RSYNC sync finished, either with or without success. 891 */ 892 void 893 rsync_finish(unsigned int id, int ok) 894 { 895 struct rsyncrepo *rr; 896 struct tarepo *tr; 897 898 tr = ta_find(id); 899 if (tr != NULL) { 900 /* repository changed state already, ignore request */ 901 if (tr->state != REPO_LOADING) 902 return; 903 if (ok) { 904 logx("ta/%s: loaded from network", tr->descr); 905 stats.rsync_repos++; 906 tr->state = REPO_DONE; 907 repo_done(tr, 1); 908 } else { 909 warnx("ta/%s: load from network failed", tr->descr); 910 stats.rsync_fails++; 911 tr->uriidx++; 912 ta_fetch(tr); 913 } 914 return; 915 } 916 917 rr = rsync_find(id); 918 if (rr == NULL) 919 errx(1, "unknown rsync repo %u", id); 920 /* repository changed state already, ignore request */ 921 if (rr->state != REPO_LOADING) 922 return; 923 924 if (ok) { 925 logx("%s: loaded from network", rr->basedir); 926 stats.rsync_repos++; 927 rr->state = REPO_DONE; 928 } else { 929 warnx("%s: load from network failed, fallback to cache", 930 rr->basedir); 931 stats.rsync_fails++; 932 rr->state = REPO_FAILED; 933 /* clear rsync repo since it failed */ 934 remove_contents(rr->basedir); 935 } 936 937 repo_done(rr, ok); 938 } 939 940 /* 941 * RRDP sync finished, either with or without success. 942 */ 943 void 944 rrdp_finish(unsigned int id, int ok) 945 { 946 struct rrdprepo *rr; 947 948 rr = rrdp_find(id); 949 if (rr == NULL) 950 errx(1, "unknown RRDP repo %u", id); 951 /* repository changed state already, ignore request */ 952 if (rr->state != REPO_LOADING) 953 return; 954 955 if (ok) { 956 logx("%s: loaded from network", rr->notifyuri); 957 stats.rrdp_repos++; 958 rr->state = REPO_DONE; 959 } else { 960 warnx("%s: load from network failed, fallback to %s", 961 rr->notifyuri, nofetch ? "cache" : "rsync"); 962 stats.rrdp_fails++; 963 rr->state = REPO_FAILED; 964 /* clear the RRDP repo since it failed */ 965 remove_contents(rr->basedir); 966 /* also clear the list of deleted files */ 967 filepath_free(&rr->deleted); 968 } 969 970 repo_done(rr, ok); 971 } 972 973 /* 974 * Handle responses from the http process. For TA file, either rename 975 * or delete the temporary file. For RRDP requests relay the request 976 * over to the rrdp process. 977 */ 978 void 979 http_finish(unsigned int id, enum http_result res, const char *last_mod) 980 { 981 struct tarepo *tr; 982 983 tr = ta_find(id); 984 if (tr == NULL) { 985 /* not a TA fetch therefore RRDP */ 986 rrdp_http_done(id, res, last_mod); 987 return; 988 } 989 990 /* repository changed state already, ignore request */ 991 if (tr->state != REPO_LOADING) 992 return; 993 994 /* Move downloaded TA file into place, or unlink on failure. */ 995 if (res == HTTP_OK) { 996 char *file; 997 998 file = ta_filename(tr, 0); 999 if (rename(tr->temp, file) == -1) 1000 warn("rename to %s", file); 1001 free(file); 1002 1003 logx("ta/%s: loaded from network", tr->descr); 1004 tr->state = REPO_DONE; 1005 stats.http_repos++; 1006 repo_done(tr, 1); 1007 } else { 1008 if (unlink(tr->temp) == -1 && errno != ENOENT) 1009 warn("unlink %s", tr->temp); 1010 1011 tr->uriidx++; 1012 warnx("ta/%s: load from network failed", tr->descr); 1013 ta_fetch(tr); 1014 } 1015 } 1016 1017 /* 1018 * Look up a trust anchor, queueing it for download if not found. 1019 */ 1020 struct repo * 1021 ta_lookup(int id, struct tal *tal) 1022 { 1023 struct repo *rp; 1024 1025 if (tal->urisz == 0) 1026 errx(1, "TAL %s has no URI", tal->descr); 1027 1028 /* Look up in repository table. (Lookup should actually fail here) */ 1029 SLIST_FOREACH(rp, &repos, entry) { 1030 if (strcmp(rp->repouri, tal->uri[0]) == 0) 1031 return rp; 1032 } 1033 1034 rp = repo_alloc(id); 1035 rp->basedir = repo_dir(tal->descr, "ta", 0); 1036 if ((rp->repouri = strdup(tal->uri[0])) == NULL) 1037 err(1, NULL); 1038 1039 /* check if sync disabled ... */ 1040 if (noop) { 1041 logx("%s: using cache", rp->basedir); 1042 entityq_flush(&rp->queue, rp); 1043 return rp; 1044 } 1045 1046 /* try to create base directory */ 1047 if (mkpath(rp->basedir) == -1) 1048 warn("mkpath %s", rp->basedir); 1049 1050 rp->ta = ta_get(tal); 1051 1052 /* need to check if it was already loaded */ 1053 if (repo_state(rp) != REPO_LOADING) 1054 entityq_flush(&rp->queue, rp); 1055 1056 return rp; 1057 } 1058 1059 /* 1060 * Look up a repository, queueing it for discovery if not found. 1061 */ 1062 struct repo * 1063 repo_lookup(int talid, const char *uri, const char *notify) 1064 { 1065 struct repo *rp; 1066 char *repouri; 1067 1068 if ((repouri = rsync_base_uri(uri)) == NULL) 1069 errx(1, "bad caRepository URI: %s", uri); 1070 1071 /* Look up in repository table. */ 1072 SLIST_FOREACH(rp, &repos, entry) { 1073 if (strcmp(rp->repouri, repouri) != 0) 1074 continue; 1075 if (rp->notifyuri != NULL) { 1076 if (notify == NULL) 1077 continue; 1078 if (strcmp(rp->notifyuri, notify) != 0) 1079 continue; 1080 } else if (notify != NULL) 1081 continue; 1082 /* found matching repo */ 1083 free(repouri); 1084 return rp; 1085 } 1086 1087 rp = repo_alloc(talid); 1088 rp->basedir = repo_dir(repouri, NULL, 0); 1089 rp->repouri = repouri; 1090 if (notify != NULL) 1091 if ((rp->notifyuri = strdup(notify)) == NULL) 1092 err(1, NULL); 1093 1094 if (++talrepocnt[talid] >= MAX_REPO_PER_TAL) { 1095 if (talrepocnt[talid] == MAX_REPO_PER_TAL) 1096 warnx("too many repositories under %s", tals[talid]); 1097 nofetch = 1; 1098 } 1099 1100 /* check if sync disabled ... */ 1101 if (noop || nofetch) { 1102 logx("%s: using cache", rp->basedir); 1103 entityq_flush(&rp->queue, rp); 1104 return rp; 1105 } 1106 1107 /* try to create base directory */ 1108 if (mkpath(rp->basedir) == -1) 1109 warn("mkpath %s", rp->basedir); 1110 1111 /* ... else try RRDP first if available then rsync */ 1112 if (notify != NULL) 1113 rp->rrdp = rrdp_get(notify); 1114 if (rp->rrdp == NULL) 1115 rp->rsync = rsync_get(uri, rp->basedir); 1116 1117 /* need to check if it was already loaded */ 1118 if (repo_state(rp) != REPO_LOADING) 1119 entityq_flush(&rp->queue, rp); 1120 1121 return rp; 1122 } 1123 1124 /* 1125 * Find repository by identifier. 1126 */ 1127 struct repo * 1128 repo_byid(unsigned int id) 1129 { 1130 struct repo *rp; 1131 1132 SLIST_FOREACH(rp, &repos, entry) { 1133 if (rp->id == id) 1134 return rp; 1135 } 1136 return NULL; 1137 } 1138 1139 /* 1140 * Find repository by base path. 1141 */ 1142 static struct repo * 1143 repo_bypath(const char *path) 1144 { 1145 struct repo *rp; 1146 1147 SLIST_FOREACH(rp, &repos, entry) { 1148 if (strcmp(rp->basedir, path) == 0) 1149 return rp; 1150 } 1151 return NULL; 1152 } 1153 1154 /* 1155 * Return the repository base or alternate directory. 1156 * Returned string must be freed by caller. 1157 */ 1158 char * 1159 repo_basedir(const struct repo *rp, int wantvalid) 1160 { 1161 char *path = NULL; 1162 1163 if (!wantvalid) { 1164 if (rp->ta) { 1165 if ((path = strdup(rp->ta->basedir)) == NULL) 1166 err(1, NULL); 1167 } else if (rp->rsync) { 1168 if ((path = strdup(rp->rsync->basedir)) == NULL) 1169 err(1, NULL); 1170 } else if (rp->rrdp) { 1171 path = rrdp_filename(rp->rrdp, rp->repouri, 0); 1172 } else 1173 path = NULL; /* only valid repo available */ 1174 } else if (rp->basedir != NULL) { 1175 if ((path = strdup(rp->basedir)) == NULL) 1176 err(1, NULL); 1177 } 1178 1179 return path; 1180 } 1181 1182 /* 1183 * Return the repository identifier. 1184 */ 1185 unsigned int 1186 repo_id(const struct repo *rp) 1187 { 1188 return rp->id; 1189 } 1190 1191 /* 1192 * Return the repository URI. 1193 */ 1194 const char * 1195 repo_uri(const struct repo *rp) 1196 { 1197 return rp->repouri; 1198 } 1199 1200 /* 1201 * Return the repository URI. 1202 */ 1203 void 1204 repo_fetch_uris(const struct repo *rp, const char **carepo, 1205 const char **notifyuri) 1206 { 1207 *carepo = rp->repouri; 1208 *notifyuri = rp->notifyuri; 1209 } 1210 1211 /* 1212 * Return 1 if repository is synced else 0. 1213 */ 1214 int 1215 repo_synced(const struct repo *rp) 1216 { 1217 if (repo_state(rp) == REPO_DONE && 1218 !(rp->rrdp == NULL && rp->rsync == NULL && rp->ta == NULL)) 1219 return 1; 1220 return 0; 1221 } 1222 1223 /* 1224 * Return the protocol string "rrdp", "rsync", "https" which was used to sync. 1225 * Result is only correct if repository was properly synced. 1226 */ 1227 const char * 1228 repo_proto(const struct repo *rp) 1229 { 1230 1231 if (rp->ta != NULL) { 1232 const struct tarepo *tr = rp->ta; 1233 if (tr->uriidx < tr->urisz && 1234 strncasecmp(tr->uri[tr->uriidx], "rsync://", 8) == 0) 1235 return "rsync"; 1236 else 1237 return "https"; 1238 } 1239 if (rp->rrdp != NULL) 1240 return "rrdp"; 1241 return "rsync"; 1242 } 1243 1244 /* 1245 * Return the repository tal ID. 1246 */ 1247 int 1248 repo_talid(const struct repo *rp) 1249 { 1250 return rp->talid; 1251 } 1252 1253 int 1254 repo_queued(struct repo *rp, struct entity *p) 1255 { 1256 if (repo_state(rp) == REPO_LOADING) { 1257 TAILQ_INSERT_TAIL(&rp->queue, p, entries); 1258 return 1; 1259 } 1260 return 0; 1261 } 1262 1263 static void 1264 repo_fail(struct repo *rp) 1265 { 1266 /* reset the alarm since code may fallback to rsync */ 1267 rp->alarm = getmonotime() + repo_timeout; 1268 1269 if (rp->ta) 1270 http_finish(rp->ta->id, HTTP_FAILED, NULL); 1271 else if (rp->rsync) 1272 rsync_finish(rp->rsync->id, 0); 1273 else if (rp->rrdp) 1274 rrdp_finish(rp->rrdp->id, 0); 1275 else 1276 errx(1, "%s: bad repo", rp->repouri); 1277 } 1278 1279 static void 1280 repo_abort(struct repo *rp) 1281 { 1282 /* reset the alarm */ 1283 rp->alarm = getmonotime() + repo_timeout; 1284 1285 if (rp->rsync) 1286 rsync_abort(rp->rsync->id); 1287 else if (rp->rrdp) 1288 rrdp_abort(rp->rrdp->id); 1289 else 1290 repo_fail(rp); 1291 } 1292 1293 int 1294 repo_check_timeout(int timeout) 1295 { 1296 struct repo *rp; 1297 time_t now; 1298 int diff; 1299 1300 now = getmonotime(); 1301 1302 /* check against our runtime deadline first */ 1303 if (deadline != 0) { 1304 if (deadline <= now) { 1305 warnx("deadline reached, giving up on repository sync"); 1306 nofetch = 1; 1307 /* clear deadline since nofetch is set */ 1308 deadline = 0; 1309 /* increase now enough so that all pending repos fail */ 1310 now += repo_timeout; 1311 } else { 1312 diff = deadline - now; 1313 diff *= 1000; 1314 if (timeout == INFTIM || diff < timeout) 1315 timeout = diff; 1316 } 1317 } 1318 /* Look up in repository table. (Lookup should actually fail here) */ 1319 SLIST_FOREACH(rp, &repos, entry) { 1320 if (repo_state(rp) == REPO_LOADING) { 1321 if (rp->alarm <= now) { 1322 warnx("%s: synchronisation timeout", 1323 rp->repouri); 1324 repo_abort(rp); 1325 } else { 1326 diff = rp->alarm - now; 1327 diff *= 1000; 1328 if (timeout == INFTIM || diff < timeout) 1329 timeout = diff; 1330 } 1331 } 1332 } 1333 return timeout; 1334 } 1335 1336 /* 1337 * Update stats object of repository depending on rtype and subtype. 1338 */ 1339 void 1340 repo_stat_inc(struct repo *rp, int talid, enum rtype type, enum stype subtype) 1341 { 1342 if (rp == NULL) 1343 return; 1344 rp->stats_used[talid] = 1; 1345 switch (type) { 1346 case RTYPE_CER: 1347 if (subtype == STYPE_OK) 1348 rp->stats[talid].certs++; 1349 if (subtype == STYPE_FAIL) 1350 rp->stats[talid].certs_fail++; 1351 if (subtype == STYPE_BGPSEC) { 1352 rp->stats[talid].certs--; 1353 rp->stats[talid].brks++; 1354 } 1355 break; 1356 case RTYPE_MFT: 1357 if (subtype == STYPE_OK) 1358 rp->stats[talid].mfts++; 1359 if (subtype == STYPE_FAIL) 1360 rp->stats[talid].mfts_fail++; 1361 if (subtype == STYPE_STALE) 1362 rp->stats[talid].mfts_stale++; 1363 break; 1364 case RTYPE_ROA: 1365 switch (subtype) { 1366 case STYPE_OK: 1367 rp->stats[talid].roas++; 1368 break; 1369 case STYPE_FAIL: 1370 rp->stats[talid].roas_fail++; 1371 break; 1372 case STYPE_INVALID: 1373 rp->stats[talid].roas_invalid++; 1374 break; 1375 case STYPE_TOTAL: 1376 rp->stats[talid].vrps++; 1377 break; 1378 case STYPE_UNIQUE: 1379 rp->stats[talid].vrps_uniqs++; 1380 break; 1381 case STYPE_DEC_UNIQUE: 1382 rp->stats[talid].vrps_uniqs--; 1383 break; 1384 default: 1385 break; 1386 } 1387 break; 1388 case RTYPE_ASPA: 1389 switch (subtype) { 1390 case STYPE_OK: 1391 rp->stats[talid].aspas++; 1392 break; 1393 case STYPE_FAIL: 1394 rp->stats[talid].aspas_fail++; 1395 break; 1396 case STYPE_INVALID: 1397 rp->stats[talid].aspas_invalid++; 1398 break; 1399 case STYPE_TOTAL: 1400 rp->stats[talid].vaps++; 1401 break; 1402 case STYPE_UNIQUE: 1403 rp->stats[talid].vaps_uniqs++; 1404 break; 1405 case STYPE_DEC_UNIQUE: 1406 rp->stats[talid].vaps_uniqs--; 1407 break; 1408 case STYPE_BOTH: 1409 rp->stats[talid].vaps_pas++; 1410 break; 1411 case STYPE_ONLY_IPV4: 1412 rp->stats[talid].vaps_pas4++; 1413 break; 1414 case STYPE_ONLY_IPV6: 1415 rp->stats[talid].vaps_pas6++; 1416 break; 1417 default: 1418 break; 1419 } 1420 break; 1421 case RTYPE_CRL: 1422 rp->stats[talid].crls++; 1423 break; 1424 case RTYPE_GBR: 1425 rp->stats[talid].gbrs++; 1426 break; 1427 case RTYPE_TAK: 1428 rp->stats[talid].taks++; 1429 break; 1430 default: 1431 break; 1432 } 1433 } 1434 1435 void 1436 repo_tal_stats_collect(void (*cb)(const struct repo *, 1437 const struct repotalstats *, void *), int talid, void *arg) 1438 { 1439 struct repo *rp; 1440 1441 SLIST_FOREACH(rp, &repos, entry) { 1442 if (rp->stats_used[talid]) 1443 cb(rp, &rp->stats[talid], arg); 1444 } 1445 } 1446 1447 void 1448 repo_stats_collect(void (*cb)(const struct repo *, const struct repostats *, 1449 void *), void *arg) 1450 { 1451 struct repo *rp; 1452 1453 SLIST_FOREACH(rp, &repos, entry) 1454 cb(rp, &rp->repostats, arg); 1455 } 1456 1457 /* 1458 * Delayed delete of files from RRDP. Since RRDP has no security built-in 1459 * this code needs to check if this RRDP repository is actually allowed to 1460 * remove the file referenced by the URI. 1461 */ 1462 static void 1463 repo_cleanup_rrdp(struct filepath_tree *tree) 1464 { 1465 struct repo *rp; 1466 struct rrdprepo *rr; 1467 struct filepath *fp, *nfp; 1468 char *fn; 1469 1470 SLIST_FOREACH(rp, &repos, entry) { 1471 if (rp->rrdp == NULL) 1472 continue; 1473 rr = (struct rrdprepo *)rp->rrdp; 1474 RB_FOREACH_SAFE(fp, filepath_tree, &rr->deleted, nfp) { 1475 if (!rrdp_uri_valid(rr, fp->file)) { 1476 warnx("%s: external URI %s", rr->notifyuri, 1477 fp->file); 1478 filepath_put(&rr->deleted, fp); 1479 continue; 1480 } 1481 /* try to remove file from rrdp repo ... */ 1482 fn = rrdp_filename(rr, fp->file, 0); 1483 1484 if (unlink(fn) == -1) { 1485 if (errno != ENOENT) 1486 warn("unlink %s", fn); 1487 } else { 1488 if (verbose > 1) 1489 logx("deleted %s", fn); 1490 rp->repostats.del_files++; 1491 } 1492 free(fn); 1493 1494 /* ... and from the valid repository if unused. */ 1495 fn = rrdp_filename(rr, fp->file, 1); 1496 if (!filepath_exists(tree, fn)) { 1497 if (unlink(fn) == -1) { 1498 if (errno != ENOENT) 1499 warn("unlink %s", fn); 1500 } else { 1501 if (verbose > 1) 1502 logx("deleted %s", fn); 1503 rp->repostats.del_files++; 1504 } 1505 } else 1506 warnx("%s: referenced file supposed to be " 1507 "deleted", fn); 1508 1509 free(fn); 1510 filepath_put(&rr->deleted, fp); 1511 } 1512 } 1513 } 1514 1515 /* 1516 * All files in tree are valid and should be moved to the valid repository 1517 * if not already there. Rename the files to the new path and readd the 1518 * filepath entry with the new path if successful. 1519 */ 1520 static void 1521 repo_move_valid(struct filepath_tree *tree) 1522 { 1523 struct filepath *fp, *nfp; 1524 size_t rsyncsz = strlen(".rsync/"); 1525 size_t rrdpsz = strlen(".rrdp/"); 1526 char *fn, *base; 1527 1528 RB_FOREACH_SAFE(fp, filepath_tree, tree, nfp) { 1529 if (strncmp(fp->file, ".rsync/", rsyncsz) != 0 && 1530 strncmp(fp->file, ".rrdp/", rrdpsz) != 0) 1531 continue; /* not a temporary file path */ 1532 1533 if (strncmp(fp->file, ".rsync/", rsyncsz) == 0) { 1534 fn = fp->file + rsyncsz; 1535 } else { 1536 base = strchr(fp->file + rrdpsz, '/'); 1537 assert(base != NULL); 1538 fn = base + 1; 1539 } 1540 1541 if (repo_mkpath(AT_FDCWD, fn) == -1) 1542 continue; 1543 1544 if (rename(fp->file, fn) == -1) { 1545 warn("rename %s", fp->file); 1546 continue; 1547 } 1548 1549 /* switch filepath node to new path */ 1550 RB_REMOVE(filepath_tree, tree, fp); 1551 base = fp->file; 1552 if ((fp->file = strdup(fn)) == NULL) 1553 err(1, NULL); 1554 free(base); 1555 if (RB_INSERT(filepath_tree, tree, fp) != NULL) 1556 errx(1, "%s: both possibilities of file present", 1557 fp->file); 1558 } 1559 } 1560 1561 struct fts_state { 1562 enum { BASE_DIR, RSYNC_DIR, RRDP_DIR } type; 1563 struct repo *rp; 1564 } fts_state; 1565 1566 static const struct rrdprepo * 1567 repo_is_rrdp(struct repo *rp) 1568 { 1569 /* check for special pointers first these are not a repository */ 1570 if (rp != NULL && rp->rrdp != NULL) 1571 return rp->rrdp->state == REPO_DONE ? rp->rrdp : NULL; 1572 return NULL; 1573 } 1574 1575 static inline char * 1576 skip_dotslash(char *in) 1577 { 1578 if (memcmp(in, "./", 2) == 0) 1579 return in + 2; 1580 return in; 1581 } 1582 1583 static void 1584 repo_cleanup_entry(FTSENT *e, struct filepath_tree *tree, int cachefd) 1585 { 1586 const struct rrdprepo *rr; 1587 char *path; 1588 1589 path = skip_dotslash(e->fts_path); 1590 switch (e->fts_info) { 1591 case FTS_NSOK: 1592 if (filepath_exists(tree, path)) { 1593 e->fts_parent->fts_number++; 1594 break; 1595 } 1596 if (fts_state.type == RRDP_DIR && fts_state.rp != NULL) { 1597 e->fts_parent->fts_number++; 1598 /* handle rrdp .state files explicitly */ 1599 if (e->fts_level == 3 && 1600 strcmp(e->fts_name, ".state") == 0) 1601 break; 1602 /* can't delete these extra files */ 1603 fts_state.rp->repostats.extra_files++; 1604 if (verbose > 1) 1605 logx("superfluous %s", path); 1606 break; 1607 } 1608 rr = repo_is_rrdp(fts_state.rp); 1609 if (rr != NULL) { 1610 struct stat st; 1611 char *fn; 1612 1613 if (asprintf(&fn, "%s/%s", rr->basedir, path) == -1) 1614 err(1, NULL); 1615 1616 /* 1617 * If the file exists in the rrdp dir 1618 * that file is newer and needs to be kept 1619 * so unlink this file instead of moving 1620 * it over the file in the rrdp dir. 1621 */ 1622 if (fstatat(cachefd, fn, &st, 0) == 0 && 1623 S_ISREG(st.st_mode)) { 1624 free(fn); 1625 goto unlink; 1626 } 1627 if (repo_mkpath(cachefd, fn) == 0) { 1628 if (renameat(AT_FDCWD, e->fts_accpath, 1629 cachefd, fn) == -1) 1630 warn("rename %s to %s", path, fn); 1631 else if (verbose > 1) 1632 logx("moved %s", path); 1633 fts_state.rp->repostats.extra_files++; 1634 } 1635 free(fn); 1636 } else { 1637 unlink: 1638 if (unlink(e->fts_accpath) == -1) { 1639 warn("unlink %s", path); 1640 } else if (fts_state.type == RSYNC_DIR) { 1641 /* no need to keep rsync files */ 1642 if (verbose > 1) 1643 logx("superfluous %s", path); 1644 if (fts_state.rp != NULL) 1645 fts_state.rp->repostats.del_extra_files++; 1646 else 1647 stats.repo_stats.del_extra_files++; 1648 } else { 1649 if (verbose > 1) 1650 logx("deleted %s", path); 1651 if (fts_state.rp != NULL) 1652 fts_state.rp->repostats.del_files++; 1653 else 1654 stats.repo_stats.del_files++; 1655 } 1656 } 1657 break; 1658 case FTS_D: 1659 if (e->fts_level == FTS_ROOTLEVEL) 1660 fts_state.type = BASE_DIR; 1661 if (e->fts_level == 1) { 1662 if (strcmp(".rsync", e->fts_name) == 0) { 1663 fts_state.type = RSYNC_DIR; 1664 fts_state.rp = NULL; 1665 } else if (strcmp(".rrdp", e->fts_name) == 0) { 1666 fts_state.type = RRDP_DIR; 1667 fts_state.rp = NULL; 1668 } else { 1669 fts_state.type = BASE_DIR; 1670 fts_state.rp = repo_bypath(path); 1671 } 1672 } 1673 if (e->fts_level == 2) { 1674 if (fts_state.type == RSYNC_DIR) 1675 fts_state.rp = repo_bypath(path); 1676 /* 1677 * special handling for rrdp directories, 1678 * clear them if they are not used anymore but 1679 * only if rrdp is active. 1680 */ 1681 if (fts_state.type == RRDP_DIR) 1682 fts_state.rp = repo_rrdp_bypath(path); 1683 } 1684 break; 1685 case FTS_DP: 1686 if (e->fts_level == FTS_ROOTLEVEL) 1687 break; 1688 if (e->fts_level == 1) { 1689 /* do not remove .rsync and .rrdp */ 1690 fts_state.rp = NULL; 1691 if (fts_state.type == RRDP_DIR || 1692 fts_state.type == RSYNC_DIR) 1693 break; 1694 } 1695 1696 e->fts_parent->fts_number += e->fts_number; 1697 1698 if (e->fts_number == 0) { 1699 if (rmdir(e->fts_accpath) == -1) 1700 warn("rmdir %s", path); 1701 if (fts_state.rp != NULL) 1702 fts_state.rp->repostats.del_dirs++; 1703 else 1704 stats.repo_stats.del_dirs++; 1705 } 1706 break; 1707 case FTS_SL: 1708 case FTS_SLNONE: 1709 warnx("symlink %s", path); 1710 if (unlink(e->fts_accpath) == -1) 1711 warn("unlink %s", path); 1712 stats.repo_stats.del_extra_files++; 1713 break; 1714 case FTS_NS: 1715 case FTS_ERR: 1716 if (e->fts_errno == ENOENT && e->fts_level == FTS_ROOTLEVEL) 1717 break; 1718 warnx("fts_read %s: %s", path, strerror(e->fts_errno)); 1719 break; 1720 default: 1721 warnx("fts_read %s: unhandled[%x]", path, e->fts_info); 1722 break; 1723 } 1724 } 1725 1726 void 1727 repo_cleanup(struct filepath_tree *tree, int cachefd) 1728 { 1729 char *argv[2] = { ".", NULL }; 1730 FTS *fts; 1731 FTSENT *e; 1732 1733 /* first move temp files which have been used to valid dir */ 1734 repo_move_valid(tree); 1735 /* then delete files requested by rrdp */ 1736 repo_cleanup_rrdp(tree); 1737 1738 if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT, NULL)) == NULL) 1739 err(1, "fts_open"); 1740 errno = 0; 1741 while ((e = fts_read(fts)) != NULL) { 1742 repo_cleanup_entry(e, tree, cachefd); 1743 errno = 0; 1744 } 1745 if (errno) 1746 err(1, "fts_read"); 1747 if (fts_close(fts) == -1) 1748 err(1, "fts_close"); 1749 } 1750 1751 void 1752 repo_free(void) 1753 { 1754 struct repo *rp; 1755 1756 while ((rp = SLIST_FIRST(&repos)) != NULL) { 1757 SLIST_REMOVE_HEAD(&repos, entry); 1758 free(rp->repouri); 1759 free(rp->notifyuri); 1760 free(rp->basedir); 1761 free(rp); 1762 } 1763 1764 ta_free(); 1765 rrdp_free(); 1766 rsync_free(); 1767 } 1768 1769 /* 1770 * Remove all files and directories under base but do not remove base itself. 1771 */ 1772 static void 1773 remove_contents(char *base) 1774 { 1775 char *argv[2] = { base, NULL }; 1776 FTS *fts; 1777 FTSENT *e; 1778 1779 if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT, NULL)) == NULL) 1780 err(1, "fts_open"); 1781 errno = 0; 1782 while ((e = fts_read(fts)) != NULL) { 1783 switch (e->fts_info) { 1784 case FTS_NSOK: 1785 case FTS_SL: 1786 case FTS_SLNONE: 1787 if (unlink(e->fts_accpath) == -1) 1788 warn("unlink %s", e->fts_path); 1789 break; 1790 case FTS_D: 1791 break; 1792 case FTS_DP: 1793 /* keep root directory */ 1794 if (e->fts_level == FTS_ROOTLEVEL) 1795 break; 1796 if (rmdir(e->fts_accpath) == -1) 1797 warn("rmdir %s", e->fts_path); 1798 break; 1799 case FTS_NS: 1800 case FTS_ERR: 1801 warnx("fts_read %s: %s", e->fts_path, 1802 strerror(e->fts_errno)); 1803 break; 1804 default: 1805 warnx("unhandled[%x] %s", e->fts_info, 1806 e->fts_path); 1807 break; 1808 } 1809 errno = 0; 1810 } 1811 if (errno) 1812 err(1, "fts_read"); 1813 if (fts_close(fts) == -1) 1814 err(1, "fts_close"); 1815 } 1816