summaryrefslogtreecommitdiffabout
authorMark Lodato <lodatom@gmail.com>2011-05-13 23:59:07 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2011-05-23 21:20:59 (UTC)
commitec79265f2053e6dc20e0ec486719f5954d2be83d (patch) (unidiff)
treebae66fbd919c03d0204554cc0c109c7eba0e3b97
parentc8ea73caabcb16ffb74baa70d35650027ed772c4 (diff)
downloadcgit-ec79265f2053e6dc20e0ec486719f5954d2be83d.zip
cgit-ec79265f2053e6dc20e0ec486719f5954d2be83d.tar.gz
cgit-ec79265f2053e6dc20e0ec486719f5954d2be83d.tar.bz2
fix virtual-root if script-name is ""
In d0cb841 (Avoid trailing slash in virtual-root), virtual-root was set from script-name using trim_end(). However, if script-name was the empty string (""), which happens when cgit is used to serve the root path on a domain (/), trim_end() returns NULL and cgit acts like virtual-root is not available. Now, set virtual-root to "" in this case, which fixes this bug. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/cgit.c b/cgit.c
index e302a7c..e498030 100644
--- a/cgit.c
+++ b/cgit.c
@@ -376,419 +376,422 @@ int find_current_ref(const char *refname, const unsigned char *sha1,
376 if (!strcmp(refname, info->req_ref)) 376 if (!strcmp(refname, info->req_ref))
377 info->match = 1; 377 info->match = 1;
378 if (!info->first_ref) 378 if (!info->first_ref)
379 info->first_ref = xstrdup(refname); 379 info->first_ref = xstrdup(refname);
380 return info->match; 380 return info->match;
381} 381}
382 382
383char *find_default_branch(struct cgit_repo *repo) 383char *find_default_branch(struct cgit_repo *repo)
384{ 384{
385 struct refmatch info; 385 struct refmatch info;
386 char *ref; 386 char *ref;
387 387
388 info.req_ref = repo->defbranch; 388 info.req_ref = repo->defbranch;
389 info.first_ref = NULL; 389 info.first_ref = NULL;
390 info.match = 0; 390 info.match = 0;
391 for_each_branch_ref(find_current_ref, &info); 391 for_each_branch_ref(find_current_ref, &info);
392 if (info.match) 392 if (info.match)
393 ref = info.req_ref; 393 ref = info.req_ref;
394 else 394 else
395 ref = info.first_ref; 395 ref = info.first_ref;
396 if (ref) 396 if (ref)
397 ref = xstrdup(ref); 397 ref = xstrdup(ref);
398 return ref; 398 return ref;
399} 399}
400 400
401static int prepare_repo_cmd(struct cgit_context *ctx) 401static int prepare_repo_cmd(struct cgit_context *ctx)
402{ 402{
403 char *tmp; 403 char *tmp;
404 unsigned char sha1[20]; 404 unsigned char sha1[20];
405 int nongit = 0; 405 int nongit = 0;
406 406
407 setenv("GIT_DIR", ctx->repo->path, 1); 407 setenv("GIT_DIR", ctx->repo->path, 1);
408 setup_git_directory_gently(&nongit); 408 setup_git_directory_gently(&nongit);
409 if (nongit) { 409 if (nongit) {
410 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, 410 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
411 "config error"); 411 "config error");
412 tmp = fmt("Not a git repository: '%s'", ctx->repo->path); 412 tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
413 ctx->repo = NULL; 413 ctx->repo = NULL;
414 cgit_print_http_headers(ctx); 414 cgit_print_http_headers(ctx);
415 cgit_print_docstart(ctx); 415 cgit_print_docstart(ctx);
416 cgit_print_pageheader(ctx); 416 cgit_print_pageheader(ctx);
417 cgit_print_error(tmp); 417 cgit_print_error(tmp);
418 cgit_print_docend(); 418 cgit_print_docend();
419 return 1; 419 return 1;
420 } 420 }
421 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); 421 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
422 422
423 if (!ctx->qry.head) { 423 if (!ctx->qry.head) {
424 ctx->qry.nohead = 1; 424 ctx->qry.nohead = 1;
425 ctx->qry.head = find_default_branch(ctx->repo); 425 ctx->qry.head = find_default_branch(ctx->repo);
426 ctx->repo->defbranch = ctx->qry.head; 426 ctx->repo->defbranch = ctx->qry.head;
427 } 427 }
428 428
429 if (!ctx->qry.head) { 429 if (!ctx->qry.head) {
430 cgit_print_http_headers(ctx); 430 cgit_print_http_headers(ctx);
431 cgit_print_docstart(ctx); 431 cgit_print_docstart(ctx);
432 cgit_print_pageheader(ctx); 432 cgit_print_pageheader(ctx);
433 cgit_print_error("Repository seems to be empty"); 433 cgit_print_error("Repository seems to be empty");
434 cgit_print_docend(); 434 cgit_print_docend();
435 return 1; 435 return 1;
436 } 436 }
437 437
438 if (get_sha1(ctx->qry.head, sha1)) { 438 if (get_sha1(ctx->qry.head, sha1)) {
439 tmp = xstrdup(ctx->qry.head); 439 tmp = xstrdup(ctx->qry.head);
440 ctx->qry.head = ctx->repo->defbranch; 440 ctx->qry.head = ctx->repo->defbranch;
441 ctx->page.status = 404; 441 ctx->page.status = 404;
442 ctx->page.statusmsg = "not found"; 442 ctx->page.statusmsg = "not found";
443 cgit_print_http_headers(ctx); 443 cgit_print_http_headers(ctx);
444 cgit_print_docstart(ctx); 444 cgit_print_docstart(ctx);
445 cgit_print_pageheader(ctx); 445 cgit_print_pageheader(ctx);
446 cgit_print_error(fmt("Invalid branch: %s", tmp)); 446 cgit_print_error(fmt("Invalid branch: %s", tmp));
447 cgit_print_docend(); 447 cgit_print_docend();
448 return 1; 448 return 1;
449 } 449 }
450 return 0; 450 return 0;
451} 451}
452 452
453static void process_request(void *cbdata) 453static void process_request(void *cbdata)
454{ 454{
455 struct cgit_context *ctx = cbdata; 455 struct cgit_context *ctx = cbdata;
456 struct cgit_cmd *cmd; 456 struct cgit_cmd *cmd;
457 457
458 cmd = cgit_get_cmd(ctx); 458 cmd = cgit_get_cmd(ctx);
459 if (!cmd) { 459 if (!cmd) {
460 ctx->page.title = "cgit error"; 460 ctx->page.title = "cgit error";
461 cgit_print_http_headers(ctx); 461 cgit_print_http_headers(ctx);
462 cgit_print_docstart(ctx); 462 cgit_print_docstart(ctx);
463 cgit_print_pageheader(ctx); 463 cgit_print_pageheader(ctx);
464 cgit_print_error("Invalid request"); 464 cgit_print_error("Invalid request");
465 cgit_print_docend(); 465 cgit_print_docend();
466 return; 466 return;
467 } 467 }
468 468
469 /* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual" 469 /* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual"
470 * in-project path limit to be made available at ctx->qry.vpath. 470 * in-project path limit to be made available at ctx->qry.vpath.
471 * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL). 471 * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL).
472 */ 472 */
473 ctx->qry.vpath = cmd->want_vpath ? ctx->qry.path : NULL; 473 ctx->qry.vpath = cmd->want_vpath ? ctx->qry.path : NULL;
474 474
475 if (cmd->want_repo && !ctx->repo) { 475 if (cmd->want_repo && !ctx->repo) {
476 cgit_print_http_headers(ctx); 476 cgit_print_http_headers(ctx);
477 cgit_print_docstart(ctx); 477 cgit_print_docstart(ctx);
478 cgit_print_pageheader(ctx); 478 cgit_print_pageheader(ctx);
479 cgit_print_error(fmt("No repository selected")); 479 cgit_print_error(fmt("No repository selected"));
480 cgit_print_docend(); 480 cgit_print_docend();
481 return; 481 return;
482 } 482 }
483 483
484 if (ctx->repo && prepare_repo_cmd(ctx)) 484 if (ctx->repo && prepare_repo_cmd(ctx))
485 return; 485 return;
486 486
487 if (cmd->want_layout) { 487 if (cmd->want_layout) {
488 cgit_print_http_headers(ctx); 488 cgit_print_http_headers(ctx);
489 cgit_print_docstart(ctx); 489 cgit_print_docstart(ctx);
490 cgit_print_pageheader(ctx); 490 cgit_print_pageheader(ctx);
491 } 491 }
492 492
493 cmd->fn(ctx); 493 cmd->fn(ctx);
494 494
495 if (cmd->want_layout) 495 if (cmd->want_layout)
496 cgit_print_docend(); 496 cgit_print_docend();
497} 497}
498 498
499int cmp_repos(const void *a, const void *b) 499int cmp_repos(const void *a, const void *b)
500{ 500{
501 const struct cgit_repo *ra = a, *rb = b; 501 const struct cgit_repo *ra = a, *rb = b;
502 return strcmp(ra->url, rb->url); 502 return strcmp(ra->url, rb->url);
503} 503}
504 504
505char *build_snapshot_setting(int bitmap) 505char *build_snapshot_setting(int bitmap)
506{ 506{
507 const struct cgit_snapshot_format *f; 507 const struct cgit_snapshot_format *f;
508 char *result = xstrdup(""); 508 char *result = xstrdup("");
509 char *tmp; 509 char *tmp;
510 int len; 510 int len;
511 511
512 for (f = cgit_snapshot_formats; f->suffix; f++) { 512 for (f = cgit_snapshot_formats; f->suffix; f++) {
513 if (f->bit & bitmap) { 513 if (f->bit & bitmap) {
514 tmp = result; 514 tmp = result;
515 result = xstrdup(fmt("%s%s ", tmp, f->suffix)); 515 result = xstrdup(fmt("%s%s ", tmp, f->suffix));
516 free(tmp); 516 free(tmp);
517 } 517 }
518 } 518 }
519 len = strlen(result); 519 len = strlen(result);
520 if (len) 520 if (len)
521 result[len - 1] = '\0'; 521 result[len - 1] = '\0';
522 return result; 522 return result;
523} 523}
524 524
525char *get_first_line(char *txt) 525char *get_first_line(char *txt)
526{ 526{
527 char *t = xstrdup(txt); 527 char *t = xstrdup(txt);
528 char *p = strchr(t, '\n'); 528 char *p = strchr(t, '\n');
529 if (p) 529 if (p)
530 *p = '\0'; 530 *p = '\0';
531 return t; 531 return t;
532} 532}
533 533
534void print_repo(FILE *f, struct cgit_repo *repo) 534void print_repo(FILE *f, struct cgit_repo *repo)
535{ 535{
536 fprintf(f, "repo.url=%s\n", repo->url); 536 fprintf(f, "repo.url=%s\n", repo->url);
537 fprintf(f, "repo.name=%s\n", repo->name); 537 fprintf(f, "repo.name=%s\n", repo->name);
538 fprintf(f, "repo.path=%s\n", repo->path); 538 fprintf(f, "repo.path=%s\n", repo->path);
539 if (repo->owner) 539 if (repo->owner)
540 fprintf(f, "repo.owner=%s\n", repo->owner); 540 fprintf(f, "repo.owner=%s\n", repo->owner);
541 if (repo->desc) { 541 if (repo->desc) {
542 char *tmp = get_first_line(repo->desc); 542 char *tmp = get_first_line(repo->desc);
543 fprintf(f, "repo.desc=%s\n", tmp); 543 fprintf(f, "repo.desc=%s\n", tmp);
544 free(tmp); 544 free(tmp);
545 } 545 }
546 if (repo->readme) 546 if (repo->readme)
547 fprintf(f, "repo.readme=%s\n", repo->readme); 547 fprintf(f, "repo.readme=%s\n", repo->readme);
548 if (repo->defbranch) 548 if (repo->defbranch)
549 fprintf(f, "repo.defbranch=%s\n", repo->defbranch); 549 fprintf(f, "repo.defbranch=%s\n", repo->defbranch);
550 if (repo->module_link) 550 if (repo->module_link)
551 fprintf(f, "repo.module-link=%s\n", repo->module_link); 551 fprintf(f, "repo.module-link=%s\n", repo->module_link);
552 if (repo->section) 552 if (repo->section)
553 fprintf(f, "repo.section=%s\n", repo->section); 553 fprintf(f, "repo.section=%s\n", repo->section);
554 if (repo->clone_url) 554 if (repo->clone_url)
555 fprintf(f, "repo.clone-url=%s\n", repo->clone_url); 555 fprintf(f, "repo.clone-url=%s\n", repo->clone_url);
556 fprintf(f, "repo.enable-commit-graph=%d\n", 556 fprintf(f, "repo.enable-commit-graph=%d\n",
557 repo->enable_commit_graph); 557 repo->enable_commit_graph);
558 fprintf(f, "repo.enable-log-filecount=%d\n", 558 fprintf(f, "repo.enable-log-filecount=%d\n",
559 repo->enable_log_filecount); 559 repo->enable_log_filecount);
560 fprintf(f, "repo.enable-log-linecount=%d\n", 560 fprintf(f, "repo.enable-log-linecount=%d\n",
561 repo->enable_log_linecount); 561 repo->enable_log_linecount);
562 if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter) 562 if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter)
563 fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd); 563 fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd);
564 if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter) 564 if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter)
565 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd); 565 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd);
566 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) 566 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter)
567 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); 567 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd);
568 if (repo->snapshots != ctx.cfg.snapshots) { 568 if (repo->snapshots != ctx.cfg.snapshots) {
569 char *tmp = build_snapshot_setting(repo->snapshots); 569 char *tmp = build_snapshot_setting(repo->snapshots);
570 fprintf(f, "repo.snapshots=%s\n", tmp); 570 fprintf(f, "repo.snapshots=%s\n", tmp);
571 free(tmp); 571 free(tmp);
572 } 572 }
573 if (repo->max_stats != ctx.cfg.max_stats) 573 if (repo->max_stats != ctx.cfg.max_stats)
574 fprintf(f, "repo.max-stats=%s\n", 574 fprintf(f, "repo.max-stats=%s\n",
575 cgit_find_stats_periodname(repo->max_stats)); 575 cgit_find_stats_periodname(repo->max_stats));
576 fprintf(f, "\n"); 576 fprintf(f, "\n");
577} 577}
578 578
579void print_repolist(FILE *f, struct cgit_repolist *list, int start) 579void print_repolist(FILE *f, struct cgit_repolist *list, int start)
580{ 580{
581 int i; 581 int i;
582 582
583 for(i = start; i < list->count; i++) 583 for(i = start; i < list->count; i++)
584 print_repo(f, &list->repos[i]); 584 print_repo(f, &list->repos[i]);
585} 585}
586 586
587/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' 587/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc'
588 * and return 0 on success. 588 * and return 0 on success.
589 */ 589 */
590static int generate_cached_repolist(const char *path, const char *cached_rc) 590static int generate_cached_repolist(const char *path, const char *cached_rc)
591{ 591{
592 char *locked_rc; 592 char *locked_rc;
593 int idx; 593 int idx;
594 FILE *f; 594 FILE *f;
595 595
596 locked_rc = xstrdup(fmt("%s.lock", cached_rc)); 596 locked_rc = xstrdup(fmt("%s.lock", cached_rc));
597 f = fopen(locked_rc, "wx"); 597 f = fopen(locked_rc, "wx");
598 if (!f) { 598 if (!f) {
599 /* Inform about the error unless the lockfile already existed, 599 /* Inform about the error unless the lockfile already existed,
600 * since that only means we've got concurrent requests. 600 * since that only means we've got concurrent requests.
601 */ 601 */
602 if (errno != EEXIST) 602 if (errno != EEXIST)
603 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", 603 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n",
604 locked_rc, strerror(errno), errno); 604 locked_rc, strerror(errno), errno);
605 return errno; 605 return errno;
606 } 606 }
607 idx = cgit_repolist.count; 607 idx = cgit_repolist.count;
608 if (ctx.cfg.project_list) 608 if (ctx.cfg.project_list)
609 scan_projects(path, ctx.cfg.project_list, repo_config); 609 scan_projects(path, ctx.cfg.project_list, repo_config);
610 else 610 else
611 scan_tree(path, repo_config); 611 scan_tree(path, repo_config);
612 print_repolist(f, &cgit_repolist, idx); 612 print_repolist(f, &cgit_repolist, idx);
613 if (rename(locked_rc, cached_rc)) 613 if (rename(locked_rc, cached_rc))
614 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", 614 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
615 locked_rc, cached_rc, strerror(errno), errno); 615 locked_rc, cached_rc, strerror(errno), errno);
616 fclose(f); 616 fclose(f);
617 return 0; 617 return 0;
618} 618}
619 619
620static void process_cached_repolist(const char *path) 620static void process_cached_repolist(const char *path)
621{ 621{
622 struct stat st; 622 struct stat st;
623 char *cached_rc; 623 char *cached_rc;
624 time_t age; 624 time_t age;
625 unsigned long hash; 625 unsigned long hash;
626 626
627 hash = hash_str(path); 627 hash = hash_str(path);
628 if (ctx.cfg.project_list) 628 if (ctx.cfg.project_list)
629 hash += hash_str(ctx.cfg.project_list); 629 hash += hash_str(ctx.cfg.project_list);
630 cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash)); 630 cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash));
631 631
632 if (stat(cached_rc, &st)) { 632 if (stat(cached_rc, &st)) {
633 /* Nothing is cached, we need to scan without forking. And 633 /* Nothing is cached, we need to scan without forking. And
634 * if we fail to generate a cached repolist, we need to 634 * if we fail to generate a cached repolist, we need to
635 * invoke scan_tree manually. 635 * invoke scan_tree manually.
636 */ 636 */
637 if (generate_cached_repolist(path, cached_rc)) { 637 if (generate_cached_repolist(path, cached_rc)) {
638 if (ctx.cfg.project_list) 638 if (ctx.cfg.project_list)
639 scan_projects(path, ctx.cfg.project_list, 639 scan_projects(path, ctx.cfg.project_list,
640 repo_config); 640 repo_config);
641 else 641 else
642 scan_tree(path, repo_config); 642 scan_tree(path, repo_config);
643 } 643 }
644 return; 644 return;
645 } 645 }
646 646
647 parse_configfile(cached_rc, config_cb); 647 parse_configfile(cached_rc, config_cb);
648 648
649 /* If the cached configfile hasn't expired, lets exit now */ 649 /* If the cached configfile hasn't expired, lets exit now */
650 age = time(NULL) - st.st_mtime; 650 age = time(NULL) - st.st_mtime;
651 if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) 651 if (age <= (ctx.cfg.cache_scanrc_ttl * 60))
652 return; 652 return;
653 653
654 /* The cached repolist has been parsed, but it was old. So lets 654 /* The cached repolist has been parsed, but it was old. So lets
655 * rescan the specified path and generate a new cached repolist 655 * rescan the specified path and generate a new cached repolist
656 * in a child-process to avoid latency for the current request. 656 * in a child-process to avoid latency for the current request.
657 */ 657 */
658 if (fork()) 658 if (fork())
659 return; 659 return;
660 660
661 exit(generate_cached_repolist(path, cached_rc)); 661 exit(generate_cached_repolist(path, cached_rc));
662} 662}
663 663
664static void cgit_parse_args(int argc, const char **argv) 664static void cgit_parse_args(int argc, const char **argv)
665{ 665{
666 int i; 666 int i;
667 int scan = 0; 667 int scan = 0;
668 668
669 for (i = 1; i < argc; i++) { 669 for (i = 1; i < argc; i++) {
670 if (!strncmp(argv[i], "--cache=", 8)) { 670 if (!strncmp(argv[i], "--cache=", 8)) {
671 ctx.cfg.cache_root = xstrdup(argv[i]+8); 671 ctx.cfg.cache_root = xstrdup(argv[i]+8);
672 } 672 }
673 if (!strcmp(argv[i], "--nocache")) { 673 if (!strcmp(argv[i], "--nocache")) {
674 ctx.cfg.nocache = 1; 674 ctx.cfg.nocache = 1;
675 } 675 }
676 if (!strcmp(argv[i], "--nohttp")) { 676 if (!strcmp(argv[i], "--nohttp")) {
677 ctx.env.no_http = "1"; 677 ctx.env.no_http = "1";
678 } 678 }
679 if (!strncmp(argv[i], "--query=", 8)) { 679 if (!strncmp(argv[i], "--query=", 8)) {
680 ctx.qry.raw = xstrdup(argv[i]+8); 680 ctx.qry.raw = xstrdup(argv[i]+8);
681 } 681 }
682 if (!strncmp(argv[i], "--repo=", 7)) { 682 if (!strncmp(argv[i], "--repo=", 7)) {
683 ctx.qry.repo = xstrdup(argv[i]+7); 683 ctx.qry.repo = xstrdup(argv[i]+7);
684 } 684 }
685 if (!strncmp(argv[i], "--page=", 7)) { 685 if (!strncmp(argv[i], "--page=", 7)) {
686 ctx.qry.page = xstrdup(argv[i]+7); 686 ctx.qry.page = xstrdup(argv[i]+7);
687 } 687 }
688 if (!strncmp(argv[i], "--head=", 7)) { 688 if (!strncmp(argv[i], "--head=", 7)) {
689 ctx.qry.head = xstrdup(argv[i]+7); 689 ctx.qry.head = xstrdup(argv[i]+7);
690 ctx.qry.has_symref = 1; 690 ctx.qry.has_symref = 1;
691 } 691 }
692 if (!strncmp(argv[i], "--sha1=", 7)) { 692 if (!strncmp(argv[i], "--sha1=", 7)) {
693 ctx.qry.sha1 = xstrdup(argv[i]+7); 693 ctx.qry.sha1 = xstrdup(argv[i]+7);
694 ctx.qry.has_sha1 = 1; 694 ctx.qry.has_sha1 = 1;
695 } 695 }
696 if (!strncmp(argv[i], "--ofs=", 6)) { 696 if (!strncmp(argv[i], "--ofs=", 6)) {
697 ctx.qry.ofs = atoi(argv[i]+6); 697 ctx.qry.ofs = atoi(argv[i]+6);
698 } 698 }
699 if (!strncmp(argv[i], "--scan-tree=", 12) || 699 if (!strncmp(argv[i], "--scan-tree=", 12) ||
700 !strncmp(argv[i], "--scan-path=", 12)) { 700 !strncmp(argv[i], "--scan-path=", 12)) {
701 /* HACK: the global snapshot bitmask defines the 701 /* HACK: the global snapshot bitmask defines the
702 * set of allowed snapshot formats, but the config 702 * set of allowed snapshot formats, but the config
703 * file hasn't been parsed yet so the mask is 703 * file hasn't been parsed yet so the mask is
704 * currently 0. By setting all bits high before 704 * currently 0. By setting all bits high before
705 * scanning we make sure that any in-repo cgitrc 705 * scanning we make sure that any in-repo cgitrc
706 * snapshot setting is respected by scan_tree(). 706 * snapshot setting is respected by scan_tree().
707 * BTW: we assume that there'll never be more than 707 * BTW: we assume that there'll never be more than
708 * 255 different snapshot formats supported by cgit... 708 * 255 different snapshot formats supported by cgit...
709 */ 709 */
710 ctx.cfg.snapshots = 0xFF; 710 ctx.cfg.snapshots = 0xFF;
711 scan++; 711 scan++;
712 scan_tree(argv[i] + 12, repo_config); 712 scan_tree(argv[i] + 12, repo_config);
713 } 713 }
714 } 714 }
715 if (scan) { 715 if (scan) {
716 qsort(cgit_repolist.repos, cgit_repolist.count, 716 qsort(cgit_repolist.repos, cgit_repolist.count,
717 sizeof(struct cgit_repo), cmp_repos); 717 sizeof(struct cgit_repo), cmp_repos);
718 print_repolist(stdout, &cgit_repolist, 0); 718 print_repolist(stdout, &cgit_repolist, 0);
719 exit(0); 719 exit(0);
720 } 720 }
721} 721}
722 722
723static int calc_ttl() 723static int calc_ttl()
724{ 724{
725 if (!ctx.repo) 725 if (!ctx.repo)
726 return ctx.cfg.cache_root_ttl; 726 return ctx.cfg.cache_root_ttl;
727 727
728 if (!ctx.qry.page) 728 if (!ctx.qry.page)
729 return ctx.cfg.cache_repo_ttl; 729 return ctx.cfg.cache_repo_ttl;
730 730
731 if (ctx.qry.has_symref) 731 if (ctx.qry.has_symref)
732 return ctx.cfg.cache_dynamic_ttl; 732 return ctx.cfg.cache_dynamic_ttl;
733 733
734 if (ctx.qry.has_sha1) 734 if (ctx.qry.has_sha1)
735 return ctx.cfg.cache_static_ttl; 735 return ctx.cfg.cache_static_ttl;
736 736
737 return ctx.cfg.cache_repo_ttl; 737 return ctx.cfg.cache_repo_ttl;
738} 738}
739 739
740int main(int argc, const char **argv) 740int main(int argc, const char **argv)
741{ 741{
742 const char *path; 742 const char *path;
743 char *qry; 743 char *qry;
744 int err, ttl; 744 int err, ttl;
745 745
746 prepare_context(&ctx); 746 prepare_context(&ctx);
747 cgit_repolist.length = 0; 747 cgit_repolist.length = 0;
748 cgit_repolist.count = 0; 748 cgit_repolist.count = 0;
749 cgit_repolist.repos = NULL; 749 cgit_repolist.repos = NULL;
750 750
751 cgit_parse_args(argc, argv); 751 cgit_parse_args(argc, argv);
752 parse_configfile(expand_macros(ctx.env.cgit_config), config_cb); 752 parse_configfile(expand_macros(ctx.env.cgit_config), config_cb);
753 ctx.repo = NULL; 753 ctx.repo = NULL;
754 http_parse_querystring(ctx.qry.raw, querystring_cb); 754 http_parse_querystring(ctx.qry.raw, querystring_cb);
755 755
756 /* If virtual-root isn't specified in cgitrc, lets pretend 756 /* If virtual-root isn't specified in cgitrc, lets pretend
757 * that virtual-root equals SCRIPT_NAME, minus any possibly 757 * that virtual-root equals SCRIPT_NAME, minus any possibly
758 * trailing slashes. 758 * trailing slashes.
759 */ 759 */
760 if (!ctx.cfg.virtual_root) 760 if (!ctx.cfg.virtual_root && ctx.cfg.script_name) {
761 ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/'); 761 ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/');
762 if (!ctx.cfg.virtual_root)
763 ctx.cfg.virtual_root = "";
764 }
762 765
763 /* If no url parameter is specified on the querystring, lets 766 /* If no url parameter is specified on the querystring, lets
764 * use PATH_INFO as url. This allows cgit to work with virtual 767 * use PATH_INFO as url. This allows cgit to work with virtual
765 * urls without the need for rewriterules in the webserver (as 768 * urls without the need for rewriterules in the webserver (as
766 * long as PATH_INFO is included in the cache lookup key). 769 * long as PATH_INFO is included in the cache lookup key).
767 */ 770 */
768 path = ctx.env.path_info; 771 path = ctx.env.path_info;
769 if (!ctx.qry.url && path) { 772 if (!ctx.qry.url && path) {
770 if (path[0] == '/') 773 if (path[0] == '/')
771 path++; 774 path++;
772 ctx.qry.url = xstrdup(path); 775 ctx.qry.url = xstrdup(path);
773 if (ctx.qry.raw) { 776 if (ctx.qry.raw) {
774 qry = ctx.qry.raw; 777 qry = ctx.qry.raw;
775 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); 778 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry));
776 free(qry); 779 free(qry);
777 } else 780 } else
778 ctx.qry.raw = xstrdup(ctx.qry.url); 781 ctx.qry.raw = xstrdup(ctx.qry.url);
779 cgit_parse_url(ctx.qry.url); 782 cgit_parse_url(ctx.qry.url);
780 } 783 }
781 784
782 ttl = calc_ttl(); 785 ttl = calc_ttl();
783 ctx.page.expires += ttl*60; 786 ctx.page.expires += ttl*60;
784 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) 787 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
785 ctx.cfg.nocache = 1; 788 ctx.cfg.nocache = 1;
786 if (ctx.cfg.nocache) 789 if (ctx.cfg.nocache)
787 ctx.cfg.cache_size = 0; 790 ctx.cfg.cache_size = 0;
788 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, 791 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
789 ctx.qry.raw, ttl, process_request, &ctx); 792 ctx.qry.raw, ttl, process_request, &ctx);
790 if (err) 793 if (err)
791 cgit_print_error(fmt("Error processing page: %s (%d)", 794 cgit_print_error(fmt("Error processing page: %s (%d)",
792 strerror(err), err)); 795 strerror(err), err));
793 return err; 796 return err;
794} 797}