aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-11-21 00:12:09 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-11-21 00:12:09 +0000
commit5d148e2646874a6f460402f2dd70ea2fb6be08dd (patch)
treefae60c2d7ca0d917f73f6a87554657c09a0ddb7b
parentfcdb00f7359488d197ac3361dfbc49ccdead8b87 (diff)
downloadbusybox-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.c68
-rw-r--r--networking/httpd.c27
-rw-r--r--networking/httpd_index_cgi_example55
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
45static char const *human_time(time_t t) 45static 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 '/'
13test "${QUERY_STRING:0:1}" = "/" || exit 1
14# /../ is not allowed
15test "${QUERY_STRING%/../*}" = "$QUERY_STRING" || exit 1
16test "${QUERY_STRING%/..}" = "$QUERY_STRING" || exit 1
17
18# Outta cgi-bin...
19cd .. 2>/dev/null || exit 1
20# Strip leading '/', go to target dir
21cd "${QUERY_STRING:1}" 2>/dev/null || exit 1
22
23f=`dirname "$QUERY_STRING"`
24test "$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{
30printf "%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
41IFS='#'
42for 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// /&nbsp;}" # 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 }
53done
54printf "</table></pre><hr></body></html>"$'\r\n'
55} | dd bs=4k