-rw-r--r-- | cgit.c | 5 |
1 files changed, 4 insertions, 1 deletions
@@ -568,227 +568,230 @@ void print_repo(FILE *f, struct cgit_repo *repo) if (repo->snapshots != ctx.cfg.snapshots) { char *tmp = build_snapshot_setting(repo->snapshots); fprintf(f, "repo.snapshots=%s\n", tmp); free(tmp); } if (repo->max_stats != ctx.cfg.max_stats) fprintf(f, "repo.max-stats=%s\n", cgit_find_stats_periodname(repo->max_stats)); fprintf(f, "\n"); } void print_repolist(FILE *f, struct cgit_repolist *list, int start) { int i; for(i = start; i < list->count; i++) print_repo(f, &list->repos[i]); } /* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' * and return 0 on success. */ static int generate_cached_repolist(const char *path, const char *cached_rc) { char *locked_rc; int idx; FILE *f; locked_rc = xstrdup(fmt("%s.lock", cached_rc)); f = fopen(locked_rc, "wx"); if (!f) { /* Inform about the error unless the lockfile already existed, * since that only means we've got concurrent requests. */ if (errno != EEXIST) fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", locked_rc, strerror(errno), errno); return errno; } idx = cgit_repolist.count; if (ctx.cfg.project_list) scan_projects(path, ctx.cfg.project_list, repo_config); else scan_tree(path, repo_config); print_repolist(f, &cgit_repolist, idx); if (rename(locked_rc, cached_rc)) fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", locked_rc, cached_rc, strerror(errno), errno); fclose(f); return 0; } static void process_cached_repolist(const char *path) { struct stat st; char *cached_rc; time_t age; unsigned long hash; hash = hash_str(path); if (ctx.cfg.project_list) hash += hash_str(ctx.cfg.project_list); cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash)); if (stat(cached_rc, &st)) { /* Nothing is cached, we need to scan without forking. And * if we fail to generate a cached repolist, we need to * invoke scan_tree manually. */ if (generate_cached_repolist(path, cached_rc)) { if (ctx.cfg.project_list) scan_projects(path, ctx.cfg.project_list, repo_config); else scan_tree(path, repo_config); } return; } parse_configfile(cached_rc, config_cb); /* If the cached configfile hasn't expired, lets exit now */ age = time(NULL) - st.st_mtime; if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) return; /* The cached repolist has been parsed, but it was old. So lets * rescan the specified path and generate a new cached repolist * in a child-process to avoid latency for the current request. */ if (fork()) return; exit(generate_cached_repolist(path, cached_rc)); } static void cgit_parse_args(int argc, const char **argv) { int i; int scan = 0; for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "--cache=", 8)) { ctx.cfg.cache_root = xstrdup(argv[i]+8); } if (!strcmp(argv[i], "--nocache")) { ctx.cfg.nocache = 1; } if (!strcmp(argv[i], "--nohttp")) { ctx.env.no_http = "1"; } if (!strncmp(argv[i], "--query=", 8)) { ctx.qry.raw = xstrdup(argv[i]+8); } if (!strncmp(argv[i], "--repo=", 7)) { ctx.qry.repo = xstrdup(argv[i]+7); } if (!strncmp(argv[i], "--page=", 7)) { ctx.qry.page = xstrdup(argv[i]+7); } if (!strncmp(argv[i], "--head=", 7)) { ctx.qry.head = xstrdup(argv[i]+7); ctx.qry.has_symref = 1; } if (!strncmp(argv[i], "--sha1=", 7)) { ctx.qry.sha1 = xstrdup(argv[i]+7); ctx.qry.has_sha1 = 1; } if (!strncmp(argv[i], "--ofs=", 6)) { ctx.qry.ofs = atoi(argv[i]+6); } if (!strncmp(argv[i], "--scan-tree=", 12) || !strncmp(argv[i], "--scan-path=", 12)) { /* HACK: the global snapshot bitmask defines the * set of allowed snapshot formats, but the config * file hasn't been parsed yet so the mask is * currently 0. By setting all bits high before * scanning we make sure that any in-repo cgitrc * snapshot setting is respected by scan_tree(). * BTW: we assume that there'll never be more than * 255 different snapshot formats supported by cgit... */ ctx.cfg.snapshots = 0xFF; scan++; scan_tree(argv[i] + 12, repo_config); } } if (scan) { qsort(cgit_repolist.repos, cgit_repolist.count, sizeof(struct cgit_repo), cmp_repos); print_repolist(stdout, &cgit_repolist, 0); exit(0); } } static int calc_ttl() { if (!ctx.repo) return ctx.cfg.cache_root_ttl; if (!ctx.qry.page) return ctx.cfg.cache_repo_ttl; if (ctx.qry.has_symref) return ctx.cfg.cache_dynamic_ttl; if (ctx.qry.has_sha1) return ctx.cfg.cache_static_ttl; return ctx.cfg.cache_repo_ttl; } int main(int argc, const char **argv) { const char *path; char *qry; int err, ttl; prepare_context(&ctx); cgit_repolist.length = 0; cgit_repolist.count = 0; cgit_repolist.repos = NULL; cgit_parse_args(argc, argv); parse_configfile(expand_macros(ctx.env.cgit_config), config_cb); ctx.repo = NULL; http_parse_querystring(ctx.qry.raw, querystring_cb); /* If virtual-root isn't specified in cgitrc, lets pretend * that virtual-root equals SCRIPT_NAME, minus any possibly * trailing slashes. */ - if (!ctx.cfg.virtual_root) + if (!ctx.cfg.virtual_root && ctx.cfg.script_name) { ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/'); + if (!ctx.cfg.virtual_root) + ctx.cfg.virtual_root = ""; + } /* If no url parameter is specified on the querystring, lets * use PATH_INFO as url. This allows cgit to work with virtual * urls without the need for rewriterules in the webserver (as * long as PATH_INFO is included in the cache lookup key). */ path = ctx.env.path_info; if (!ctx.qry.url && path) { if (path[0] == '/') path++; ctx.qry.url = xstrdup(path); if (ctx.qry.raw) { qry = ctx.qry.raw; ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); free(qry); } else ctx.qry.raw = xstrdup(ctx.qry.url); cgit_parse_url(ctx.qry.url); } ttl = calc_ttl(); ctx.page.expires += ttl*60; if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) ctx.cfg.nocache = 1; if (ctx.cfg.nocache) ctx.cfg.cache_size = 0; err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, ctx.qry.raw, ttl, process_request, &ctx); if (err) cgit_print_error(fmt("Error processing page: %s (%d)", strerror(err), err)); return err; } |