diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-21 00:12:09 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-21 00:12:09 +0000 |
| commit | 5d148e2646874a6f460402f2dd70ea2fb6be08dd (patch) | |
| tree | fae60c2d7ca0d917f73f6a87554657c09a0ddb7b | |
| parent | fcdb00f7359488d197ac3361dfbc49ccdead8b87 (diff) | |
| download | busybox-w32-5d148e2646874a6f460402f2dd70ea2fb6be08dd.tar.gz busybox-w32-5d148e2646874a6f460402f2dd70ea2fb6be08dd.tar.bz2 busybox-w32-5d148e2646874a6f460402f2dd70ea2fb6be08dd.zip | |
httpd: fix cgi-bin/index.cgi support, add example of it,
stat: fix end-of-line if format is specified (wasn't printing it),
fix %z (time) format to match coreutils 6.3
| -rw-r--r-- | coreutils/stat.c | 68 | ||||
| -rw-r--r-- | networking/httpd.c | 27 | ||||
| -rw-r--r-- | networking/httpd_index_cgi_example | 55 |
3 files changed, 111 insertions, 39 deletions
diff --git a/coreutils/stat.c b/coreutils/stat.c index b9fd42f4a..31dd6624e 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c | |||
| @@ -44,10 +44,16 @@ static char const *file_type(struct stat const *st) | |||
| 44 | 44 | ||
| 45 | static char const *human_time(time_t t) | 45 | static char const *human_time(time_t t) |
| 46 | { | 46 | { |
| 47 | /* Old | ||
| 47 | static char *str; | 48 | static char *str; |
| 48 | str = ctime(&t); | 49 | str = ctime(&t); |
| 49 | str[strlen(str)-1] = '\0'; | 50 | str[strlen(str)-1] = '\0'; |
| 50 | return str; | 51 | return str; |
| 52 | */ | ||
| 53 | /* coreutils 6.3 compat: */ | ||
| 54 | static char buf[sizeof("YYYY-MM-DD HH:MM:SS.000000000")]; | ||
| 55 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.000000000", localtime(&t)); | ||
| 56 | return buf; | ||
| 51 | } | 57 | } |
| 52 | 58 | ||
| 53 | /* Return the type of the specified file system. | 59 | /* Return the type of the specified file system. |
| @@ -311,41 +317,41 @@ static void print_it(char const *masterformat, char const *filename, | |||
| 311 | /* create a working copy of the format string */ | 317 | /* create a working copy of the format string */ |
| 312 | char *format = xstrdup(masterformat); | 318 | char *format = xstrdup(masterformat); |
| 313 | 319 | ||
| 314 | /* Add 2 to accommodate our conversion of the stat `%s' format string | 320 | /* Add 2 to accomodate our conversion of the stat '%s' format string |
| 315 | * to the printf `%llu' one. */ | 321 | * to the printf '%llu' one. */ |
| 316 | size_t n_alloc = strlen(format) + 2 + 1; | 322 | size_t n_alloc = strlen(format) + 2 + 1; |
| 317 | char *dest = xmalloc(n_alloc); | 323 | char *dest = xmalloc(n_alloc); |
| 318 | 324 | ||
| 319 | b = format; | 325 | b = format; |
| 320 | while (b) { | 326 | while (b) { |
| 327 | size_t len; | ||
| 321 | char *p = strchr(b, '%'); | 328 | char *p = strchr(b, '%'); |
| 322 | if (p != NULL) { | 329 | if (!p) { |
| 323 | size_t len; | 330 | /* coreutils 6.3 always print <cr> at the end */ |
| 324 | *p++ = '\0'; | 331 | /*fputs(b, stdout);*/ |
| 325 | fputs(b, stdout); | 332 | puts(b); |
| 326 | 333 | break; | |
| 327 | len = strspn(p, "#-+.I 0123456789"); | 334 | } |
| 328 | dest[0] = '%'; | 335 | *p++ = '\0'; |
| 329 | memcpy(dest + 1, p, len); | 336 | fputs(b, stdout); |
| 330 | dest[1 + len] = 0; | 337 | |
| 331 | p += len; | 338 | len = strspn(p, "#-+.I 0123456789"); |
| 332 | 339 | dest[0] = '%'; | |
| 333 | b = p + 1; | 340 | memcpy(dest + 1, p, len); |
| 334 | switch (*p) { | 341 | dest[1 + len] = 0; |
| 335 | case '\0': | 342 | p += len; |
| 336 | b = NULL; | 343 | |
| 337 | /* fall through */ | 344 | b = p + 1; |
| 338 | case '%': | 345 | switch (*p) { |
| 339 | putchar('%'); | 346 | case '\0': |
| 340 | break; | ||
| 341 | default: | ||
| 342 | print_func(dest, n_alloc, *p, filename, data); | ||
| 343 | break; | ||
| 344 | } | ||
| 345 | |||
| 346 | } else { | ||
| 347 | fputs(b, stdout); | ||
| 348 | b = NULL; | 347 | b = NULL; |
| 348 | /* fall through */ | ||
| 349 | case '%': | ||
| 350 | putchar('%'); | ||
| 351 | break; | ||
| 352 | default: | ||
| 353 | print_func(dest, n_alloc, *p, filename, data); | ||
| 354 | break; | ||
| 349 | } | 355 | } |
| 350 | } | 356 | } |
| 351 | 357 | ||
| @@ -372,7 +378,7 @@ static int do_statfs(char const *filename, char const *format) | |||
| 372 | " ID: %-8i Namelen: %-7l Type: %T\n" | 378 | " ID: %-8i Namelen: %-7l Type: %T\n" |
| 373 | "Block size: %-10s\n" | 379 | "Block size: %-10s\n" |
| 374 | "Blocks: Total: %-10b Free: %-10f Available: %a\n" | 380 | "Blocks: Total: %-10b Free: %-10f Available: %a\n" |
| 375 | "Inodes: Total: %-10c Free: %d\n"); | 381 | "Inodes: Total: %-10c Free: %d"); |
| 376 | print_it(format, filename, print_statfs, &statfsbuf); | 382 | print_it(format, filename, print_statfs, &statfsbuf); |
| 377 | #else | 383 | #else |
| 378 | 384 | ||
| @@ -420,7 +426,7 @@ static int do_stat(char const *filename, char const *format) | |||
| 420 | #ifdef CONFIG_FEATURE_STAT_FORMAT | 426 | #ifdef CONFIG_FEATURE_STAT_FORMAT |
| 421 | if (format == NULL) { | 427 | if (format == NULL) { |
| 422 | if (flags & OPT_TERSE) { | 428 | if (flags & OPT_TERSE) { |
| 423 | format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"; | 429 | format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o"; |
| 424 | } else { | 430 | } else { |
| 425 | if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) { | 431 | if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) { |
| 426 | format = | 432 | format = |
| @@ -517,7 +523,7 @@ int stat_main(int argc, char **argv) | |||
| 517 | int (*statfunc)(char const *, char const *) = do_stat; | 523 | int (*statfunc)(char const *, char const *) = do_stat; |
| 518 | 524 | ||
| 519 | flags = getopt32(argc, argv, "ftL" | 525 | flags = getopt32(argc, argv, "ftL" |
| 520 | USE_FEATURE_STAT_FORMAT("c:", &format) | 526 | USE_FEATURE_STAT_FORMAT("c:", &format) |
| 521 | ); | 527 | ); |
| 522 | 528 | ||
| 523 | if (flags & 1) /* -f */ | 529 | if (flags & 1) /* -f */ |
diff --git a/networking/httpd.c b/networking/httpd.c index 47d41a1e2..08b40e014 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
| @@ -1103,7 +1103,7 @@ static int sendCgi(const char *url, | |||
| 1103 | 1103 | ||
| 1104 | post_readed_size = 0; | 1104 | post_readed_size = 0; |
| 1105 | post_readed_idx = 0; | 1105 | post_readed_idx = 0; |
| 1106 | inFd = fromCgi[0]; | 1106 | inFd = fromCgi[0]; |
| 1107 | outFd = toCgi[1]; | 1107 | outFd = toCgi[1]; |
| 1108 | close(fromCgi[1]); | 1108 | close(fromCgi[1]); |
| 1109 | close(toCgi[0]); | 1109 | close(toCgi[0]); |
| @@ -1190,6 +1190,10 @@ static int sendCgi(const char *url, | |||
| 1190 | if (strncmp(rbuf, "HTTP/1.0 200 OK\r\n", 4) != 0) { | 1190 | if (strncmp(rbuf, "HTTP/1.0 200 OK\r\n", 4) != 0) { |
| 1191 | full_write(s, "HTTP/1.0 200 OK\r\n", 17); | 1191 | full_write(s, "HTTP/1.0 200 OK\r\n", 17); |
| 1192 | } | 1192 | } |
| 1193 | /* Sometimes CGI is writing to pipe in small chunks | ||
| 1194 | * and we don't see Content-type (because the read | ||
| 1195 | * is too short) and we emit bogus "text/plain"! | ||
| 1196 | * Is it a bug or CGI *has to* write it in one piece? */ | ||
| 1193 | if (strstr(rbuf, "ontent-") == 0) { | 1197 | if (strstr(rbuf, "ontent-") == 0) { |
| 1194 | full_write(s, "Content-type: text/plain\r\n\r\n", 28); | 1198 | full_write(s, "Content-type: text/plain\r\n\r\n", 28); |
| 1195 | } | 1199 | } |
| @@ -1480,6 +1484,7 @@ static void handleIncoming(void) | |||
| 1480 | strcpy(url, buf); | 1484 | strcpy(url, buf); |
| 1481 | /* extract url args if present */ | 1485 | /* extract url args if present */ |
| 1482 | test = strchr(url, '?'); | 1486 | test = strchr(url, '?'); |
| 1487 | config->query = NULL; | ||
| 1483 | if (test) { | 1488 | if (test) { |
| 1484 | *test++ = '\0'; | 1489 | *test++ = '\0'; |
| 1485 | config->query = test; | 1490 | config->query = test; |
| @@ -1640,20 +1645,26 @@ static void handleIncoming(void) | |||
| 1640 | sendHeaders(HTTP_NOT_IMPLEMENTED); | 1645 | sendHeaders(HTTP_NOT_IMPLEMENTED); |
| 1641 | break; | 1646 | break; |
| 1642 | } | 1647 | } |
| 1643 | if (purl[-1] == '/') { | ||
| 1644 | if (access("cgi-bin/index.cgi", X_OK) == 0) { | ||
| 1645 | config->query = url; | ||
| 1646 | sendCgi("/cgi-bin/index.cgi", prequest, length, cookie, content_type); | ||
| 1647 | break; | ||
| 1648 | } | ||
| 1649 | } | ||
| 1650 | #endif /* FEATURE_HTTPD_CGI */ | 1648 | #endif /* FEATURE_HTTPD_CGI */ |
| 1651 | if (purl[-1] == '/') | 1649 | if (purl[-1] == '/') |
| 1652 | strcpy(purl, "index.html"); | 1650 | strcpy(purl, "index.html"); |
| 1653 | if (stat(test, &sb) == 0) { | 1651 | if (stat(test, &sb) == 0) { |
| 1652 | /* It's a dir URL and there is index.html */ | ||
| 1654 | config->ContentLength = sb.st_size; | 1653 | config->ContentLength = sb.st_size; |
| 1655 | config->last_mod = sb.st_mtime; | 1654 | config->last_mod = sb.st_mtime; |
| 1656 | } | 1655 | } |
| 1656 | #if ENABLE_FEATURE_HTTPD_CGI | ||
| 1657 | else if (purl[-1] == '/') { | ||
| 1658 | /* It's a dir URL and there is no index.html | ||
| 1659 | * Try cgi-bin/index.cgi */ | ||
| 1660 | if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { | ||
| 1661 | purl[0] = '\0'; | ||
| 1662 | config->query = url; | ||
| 1663 | sendCgi("/cgi-bin/index.cgi", prequest, length, cookie, content_type); | ||
| 1664 | break; | ||
| 1665 | } | ||
| 1666 | } | ||
| 1667 | #endif /* FEATURE_HTTPD_CGI */ | ||
| 1657 | sendFile(test); | 1668 | sendFile(test); |
| 1658 | config->ContentLength = -1; | 1669 | config->ContentLength = -1; |
| 1659 | } while (0); | 1670 | } while (0); |
diff --git a/networking/httpd_index_cgi_example b/networking/httpd_index_cgi_example new file mode 100644 index 000000000..31e768c70 --- /dev/null +++ b/networking/httpd_index_cgi_example | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # This CGI creates directory index. | ||
| 3 | # Put it into cgi-bin/index.cgi and chmod 0755. | ||
| 4 | # | ||
| 5 | # Problems: | ||
| 6 | # * Unsafe wrt weird filenames with <>"'& etc... | ||
| 7 | # * Not efficient: calls stat (program, not syscall) for each file | ||
| 8 | # * Probably requires bash | ||
| 9 | # | ||
| 10 | # If you want speed and safety, you need to code it in C | ||
| 11 | |||
| 12 | # Must start with '/' | ||
| 13 | test "${QUERY_STRING:0:1}" = "/" || exit 1 | ||
| 14 | # /../ is not allowed | ||
| 15 | test "${QUERY_STRING%/../*}" = "$QUERY_STRING" || exit 1 | ||
| 16 | test "${QUERY_STRING%/..}" = "$QUERY_STRING" || exit 1 | ||
| 17 | |||
| 18 | # Outta cgi-bin... | ||
| 19 | cd .. 2>/dev/null || exit 1 | ||
| 20 | # Strip leading '/', go to target dir | ||
| 21 | cd "${QUERY_STRING:1}" 2>/dev/null || exit 1 | ||
| 22 | |||
| 23 | f=`dirname "$QUERY_STRING"` | ||
| 24 | test "$f" = "/" && f="" | ||
| 25 | |||
| 26 | # Pipe thru dd (need to write header as single write(), | ||
| 27 | # or else httpd doesn't see "Content-type: text/html" | ||
| 28 | # in first read() and decides that it is not html) | ||
| 29 | { | ||
| 30 | printf "%s" \ | ||
| 31 | $'HTTP/1.0 200 OK\r\n'\ | ||
| 32 | $'Content-type: text/html\r\n\r\n'\ | ||
| 33 | "<html><head><title>Index of $QUERY_STRING</title></head>"$'\r\n'\ | ||
| 34 | "<body><h1>Index of $QUERY_STRING</h1><pre>"$'\r\n'\ | ||
| 35 | $'<table width=100%>\r\n'\ | ||
| 36 | $'<col><col><col width=0*>\r\n'\ | ||
| 37 | $'<tr><th>Name<th align=right>Last modified<th align=right>Size\r\n'\ | ||
| 38 | \ | ||
| 39 | "<tr><td><a href='$f/'>..</a><td><td>"$'\r\n' | ||
| 40 | |||
| 41 | IFS='#' | ||
| 42 | for f in *; do | ||
| 43 | # Guard against empty dirs... | ||
| 44 | test -e "$f" && \ | ||
| 45 | stat -c "%F#%s#%z" "$f" | { | ||
| 46 | read type size cdt junk | ||
| 47 | dir='' | ||
| 48 | test "$type" = "directory" && dir='/' | ||
| 49 | cdt="${cdt//.*}" # no fractional seconds | ||
| 50 | cdt="${cdt// / }" # prevent wrapping around space | ||
| 51 | printf "%s" "<tr><td><a href='$f$dir'>$f</a><td align=right>$cdt<td align=right>$size"$'\r\n' | ||
| 52 | } | ||
| 53 | done | ||
| 54 | printf "</table></pre><hr></body></html>"$'\r\n' | ||
| 55 | } | dd bs=4k | ||
