Diffstat (limited to 'cgit.c')
| -rw-r--r-- | cgit.c | 361 |
1 files changed, 212 insertions, 149 deletions
@@ -1,11 +1,17 @@ /* cgit.c: cgi for the git scm * * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com> + * Copyright (C) 2026 Saya Andy <saya.andy@posteo.com> + * + * Modified 2026 by Saya Andy: + * Always check there is git repo on repo.path * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ +#define USE_THE_REPOSITORY_VARIABLE + #include "cgit.h" #include "cache.h" #include "cmd.h" @@ -19,36 +25,67 @@ const char *cgit_version = CGIT_VERSION; +__attribute__((constructor)) +static void constructor_environment() +{ + /* Do not look in /etc/ for gitconfig and gitattributes. */ + setenv("GIT_CONFIG_NOSYSTEM", "1", 1); + setenv("GIT_ATTR_NOSYSTEM", "1", 1); + unsetenv("HOME"); + unsetenv("XDG_CONFIG_HOME"); +} + static void add_mimetype(const char *name, const char *value) { struct string_list_item *item; - item = string_list_insert(&ctx.cfg.mimetypes, xstrdup(name)); + item = string_list_insert(&ctx.cfg.mimetypes, name); item->util = xstrdup(value); } static void process_cached_repolist(const char *path); -static void repo_config(struct cgit_repo *repo, const char *name, const char *value) +void cgit_repo_config(struct cgit_repo *repo, const char *name, const char *value) { + const char *path; struct string_list_item *item; if (!strcmp(name, "name")) - repo->name = xstrdup(value); + repo->name = strdup_first_line(value); else if (!strcmp(name, "clone-url")) - repo->clone_url = xstrdup(value); + repo->clone_url = strdup_first_line(value); else if (!strcmp(name, "desc")) - repo->desc = xstrdup(value); + repo->desc = strdup_first_line(value); else if (!strcmp(name, "owner")) - repo->owner = xstrdup(value); + repo->owner = strdup_first_line(value); else if (!strcmp(name, "homepage")) - repo->homepage = xstrdup(value); + repo->homepage = strdup_first_line(value); + else if (!strcmp(name, "ci-url")) { + repo->ci_url = strdup_first_line(value); + /* An explicit repo.ci-url would otherwise never be used + * when the more specific urls are inherited from the + * global settings, so discard those. + */ + if (repo->ci_branch_url == ctx.cfg.ci_branch_url) + repo->ci_branch_url = NULL; + if (repo->ci_tag_url == ctx.cfg.ci_tag_url) + repo->ci_tag_url = NULL; + } else if (!strcmp(name, "ci-branch-url")) + repo->ci_branch_url = strdup_first_line(value); + else if (!strcmp(name, "ci-tag-url")) + repo->ci_tag_url = strdup_first_line(value); else if (!strcmp(name, "defbranch")) - repo->defbranch = xstrdup(value); + repo->defbranch = strdup_first_line(value); + else if (!strcmp(name, "extra-head-content")) + repo->extra_head_content = strdup_first_line(value); else if (!strcmp(name, "snapshots")) repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); + else if (!strcmp(name, "enable-blame")) + repo->enable_blame = atoi(value); else if (!strcmp(name, "enable-commit-graph")) repo->enable_commit_graph = atoi(value); + else if (!strcmp(name, "enable-follow-links")) + repo->enable_follow_links = atoi(value); else if (!strcmp(name, "enable-log-filecount")) repo->enable_log_filecount = atoi(value); else if (!strcmp(name, "enable-log-linecount")) @@ -72,20 +109,22 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va } else if (!strcmp(name, "max-stats")) repo->max_stats = cgit_find_stats_period(value, NULL); else if (!strcmp(name, "module-link")) - repo->module_link= xstrdup(value); - else if (starts_with(name, "module-link.")) { - item = string_list_append(&repo->submodules, xstrdup(name + 12)); - item->util = xstrdup(value); + repo->module_link= strdup_first_line(value); + else if (skip_prefix(name, "module-link.", &path)) { + item = string_list_append(&repo->submodules, strdup_first_line(path)); + item->util = strdup_first_line(value); } else if (!strcmp(name, "section")) - repo->section = xstrdup(value); + repo->section = strdup_first_line(value); + else if (!strcmp(name, "snapshot-prefix")) + repo->snapshot_prefix = strdup_first_line(value); else if (!strcmp(name, "readme") && value != NULL) { if (repo->readme.items == ctx.cfg.readme.items) memset(&repo->readme, 0, sizeof(repo->readme)); - string_list_append(&repo->readme, xstrdup(value)); + string_list_append(&repo->readme, strdup_first_line(value)); } else if (!strcmp(name, "logo") && value != NULL) - repo->logo = xstrdup(value); + repo->logo = strdup_first_line(value); else if (!strcmp(name, "logo-link") && value != NULL) - repo->logo_link = xstrdup(value); + repo->logo_link = strdup_first_line(value); else if (!strcmp(name, "hide")) repo->hide = atoi(value); else if (!strcmp(name, "ignore")) @@ -101,53 +140,59 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va repo->email_filter = cgit_new_filter(value, EMAIL); else if (!strcmp(name, "owner-filter")) repo->owner_filter = cgit_new_filter(value, OWNER); + else if (!strcmp(name, "ci-filter")) + repo->ci_filter = cgit_new_filter(value, CI); } } static void config_cb(const char *name, const char *value) { - if (!strcmp(name, "section") || !strcmp(name, "repo.group")) - ctx.cfg.section = xstrdup(value); + const char *arg; + + if (!strcmp(name, "section")) + ctx.cfg.section = strdup_first_line(value); else if (!strcmp(name, "repo.url")) ctx.repo = cgit_add_repo(value); else if (ctx.repo && !strcmp(name, "repo.path")) ctx.repo->path = trim_end(value, '/'); - else if (ctx.repo && starts_with(name, "repo.")) - repo_config(ctx.repo, name + 5, value); + else if (ctx.repo && skip_prefix(name, "repo.", &arg)) + cgit_repo_config(ctx.repo, arg, value); else if (!strcmp(name, "readme")) - string_list_append(&ctx.cfg.readme, xstrdup(value)); + string_list_append(&ctx.cfg.readme, strdup_first_line(value)); else if (!strcmp(name, "root-title")) - ctx.cfg.root_title = xstrdup(value); + ctx.cfg.root_title = strdup_first_line(value); else if (!strcmp(name, "root-desc")) - ctx.cfg.root_desc = xstrdup(value); + ctx.cfg.root_desc = strdup_first_line(value); else if (!strcmp(name, "root-readme")) - ctx.cfg.root_readme = xstrdup(value); + ctx.cfg.root_readme = strdup_first_line(value); else if (!strcmp(name, "css")) - ctx.cfg.css = xstrdup(value); + string_list_append(&ctx.cfg.css, strdup_first_line(value)); + else if (!strcmp(name, "js")) + string_list_append(&ctx.cfg.js, strdup_first_line(value)); else if (!strcmp(name, "favicon")) - ctx.cfg.favicon = xstrdup(value); + ctx.cfg.favicon = strdup_first_line(value); else if (!strcmp(name, "footer")) - ctx.cfg.footer = xstrdup(value); + ctx.cfg.footer = strdup_first_line(value); else if (!strcmp(name, "head-include")) - ctx.cfg.head_include = xstrdup(value); + ctx.cfg.head_include = strdup_first_line(value); else if (!strcmp(name, "header")) - ctx.cfg.header = xstrdup(value); + ctx.cfg.header = strdup_first_line(value); else if (!strcmp(name, "logo")) - ctx.cfg.logo = xstrdup(value); - else if (!strcmp(name, "index-header")) - ctx.cfg.index_header = xstrdup(value); - else if (!strcmp(name, "index-info")) - ctx.cfg.index_info = xstrdup(value); + ctx.cfg.logo = strdup_first_line(value); else if (!strcmp(name, "logo-link")) - ctx.cfg.logo_link = xstrdup(value); + ctx.cfg.logo_link = strdup_first_line(value); else if (!strcmp(name, "module-link")) - ctx.cfg.module_link = xstrdup(value); + ctx.cfg.module_link = strdup_first_line(value); + else if (!strcmp(name, "ci-url")) + ctx.cfg.ci_url = strdup_first_line(value); + else if (!strcmp(name, "ci-branch-url")) + ctx.cfg.ci_branch_url = strdup_first_line(value); + else if (!strcmp(name, "ci-tag-url")) + ctx.cfg.ci_tag_url = strdup_first_line(value); else if (!strcmp(name, "strict-export")) - ctx.cfg.strict_export = xstrdup(value); - else if (!strcmp(name, "virtual-root")) { + ctx.cfg.strict_export = strdup_first_line(value); + else if (!strcmp(name, "virtual-root")) ctx.cfg.virtual_root = ensure_end(value, '/'); - } else if (!strcmp(name, "nocache")) - ctx.cfg.nocache = atoi(value); else if (!strcmp(name, "noplainemail")) ctx.cfg.noplainemail = atoi(value); else if (!strcmp(name, "noheader")) @@ -164,6 +209,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.enable_index_links = atoi(value); else if (!strcmp(name, "enable-index-owner")) ctx.cfg.enable_index_owner = atoi(value); + else if (!strcmp(name, "enable-blame")) + ctx.cfg.enable_blame = atoi(value); else if (!strcmp(name, "enable-commit-graph")) ctx.cfg.enable_commit_graph = atoi(value); else if (!strcmp(name, "enable-log-filecount")) @@ -185,7 +232,7 @@ static void config_cb(const char *name, const char *value) else if (!strcmp(name, "cache-size")) ctx.cfg.cache_size = atoi(value); else if (!strcmp(name, "cache-root")) - ctx.cfg.cache_root = xstrdup(expand_macros(value)); + ctx.cfg.cache_root = strdup_first_line(expand_macros(value)); else if (!strcmp(name, "cache-root-ttl")) ctx.cfg.cache_root_ttl = atoi(value); else if (!strcmp(name, "cache-repo-ttl")) @@ -212,6 +259,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.owner_filter = cgit_new_filter(value, OWNER); else if (!strcmp(name, "auth-filter")) ctx.cfg.auth_filter = cgit_new_filter(value, AUTH); + else if (!strcmp(name, "ci-filter")) + ctx.cfg.ci_filter = cgit_new_filter(value, CI); else if (!strcmp(name, "embedded")) ctx.cfg.embedded = atoi(value); else if (!strcmp(name, "max-atom-items")) @@ -222,26 +271,28 @@ static void config_cb(const char *name, const char *value) ctx.cfg.max_repodesc_len = atoi(value); else if (!strcmp(name, "max-blob-size")) ctx.cfg.max_blob_size = atoi(value); - else if (!strcmp(name, "max-repo-count")) + else if (!strcmp(name, "max-repo-count")) { ctx.cfg.max_repo_count = atoi(value); - else if (!strcmp(name, "max-commit-count")) + if (ctx.cfg.max_repo_count <= 0) + ctx.cfg.max_repo_count = INT_MAX; + } else if (!strcmp(name, "max-commit-count")) ctx.cfg.max_commit_count = atoi(value); else if (!strcmp(name, "project-list")) - ctx.cfg.project_list = xstrdup(expand_macros(value)); + ctx.cfg.project_list = strdup_first_line(expand_macros(value)); else if (!strcmp(name, "scan-path")) - if (!ctx.cfg.nocache && ctx.cfg.cache_size) + if (ctx.cfg.cache_size) process_cached_repolist(expand_macros(value)); else if (ctx.cfg.project_list) scan_projects(expand_macros(value), - ctx.cfg.project_list, repo_config); + ctx.cfg.project_list); else - scan_tree(expand_macros(value), repo_config); + scan_tree(expand_macros(value)); else if (!strcmp(name, "scan-hidden-path")) ctx.cfg.scan_hidden_path = atoi(value); else if (!strcmp(name, "section-from-path")) ctx.cfg.section_from_path = atoi(value); else if (!strcmp(name, "repository-sort")) - ctx.cfg.repository_sort = xstrdup(value); + ctx.cfg.repository_sort = strdup_first_line(value); else if (!strcmp(name, "section-sort")) ctx.cfg.section_sort = atoi(value); else if (!strcmp(name, "source-filter")) @@ -255,19 +306,19 @@ static void config_cb(const char *name, const char *value) else if (!strcmp(name, "side-by-side-diffs")) ctx.cfg.difftype = atoi(value) ? DIFF_SSDIFF : DIFF_UNIFIED; else if (!strcmp(name, "agefile")) - ctx.cfg.agefile = xstrdup(value); + ctx.cfg.agefile = strdup_first_line(value); else if (!strcmp(name, "mimetype-file")) - ctx.cfg.mimetype_file = xstrdup(value); + ctx.cfg.mimetype_file = strdup_first_line(value); else if (!strcmp(name, "renamelimit")) ctx.cfg.renamelimit = atoi(value); else if (!strcmp(name, "remove-suffix")) ctx.cfg.remove_suffix = atoi(value); else if (!strcmp(name, "robots")) - ctx.cfg.robots = xstrdup(value); + ctx.cfg.robots = strdup_first_line(value); else if (!strcmp(name, "clone-prefix")) - ctx.cfg.clone_prefix = xstrdup(value); + ctx.cfg.clone_prefix = strdup_first_line(value); else if (!strcmp(name, "clone-url")) - ctx.cfg.clone_url = xstrdup(value); + ctx.cfg.clone_url = strdup_first_line(value); else if (!strcmp(name, "local-time")) ctx.cfg.local_time = atoi(value); else if (!strcmp(name, "commit-sort")) { @@ -280,8 +331,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.branch_sort = 1; if (!strcmp(value, "name")) ctx.cfg.branch_sort = 0; - } else if (starts_with(name, "mimetype.")) - add_mimetype(name + 9, value); + } else if (skip_prefix(name, "mimetype.", &arg)) + add_mimetype(arg, value); else if (!strcmp(name, "include")) parse_configfile(expand_macros(value), config_cb); } @@ -309,11 +360,11 @@ static void querystring_cb(const char *name, const char *value) ctx.qry.head = xstrdup(value); ctx.qry.has_symref = 1; } else if (!strcmp(name, "id")) { - ctx.qry.sha1 = xstrdup(value); - ctx.qry.has_sha1 = 1; + ctx.qry.oid = xstrdup(value); + ctx.qry.has_oid = 1; } else if (!strcmp(name, "id2")) { - ctx.qry.sha2 = xstrdup(value); - ctx.qry.has_sha1 = 1; + ctx.qry.oid2 = xstrdup(value); + ctx.qry.has_oid = 1; } else if (!strcmp(name, "ofs")) { ctx.qry.ofs = atoi(value); } else if (!strcmp(name, "path")) { @@ -348,7 +399,6 @@ static void prepare_context(void) { memset(&ctx, 0, sizeof(ctx)); ctx.cfg.agefile = "info/web/last-modified"; - ctx.cfg.nocache = 0; ctx.cfg.cache_size = 0; ctx.cfg.cache_max_create_time = 5; ctx.cfg.cache_root = CGIT_CACHE_ROOT; @@ -362,7 +412,6 @@ static void prepare_context(void) ctx.cfg.case_sensitive_sort = 1; ctx.cfg.branch_sort = 0; ctx.cfg.commit_sort = 0; - ctx.cfg.css = "/cgit.css"; ctx.cfg.logo = "/cgit.png"; ctx.cfg.favicon = "/favicon.ico"; ctx.cfg.local_time = 0; @@ -414,7 +463,7 @@ static void prepare_context(void) ctx.page.modified = time(NULL); ctx.page.expires = ctx.page.modified; ctx.page.etag = NULL; - memset(&ctx.cfg.mimetypes, 0, sizeof(struct string_list)); + string_list_init_dup(&ctx.cfg.mimetypes); if (ctx.env.script_name) ctx.cfg.script_name = xstrdup(ctx.env.script_name); if (ctx.env.query_string) @@ -429,16 +478,15 @@ struct refmatch { int match; }; -static int find_current_ref(const char *refname, const struct object_id *oid, - int flags, void *cb_data) +static int find_current_ref(const struct reference *ref, void *cb_data) { struct refmatch *info; info = (struct refmatch *)cb_data; - if (!strcmp(refname, info->req_ref)) + if (!strcmp(ref->name, info->req_ref)) info->match = 1; if (!info->first_ref) - info->first_ref = xstrdup(refname); + info->first_ref = xstrdup(ref->name); return info->match; } @@ -456,7 +504,8 @@ static char *find_default_branch(struct cgit_repo *repo) info.req_ref = repo->defbranch; info.first_ref = NULL; info.match = 0; - for_each_branch_ref(find_current_ref, &info); + refs_for_each_branch_ref(get_main_ref_store(the_repository), + find_current_ref, &info); if (info.match) ref = info.req_ref; else @@ -470,14 +519,16 @@ static char *find_default_branch(struct cgit_repo *repo) static char *guess_defbranch(void) { - const char *ref; - unsigned char sha1[20]; + const char *ref, *refname; + struct object_id oid; - ref = resolve_ref_unsafe("HEAD", 0, sha1, NULL); - if (!ref || !starts_with(ref, "refs/heads/")) + ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository), + "HEAD", 0, &oid, NULL); + if (!ref || !skip_prefix(ref, "refs/heads/", &refname)) return "master"; - return xstrdup(ref + 11); + return xstrdup(refname); } + /* The caller must free filename and ref after calling this. */ static inline void parse_readme(const char *readme, char **filename, char **ref, struct cgit_repo *repo) { @@ -492,9 +543,11 @@ static inline void parse_readme(const char *readme, char **filename, char **ref, /* Check if the readme is tracked in the git repo. */ colon = strchr(readme, ':'); if (colon && strlen(colon) > 1) { - /* If it starts with a colon, we want to use - * the default branch */ - if (colon == readme && repo->defbranch) + /* If it starts with a colon, we want to use head given + * from query or the default branch */ + if (colon == readme && ctx.qry.head) + *ref = xstrdup(ctx.qry.head); + else if (colon == readme && repo->defbranch) *ref = xstrdup(repo->defbranch); else *ref = xstrndup(readme, colon - readme); @@ -555,26 +608,25 @@ static void print_no_repo_clone_urls(const char *url) html("</a></td></tr>\n"); } -static int prepare_repo_cmd(void) +static void prepare_repo_env(int *nongit) { - unsigned char sha1[20]; - int nongit = 0; - int rc; - /* The path to the git repository. */ setenv("GIT_DIR", ctx.repo->path, 1); - /* Do not look in /etc/ for gitconfig and gitattributes. */ - setenv("GIT_CONFIG_NOSYSTEM", "1", 1); - setenv("GIT_ATTR_NOSYSTEM", "1", 1); - unsetenv("HOME"); - unsetenv("XDG_CONFIG_HOME"); - /* Setup the git directory and initialize the notes system. Both of these * load local configuration from the git repository, so we do them both while - * the HOME variables are unset. */ - setup_git_directory_gently(&nongit); - init_display_notes(NULL); + * the HOME variables are unset. Initializing the notes system requires an + * actual repository, as it would otherwise dereference the not yet known + * hash algorithm. */ + setup_git_directory_gently(nongit); + if (!*nongit) + load_display_notes(NULL); +} + +static int prepare_repo_cmd(int nongit) +{ + struct object_id oid; + int rc; if (nongit) { const char *name = ctx.repo->name; @@ -615,12 +667,12 @@ static int prepare_repo_cmd(void) return 1; } - if (get_sha1(ctx.qry.head, sha1)) { - char *tmp = xstrdup(ctx.qry.head); - ctx.qry.head = ctx.repo->defbranch; + if (repo_get_oid(the_repository, ctx.qry.head, &oid)) { + char *old_head = ctx.qry.head; + ctx.qry.head = xstrdup(ctx.repo->defbranch); cgit_print_error_page(404, "Not found", - "Invalid branch: %s", tmp); - free(tmp); + "Invalid branch: %s", old_head); + free(old_head); return 1; } string_list_sort(&ctx.repo->submodules); @@ -641,7 +693,7 @@ static inline void open_auth_filter(const char *function) ctx.env.https ? ctx.env.https : "", ctx.qry.repo ? ctx.qry.repo : "", ctx.qry.page ? ctx.qry.page : "", - ctx.qry.url ? ctx.qry.url : "", + cgit_currentfullurl(), cgit_loginurl()); } @@ -655,13 +707,13 @@ static inline void open_auth_filter(const char *function) static inline void authenticate_post(void) { char buffer[MAX_AUTHENTICATION_POST_BYTES]; - unsigned int len; + ssize_t len; open_auth_filter("authenticate-post"); len = ctx.env.content_length; if (len > MAX_AUTHENTICATION_POST_BYTES) len = MAX_AUTHENTICATION_POST_BYTES; - if (read(STDIN_FILENO, buffer, len) < 0) + if ((len = read(STDIN_FILENO, buffer, len)) < 0) die_errno("Could not read POST from stdin"); if (write(STDOUT_FILENO, buffer, len) < 0) die_errno("Could not write POST to stdout"); @@ -694,6 +746,7 @@ static inline void authenticate_cookie(void) static void process_request(void) { struct cgit_cmd *cmd; + int nongit = 0; /* If we're not yet authenticated, no matter what page we're on, * display the authentication body from the auth_filter. This should @@ -709,6 +762,9 @@ static void process_request(void) return; } + if (ctx.repo) + prepare_repo_env(&nongit); + cmd = cgit_get_cmd(); if (!cmd) { ctx.page.title = "cgit error"; @@ -722,19 +778,19 @@ static void process_request(void) return; } - /* If cmd->want_vpath is set, assume ctx.qry.path contains a "virtual" - * in-project path limit to be made available at ctx.qry.vpath. - * Otherwise, no path limit is in effect (ctx.qry.vpath = NULL). - */ - ctx.qry.vpath = cmd->want_vpath ? ctx.qry.path : NULL; - if (cmd->want_repo && !ctx.repo) { cgit_print_error_page(400, "Bad request", "No repository selected"); return; } - if (ctx.repo && prepare_repo_cmd()) + /* If cmd->want_vpath is set, assume ctx.qry.path contains a "virtual" + * in-project path limit to be made available at ctx.qry.vpath. + * Otherwise, no path limit is in effect (ctx.qry.vpath = NULL). + */ + ctx.qry.vpath = cmd->want_vpath ? ctx.qry.path : NULL; + + if (ctx.repo && prepare_repo_cmd(nongit)) return; cmd->fn(); @@ -752,7 +808,7 @@ static char *build_snapshot_setting(int bitmap) struct strbuf result = STRBUF_INIT; for (f = cgit_snapshot_formats; f->suffix; f++) { - if (f->bit & bitmap) { + if (cgit_snapshot_format_bit(f) & bitmap) { if (result.len) strbuf_addch(&result, ' '); strbuf_addstr(&result, f->suffix); @@ -761,15 +817,6 @@ static char *build_snapshot_setting(int bitmap) return strbuf_detach(&result, NULL); } -static char *get_first_line(char *txt) -{ - char *t = xstrdup(txt); - char *p = strchr(t, '\n'); - if (p) - *p = '\0'; - return t; -} - static void print_repo(FILE *f, struct cgit_repo *repo) { struct string_list_item *item; @@ -778,11 +825,8 @@ static void print_repo(FILE *f, struct cgit_repo *repo) fprintf(f, "repo.path=%s\n", repo->path); if (repo->owner) fprintf(f, "repo.owner=%s\n", repo->owner); - if (repo->desc) { - char *tmp = get_first_line(repo->desc); - fprintf(f, "repo.desc=%s\n", tmp); - free(tmp); - } + if (repo->desc) + fprintf(f, "repo.desc=%s\n", repo->desc); for_each_string_list_item(item, &repo->readme) { if (item->util) fprintf(f, "repo.readme=%s:%s\n", (char *)item->util, item->string); @@ -791,16 +835,28 @@ static void print_repo(FILE *f, struct cgit_repo *repo) } if (repo->defbranch) fprintf(f, "repo.defbranch=%s\n", repo->defbranch); + if (repo->extra_head_content) + fprintf(f, "repo.extra-head-content=%s\n", repo->extra_head_content); if (repo->module_link) fprintf(f, "repo.module-link=%s\n", repo->module_link); if (repo->section) fprintf(f, "repo.section=%s\n", repo->section); if (repo->homepage) fprintf(f, "repo.homepage=%s\n", repo->homepage); + if (repo->ci_url) + fprintf(f, "repo.ci-url=%s\n", repo->ci_url); + if (repo->ci_branch_url) + fprintf(f, "repo.ci-branch-url=%s\n", repo->ci_branch_url); + if (repo->ci_tag_url) + fprintf(f, "repo.ci-tag-url=%s\n", repo->ci_tag_url); if (repo->clone_url) fprintf(f, "repo.clone-url=%s\n", repo->clone_url); + fprintf(f, "repo.enable-blame=%d\n", + repo->enable_blame); fprintf(f, "repo.enable-commit-graph=%d\n", repo->enable_commit_graph); + fprintf(f, "repo.enable-follow-links=%d\n", + repo->enable_follow_links); fprintf(f, "repo.enable-log-filecount=%d\n", repo->enable_log_filecount); fprintf(f, "repo.enable-log-linecount=%d\n", @@ -815,11 +871,15 @@ static void print_repo(FILE *f, struct cgit_repo *repo) cgit_fprintf_filter(repo->email_filter, f, "repo.email-filter="); if (repo->owner_filter && repo->owner_filter != ctx.cfg.owner_filter) cgit_fprintf_filter(repo->owner_filter, f, "repo.owner-filter="); + if (repo->ci_filter && repo->ci_filter != ctx.cfg.ci_filter) + cgit_fprintf_filter(repo->ci_filter, f, "repo.ci-filter="); if (repo->snapshots != ctx.cfg.snapshots) { char *tmp = build_snapshot_setting(repo->snapshots); fprintf(f, "repo.snapshots=%s\n", tmp ? tmp : ""); free(tmp); } + if (repo->snapshot_prefix) + fprintf(f, "repo.snapshot-prefix=%s\n", repo->snapshot_prefix); if (repo->max_stats != ctx.cfg.max_stats) fprintf(f, "repo.max-stats=%s\n", cgit_find_stats_periodname(repo->max_stats)); @@ -875,9 +935,9 @@ static int generate_cached_repolist(const char *path, const char *cached_rc) } idx = cgit_repolist.count; if (ctx.cfg.project_list) - scan_projects(path, ctx.cfg.project_list, repo_config); + scan_projects(path, ctx.cfg.project_list); else - scan_tree(path, repo_config); + scan_tree(path); print_repolist(f, &cgit_repolist, idx); if (rename(locked_rc.buf, cached_rc)) fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", @@ -907,10 +967,9 @@ static void process_cached_repolist(const char *path) */ if (generate_cached_repolist(path, cached_rc.buf)) { if (ctx.cfg.project_list) - scan_projects(path, ctx.cfg.project_list, - repo_config); + scan_projects(path, ctx.cfg.project_list); else - scan_tree(path, repo_config); + scan_tree(path); } goto out; } @@ -937,11 +996,12 @@ out: static void cgit_parse_args(int argc, const char **argv) { int i; + const char *arg; int scan = 0; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--version")) { - printf("CGit %s | http://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION); + printf("CGit %s | https://sayag.it/cgitext.git | https://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION); #ifdef NO_LUA printf("[-] "); #else @@ -957,28 +1017,26 @@ static void cgit_parse_args(int argc, const char **argv) exit(0); } - if (starts_with(argv[i], "--cache=")) { - ctx.cfg.cache_root = xstrdup(argv[i] + 8); - } else if (!strcmp(argv[i], "--nocache")) { - ctx.cfg.nocache = 1; + if (skip_prefix(argv[i], "--cache=", &arg)) { + ctx.cfg.cache_root = xstrdup(arg); } else if (!strcmp(argv[i], "--nohttp")) { ctx.env.no_http = "1"; - } else if (starts_with(argv[i], "--query=")) { - ctx.qry.raw = xstrdup(argv[i] + 8); - } else if (starts_with(argv[i], "--repo=")) { - ctx.qry.repo = xstrdup(argv[i] + 7); - } else if (starts_with(argv[i], "--page=")) { - ctx.qry.page = xstrdup(argv[i] + 7); - } else if (starts_with(argv[i], "--head=")) { - ctx.qry.head = xstrdup(argv[i] + 7); + } else if (skip_prefix(argv[i], "--query=", &arg)) { + ctx.qry.raw = xstrdup(arg); + } else if (skip_prefix(argv[i], "--repo=", &arg)) { + ctx.qry.repo = xstrdup(arg); + } else if (skip_prefix(argv[i], "--page=", &arg)) { + ctx.qry.page = xstrdup(arg); + } else if (skip_prefix(argv[i], "--head=", &arg)) { + ctx.qry.head = xstrdup(arg); ctx.qry.has_symref = 1; - } else if (starts_with(argv[i], "--sha1=")) { - ctx.qry.sha1 = xstrdup(argv[i] + 7); - ctx.qry.has_sha1 = 1; - } else if (starts_with(argv[i], "--ofs=")) { - ctx.qry.ofs = atoi(argv[i] + 6); - } else if (starts_with(argv[i], "--scan-tree=") || - starts_with(argv[i], "--scan-path=")) { + } else if (skip_prefix(argv[i], "--oid=", &arg)) { + ctx.qry.oid = xstrdup(arg); + ctx.qry.has_oid = 1; + } else if (skip_prefix(argv[i], "--ofs=", &arg)) { + ctx.qry.ofs = atoi(arg); + } else if (skip_prefix(argv[i], "--scan-tree=", &arg) || + skip_prefix(argv[i], "--scan-path=", &arg)) { /* * HACK: The global snapshot bit mask defines the set * of allowed snapshot formats, but the config file @@ -992,7 +1050,7 @@ static void cgit_parse_args(int argc, const char **argv) */ ctx.cfg.snapshots = 0xFF; scan++; - scan_tree(argv[i] + 12, repo_config); + scan_tree(arg); } } if (scan) { @@ -1017,7 +1075,7 @@ static int calc_ttl(void) if (!strcmp(ctx.qry.page, "snapshot")) return ctx.cfg.cache_snapshot_ttl; - if (ctx.qry.has_sha1) + if (ctx.qry.has_oid) return ctx.cfg.cache_static_ttl; if (ctx.qry.has_symref) @@ -1026,13 +1084,20 @@ static int calc_ttl(void) return ctx.cfg.cache_repo_ttl; } -int main(int argc, const char **argv) +static NORETURN void cgit_die_routine(const char *msg, va_list params) +{ + cgit_vprint_error_page(400, "Bad request", msg, params); + exit(0); +} + +int cmd_main(int argc, const char **argv) { const char *path; int err, ttl; cgit_init_filters(); atexit(cgit_cleanup_filters); + set_die_routine(cgit_die_routine); prepare_context(); cgit_repolist.length = 0; @@ -1081,8 +1146,6 @@ int main(int argc, const char **argv) else ctx.page.expires += ttl * 60; if (!ctx.env.authenticated || (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); |