summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/cgit.c b/cgit.c
index 6ece411..a792fe4 100644
--- a/cgit.c
+++ b/cgit.c
@@ -422,212 +422,213 @@ int cmp_repos(const void *a, const void *b)
422{ 422{
423 const struct cgit_repo *ra = a, *rb = b; 423 const struct cgit_repo *ra = a, *rb = b;
424 return strcmp(ra->url, rb->url); 424 return strcmp(ra->url, rb->url);
425} 425}
426 426
427void print_repo(FILE *f, struct cgit_repo *repo) 427void print_repo(FILE *f, struct cgit_repo *repo)
428{ 428{
429 fprintf(f, "repo.url=%s\n", repo->url); 429 fprintf(f, "repo.url=%s\n", repo->url);
430 fprintf(f, "repo.name=%s\n", repo->name); 430 fprintf(f, "repo.name=%s\n", repo->name);
431 fprintf(f, "repo.path=%s\n", repo->path); 431 fprintf(f, "repo.path=%s\n", repo->path);
432 if (repo->owner) 432 if (repo->owner)
433 fprintf(f, "repo.owner=%s\n", repo->owner); 433 fprintf(f, "repo.owner=%s\n", repo->owner);
434 if (repo->desc) 434 if (repo->desc)
435 fprintf(f, "repo.desc=%s\n", repo->desc); 435 fprintf(f, "repo.desc=%s\n", repo->desc);
436 if (repo->readme) 436 if (repo->readme)
437 fprintf(f, "repo.readme=%s\n", repo->readme); 437 fprintf(f, "repo.readme=%s\n", repo->readme);
438 fprintf(f, "\n"); 438 fprintf(f, "\n");
439} 439}
440 440
441void print_repolist(FILE *f, struct cgit_repolist *list, int start) 441void print_repolist(FILE *f, struct cgit_repolist *list, int start)
442{ 442{
443 int i; 443 int i;
444 444
445 for(i = start; i < list->count; i++) 445 for(i = start; i < list->count; i++)
446 print_repo(f, &list->repos[i]); 446 print_repo(f, &list->repos[i]);
447} 447}
448 448
449/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' 449/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc'
450 * and return 0 on success. 450 * and return 0 on success.
451 */ 451 */
452static int generate_cached_repolist(const char *path, const char *cached_rc) 452static int generate_cached_repolist(const char *path, const char *cached_rc)
453{ 453{
454 char *locked_rc; 454 char *locked_rc;
455 int idx; 455 int idx;
456 FILE *f; 456 FILE *f;
457 457
458 locked_rc = xstrdup(fmt("%s.lock", cached_rc)); 458 locked_rc = xstrdup(fmt("%s.lock", cached_rc));
459 f = fopen(locked_rc, "wx"); 459 f = fopen(locked_rc, "wx");
460 if (!f) { 460 if (!f) {
461 /* Inform about the error unless the lockfile already existed, 461 /* Inform about the error unless the lockfile already existed,
462 * since that only means we've got concurrent requests. 462 * since that only means we've got concurrent requests.
463 */ 463 */
464 if (errno != EEXIST) 464 if (errno != EEXIST)
465 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", 465 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n",
466 locked_rc, strerror(errno), errno); 466 locked_rc, strerror(errno), errno);
467 return errno; 467 return errno;
468 } 468 }
469 idx = cgit_repolist.count; 469 idx = cgit_repolist.count;
470 scan_tree(path); 470 scan_tree(path);
471 print_repolist(f, &cgit_repolist, idx); 471 print_repolist(f, &cgit_repolist, idx);
472 if (rename(locked_rc, cached_rc)) 472 if (rename(locked_rc, cached_rc))
473 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", 473 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
474 locked_rc, cached_rc, strerror(errno), errno); 474 locked_rc, cached_rc, strerror(errno), errno);
475 fclose(f); 475 fclose(f);
476 return 0; 476 return 0;
477} 477}
478 478
479static void process_cached_repolist(const char *path) 479static void process_cached_repolist(const char *path)
480{ 480{
481 struct stat st; 481 struct stat st;
482 char *cached_rc; 482 char *cached_rc;
483 time_t age; 483 time_t age;
484 484
485 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, 485 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root,
486 hash_str(path))); 486 hash_str(path)));
487 487
488 if (stat(cached_rc, &st)) { 488 if (stat(cached_rc, &st)) {
489 /* Nothing is cached, we need to scan without forking. And 489 /* Nothing is cached, we need to scan without forking. And
490 * if we fail to generate a cached repolist, we need to 490 * if we fail to generate a cached repolist, we need to
491 * invoke scan_tree manually. 491 * invoke scan_tree manually.
492 */ 492 */
493 if (generate_cached_repolist(path, cached_rc)) 493 if (generate_cached_repolist(path, cached_rc))
494 scan_tree(path); 494 scan_tree(path);
495 return; 495 return;
496 } 496 }
497 497
498 parse_configfile(cached_rc, config_cb); 498 parse_configfile(cached_rc, config_cb);
499 499
500 /* If the cached configfile hasn't expired, lets exit now */ 500 /* If the cached configfile hasn't expired, lets exit now */
501 age = time(NULL) - st.st_mtime; 501 age = time(NULL) - st.st_mtime;
502 if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) 502 if (age <= (ctx.cfg.cache_scanrc_ttl * 60))
503 return; 503 return;
504 504
505 /* The cached repolist has been parsed, but it was old. So lets 505 /* The cached repolist has been parsed, but it was old. So lets
506 * rescan the specified path and generate a new cached repolist 506 * rescan the specified path and generate a new cached repolist
507 * in a child-process to avoid latency for the current request. 507 * in a child-process to avoid latency for the current request.
508 */ 508 */
509 if (fork()) 509 if (fork())
510 return; 510 return;
511 511
512 exit(generate_cached_repolist(path, cached_rc)); 512 exit(generate_cached_repolist(path, cached_rc));
513} 513}
514 514
515static void cgit_parse_args(int argc, const char **argv) 515static void cgit_parse_args(int argc, const char **argv)
516{ 516{
517 int i; 517 int i;
518 int scan = 0; 518 int scan = 0;
519 519
520 for (i = 1; i < argc; i++) { 520 for (i = 1; i < argc; i++) {
521 if (!strncmp(argv[i], "--cache=", 8)) { 521 if (!strncmp(argv[i], "--cache=", 8)) {
522 ctx.cfg.cache_root = xstrdup(argv[i]+8); 522 ctx.cfg.cache_root = xstrdup(argv[i]+8);
523 } 523 }
524 if (!strcmp(argv[i], "--nocache")) { 524 if (!strcmp(argv[i], "--nocache")) {
525 ctx.cfg.nocache = 1; 525 ctx.cfg.nocache = 1;
526 } 526 }
527 if (!strcmp(argv[i], "--nohttp")) { 527 if (!strcmp(argv[i], "--nohttp")) {
528 ctx.env.no_http = "1"; 528 ctx.env.no_http = "1";
529 } 529 }
530 if (!strncmp(argv[i], "--query=", 8)) { 530 if (!strncmp(argv[i], "--query=", 8)) {
531 ctx.qry.raw = xstrdup(argv[i]+8); 531 ctx.qry.raw = xstrdup(argv[i]+8);
532 } 532 }
533 if (!strncmp(argv[i], "--repo=", 7)) { 533 if (!strncmp(argv[i], "--repo=", 7)) {
534 ctx.qry.repo = xstrdup(argv[i]+7); 534 ctx.qry.repo = xstrdup(argv[i]+7);
535 } 535 }
536 if (!strncmp(argv[i], "--page=", 7)) { 536 if (!strncmp(argv[i], "--page=", 7)) {
537 ctx.qry.page = xstrdup(argv[i]+7); 537 ctx.qry.page = xstrdup(argv[i]+7);
538 } 538 }
539 if (!strncmp(argv[i], "--head=", 7)) { 539 if (!strncmp(argv[i], "--head=", 7)) {
540 ctx.qry.head = xstrdup(argv[i]+7); 540 ctx.qry.head = xstrdup(argv[i]+7);
541 ctx.qry.has_symref = 1; 541 ctx.qry.has_symref = 1;
542 } 542 }
543 if (!strncmp(argv[i], "--sha1=", 7)) { 543 if (!strncmp(argv[i], "--sha1=", 7)) {
544 ctx.qry.sha1 = xstrdup(argv[i]+7); 544 ctx.qry.sha1 = xstrdup(argv[i]+7);
545 ctx.qry.has_sha1 = 1; 545 ctx.qry.has_sha1 = 1;
546 } 546 }
547 if (!strncmp(argv[i], "--ofs=", 6)) { 547 if (!strncmp(argv[i], "--ofs=", 6)) {
548 ctx.qry.ofs = atoi(argv[i]+6); 548 ctx.qry.ofs = atoi(argv[i]+6);
549 } 549 }
550 if (!strncmp(argv[i], "--scan-tree=", 12)) { 550 if (!strncmp(argv[i], "--scan-tree=", 12) ||
551 !strncmp(argv[i], "--scan-path=", 12)) {
551 scan++; 552 scan++;
552 scan_tree(argv[i] + 12); 553 scan_tree(argv[i] + 12);
553 } 554 }
554 } 555 }
555 if (scan) { 556 if (scan) {
556 qsort(cgit_repolist.repos, cgit_repolist.count, 557 qsort(cgit_repolist.repos, cgit_repolist.count,
557 sizeof(struct cgit_repo), cmp_repos); 558 sizeof(struct cgit_repo), cmp_repos);
558 print_repolist(stdout, &cgit_repolist, 0); 559 print_repolist(stdout, &cgit_repolist, 0);
559 exit(0); 560 exit(0);
560 } 561 }
561} 562}
562 563
563static int calc_ttl() 564static int calc_ttl()
564{ 565{
565 if (!ctx.repo) 566 if (!ctx.repo)
566 return ctx.cfg.cache_root_ttl; 567 return ctx.cfg.cache_root_ttl;
567 568
568 if (!ctx.qry.page) 569 if (!ctx.qry.page)
569 return ctx.cfg.cache_repo_ttl; 570 return ctx.cfg.cache_repo_ttl;
570 571
571 if (ctx.qry.has_symref) 572 if (ctx.qry.has_symref)
572 return ctx.cfg.cache_dynamic_ttl; 573 return ctx.cfg.cache_dynamic_ttl;
573 574
574 if (ctx.qry.has_sha1) 575 if (ctx.qry.has_sha1)
575 return ctx.cfg.cache_static_ttl; 576 return ctx.cfg.cache_static_ttl;
576 577
577 return ctx.cfg.cache_repo_ttl; 578 return ctx.cfg.cache_repo_ttl;
578} 579}
579 580
580int main(int argc, const char **argv) 581int main(int argc, const char **argv)
581{ 582{
582 const char *path; 583 const char *path;
583 char *qry; 584 char *qry;
584 int err, ttl; 585 int err, ttl;
585 586
586 prepare_context(&ctx); 587 prepare_context(&ctx);
587 cgit_repolist.length = 0; 588 cgit_repolist.length = 0;
588 cgit_repolist.count = 0; 589 cgit_repolist.count = 0;
589 cgit_repolist.repos = NULL; 590 cgit_repolist.repos = NULL;
590 591
591 cgit_parse_args(argc, argv); 592 cgit_parse_args(argc, argv);
592 parse_configfile(ctx.env.cgit_config, config_cb); 593 parse_configfile(ctx.env.cgit_config, config_cb);
593 ctx.repo = NULL; 594 ctx.repo = NULL;
594 http_parse_querystring(ctx.qry.raw, querystring_cb); 595 http_parse_querystring(ctx.qry.raw, querystring_cb);
595 596
596 /* If virtual-root isn't specified in cgitrc, lets pretend 597 /* If virtual-root isn't specified in cgitrc, lets pretend
597 * that virtual-root equals SCRIPT_NAME. 598 * that virtual-root equals SCRIPT_NAME.
598 */ 599 */
599 if (!ctx.cfg.virtual_root) 600 if (!ctx.cfg.virtual_root)
600 ctx.cfg.virtual_root = ctx.cfg.script_name; 601 ctx.cfg.virtual_root = ctx.cfg.script_name;
601 602
602 /* If no url parameter is specified on the querystring, lets 603 /* If no url parameter is specified on the querystring, lets
603 * use PATH_INFO as url. This allows cgit to work with virtual 604 * use PATH_INFO as url. This allows cgit to work with virtual
604 * urls without the need for rewriterules in the webserver (as 605 * urls without the need for rewriterules in the webserver (as
605 * long as PATH_INFO is included in the cache lookup key). 606 * long as PATH_INFO is included in the cache lookup key).
606 */ 607 */
607 path = ctx.env.path_info; 608 path = ctx.env.path_info;
608 if (!ctx.qry.url && path) { 609 if (!ctx.qry.url && path) {
609 if (path[0] == '/') 610 if (path[0] == '/')
610 path++; 611 path++;
611 ctx.qry.url = xstrdup(path); 612 ctx.qry.url = xstrdup(path);
612 if (ctx.qry.raw) { 613 if (ctx.qry.raw) {
613 qry = ctx.qry.raw; 614 qry = ctx.qry.raw;
614 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); 615 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry));
615 free(qry); 616 free(qry);
616 } else 617 } else
617 ctx.qry.raw = xstrdup(ctx.qry.url); 618 ctx.qry.raw = xstrdup(ctx.qry.url);
618 cgit_parse_url(ctx.qry.url); 619 cgit_parse_url(ctx.qry.url);
619 } 620 }
620 621
621 ttl = calc_ttl(); 622 ttl = calc_ttl();
622 ctx.page.expires += ttl*60; 623 ctx.page.expires += ttl*60;
623 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) 624 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
624 ctx.cfg.nocache = 1; 625 ctx.cfg.nocache = 1;
625 if (ctx.cfg.nocache) 626 if (ctx.cfg.nocache)
626 ctx.cfg.cache_size = 0; 627 ctx.cfg.cache_size = 0;
627 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, 628 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
628 ctx.qry.raw, ttl, process_request, &ctx); 629 ctx.qry.raw, ttl, process_request, &ctx);
629 if (err) 630 if (err)
630 cgit_print_error(fmt("Error processing page: %s (%d)", 631 cgit_print_error(fmt("Error processing page: %s (%d)",
631 strerror(err), err)); 632 strerror(err), err));
632 return err; 633 return err;
633} 634}