242 execv(hg_shell, nargv); |
242 execv(hg_shell, nargv); |
243 perror(hg_shell); |
243 perror(hg_shell); |
244 exit(EX_OSFILE); |
244 exit(EX_OSFILE); |
245 } |
245 } |
246 |
246 |
|
247 enum cmdline { |
|
248 hg_init, |
|
249 hg_serve, |
|
250 }; |
|
251 |
|
252 |
247 /* |
253 /* |
248 * paranoid wrapper, runs hg executable in server mode. |
254 * paranoid wrapper, runs hg executable in server mode. |
249 */ |
255 */ |
250 static void serve_data(int argc, char **argv) |
256 static void serve_data(int argc, char **argv) |
251 { |
257 { |
252 char *hg_root = HG_ROOT; |
258 char *hg_root = HG_ROOT; |
253 char *repo, *abspath; |
259 char *repo, *repo_root; |
|
260 enum cmdline cmd; |
254 char *nargv[6]; |
261 char *nargv[6]; |
255 struct stat st; |
262 struct stat st; |
256 size_t repolen; |
263 size_t repolen; |
257 int i; |
264 int i; |
258 |
265 |
273 |
280 |
274 if (strcmp(argv[1], "-c") != 0) { |
281 if (strcmp(argv[1], "-c") != 0) { |
275 goto badargs; |
282 goto badargs; |
276 } |
283 } |
277 |
284 |
278 if (sscanf(argv[2], "hg -R %as serve --stdio", &repo) != 1) { |
285 if (sscanf(argv[2], "hg init %as", &repo) == 1) { |
|
286 cmd = hg_init; |
|
287 } |
|
288 else if (sscanf(argv[2], "hg -R %as serve --stdio", &repo) == 1) { |
|
289 cmd = hg_serve; |
|
290 } else { |
279 goto badargs; |
291 goto badargs; |
280 } |
292 } |
281 |
293 |
282 repolen = repo ? strlen(repo) : 0; |
294 repolen = repo ? strlen(repo) : 0; |
283 |
295 |
284 if (repolen == 0) { |
296 if (repolen == 0) { |
285 goto badargs; |
297 goto badargs; |
286 } |
298 } |
287 |
299 |
288 if (hg_root) { |
300 if (hg_root) { |
289 if (asprintf(&abspath, "%s/%s/.hg/data", hg_root, repo) == -1) { |
301 if (asprintf(&repo_root, "%s/%s/", hg_root, repo) == -1) { |
290 goto badargs; |
302 goto badargs; |
291 } |
303 } |
292 |
304 |
293 /* |
305 /* |
294 * attempt to stop break out from inside the repository tree. could |
306 * attempt to stop break out from inside the repository tree. could |
295 * do something more clever here, because e.g. we could traverse a |
307 * do something more clever here, because e.g. we could traverse a |
296 * symlink that looks safe, but really breaks us out of tree. |
308 * symlink that looks safe, but really breaks us out of tree. |
297 */ |
309 */ |
298 |
310 |
299 if (strstr(abspath, "/../") != NULL) { |
311 if (strstr(repo_root, "/../") != NULL) { |
300 goto badargs; |
312 goto badargs; |
301 } |
313 } |
302 |
314 |
303 /* verify that we really are looking at valid repo. */ |
315 /* only hg init expects no repo. */ |
304 |
316 |
305 if (stat(abspath, &st) == -1) { |
317 if (cmd != hg_init) { |
306 perror(repo); |
318 char *abs_path; |
307 exit(EX_DATAERR); |
319 |
308 } |
320 if (asprintf(&abs_path, "%s.hg/data", repo_root) == -1) { |
|
321 goto badargs; |
|
322 } |
|
323 |
|
324 /* verify that we really are looking at valid repo. */ |
|
325 |
|
326 if (stat(abs_path, &st) == -1) { |
|
327 perror(repo); |
|
328 exit(EX_DATAERR); |
|
329 } |
|
330 } |
309 |
331 |
310 if (chdir(hg_root) == -1) { |
332 if (chdir(hg_root) == -1) { |
311 perror(hg_root); |
333 perror(hg_root); |
312 exit(EX_SOFTWARE); |
334 exit(EX_SOFTWARE); |
313 } |
335 } |
314 } |
336 } |
315 |
337 |
316 i = 0; |
338 i = 0; |
317 nargv[i++] = HG; |
339 |
318 nargv[i++] = "-R"; |
340 switch (cmd) { |
319 nargv[i++] = repo; |
341 case hg_serve: |
320 nargv[i++] = "serve"; |
342 nargv[i++] = HG; |
321 nargv[i++] = "--stdio"; |
343 nargv[i++] = "-R"; |
|
344 nargv[i++] = repo; |
|
345 nargv[i++] = "serve"; |
|
346 nargv[i++] = "--stdio"; |
|
347 break; |
|
348 case hg_init: |
|
349 nargv[i++] = HG; |
|
350 nargv[i++] = "init"; |
|
351 nargv[i++] = repo; |
|
352 break; |
|
353 } |
|
354 |
322 nargv[i] = NULL; |
355 nargv[i] = NULL; |
323 |
356 |
324 if (debug) { |
357 if (debug) { |
325 print_cmdline(i, nargv); |
358 print_cmdline(i, nargv); |
326 } |
359 } |