summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2009-08-24 11:31:49 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-08-24 11:31:49 (UTC)
commitee554849ac7209fa8f7486327ec9f3b370e4c876 (patch) (unidiff)
tree63c284ebf72ea401067dd5d4d59ae8ede8f8743c
parent588fb8efc69778b85062e8fc2f482a8de43bad75 (diff)
downloadcgit-ee554849ac7209fa8f7486327ec9f3b370e4c876.zip
cgit-ee554849ac7209fa8f7486327ec9f3b370e4c876.tar.gz
cgit-ee554849ac7209fa8f7486327ec9f3b370e4c876.tar.bz2
cgit.c: respect repo-local 'snapshots' option for --scan-path
The repo-specific 'snapshots' option is bitwise AND'ed with the global 'snapshots' option during parsing, and since the global cgitrc hasn't been parsed when --scan-path is processed the global 'snapshots' will always be 0 (i.e. no repo-specific 'snapshots' setting will have any effect). This patch fixes the issue by setting the global 'snapshots' mask to 0xFF (hence relying on later parsing of the generated cgitrc repolist to do the right thing). Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/cgit.c b/cgit.c
index 8381630..3fcca2a 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,705 +1,715 @@
1/* cgit.c: cgi for the git scm 1/* cgit.c: cgi for the git scm
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "cache.h" 10#include "cache.h"
11#include "cmd.h" 11#include "cmd.h"
12#include "configfile.h" 12#include "configfile.h"
13#include "html.h" 13#include "html.h"
14#include "ui-shared.h" 14#include "ui-shared.h"
15#include "ui-stats.h" 15#include "ui-stats.h"
16#include "scan-tree.h" 16#include "scan-tree.h"
17 17
18const char *cgit_version = CGIT_VERSION; 18const char *cgit_version = CGIT_VERSION;
19 19
20void add_mimetype(const char *name, const char *value) 20void add_mimetype(const char *name, const char *value)
21{ 21{
22 struct string_list_item *item; 22 struct string_list_item *item;
23 23
24 item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes); 24 item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes);
25 item->util = xstrdup(value); 25 item->util = xstrdup(value);
26} 26}
27 27
28struct cgit_filter *new_filter(const char *cmd, int extra_args) 28struct cgit_filter *new_filter(const char *cmd, int extra_args)
29{ 29{
30 struct cgit_filter *f; 30 struct cgit_filter *f;
31 31
32 if (!cmd || !cmd[0]) 32 if (!cmd || !cmd[0])
33 return NULL; 33 return NULL;
34 34
35 f = xmalloc(sizeof(struct cgit_filter)); 35 f = xmalloc(sizeof(struct cgit_filter));
36 f->cmd = xstrdup(cmd); 36 f->cmd = xstrdup(cmd);
37 f->argv = xmalloc((2 + extra_args) * sizeof(char *)); 37 f->argv = xmalloc((2 + extra_args) * sizeof(char *));
38 f->argv[0] = f->cmd; 38 f->argv[0] = f->cmd;
39 f->argv[1] = NULL; 39 f->argv[1] = NULL;
40 return f; 40 return f;
41} 41}
42 42
43static void process_cached_repolist(const char *path); 43static void process_cached_repolist(const char *path);
44 44
45void repo_config(struct cgit_repo *repo, const char *name, const char *value) 45void repo_config(struct cgit_repo *repo, const char *name, const char *value)
46{ 46{
47 if (!strcmp(name, "name")) 47 if (!strcmp(name, "name"))
48 repo->name = xstrdup(value); 48 repo->name = xstrdup(value);
49 else if (!strcmp(name, "clone-url")) 49 else if (!strcmp(name, "clone-url"))
50 repo->clone_url = xstrdup(value); 50 repo->clone_url = xstrdup(value);
51 else if (!strcmp(name, "desc")) 51 else if (!strcmp(name, "desc"))
52 repo->desc = xstrdup(value); 52 repo->desc = xstrdup(value);
53 else if (!strcmp(name, "owner")) 53 else if (!strcmp(name, "owner"))
54 repo->owner = xstrdup(value); 54 repo->owner = xstrdup(value);
55 else if (!strcmp(name, "defbranch")) 55 else if (!strcmp(name, "defbranch"))
56 repo->defbranch = xstrdup(value); 56 repo->defbranch = xstrdup(value);
57 else if (!strcmp(name, "snapshots")) 57 else if (!strcmp(name, "snapshots"))
58 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); 58 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value);
59 else if (!strcmp(name, "enable-log-filecount")) 59 else if (!strcmp(name, "enable-log-filecount"))
60 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 60 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
61 else if (!strcmp(name, "enable-log-linecount")) 61 else if (!strcmp(name, "enable-log-linecount"))
62 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 62 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
63 else if (!strcmp(name, "max-stats")) 63 else if (!strcmp(name, "max-stats"))
64 repo->max_stats = cgit_find_stats_period(value, NULL); 64 repo->max_stats = cgit_find_stats_period(value, NULL);
65 else if (!strcmp(name, "module-link")) 65 else if (!strcmp(name, "module-link"))
66 repo->module_link= xstrdup(value); 66 repo->module_link= xstrdup(value);
67 else if (!strcmp(name, "section")) 67 else if (!strcmp(name, "section"))
68 repo->section = xstrdup(value); 68 repo->section = xstrdup(value);
69 else if (!strcmp(name, "readme") && value != NULL) { 69 else if (!strcmp(name, "readme") && value != NULL) {
70 if (*value == '/') 70 if (*value == '/')
71 ctx.repo->readme = xstrdup(value); 71 ctx.repo->readme = xstrdup(value);
72 else 72 else
73 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); 73 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
74 } else if (ctx.cfg.enable_filter_overrides) { 74 } else if (ctx.cfg.enable_filter_overrides) {
75 if (!strcmp(name, "about-filter")) 75 if (!strcmp(name, "about-filter"))
76 repo->about_filter = new_filter(value, 0); 76 repo->about_filter = new_filter(value, 0);
77 else if (!strcmp(name, "commit-filter")) 77 else if (!strcmp(name, "commit-filter"))
78 repo->commit_filter = new_filter(value, 0); 78 repo->commit_filter = new_filter(value, 0);
79 else if (!strcmp(name, "source-filter")) 79 else if (!strcmp(name, "source-filter"))
80 repo->source_filter = new_filter(value, 1); 80 repo->source_filter = new_filter(value, 1);
81 } 81 }
82} 82}
83 83
84void config_cb(const char *name, const char *value) 84void config_cb(const char *name, const char *value)
85{ 85{
86 if (!strcmp(name, "section") || !strcmp(name, "repo.group")) 86 if (!strcmp(name, "section") || !strcmp(name, "repo.group"))
87 ctx.cfg.section = xstrdup(value); 87 ctx.cfg.section = xstrdup(value);
88 else if (!strcmp(name, "repo.url")) 88 else if (!strcmp(name, "repo.url"))
89 ctx.repo = cgit_add_repo(value); 89 ctx.repo = cgit_add_repo(value);
90 else if (ctx.repo && !strcmp(name, "repo.path")) 90 else if (ctx.repo && !strcmp(name, "repo.path"))
91 ctx.repo->path = trim_end(value, '/'); 91 ctx.repo->path = trim_end(value, '/');
92 else if (ctx.repo && !prefixcmp(name, "repo.")) 92 else if (ctx.repo && !prefixcmp(name, "repo."))
93 repo_config(ctx.repo, name + 5, value); 93 repo_config(ctx.repo, name + 5, value);
94 else if (!strcmp(name, "root-title")) 94 else if (!strcmp(name, "root-title"))
95 ctx.cfg.root_title = xstrdup(value); 95 ctx.cfg.root_title = xstrdup(value);
96 else if (!strcmp(name, "root-desc")) 96 else if (!strcmp(name, "root-desc"))
97 ctx.cfg.root_desc = xstrdup(value); 97 ctx.cfg.root_desc = xstrdup(value);
98 else if (!strcmp(name, "root-readme")) 98 else if (!strcmp(name, "root-readme"))
99 ctx.cfg.root_readme = xstrdup(value); 99 ctx.cfg.root_readme = xstrdup(value);
100 else if (!strcmp(name, "css")) 100 else if (!strcmp(name, "css"))
101 ctx.cfg.css = xstrdup(value); 101 ctx.cfg.css = xstrdup(value);
102 else if (!strcmp(name, "favicon")) 102 else if (!strcmp(name, "favicon"))
103 ctx.cfg.favicon = xstrdup(value); 103 ctx.cfg.favicon = xstrdup(value);
104 else if (!strcmp(name, "footer")) 104 else if (!strcmp(name, "footer"))
105 ctx.cfg.footer = xstrdup(value); 105 ctx.cfg.footer = xstrdup(value);
106 else if (!strcmp(name, "head-include")) 106 else if (!strcmp(name, "head-include"))
107 ctx.cfg.head_include = xstrdup(value); 107 ctx.cfg.head_include = xstrdup(value);
108 else if (!strcmp(name, "header")) 108 else if (!strcmp(name, "header"))
109 ctx.cfg.header = xstrdup(value); 109 ctx.cfg.header = xstrdup(value);
110 else if (!strcmp(name, "logo")) 110 else if (!strcmp(name, "logo"))
111 ctx.cfg.logo = xstrdup(value); 111 ctx.cfg.logo = xstrdup(value);
112 else if (!strcmp(name, "index-header")) 112 else if (!strcmp(name, "index-header"))
113 ctx.cfg.index_header = xstrdup(value); 113 ctx.cfg.index_header = xstrdup(value);
114 else if (!strcmp(name, "index-info")) 114 else if (!strcmp(name, "index-info"))
115 ctx.cfg.index_info = xstrdup(value); 115 ctx.cfg.index_info = xstrdup(value);
116 else if (!strcmp(name, "logo-link")) 116 else if (!strcmp(name, "logo-link"))
117 ctx.cfg.logo_link = xstrdup(value); 117 ctx.cfg.logo_link = xstrdup(value);
118 else if (!strcmp(name, "module-link")) 118 else if (!strcmp(name, "module-link"))
119 ctx.cfg.module_link = xstrdup(value); 119 ctx.cfg.module_link = xstrdup(value);
120 else if (!strcmp(name, "virtual-root")) { 120 else if (!strcmp(name, "virtual-root")) {
121 ctx.cfg.virtual_root = trim_end(value, '/'); 121 ctx.cfg.virtual_root = trim_end(value, '/');
122 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 122 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
123 ctx.cfg.virtual_root = ""; 123 ctx.cfg.virtual_root = "";
124 } else if (!strcmp(name, "nocache")) 124 } else if (!strcmp(name, "nocache"))
125 ctx.cfg.nocache = atoi(value); 125 ctx.cfg.nocache = atoi(value);
126 else if (!strcmp(name, "noplainemail")) 126 else if (!strcmp(name, "noplainemail"))
127 ctx.cfg.noplainemail = atoi(value); 127 ctx.cfg.noplainemail = atoi(value);
128 else if (!strcmp(name, "noheader")) 128 else if (!strcmp(name, "noheader"))
129 ctx.cfg.noheader = atoi(value); 129 ctx.cfg.noheader = atoi(value);
130 else if (!strcmp(name, "snapshots")) 130 else if (!strcmp(name, "snapshots"))
131 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 131 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
132 else if (!strcmp(name, "enable-filter-overrides")) 132 else if (!strcmp(name, "enable-filter-overrides"))
133 ctx.cfg.enable_filter_overrides = atoi(value); 133 ctx.cfg.enable_filter_overrides = atoi(value);
134 else if (!strcmp(name, "enable-index-links")) 134 else if (!strcmp(name, "enable-index-links"))
135 ctx.cfg.enable_index_links = atoi(value); 135 ctx.cfg.enable_index_links = atoi(value);
136 else if (!strcmp(name, "enable-log-filecount")) 136 else if (!strcmp(name, "enable-log-filecount"))
137 ctx.cfg.enable_log_filecount = atoi(value); 137 ctx.cfg.enable_log_filecount = atoi(value);
138 else if (!strcmp(name, "enable-log-linecount")) 138 else if (!strcmp(name, "enable-log-linecount"))
139 ctx.cfg.enable_log_linecount = atoi(value); 139 ctx.cfg.enable_log_linecount = atoi(value);
140 else if (!strcmp(name, "max-stats")) 140 else if (!strcmp(name, "max-stats"))
141 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); 141 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
142 else if (!strcmp(name, "cache-size")) 142 else if (!strcmp(name, "cache-size"))
143 ctx.cfg.cache_size = atoi(value); 143 ctx.cfg.cache_size = atoi(value);
144 else if (!strcmp(name, "cache-root")) 144 else if (!strcmp(name, "cache-root"))
145 ctx.cfg.cache_root = xstrdup(value); 145 ctx.cfg.cache_root = xstrdup(value);
146 else if (!strcmp(name, "cache-root-ttl")) 146 else if (!strcmp(name, "cache-root-ttl"))
147 ctx.cfg.cache_root_ttl = atoi(value); 147 ctx.cfg.cache_root_ttl = atoi(value);
148 else if (!strcmp(name, "cache-repo-ttl")) 148 else if (!strcmp(name, "cache-repo-ttl"))
149 ctx.cfg.cache_repo_ttl = atoi(value); 149 ctx.cfg.cache_repo_ttl = atoi(value);
150 else if (!strcmp(name, "cache-scanrc-ttl")) 150 else if (!strcmp(name, "cache-scanrc-ttl"))
151 ctx.cfg.cache_scanrc_ttl = atoi(value); 151 ctx.cfg.cache_scanrc_ttl = atoi(value);
152 else if (!strcmp(name, "cache-static-ttl")) 152 else if (!strcmp(name, "cache-static-ttl"))
153 ctx.cfg.cache_static_ttl = atoi(value); 153 ctx.cfg.cache_static_ttl = atoi(value);
154 else if (!strcmp(name, "cache-dynamic-ttl")) 154 else if (!strcmp(name, "cache-dynamic-ttl"))
155 ctx.cfg.cache_dynamic_ttl = atoi(value); 155 ctx.cfg.cache_dynamic_ttl = atoi(value);
156 else if (!strcmp(name, "about-filter")) 156 else if (!strcmp(name, "about-filter"))
157 ctx.cfg.about_filter = new_filter(value, 0); 157 ctx.cfg.about_filter = new_filter(value, 0);
158 else if (!strcmp(name, "commit-filter")) 158 else if (!strcmp(name, "commit-filter"))
159 ctx.cfg.commit_filter = new_filter(value, 0); 159 ctx.cfg.commit_filter = new_filter(value, 0);
160 else if (!strcmp(name, "embedded")) 160 else if (!strcmp(name, "embedded"))
161 ctx.cfg.embedded = atoi(value); 161 ctx.cfg.embedded = atoi(value);
162 else if (!strcmp(name, "max-message-length")) 162 else if (!strcmp(name, "max-message-length"))
163 ctx.cfg.max_msg_len = atoi(value); 163 ctx.cfg.max_msg_len = atoi(value);
164 else if (!strcmp(name, "max-repodesc-length")) 164 else if (!strcmp(name, "max-repodesc-length"))
165 ctx.cfg.max_repodesc_len = atoi(value); 165 ctx.cfg.max_repodesc_len = atoi(value);
166 else if (!strcmp(name, "max-repo-count")) 166 else if (!strcmp(name, "max-repo-count"))
167 ctx.cfg.max_repo_count = atoi(value); 167 ctx.cfg.max_repo_count = atoi(value);
168 else if (!strcmp(name, "max-commit-count")) 168 else if (!strcmp(name, "max-commit-count"))
169 ctx.cfg.max_commit_count = atoi(value); 169 ctx.cfg.max_commit_count = atoi(value);
170 else if (!strcmp(name, "scan-path")) 170 else if (!strcmp(name, "scan-path"))
171 if (!ctx.cfg.nocache && ctx.cfg.cache_size) 171 if (!ctx.cfg.nocache && ctx.cfg.cache_size)
172 process_cached_repolist(value); 172 process_cached_repolist(value);
173 else 173 else
174 scan_tree(value, repo_config); 174 scan_tree(value, repo_config);
175 else if (!strcmp(name, "source-filter")) 175 else if (!strcmp(name, "source-filter"))
176 ctx.cfg.source_filter = new_filter(value, 1); 176 ctx.cfg.source_filter = new_filter(value, 1);
177 else if (!strcmp(name, "summary-log")) 177 else if (!strcmp(name, "summary-log"))
178 ctx.cfg.summary_log = atoi(value); 178 ctx.cfg.summary_log = atoi(value);
179 else if (!strcmp(name, "summary-branches")) 179 else if (!strcmp(name, "summary-branches"))
180 ctx.cfg.summary_branches = atoi(value); 180 ctx.cfg.summary_branches = atoi(value);
181 else if (!strcmp(name, "summary-tags")) 181 else if (!strcmp(name, "summary-tags"))
182 ctx.cfg.summary_tags = atoi(value); 182 ctx.cfg.summary_tags = atoi(value);
183 else if (!strcmp(name, "agefile")) 183 else if (!strcmp(name, "agefile"))
184 ctx.cfg.agefile = xstrdup(value); 184 ctx.cfg.agefile = xstrdup(value);
185 else if (!strcmp(name, "renamelimit")) 185 else if (!strcmp(name, "renamelimit"))
186 ctx.cfg.renamelimit = atoi(value); 186 ctx.cfg.renamelimit = atoi(value);
187 else if (!strcmp(name, "robots")) 187 else if (!strcmp(name, "robots"))
188 ctx.cfg.robots = xstrdup(value); 188 ctx.cfg.robots = xstrdup(value);
189 else if (!strcmp(name, "clone-prefix")) 189 else if (!strcmp(name, "clone-prefix"))
190 ctx.cfg.clone_prefix = xstrdup(value); 190 ctx.cfg.clone_prefix = xstrdup(value);
191 else if (!strcmp(name, "local-time")) 191 else if (!strcmp(name, "local-time"))
192 ctx.cfg.local_time = atoi(value); 192 ctx.cfg.local_time = atoi(value);
193 else if (!prefixcmp(name, "mimetype.")) 193 else if (!prefixcmp(name, "mimetype."))
194 add_mimetype(name + 9, value); 194 add_mimetype(name + 9, value);
195 else if (!strcmp(name, "include")) 195 else if (!strcmp(name, "include"))
196 parse_configfile(value, config_cb); 196 parse_configfile(value, config_cb);
197} 197}
198 198
199static void querystring_cb(const char *name, const char *value) 199static void querystring_cb(const char *name, const char *value)
200{ 200{
201 if (!value) 201 if (!value)
202 value = ""; 202 value = "";
203 203
204 if (!strcmp(name,"r")) { 204 if (!strcmp(name,"r")) {
205 ctx.qry.repo = xstrdup(value); 205 ctx.qry.repo = xstrdup(value);
206 ctx.repo = cgit_get_repoinfo(value); 206 ctx.repo = cgit_get_repoinfo(value);
207 } else if (!strcmp(name, "p")) { 207 } else if (!strcmp(name, "p")) {
208 ctx.qry.page = xstrdup(value); 208 ctx.qry.page = xstrdup(value);
209 } else if (!strcmp(name, "url")) { 209 } else if (!strcmp(name, "url")) {
210 ctx.qry.url = xstrdup(value); 210 ctx.qry.url = xstrdup(value);
211 cgit_parse_url(value); 211 cgit_parse_url(value);
212 } else if (!strcmp(name, "qt")) { 212 } else if (!strcmp(name, "qt")) {
213 ctx.qry.grep = xstrdup(value); 213 ctx.qry.grep = xstrdup(value);
214 } else if (!strcmp(name, "q")) { 214 } else if (!strcmp(name, "q")) {
215 ctx.qry.search = xstrdup(value); 215 ctx.qry.search = xstrdup(value);
216 } else if (!strcmp(name, "h")) { 216 } else if (!strcmp(name, "h")) {
217 ctx.qry.head = xstrdup(value); 217 ctx.qry.head = xstrdup(value);
218 ctx.qry.has_symref = 1; 218 ctx.qry.has_symref = 1;
219 } else if (!strcmp(name, "id")) { 219 } else if (!strcmp(name, "id")) {
220 ctx.qry.sha1 = xstrdup(value); 220 ctx.qry.sha1 = xstrdup(value);
221 ctx.qry.has_sha1 = 1; 221 ctx.qry.has_sha1 = 1;
222 } else if (!strcmp(name, "id2")) { 222 } else if (!strcmp(name, "id2")) {
223 ctx.qry.sha2 = xstrdup(value); 223 ctx.qry.sha2 = xstrdup(value);
224 ctx.qry.has_sha1 = 1; 224 ctx.qry.has_sha1 = 1;
225 } else if (!strcmp(name, "ofs")) { 225 } else if (!strcmp(name, "ofs")) {
226 ctx.qry.ofs = atoi(value); 226 ctx.qry.ofs = atoi(value);
227 } else if (!strcmp(name, "path")) { 227 } else if (!strcmp(name, "path")) {
228 ctx.qry.path = trim_end(value, '/'); 228 ctx.qry.path = trim_end(value, '/');
229 } else if (!strcmp(name, "name")) { 229 } else if (!strcmp(name, "name")) {
230 ctx.qry.name = xstrdup(value); 230 ctx.qry.name = xstrdup(value);
231 } else if (!strcmp(name, "mimetype")) { 231 } else if (!strcmp(name, "mimetype")) {
232 ctx.qry.mimetype = xstrdup(value); 232 ctx.qry.mimetype = xstrdup(value);
233 } else if (!strcmp(name, "s")){ 233 } else if (!strcmp(name, "s")){
234 ctx.qry.sort = xstrdup(value); 234 ctx.qry.sort = xstrdup(value);
235 } else if (!strcmp(name, "showmsg")) { 235 } else if (!strcmp(name, "showmsg")) {
236 ctx.qry.showmsg = atoi(value); 236 ctx.qry.showmsg = atoi(value);
237 } else if (!strcmp(name, "period")) { 237 } else if (!strcmp(name, "period")) {
238 ctx.qry.period = xstrdup(value); 238 ctx.qry.period = xstrdup(value);
239 } 239 }
240} 240}
241 241
242char *xstrdupn(const char *str) 242char *xstrdupn(const char *str)
243{ 243{
244 return (str ? xstrdup(str) : NULL); 244 return (str ? xstrdup(str) : NULL);
245} 245}
246 246
247static void prepare_context(struct cgit_context *ctx) 247static void prepare_context(struct cgit_context *ctx)
248{ 248{
249 memset(ctx, 0, sizeof(ctx)); 249 memset(ctx, 0, sizeof(ctx));
250 ctx->cfg.agefile = "info/web/last-modified"; 250 ctx->cfg.agefile = "info/web/last-modified";
251 ctx->cfg.nocache = 0; 251 ctx->cfg.nocache = 0;
252 ctx->cfg.cache_size = 0; 252 ctx->cfg.cache_size = 0;
253 ctx->cfg.cache_dynamic_ttl = 5; 253 ctx->cfg.cache_dynamic_ttl = 5;
254 ctx->cfg.cache_max_create_time = 5; 254 ctx->cfg.cache_max_create_time = 5;
255 ctx->cfg.cache_repo_ttl = 5; 255 ctx->cfg.cache_repo_ttl = 5;
256 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 256 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
257 ctx->cfg.cache_root_ttl = 5; 257 ctx->cfg.cache_root_ttl = 5;
258 ctx->cfg.cache_scanrc_ttl = 15; 258 ctx->cfg.cache_scanrc_ttl = 15;
259 ctx->cfg.cache_static_ttl = -1; 259 ctx->cfg.cache_static_ttl = -1;
260 ctx->cfg.css = "/cgit.css"; 260 ctx->cfg.css = "/cgit.css";
261 ctx->cfg.logo = "/cgit.png"; 261 ctx->cfg.logo = "/cgit.png";
262 ctx->cfg.local_time = 0; 262 ctx->cfg.local_time = 0;
263 ctx->cfg.max_repo_count = 50; 263 ctx->cfg.max_repo_count = 50;
264 ctx->cfg.max_commit_count = 50; 264 ctx->cfg.max_commit_count = 50;
265 ctx->cfg.max_lock_attempts = 5; 265 ctx->cfg.max_lock_attempts = 5;
266 ctx->cfg.max_msg_len = 80; 266 ctx->cfg.max_msg_len = 80;
267 ctx->cfg.max_repodesc_len = 80; 267 ctx->cfg.max_repodesc_len = 80;
268 ctx->cfg.max_stats = 0; 268 ctx->cfg.max_stats = 0;
269 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 269 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
270 ctx->cfg.renamelimit = -1; 270 ctx->cfg.renamelimit = -1;
271 ctx->cfg.robots = "index, nofollow"; 271 ctx->cfg.robots = "index, nofollow";
272 ctx->cfg.root_title = "Git repository browser"; 272 ctx->cfg.root_title = "Git repository browser";
273 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 273 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
274 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 274 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
275 ctx->cfg.section = ""; 275 ctx->cfg.section = "";
276 ctx->cfg.summary_branches = 10; 276 ctx->cfg.summary_branches = 10;
277 ctx->cfg.summary_log = 10; 277 ctx->cfg.summary_log = 10;
278 ctx->cfg.summary_tags = 10; 278 ctx->cfg.summary_tags = 10;
279 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); 279 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
280 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); 280 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
281 ctx->env.https = xstrdupn(getenv("HTTPS")); 281 ctx->env.https = xstrdupn(getenv("HTTPS"));
282 ctx->env.no_http = xstrdupn(getenv("NO_HTTP")); 282 ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
283 ctx->env.path_info = xstrdupn(getenv("PATH_INFO")); 283 ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
284 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING")); 284 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
285 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD")); 285 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
286 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME")); 286 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
287 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME")); 287 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
288 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT")); 288 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
289 ctx->page.mimetype = "text/html"; 289 ctx->page.mimetype = "text/html";
290 ctx->page.charset = PAGE_ENCODING; 290 ctx->page.charset = PAGE_ENCODING;
291 ctx->page.filename = NULL; 291 ctx->page.filename = NULL;
292 ctx->page.size = 0; 292 ctx->page.size = 0;
293 ctx->page.modified = time(NULL); 293 ctx->page.modified = time(NULL);
294 ctx->page.expires = ctx->page.modified; 294 ctx->page.expires = ctx->page.modified;
295 ctx->page.etag = NULL; 295 ctx->page.etag = NULL;
296 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list)); 296 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list));
297 if (ctx->env.script_name) 297 if (ctx->env.script_name)
298 ctx->cfg.script_name = ctx->env.script_name; 298 ctx->cfg.script_name = ctx->env.script_name;
299 if (ctx->env.query_string) 299 if (ctx->env.query_string)
300 ctx->qry.raw = ctx->env.query_string; 300 ctx->qry.raw = ctx->env.query_string;
301 if (!ctx->env.cgit_config) 301 if (!ctx->env.cgit_config)
302 ctx->env.cgit_config = CGIT_CONFIG; 302 ctx->env.cgit_config = CGIT_CONFIG;
303} 303}
304 304
305struct refmatch { 305struct refmatch {
306 char *req_ref; 306 char *req_ref;
307 char *first_ref; 307 char *first_ref;
308 int match; 308 int match;
309}; 309};
310 310
311int find_current_ref(const char *refname, const unsigned char *sha1, 311int find_current_ref(const char *refname, const unsigned char *sha1,
312 int flags, void *cb_data) 312 int flags, void *cb_data)
313{ 313{
314 struct refmatch *info; 314 struct refmatch *info;
315 315
316 info = (struct refmatch *)cb_data; 316 info = (struct refmatch *)cb_data;
317 if (!strcmp(refname, info->req_ref)) 317 if (!strcmp(refname, info->req_ref))
318 info->match = 1; 318 info->match = 1;
319 if (!info->first_ref) 319 if (!info->first_ref)
320 info->first_ref = xstrdup(refname); 320 info->first_ref = xstrdup(refname);
321 return info->match; 321 return info->match;
322} 322}
323 323
324char *find_default_branch(struct cgit_repo *repo) 324char *find_default_branch(struct cgit_repo *repo)
325{ 325{
326 struct refmatch info; 326 struct refmatch info;
327 char *ref; 327 char *ref;
328 328
329 info.req_ref = repo->defbranch; 329 info.req_ref = repo->defbranch;
330 info.first_ref = NULL; 330 info.first_ref = NULL;
331 info.match = 0; 331 info.match = 0;
332 for_each_branch_ref(find_current_ref, &info); 332 for_each_branch_ref(find_current_ref, &info);
333 if (info.match) 333 if (info.match)
334 ref = info.req_ref; 334 ref = info.req_ref;
335 else 335 else
336 ref = info.first_ref; 336 ref = info.first_ref;
337 if (ref) 337 if (ref)
338 ref = xstrdup(ref); 338 ref = xstrdup(ref);
339 return ref; 339 return ref;
340} 340}
341 341
342static int prepare_repo_cmd(struct cgit_context *ctx) 342static int prepare_repo_cmd(struct cgit_context *ctx)
343{ 343{
344 char *tmp; 344 char *tmp;
345 unsigned char sha1[20]; 345 unsigned char sha1[20];
346 int nongit = 0; 346 int nongit = 0;
347 347
348 setenv("GIT_DIR", ctx->repo->path, 1); 348 setenv("GIT_DIR", ctx->repo->path, 1);
349 setup_git_directory_gently(&nongit); 349 setup_git_directory_gently(&nongit);
350 if (nongit) { 350 if (nongit) {
351 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, 351 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
352 "config error"); 352 "config error");
353 tmp = fmt("Not a git repository: '%s'", ctx->repo->path); 353 tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
354 ctx->repo = NULL; 354 ctx->repo = NULL;
355 cgit_print_http_headers(ctx); 355 cgit_print_http_headers(ctx);
356 cgit_print_docstart(ctx); 356 cgit_print_docstart(ctx);
357 cgit_print_pageheader(ctx); 357 cgit_print_pageheader(ctx);
358 cgit_print_error(tmp); 358 cgit_print_error(tmp);
359 cgit_print_docend(); 359 cgit_print_docend();
360 return 1; 360 return 1;
361 } 361 }
362 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); 362 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
363 363
364 if (!ctx->qry.head) { 364 if (!ctx->qry.head) {
365 ctx->qry.nohead = 1; 365 ctx->qry.nohead = 1;
366 ctx->qry.head = find_default_branch(ctx->repo); 366 ctx->qry.head = find_default_branch(ctx->repo);
367 ctx->repo->defbranch = ctx->qry.head; 367 ctx->repo->defbranch = ctx->qry.head;
368 } 368 }
369 369
370 if (!ctx->qry.head) { 370 if (!ctx->qry.head) {
371 cgit_print_http_headers(ctx); 371 cgit_print_http_headers(ctx);
372 cgit_print_docstart(ctx); 372 cgit_print_docstart(ctx);
373 cgit_print_pageheader(ctx); 373 cgit_print_pageheader(ctx);
374 cgit_print_error("Repository seems to be empty"); 374 cgit_print_error("Repository seems to be empty");
375 cgit_print_docend(); 375 cgit_print_docend();
376 return 1; 376 return 1;
377 } 377 }
378 378
379 if (get_sha1(ctx->qry.head, sha1)) { 379 if (get_sha1(ctx->qry.head, sha1)) {
380 tmp = xstrdup(ctx->qry.head); 380 tmp = xstrdup(ctx->qry.head);
381 ctx->qry.head = ctx->repo->defbranch; 381 ctx->qry.head = ctx->repo->defbranch;
382 ctx->page.status = 404; 382 ctx->page.status = 404;
383 ctx->page.statusmsg = "not found"; 383 ctx->page.statusmsg = "not found";
384 cgit_print_http_headers(ctx); 384 cgit_print_http_headers(ctx);
385 cgit_print_docstart(ctx); 385 cgit_print_docstart(ctx);
386 cgit_print_pageheader(ctx); 386 cgit_print_pageheader(ctx);
387 cgit_print_error(fmt("Invalid branch: %s", tmp)); 387 cgit_print_error(fmt("Invalid branch: %s", tmp));
388 cgit_print_docend(); 388 cgit_print_docend();
389 return 1; 389 return 1;
390 } 390 }
391 return 0; 391 return 0;
392} 392}
393 393
394static void process_request(void *cbdata) 394static void process_request(void *cbdata)
395{ 395{
396 struct cgit_context *ctx = cbdata; 396 struct cgit_context *ctx = cbdata;
397 struct cgit_cmd *cmd; 397 struct cgit_cmd *cmd;
398 398
399 cmd = cgit_get_cmd(ctx); 399 cmd = cgit_get_cmd(ctx);
400 if (!cmd) { 400 if (!cmd) {
401 ctx->page.title = "cgit error"; 401 ctx->page.title = "cgit error";
402 cgit_print_http_headers(ctx); 402 cgit_print_http_headers(ctx);
403 cgit_print_docstart(ctx); 403 cgit_print_docstart(ctx);
404 cgit_print_pageheader(ctx); 404 cgit_print_pageheader(ctx);
405 cgit_print_error("Invalid request"); 405 cgit_print_error("Invalid request");
406 cgit_print_docend(); 406 cgit_print_docend();
407 return; 407 return;
408 } 408 }
409 409
410 if (cmd->want_repo && !ctx->repo) { 410 if (cmd->want_repo && !ctx->repo) {
411 cgit_print_http_headers(ctx); 411 cgit_print_http_headers(ctx);
412 cgit_print_docstart(ctx); 412 cgit_print_docstart(ctx);
413 cgit_print_pageheader(ctx); 413 cgit_print_pageheader(ctx);
414 cgit_print_error(fmt("No repository selected")); 414 cgit_print_error(fmt("No repository selected"));
415 cgit_print_docend(); 415 cgit_print_docend();
416 return; 416 return;
417 } 417 }
418 418
419 if (ctx->repo && prepare_repo_cmd(ctx)) 419 if (ctx->repo && prepare_repo_cmd(ctx))
420 return; 420 return;
421 421
422 if (cmd->want_layout) { 422 if (cmd->want_layout) {
423 cgit_print_http_headers(ctx); 423 cgit_print_http_headers(ctx);
424 cgit_print_docstart(ctx); 424 cgit_print_docstart(ctx);
425 cgit_print_pageheader(ctx); 425 cgit_print_pageheader(ctx);
426 } 426 }
427 427
428 cmd->fn(ctx); 428 cmd->fn(ctx);
429 429
430 if (cmd->want_layout) 430 if (cmd->want_layout)
431 cgit_print_docend(); 431 cgit_print_docend();
432} 432}
433 433
434int cmp_repos(const void *a, const void *b) 434int cmp_repos(const void *a, const void *b)
435{ 435{
436 const struct cgit_repo *ra = a, *rb = b; 436 const struct cgit_repo *ra = a, *rb = b;
437 return strcmp(ra->url, rb->url); 437 return strcmp(ra->url, rb->url);
438} 438}
439 439
440char *build_snapshot_setting(int bitmap) 440char *build_snapshot_setting(int bitmap)
441{ 441{
442 const struct cgit_snapshot_format *f; 442 const struct cgit_snapshot_format *f;
443 char *result = xstrdup(""); 443 char *result = xstrdup("");
444 char *tmp; 444 char *tmp;
445 int len; 445 int len;
446 446
447 for (f = cgit_snapshot_formats; f->suffix; f++) { 447 for (f = cgit_snapshot_formats; f->suffix; f++) {
448 if (f->bit & bitmap) { 448 if (f->bit & bitmap) {
449 tmp = result; 449 tmp = result;
450 result = xstrdup(fmt("%s%s ", tmp, f->suffix)); 450 result = xstrdup(fmt("%s%s ", tmp, f->suffix));
451 free(tmp); 451 free(tmp);
452 } 452 }
453 } 453 }
454 len = strlen(result); 454 len = strlen(result);
455 if (len) 455 if (len)
456 result[len - 1] = '\0'; 456 result[len - 1] = '\0';
457 return result; 457 return result;
458} 458}
459 459
460char *get_first_line(char *txt) 460char *get_first_line(char *txt)
461{ 461{
462 char *t = xstrdup(txt); 462 char *t = xstrdup(txt);
463 char *p = strchr(t, '\n'); 463 char *p = strchr(t, '\n');
464 if (p) 464 if (p)
465 *p = '\0'; 465 *p = '\0';
466 return t; 466 return t;
467} 467}
468 468
469void print_repo(FILE *f, struct cgit_repo *repo) 469void print_repo(FILE *f, struct cgit_repo *repo)
470{ 470{
471 fprintf(f, "repo.url=%s\n", repo->url); 471 fprintf(f, "repo.url=%s\n", repo->url);
472 fprintf(f, "repo.name=%s\n", repo->name); 472 fprintf(f, "repo.name=%s\n", repo->name);
473 fprintf(f, "repo.path=%s\n", repo->path); 473 fprintf(f, "repo.path=%s\n", repo->path);
474 if (repo->owner) 474 if (repo->owner)
475 fprintf(f, "repo.owner=%s\n", repo->owner); 475 fprintf(f, "repo.owner=%s\n", repo->owner);
476 if (repo->desc) { 476 if (repo->desc) {
477 char *tmp = get_first_line(repo->desc); 477 char *tmp = get_first_line(repo->desc);
478 fprintf(f, "repo.desc=%s\n", tmp); 478 fprintf(f, "repo.desc=%s\n", tmp);
479 free(tmp); 479 free(tmp);
480 } 480 }
481 if (repo->readme) 481 if (repo->readme)
482 fprintf(f, "repo.readme=%s\n", repo->readme); 482 fprintf(f, "repo.readme=%s\n", repo->readme);
483 if (repo->defbranch) 483 if (repo->defbranch)
484 fprintf(f, "repo.defbranch=%s\n", repo->defbranch); 484 fprintf(f, "repo.defbranch=%s\n", repo->defbranch);
485 if (repo->module_link) 485 if (repo->module_link)
486 fprintf(f, "repo.module-link=%s\n", repo->module_link); 486 fprintf(f, "repo.module-link=%s\n", repo->module_link);
487 if (repo->section) 487 if (repo->section)
488 fprintf(f, "repo.section=%s\n", repo->section); 488 fprintf(f, "repo.section=%s\n", repo->section);
489 if (repo->clone_url) 489 if (repo->clone_url)
490 fprintf(f, "repo.clone-url=%s\n", repo->clone_url); 490 fprintf(f, "repo.clone-url=%s\n", repo->clone_url);
491 fprintf(f, "repo.enable-log-filecount=%d\n", 491 fprintf(f, "repo.enable-log-filecount=%d\n",
492 repo->enable_log_filecount); 492 repo->enable_log_filecount);
493 fprintf(f, "repo.enable-log-linecount=%d\n", 493 fprintf(f, "repo.enable-log-linecount=%d\n",
494 repo->enable_log_linecount); 494 repo->enable_log_linecount);
495 if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter) 495 if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter)
496 fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd); 496 fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd);
497 if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter) 497 if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter)
498 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd); 498 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd);
499 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) 499 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter)
500 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); 500 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd);
501 if (repo->snapshots != ctx.cfg.snapshots) { 501 if (repo->snapshots != ctx.cfg.snapshots) {
502 char *tmp = build_snapshot_setting(repo->snapshots); 502 char *tmp = build_snapshot_setting(repo->snapshots);
503 fprintf(f, "repo.snapshots=%s\n", tmp); 503 fprintf(f, "repo.snapshots=%s\n", tmp);
504 free(tmp); 504 free(tmp);
505 } 505 }
506 if (repo->max_stats != ctx.cfg.max_stats) 506 if (repo->max_stats != ctx.cfg.max_stats)
507 fprintf(f, "repo.max-stats=%s\n", 507 fprintf(f, "repo.max-stats=%s\n",
508 cgit_find_stats_periodname(repo->max_stats)); 508 cgit_find_stats_periodname(repo->max_stats));
509 fprintf(f, "\n"); 509 fprintf(f, "\n");
510} 510}
511 511
512void print_repolist(FILE *f, struct cgit_repolist *list, int start) 512void print_repolist(FILE *f, struct cgit_repolist *list, int start)
513{ 513{
514 int i; 514 int i;
515 515
516 for(i = start; i < list->count; i++) 516 for(i = start; i < list->count; i++)
517 print_repo(f, &list->repos[i]); 517 print_repo(f, &list->repos[i]);
518} 518}
519 519
520/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' 520/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc'
521 * and return 0 on success. 521 * and return 0 on success.
522 */ 522 */
523static int generate_cached_repolist(const char *path, const char *cached_rc) 523static int generate_cached_repolist(const char *path, const char *cached_rc)
524{ 524{
525 char *locked_rc; 525 char *locked_rc;
526 int idx; 526 int idx;
527 FILE *f; 527 FILE *f;
528 528
529 locked_rc = xstrdup(fmt("%s.lock", cached_rc)); 529 locked_rc = xstrdup(fmt("%s.lock", cached_rc));
530 f = fopen(locked_rc, "wx"); 530 f = fopen(locked_rc, "wx");
531 if (!f) { 531 if (!f) {
532 /* Inform about the error unless the lockfile already existed, 532 /* Inform about the error unless the lockfile already existed,
533 * since that only means we've got concurrent requests. 533 * since that only means we've got concurrent requests.
534 */ 534 */
535 if (errno != EEXIST) 535 if (errno != EEXIST)
536 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", 536 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n",
537 locked_rc, strerror(errno), errno); 537 locked_rc, strerror(errno), errno);
538 return errno; 538 return errno;
539 } 539 }
540 idx = cgit_repolist.count; 540 idx = cgit_repolist.count;
541 scan_tree(path, repo_config); 541 scan_tree(path, repo_config);
542 print_repolist(f, &cgit_repolist, idx); 542 print_repolist(f, &cgit_repolist, idx);
543 if (rename(locked_rc, cached_rc)) 543 if (rename(locked_rc, cached_rc))
544 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", 544 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
545 locked_rc, cached_rc, strerror(errno), errno); 545 locked_rc, cached_rc, strerror(errno), errno);
546 fclose(f); 546 fclose(f);
547 return 0; 547 return 0;
548} 548}
549 549
550static void process_cached_repolist(const char *path) 550static void process_cached_repolist(const char *path)
551{ 551{
552 struct stat st; 552 struct stat st;
553 char *cached_rc; 553 char *cached_rc;
554 time_t age; 554 time_t age;
555 555
556 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, 556 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root,
557 hash_str(path))); 557 hash_str(path)));
558 558
559 if (stat(cached_rc, &st)) { 559 if (stat(cached_rc, &st)) {
560 /* Nothing is cached, we need to scan without forking. And 560 /* Nothing is cached, we need to scan without forking. And
561 * if we fail to generate a cached repolist, we need to 561 * if we fail to generate a cached repolist, we need to
562 * invoke scan_tree manually. 562 * invoke scan_tree manually.
563 */ 563 */
564 if (generate_cached_repolist(path, cached_rc)) 564 if (generate_cached_repolist(path, cached_rc))
565 scan_tree(path, repo_config); 565 scan_tree(path, repo_config);
566 return; 566 return;
567 } 567 }
568 568
569 parse_configfile(cached_rc, config_cb); 569 parse_configfile(cached_rc, config_cb);
570 570
571 /* If the cached configfile hasn't expired, lets exit now */ 571 /* If the cached configfile hasn't expired, lets exit now */
572 age = time(NULL) - st.st_mtime; 572 age = time(NULL) - st.st_mtime;
573 if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) 573 if (age <= (ctx.cfg.cache_scanrc_ttl * 60))
574 return; 574 return;
575 575
576 /* The cached repolist has been parsed, but it was old. So lets 576 /* The cached repolist has been parsed, but it was old. So lets
577 * rescan the specified path and generate a new cached repolist 577 * rescan the specified path and generate a new cached repolist
578 * in a child-process to avoid latency for the current request. 578 * in a child-process to avoid latency for the current request.
579 */ 579 */
580 if (fork()) 580 if (fork())
581 return; 581 return;
582 582
583 exit(generate_cached_repolist(path, cached_rc)); 583 exit(generate_cached_repolist(path, cached_rc));
584} 584}
585 585
586static void cgit_parse_args(int argc, const char **argv) 586static void cgit_parse_args(int argc, const char **argv)
587{ 587{
588 int i; 588 int i;
589 int scan = 0; 589 int scan = 0;
590 590
591 for (i = 1; i < argc; i++) { 591 for (i = 1; i < argc; i++) {
592 if (!strncmp(argv[i], "--cache=", 8)) { 592 if (!strncmp(argv[i], "--cache=", 8)) {
593 ctx.cfg.cache_root = xstrdup(argv[i]+8); 593 ctx.cfg.cache_root = xstrdup(argv[i]+8);
594 } 594 }
595 if (!strcmp(argv[i], "--nocache")) { 595 if (!strcmp(argv[i], "--nocache")) {
596 ctx.cfg.nocache = 1; 596 ctx.cfg.nocache = 1;
597 } 597 }
598 if (!strcmp(argv[i], "--nohttp")) { 598 if (!strcmp(argv[i], "--nohttp")) {
599 ctx.env.no_http = "1"; 599 ctx.env.no_http = "1";
600 } 600 }
601 if (!strncmp(argv[i], "--query=", 8)) { 601 if (!strncmp(argv[i], "--query=", 8)) {
602 ctx.qry.raw = xstrdup(argv[i]+8); 602 ctx.qry.raw = xstrdup(argv[i]+8);
603 } 603 }
604 if (!strncmp(argv[i], "--repo=", 7)) { 604 if (!strncmp(argv[i], "--repo=", 7)) {
605 ctx.qry.repo = xstrdup(argv[i]+7); 605 ctx.qry.repo = xstrdup(argv[i]+7);
606 } 606 }
607 if (!strncmp(argv[i], "--page=", 7)) { 607 if (!strncmp(argv[i], "--page=", 7)) {
608 ctx.qry.page = xstrdup(argv[i]+7); 608 ctx.qry.page = xstrdup(argv[i]+7);
609 } 609 }
610 if (!strncmp(argv[i], "--head=", 7)) { 610 if (!strncmp(argv[i], "--head=", 7)) {
611 ctx.qry.head = xstrdup(argv[i]+7); 611 ctx.qry.head = xstrdup(argv[i]+7);
612 ctx.qry.has_symref = 1; 612 ctx.qry.has_symref = 1;
613 } 613 }
614 if (!strncmp(argv[i], "--sha1=", 7)) { 614 if (!strncmp(argv[i], "--sha1=", 7)) {
615 ctx.qry.sha1 = xstrdup(argv[i]+7); 615 ctx.qry.sha1 = xstrdup(argv[i]+7);
616 ctx.qry.has_sha1 = 1; 616 ctx.qry.has_sha1 = 1;
617 } 617 }
618 if (!strncmp(argv[i], "--ofs=", 6)) { 618 if (!strncmp(argv[i], "--ofs=", 6)) {
619 ctx.qry.ofs = atoi(argv[i]+6); 619 ctx.qry.ofs = atoi(argv[i]+6);
620 } 620 }
621 if (!strncmp(argv[i], "--scan-tree=", 12) || 621 if (!strncmp(argv[i], "--scan-tree=", 12) ||
622 !strncmp(argv[i], "--scan-path=", 12)) { 622 !strncmp(argv[i], "--scan-path=", 12)) {
623 /* HACK: the global snapshot bitmask defines the
624 * set of allowed snapshot formats, but the config
625 * file hasn't been parsed yet so the mask is
626 * currently 0. By setting all bits high before
627 * scanning we make sure that any in-repo cgitrc
628 * snapshot setting is respected by scan_tree().
629 * BTW: we assume that there'll never be more than
630 * 255 different snapshot formats supported by cgit...
631 */
632 ctx.cfg.snapshots = 0xFF;
623 scan++; 633 scan++;
624 scan_tree(argv[i] + 12, repo_config); 634 scan_tree(argv[i] + 12, repo_config);
625 } 635 }
626 } 636 }
627 if (scan) { 637 if (scan) {
628 qsort(cgit_repolist.repos, cgit_repolist.count, 638 qsort(cgit_repolist.repos, cgit_repolist.count,
629 sizeof(struct cgit_repo), cmp_repos); 639 sizeof(struct cgit_repo), cmp_repos);
630 print_repolist(stdout, &cgit_repolist, 0); 640 print_repolist(stdout, &cgit_repolist, 0);
631 exit(0); 641 exit(0);
632 } 642 }
633} 643}
634 644
635static int calc_ttl() 645static int calc_ttl()
636{ 646{
637 if (!ctx.repo) 647 if (!ctx.repo)
638 return ctx.cfg.cache_root_ttl; 648 return ctx.cfg.cache_root_ttl;
639 649
640 if (!ctx.qry.page) 650 if (!ctx.qry.page)
641 return ctx.cfg.cache_repo_ttl; 651 return ctx.cfg.cache_repo_ttl;
642 652
643 if (ctx.qry.has_symref) 653 if (ctx.qry.has_symref)
644 return ctx.cfg.cache_dynamic_ttl; 654 return ctx.cfg.cache_dynamic_ttl;
645 655
646 if (ctx.qry.has_sha1) 656 if (ctx.qry.has_sha1)
647 return ctx.cfg.cache_static_ttl; 657 return ctx.cfg.cache_static_ttl;
648 658
649 return ctx.cfg.cache_repo_ttl; 659 return ctx.cfg.cache_repo_ttl;
650} 660}
651 661
652int main(int argc, const char **argv) 662int main(int argc, const char **argv)
653{ 663{
654 const char *path; 664 const char *path;
655 char *qry; 665 char *qry;
656 int err, ttl; 666 int err, ttl;
657 667
658 prepare_context(&ctx); 668 prepare_context(&ctx);
659 cgit_repolist.length = 0; 669 cgit_repolist.length = 0;
660 cgit_repolist.count = 0; 670 cgit_repolist.count = 0;
661 cgit_repolist.repos = NULL; 671 cgit_repolist.repos = NULL;
662 672
663 cgit_parse_args(argc, argv); 673 cgit_parse_args(argc, argv);
664 parse_configfile(ctx.env.cgit_config, config_cb); 674 parse_configfile(ctx.env.cgit_config, config_cb);
665 ctx.repo = NULL; 675 ctx.repo = NULL;
666 http_parse_querystring(ctx.qry.raw, querystring_cb); 676 http_parse_querystring(ctx.qry.raw, querystring_cb);
667 677
668 /* If virtual-root isn't specified in cgitrc, lets pretend 678 /* If virtual-root isn't specified in cgitrc, lets pretend
669 * that virtual-root equals SCRIPT_NAME. 679 * that virtual-root equals SCRIPT_NAME.
670 */ 680 */
671 if (!ctx.cfg.virtual_root) 681 if (!ctx.cfg.virtual_root)
672 ctx.cfg.virtual_root = ctx.cfg.script_name; 682 ctx.cfg.virtual_root = ctx.cfg.script_name;
673 683
674 /* If no url parameter is specified on the querystring, lets 684 /* If no url parameter is specified on the querystring, lets
675 * use PATH_INFO as url. This allows cgit to work with virtual 685 * use PATH_INFO as url. This allows cgit to work with virtual
676 * urls without the need for rewriterules in the webserver (as 686 * urls without the need for rewriterules in the webserver (as
677 * long as PATH_INFO is included in the cache lookup key). 687 * long as PATH_INFO is included in the cache lookup key).
678 */ 688 */
679 path = ctx.env.path_info; 689 path = ctx.env.path_info;
680 if (!ctx.qry.url && path) { 690 if (!ctx.qry.url && path) {
681 if (path[0] == '/') 691 if (path[0] == '/')
682 path++; 692 path++;
683 ctx.qry.url = xstrdup(path); 693 ctx.qry.url = xstrdup(path);
684 if (ctx.qry.raw) { 694 if (ctx.qry.raw) {
685 qry = ctx.qry.raw; 695 qry = ctx.qry.raw;
686 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); 696 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry));
687 free(qry); 697 free(qry);
688 } else 698 } else
689 ctx.qry.raw = xstrdup(ctx.qry.url); 699 ctx.qry.raw = xstrdup(ctx.qry.url);
690 cgit_parse_url(ctx.qry.url); 700 cgit_parse_url(ctx.qry.url);
691 } 701 }
692 702
693 ttl = calc_ttl(); 703 ttl = calc_ttl();
694 ctx.page.expires += ttl*60; 704 ctx.page.expires += ttl*60;
695 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) 705 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
696 ctx.cfg.nocache = 1; 706 ctx.cfg.nocache = 1;
697 if (ctx.cfg.nocache) 707 if (ctx.cfg.nocache)
698 ctx.cfg.cache_size = 0; 708 ctx.cfg.cache_size = 0;
699 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, 709 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
700 ctx.qry.raw, ttl, process_request, &ctx); 710 ctx.qry.raw, ttl, process_request, &ctx);
701 if (err) 711 if (err)
702 cgit_print_error(fmt("Error processing page: %s (%d)", 712 cgit_print_error(fmt("Error processing page: %s (%d)",
703 strerror(err), err)); 713 strerror(err), err));
704 return err; 714 return err;
705} 715}