diff options
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | cgit.c | 47 | ||||
| -rw-r--r-- | scan-tree.c | 136 | ||||
| -rw-r--r-- | scan-tree.h | 3 |
4 files changed, 184 insertions, 3 deletions
| @@ -54,6 +54,7 @@ OBJECTS += cmd.o | |||
| 54 | OBJECTS += configfile.o | 54 | OBJECTS += configfile.o |
| 55 | OBJECTS += html.o | 55 | OBJECTS += html.o |
| 56 | OBJECTS += parsing.o | 56 | OBJECTS += parsing.o |
| 57 | OBJECTS += scan-tree.o | ||
| 57 | OBJECTS += shared.o | 58 | OBJECTS += shared.o |
| 58 | OBJECTS += ui-atom.o | 59 | OBJECTS += ui-atom.o |
| 59 | OBJECTS += ui-blob.o | 60 | OBJECTS += ui-blob.o |
| @@ -12,6 +12,7 @@ | |||
| 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 "scan-tree.h" | ||
| 15 | 16 | ||
| 16 | const char *cgit_version = CGIT_VERSION; | 17 | const char *cgit_version = CGIT_VERSION; |
| 17 | 18 | ||
| @@ -320,9 +321,39 @@ static void process_request(void *cbdata) | |||
| 320 | cgit_print_docend(); | 321 | cgit_print_docend(); |
| 321 | } | 322 | } |
| 322 | 323 | ||
| 324 | int cmp_repos(const void *a, const void *b) | ||
| 325 | { | ||
| 326 | const struct cgit_repo *ra = a, *rb = b; | ||
| 327 | return strcmp(ra->url, rb->url); | ||
| 328 | } | ||
| 329 | |||
| 330 | void print_repo(struct cgit_repo *repo) | ||
| 331 | { | ||
| 332 | printf("repo.url=%s\n", repo->url); | ||
| 333 | printf("repo.name=%s\n", repo->name); | ||
| 334 | printf("repo.path=%s\n", repo->path); | ||
| 335 | if (repo->owner) | ||
| 336 | printf("repo.owner=%s\n", repo->owner); | ||
| 337 | if (repo->desc) | ||
| 338 | printf("repo.desc=%s\n", repo->desc); | ||
| 339 | if (repo->readme) | ||
| 340 | printf("repo.readme=%s\n", repo->readme); | ||
| 341 | printf("\n"); | ||
| 342 | } | ||
| 343 | |||
| 344 | void print_repolist(struct cgit_repolist *list) | ||
| 345 | { | ||
| 346 | int i; | ||
| 347 | |||
| 348 | for(i = 0; i < list->count; i++) | ||
| 349 | print_repo(&list->repos[i]); | ||
| 350 | } | ||
| 351 | |||
| 352 | |||
| 323 | static void cgit_parse_args(int argc, const char **argv) | 353 | static void cgit_parse_args(int argc, const char **argv) |
| 324 | { | 354 | { |
| 325 | int i; | 355 | int i; |
| 356 | int scan = 0; | ||
| 326 | 357 | ||
| 327 | for (i = 1; i < argc; i++) { | 358 | for (i = 1; i < argc; i++) { |
| 328 | if (!strncmp(argv[i], "--cache=", 8)) { | 359 | if (!strncmp(argv[i], "--cache=", 8)) { |
| @@ -351,6 +382,16 @@ static void cgit_parse_args(int argc, const char **argv) | |||
| 351 | if (!strncmp(argv[i], "--ofs=", 6)) { | 382 | if (!strncmp(argv[i], "--ofs=", 6)) { |
| 352 | ctx.qry.ofs = atoi(argv[i]+6); | 383 | ctx.qry.ofs = atoi(argv[i]+6); |
| 353 | } | 384 | } |
| 385 | if (!strncmp(argv[i], "--scan-tree=", 12)) { | ||
| 386 | scan++; | ||
| 387 | scan_tree(argv[i] + 12); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | if (scan) { | ||
| 391 | qsort(cgit_repolist.repos, cgit_repolist.count, | ||
| 392 | sizeof(struct cgit_repo), cmp_repos); | ||
| 393 | print_repolist(&cgit_repolist); | ||
| 394 | exit(0); | ||
| 354 | } | 395 | } |
| 355 | } | 396 | } |
| 356 | 397 | ||
| @@ -383,14 +424,14 @@ int main(int argc, const char **argv) | |||
| 383 | cgit_repolist.count = 0; | 424 | cgit_repolist.count = 0; |
| 384 | cgit_repolist.repos = NULL; | 425 | cgit_repolist.repos = NULL; |
| 385 | 426 | ||
| 386 | parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG, | ||
| 387 | config_cb); | ||
| 388 | ctx.repo = NULL; | ||
| 389 | if (getenv("SCRIPT_NAME")) | 427 | if (getenv("SCRIPT_NAME")) |
| 390 | ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME")); | 428 | ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME")); |
| 391 | if (getenv("QUERY_STRING")) | 429 | if (getenv("QUERY_STRING")) |
| 392 | ctx.qry.raw = xstrdup(getenv("QUERY_STRING")); | 430 | ctx.qry.raw = xstrdup(getenv("QUERY_STRING")); |
| 393 | cgit_parse_args(argc, argv); | 431 | cgit_parse_args(argc, argv); |
| 432 | parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG, | ||
| 433 | config_cb); | ||
| 434 | ctx.repo = NULL; | ||
| 394 | http_parse_querystring(ctx.qry.raw, querystring_cb); | 435 | http_parse_querystring(ctx.qry.raw, querystring_cb); |
| 395 | 436 | ||
| 396 | /* If virtual-root isn't specified in cgitrc and no url | 437 | /* If virtual-root isn't specified in cgitrc and no url |
diff --git a/scan-tree.c b/scan-tree.c new file mode 100644 index 0000000..cdafb02 --- /dev/null +++ b/scan-tree.c | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | #include "cgit.h" | ||
| 2 | #include "html.h" | ||
| 3 | |||
| 4 | #define MAX_PATH 4096 | ||
| 5 | |||
| 6 | /* return 1 if path contains a objects/ directory and a HEAD file */ | ||
| 7 | static int is_git_dir(const char *path) | ||
| 8 | { | ||
| 9 | struct stat st; | ||
| 10 | static char buf[MAX_PATH]; | ||
| 11 | |||
| 12 | if (snprintf(buf, MAX_PATH, "%s/objects", path) >= MAX_PATH) { | ||
| 13 | fprintf(stderr, "Insanely long path: %s\n", path); | ||
| 14 | return 0; | ||
| 15 | } | ||
| 16 | if (stat(buf, &st)) { | ||
| 17 | if (errno != ENOENT) | ||
| 18 | fprintf(stderr, "Error checking path %s: %s (%d)\n", | ||
| 19 | path, strerror(errno), errno); | ||
| 20 | return 0; | ||
| 21 | } | ||
| 22 | if (!S_ISDIR(st.st_mode)) | ||
| 23 | return 0; | ||
| 24 | |||
| 25 | sprintf(buf, "%s/HEAD", path); | ||
| 26 | if (stat(buf, &st)) { | ||
| 27 | if (errno != ENOENT) | ||
| 28 | fprintf(stderr, "Error checking path %s: %s (%d)\n", | ||
| 29 | path, strerror(errno), errno); | ||
| 30 | return 0; | ||
| 31 | } | ||
| 32 | if (!S_ISREG(st.st_mode)) | ||
| 33 | return 0; | ||
| 34 | |||
| 35 | return 1; | ||
| 36 | } | ||
| 37 | |||
| 38 | char *readfile(const char *path) | ||
| 39 | { | ||
| 40 | FILE *f; | ||
| 41 | static char buf[MAX_PATH]; | ||
| 42 | |||
| 43 | if (!(f = fopen(path, "r"))) | ||
| 44 | return NULL; | ||
| 45 | fgets(buf, MAX_PATH, f); | ||
| 46 | fclose(f); | ||
| 47 | return buf; | ||
| 48 | } | ||
| 49 | |||
| 50 | static void add_repo(const char *base, const char *path) | ||
| 51 | { | ||
| 52 | struct cgit_repo *repo; | ||
| 53 | struct stat st; | ||
| 54 | struct passwd *pwd; | ||
| 55 | char *p; | ||
| 56 | |||
| 57 | if (stat(path, &st)) { | ||
| 58 | fprintf(stderr, "Error accessing %s: %s (%d)\n", | ||
| 59 | path, strerror(errno), errno); | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | if ((pwd = getpwuid(st.st_uid)) == NULL) { | ||
| 63 | fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", | ||
| 64 | path, strerror(errno), errno); | ||
| 65 | return; | ||
| 66 | } | ||
| 67 | if (base == path) | ||
| 68 | p = fmt("%s", path); | ||
| 69 | else | ||
| 70 | p = fmt("%s", path + strlen(base) + 1); | ||
| 71 | |||
| 72 | if (!strcmp(p + strlen(p) - 5, "/.git")) | ||
| 73 | p[strlen(p) - 5] = '\0'; | ||
| 74 | |||
| 75 | repo = cgit_add_repo(xstrdup(p)); | ||
| 76 | repo->name = repo->url; | ||
| 77 | repo->path = xstrdup(path); | ||
| 78 | repo->owner = (pwd ? xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name) : ""); | ||
| 79 | |||
| 80 | p = fmt("%s/description", path); | ||
| 81 | if (!stat(p, &st)) | ||
| 82 | repo->desc = xstrdup(readfile(p)); | ||
| 83 | |||
| 84 | p = fmt("%s/README.html", path); | ||
| 85 | if (!stat(p, &st)) | ||
| 86 | repo->readme = "README.html"; | ||
| 87 | } | ||
| 88 | |||
| 89 | static void scan_path(const char *base, const char *path) | ||
| 90 | { | ||
| 91 | DIR *dir; | ||
| 92 | struct dirent *ent; | ||
| 93 | char *buf; | ||
| 94 | struct stat st; | ||
| 95 | |||
| 96 | if (is_git_dir(path)) { | ||
| 97 | add_repo(base, path); | ||
| 98 | return; | ||
| 99 | } | ||
| 100 | dir = opendir(path); | ||
| 101 | if (!dir) { | ||
| 102 | fprintf(stderr, "Error opening directory %s: %s (%d)\n", | ||
| 103 | path, strerror(errno), errno); | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | while((ent = readdir(dir)) != NULL) { | ||
| 107 | if (ent->d_name[0] == '.') { | ||
| 108 | if (ent->d_name[1] == '\0') | ||
| 109 | continue; | ||
| 110 | if (ent->d_name[1] == '.' && ent->d_name[2] == '\0') | ||
| 111 | continue; | ||
| 112 | } | ||
| 113 | buf = malloc(strlen(path) + strlen(ent->d_name) + 2); | ||
| 114 | if (!buf) { | ||
| 115 | fprintf(stderr, "Alloc error on %s: %s (%d)\n", | ||
| 116 | path, strerror(errno), errno); | ||
| 117 | exit(1); | ||
| 118 | } | ||
| 119 | sprintf(buf, "%s/%s", path, ent->d_name); | ||
| 120 | if (stat(buf, &st)) { | ||
| 121 | fprintf(stderr, "Error checking path %s: %s (%d)\n", | ||
| 122 | buf, strerror(errno), errno); | ||
| 123 | free(buf); | ||
| 124 | continue; | ||
| 125 | } | ||
| 126 | if (S_ISDIR(st.st_mode)) | ||
| 127 | scan_path(base, buf); | ||
| 128 | free(buf); | ||
| 129 | } | ||
| 130 | closedir(dir); | ||
| 131 | } | ||
| 132 | |||
| 133 | void scan_tree(const char *path) | ||
| 134 | { | ||
| 135 | scan_path(path, path); | ||
| 136 | } | ||
diff --git a/scan-tree.h b/scan-tree.h new file mode 100644 index 0000000..b103b16 --- /dev/null +++ b/scan-tree.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | |||
| 3 | extern void scan_tree(const char *path); | ||
