summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (show 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
@@ -358,276 +358,277 @@ static int prepare_repo_cmd(struct cgit_context *ctx)
cgit_print_http_headers(ctx);
cgit_print_docstart(ctx);
cgit_print_pageheader(ctx);
cgit_print_error("Repository seems to be empty");
cgit_print_docend();
return 1;
}
if (get_sha1(ctx->qry.head, sha1)) {
tmp = xstrdup(ctx->qry.head);
ctx->qry.head = ctx->repo->defbranch;
ctx->page.status = 404;
ctx->page.statusmsg = "not found";
cgit_print_http_headers(ctx);
cgit_print_docstart(ctx);
cgit_print_pageheader(ctx);
cgit_print_error(fmt("Invalid branch: %s", tmp));
cgit_print_docend();
return 1;
}
return 0;
}
static void process_request(void *cbdata)
{
struct cgit_context *ctx = cbdata;
struct cgit_cmd *cmd;
cmd = cgit_get_cmd(ctx);
if (!cmd) {
ctx->page.title = "cgit error";
cgit_print_http_headers(ctx);
cgit_print_docstart(ctx);
cgit_print_pageheader(ctx);
cgit_print_error("Invalid request");
cgit_print_docend();
return;
}
if (cmd->want_repo && !ctx->repo) {
cgit_print_http_headers(ctx);
cgit_print_docstart(ctx);
cgit_print_pageheader(ctx);
cgit_print_error(fmt("No repository selected"));
cgit_print_docend();
return;
}
if (ctx->repo && prepare_repo_cmd(ctx))
return;
if (cmd->want_layout) {
cgit_print_http_headers(ctx);
cgit_print_docstart(ctx);
cgit_print_pageheader(ctx);
}
cmd->fn(ctx);
if (cmd->want_layout)
cgit_print_docend();
}
int cmp_repos(const void *a, const void *b)
{
const struct cgit_repo *ra = a, *rb = b;
return strcmp(ra->url, rb->url);
}
void print_repo(FILE *f, struct cgit_repo *repo)
{
fprintf(f, "repo.url=%s\n", repo->url);
fprintf(f, "repo.name=%s\n", repo->name);
fprintf(f, "repo.path=%s\n", repo->path);
if (repo->owner)
fprintf(f, "repo.owner=%s\n", repo->owner);
if (repo->desc)
fprintf(f, "repo.desc=%s\n", repo->desc);
if (repo->readme)
fprintf(f, "repo.readme=%s\n", repo->readme);
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;
scan_tree(path);
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;
cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root,
hash_str(path)));
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))
scan_tree(path);
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)) {
+ if (!strncmp(argv[i], "--scan-tree=", 12) ||
+ !strncmp(argv[i], "--scan-path=", 12)) {
scan++;
scan_tree(argv[i] + 12);
}
}
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(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.
*/
if (!ctx.cfg.virtual_root)
ctx.cfg.virtual_root = ctx.cfg.script_name;
/* 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;
}