Fossil SCM
Split the various server implementations out of "main.c" and into a new source file "server.c". This is groundwork for adding SCGI and FastCGI.
Commit
bc20a30f4982d827b8a5210a27a6f76a27f3b3af
Parent
75e042503bfe901…
7 files changed
+2
-545
+11
-1
+1
+567
+10
-4
+12
+10
+2
-545
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -21,18 +21,11 @@ | ||
| 21 | 21 | #include "config.h" |
| 22 | 22 | #include "main.h" |
| 23 | 23 | #include <string.h> |
| 24 | 24 | #include <time.h> |
| 25 | 25 | #include <fcntl.h> |
| 26 | -#include <sys/types.h> | |
| 27 | -#include <sys/stat.h> | |
| 28 | 26 | #include <stdlib.h> /* atexit() */ |
| 29 | -#if defined(_WIN32) | |
| 30 | -# include <windows.h> | |
| 31 | -#else | |
| 32 | -# include <errno.h> /* errno global */ | |
| 33 | -#endif | |
| 34 | 27 | #include "zlib.h" |
| 35 | 28 | #ifdef FOSSIL_ENABLE_SSL |
| 36 | 29 | # include "openssl/opensslv.h" |
| 37 | 30 | #endif |
| 38 | 31 | #if INTERFACE |
| @@ -1023,11 +1016,11 @@ | ||
| 1023 | 1016 | ** The g.zBaseURL is normally set based on HTTP_HOST and SCRIPT_NAME |
| 1024 | 1017 | ** environment variables. However, if zAltBase is not NULL then it |
| 1025 | 1018 | ** is the argument to the --baseurl option command-line option and |
| 1026 | 1019 | ** g.zBaseURL and g.zTop is set from that instead. |
| 1027 | 1020 | */ |
| 1028 | -static void set_base_url(const char *zAltBase){ | |
| 1021 | +void set_base_url(const char *zAltBase){ | |
| 1029 | 1022 | int i; |
| 1030 | 1023 | const char *zHost; |
| 1031 | 1024 | const char *zMode; |
| 1032 | 1025 | const char *zCur; |
| 1033 | 1026 | |
| @@ -1085,65 +1078,10 @@ | ||
| 1085 | 1078 | */ |
| 1086 | 1079 | NORETURN void fossil_redirect_home(void){ |
| 1087 | 1080 | cgi_redirectf("%s%s", g.zTop, db_get("index-page", "/index")); |
| 1088 | 1081 | } |
| 1089 | 1082 | |
| 1090 | -/* | |
| 1091 | -** If running as root, chroot to the directory containing the | |
| 1092 | -** repository zRepo and then drop root privileges. Return the | |
| 1093 | -** new repository name. | |
| 1094 | -** | |
| 1095 | -** zRepo might be a directory itself. In that case chroot into | |
| 1096 | -** the directory zRepo. | |
| 1097 | -** | |
| 1098 | -** Assume the user-id and group-id of the repository, or if zRepo | |
| 1099 | -** is a directory, of that directory. | |
| 1100 | -*/ | |
| 1101 | -static char *enter_chroot_jail(char *zRepo){ | |
| 1102 | -#if !defined(_WIN32) | |
| 1103 | - if( getuid()==0 ){ | |
| 1104 | - int i; | |
| 1105 | - struct stat sStat; | |
| 1106 | - Blob dir; | |
| 1107 | - char *zDir; | |
| 1108 | - | |
| 1109 | - file_canonical_name(zRepo, &dir, 0); | |
| 1110 | - zDir = blob_str(&dir); | |
| 1111 | - if( file_isdir(zDir)==1 ){ | |
| 1112 | - if( file_chdir(zDir, 1) ){ | |
| 1113 | - fossil_fatal("unable to chroot into %s", zDir); | |
| 1114 | - } | |
| 1115 | - zRepo = "/"; | |
| 1116 | - }else{ | |
| 1117 | - for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){} | |
| 1118 | - if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo); | |
| 1119 | - if( i>0 ){ | |
| 1120 | - zDir[i] = 0; | |
| 1121 | - if( file_chdir(zDir, 1) ){ | |
| 1122 | - fossil_fatal("unable to chroot into %s", zDir); | |
| 1123 | - } | |
| 1124 | - zDir[i] = '/'; | |
| 1125 | - } | |
| 1126 | - zRepo = &zDir[i]; | |
| 1127 | - } | |
| 1128 | - if( stat(zRepo, &sStat)!=0 ){ | |
| 1129 | - fossil_fatal("cannot stat() repository: %s", zRepo); | |
| 1130 | - } | |
| 1131 | - i = setgid(sStat.st_gid); | |
| 1132 | - i = i || setuid(sStat.st_uid); | |
| 1133 | - if(i){ | |
| 1134 | - fossil_fatal("setgid/uid() failed with errno %d", errno); | |
| 1135 | - } | |
| 1136 | - if( g.db!=0 ){ | |
| 1137 | - db_close(1); | |
| 1138 | - db_open_repository(zRepo); | |
| 1139 | - } | |
| 1140 | - } | |
| 1141 | -#endif | |
| 1142 | - return zRepo; | |
| 1143 | -} | |
| 1144 | - | |
| 1145 | 1083 | /* |
| 1146 | 1084 | ** Preconditions: |
| 1147 | 1085 | ** |
| 1148 | 1086 | ** * Environment variables are set up according to the CGI standard. |
| 1149 | 1087 | ** |
| @@ -1162,11 +1100,11 @@ | ||
| 1162 | 1100 | ** $prefix can be determined from its suffix, then the file $prefix is |
| 1163 | 1101 | ** returned as static text. |
| 1164 | 1102 | ** |
| 1165 | 1103 | ** If no suitable webpage is found, try to redirect to zNotFound. |
| 1166 | 1104 | */ |
| 1167 | -static void process_one_web_page(const char *zNotFound, Glob *pFileGlob){ | |
| 1105 | +void process_one_web_page(const char *zNotFound, Glob *pFileGlob){ | |
| 1168 | 1106 | const char *zPathInfo; |
| 1169 | 1107 | char *zPath = NULL; |
| 1170 | 1108 | int idx; |
| 1171 | 1109 | int i; |
| 1172 | 1110 | |
| @@ -1407,491 +1345,10 @@ | ||
| 1407 | 1345 | /* Return the result. |
| 1408 | 1346 | */ |
| 1409 | 1347 | cgi_reply(); |
| 1410 | 1348 | } |
| 1411 | 1349 | |
| 1412 | -/* If the CGI program contains one or more lines of the form | |
| 1413 | -** | |
| 1414 | -** redirect: repository-filename http://hostname/path/%s | |
| 1415 | -** | |
| 1416 | -** then control jumps here. Search each repository for an artifact ID | |
| 1417 | -** that matches the "name" CGI parameter and for the first match, | |
| 1418 | -** redirect to the corresponding URL with the "name" CGI parameter | |
| 1419 | -** inserted. Paint an error page if no match is found. | |
| 1420 | -** | |
| 1421 | -** If there is a line of the form: | |
| 1422 | -** | |
| 1423 | -** redirect: * URL | |
| 1424 | -** | |
| 1425 | -** Then a redirect is made to URL if no match is found. Otherwise a | |
| 1426 | -** very primitive error message is returned. | |
| 1427 | -*/ | |
| 1428 | -static void redirect_web_page(int nRedirect, char **azRedirect){ | |
| 1429 | - int i; /* Loop counter */ | |
| 1430 | - const char *zNotFound = 0; /* Not found URL */ | |
| 1431 | - const char *zName = P("name"); | |
| 1432 | - set_base_url(0); | |
| 1433 | - if( zName==0 ){ | |
| 1434 | - zName = P("SCRIPT_NAME"); | |
| 1435 | - if( zName && zName[0]=='/' ) zName++; | |
| 1436 | - } | |
| 1437 | - if( zName && validate16(zName, strlen(zName)) ){ | |
| 1438 | - for(i=0; i<nRedirect; i++){ | |
| 1439 | - if( fossil_strcmp(azRedirect[i*2],"*")==0 ){ | |
| 1440 | - zNotFound = azRedirect[i*2+1]; | |
| 1441 | - continue; | |
| 1442 | - } | |
| 1443 | - db_open_repository(azRedirect[i*2]); | |
| 1444 | - if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){ | |
| 1445 | - cgi_redirectf(azRedirect[i*2+1], zName); | |
| 1446 | - return; | |
| 1447 | - } | |
| 1448 | - db_close(1); | |
| 1449 | - } | |
| 1450 | - } | |
| 1451 | - if( zNotFound ){ | |
| 1452 | - cgi_redirectf(zNotFound, zName); | |
| 1453 | - }else{ | |
| 1454 | - @ <html> | |
| 1455 | - @ <head><title>No Such Object</title></head> | |
| 1456 | - @ <body> | |
| 1457 | - @ <p>No such object: <b>%h(zName)</b></p> | |
| 1458 | - @ </body> | |
| 1459 | - cgi_reply(); | |
| 1460 | - } | |
| 1461 | -} | |
| 1462 | - | |
| 1463 | -/* | |
| 1464 | -** COMMAND: cgi* | |
| 1465 | -** | |
| 1466 | -** Usage: %fossil ?cgi? SCRIPT | |
| 1467 | -** | |
| 1468 | -** The SCRIPT argument is the name of a file that is the CGI script | |
| 1469 | -** that is being run. The command name, "cgi", may be omitted if | |
| 1470 | -** the GATEWAY_INTERFACE environment variable is set to "CGI" (which | |
| 1471 | -** should always be the case for CGI scripts run by a webserver.) The | |
| 1472 | -** SCRIPT file should look something like this: | |
| 1473 | -** | |
| 1474 | -** #!/usr/bin/fossil | |
| 1475 | -** repository: /home/somebody/project.db | |
| 1476 | -** | |
| 1477 | -** The second line defines the name of the repository. After locating | |
| 1478 | -** the repository, fossil will generate a webpage on stdout based on | |
| 1479 | -** the values of standard CGI environment variables. | |
| 1480 | -** | |
| 1481 | -** See also: http, server, winsrv | |
| 1482 | -*/ | |
| 1483 | -void cmd_cgi(void){ | |
| 1484 | - const char *zFile; | |
| 1485 | - const char *zNotFound = 0; | |
| 1486 | - char **azRedirect = 0; /* List of repositories to redirect to */ | |
| 1487 | - int nRedirect = 0; /* Number of entries in azRedirect */ | |
| 1488 | - Glob *pFileGlob = 0; /* Pattern for files */ | |
| 1489 | - Blob config, line, key, value, value2; | |
| 1490 | - if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ | |
| 1491 | - zFile = g.argv[2]; | |
| 1492 | - }else{ | |
| 1493 | - zFile = g.argv[1]; | |
| 1494 | - } | |
| 1495 | - g.httpOut = stdout; | |
| 1496 | - g.httpIn = stdin; | |
| 1497 | - fossil_binary_mode(g.httpOut); | |
| 1498 | - fossil_binary_mode(g.httpIn); | |
| 1499 | - g.cgiOutput = 1; | |
| 1500 | - blob_read_from_file(&config, zFile); | |
| 1501 | - while( blob_line(&config, &line) ){ | |
| 1502 | - if( !blob_token(&line, &key) ) continue; | |
| 1503 | - if( blob_buffer(&key)[0]=='#' ) continue; | |
| 1504 | - if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ | |
| 1505 | - g.fDebug = fossil_fopen(blob_str(&value), "ab"); | |
| 1506 | - blob_reset(&value); | |
| 1507 | - continue; | |
| 1508 | - } | |
| 1509 | - if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){ | |
| 1510 | - cgi_setenv("HOME", blob_str(&value)); | |
| 1511 | - blob_reset(&value); | |
| 1512 | - continue; | |
| 1513 | - } | |
| 1514 | - if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){ | |
| 1515 | - blob_trim(&value); | |
| 1516 | - db_open_repository(blob_str(&value)); | |
| 1517 | - blob_reset(&value); | |
| 1518 | - continue; | |
| 1519 | - } | |
| 1520 | - if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){ | |
| 1521 | - db_close(1); | |
| 1522 | - g.zRepositoryName = mprintf("%s", blob_str(&value)); | |
| 1523 | - blob_reset(&value); | |
| 1524 | - continue; | |
| 1525 | - } | |
| 1526 | - if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){ | |
| 1527 | - zNotFound = mprintf("%s", blob_str(&value)); | |
| 1528 | - blob_reset(&value); | |
| 1529 | - continue; | |
| 1530 | - } | |
| 1531 | - if( blob_eq(&key, "localauth") ){ | |
| 1532 | - g.useLocalauth = 1; | |
| 1533 | - continue; | |
| 1534 | - } | |
| 1535 | - if( blob_eq(&key, "redirect:") && blob_token(&line, &value) | |
| 1536 | - && blob_token(&line, &value2) ){ | |
| 1537 | - nRedirect++; | |
| 1538 | - azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*)); | |
| 1539 | - azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value)); | |
| 1540 | - azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2)); | |
| 1541 | - blob_reset(&value); | |
| 1542 | - blob_reset(&value2); | |
| 1543 | - continue; | |
| 1544 | - } | |
| 1545 | - if( blob_eq(&key, "files:") && blob_token(&line, &value) ){ | |
| 1546 | - pFileGlob = glob_create(blob_str(&value)); | |
| 1547 | - continue; | |
| 1548 | - } | |
| 1549 | - } | |
| 1550 | - blob_reset(&config); | |
| 1551 | - if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){ | |
| 1552 | - cgi_panic("Unable to find or open the project repository"); | |
| 1553 | - } | |
| 1554 | - cgi_init(); | |
| 1555 | - if( nRedirect ){ | |
| 1556 | - redirect_web_page(nRedirect, azRedirect); | |
| 1557 | - }else{ | |
| 1558 | - process_one_web_page(zNotFound, pFileGlob); | |
| 1559 | - } | |
| 1560 | -} | |
| 1561 | - | |
| 1562 | -/* | |
| 1563 | -** If g.argv[2] exists then it is either the name of a repository | |
| 1564 | -** that will be used by a server, or else it is a directory that | |
| 1565 | -** contains multiple repositories that can be served. If g.argv[2] | |
| 1566 | -** is a directory, the repositories it contains must be named | |
| 1567 | -** "*.fossil". If g.argv[2] does not exists, then we must be within | |
| 1568 | -** a check-out and the repository to be served is the repository of | |
| 1569 | -** that check-out. | |
| 1570 | -** | |
| 1571 | -** Open the repository to be served if it is known. If g.argv[2] is | |
| 1572 | -** a directory full of repositories, then set g.zRepositoryName to | |
| 1573 | -** the name of that directory and the specific repository will be | |
| 1574 | -** opened later by process_one_web_page() based on the content of | |
| 1575 | -** the PATH_INFO variable. | |
| 1576 | -** | |
| 1577 | -** If disallowDir is set, then the directory full of repositories method | |
| 1578 | -** is disallowed. | |
| 1579 | -*/ | |
| 1580 | -static void find_server_repository(int disallowDir){ | |
| 1581 | - if( g.argc<3 ){ | |
| 1582 | - db_must_be_within_tree(); | |
| 1583 | - }else if( file_isdir(g.argv[2])==1 ){ | |
| 1584 | - if( disallowDir ){ | |
| 1585 | - fossil_fatal("\"%s\" is a directory, not a repository file", g.argv[2]); | |
| 1586 | - }else{ | |
| 1587 | - g.zRepositoryName = mprintf("%s", g.argv[2]); | |
| 1588 | - file_simplify_name(g.zRepositoryName, -1, 0); | |
| 1589 | - } | |
| 1590 | - }else{ | |
| 1591 | - db_open_repository(g.argv[2]); | |
| 1592 | - } | |
| 1593 | -} | |
| 1594 | - | |
| 1595 | -/* | |
| 1596 | -** undocumented format: | |
| 1597 | -** | |
| 1598 | -** fossil http REPOSITORY INFILE OUTFILE IPADDR | |
| 1599 | -** | |
| 1600 | -** The argv==6 form is used by the win32 server only. | |
| 1601 | -** | |
| 1602 | -** COMMAND: http* | |
| 1603 | -** | |
| 1604 | -** Usage: %fossil http REPOSITORY ?OPTIONS? | |
| 1605 | -** | |
| 1606 | -** Handle a single HTTP request appearing on stdin. The resulting webpage | |
| 1607 | -** is delivered on stdout. This method is used to launch an HTTP request | |
| 1608 | -** handler from inetd, for example. The argument is the name of the | |
| 1609 | -** repository. | |
| 1610 | -** | |
| 1611 | -** If REPOSITORY is a directory that contains one or more repositories, | |
| 1612 | -** either directly in REPOSITORY itself, or in subdirectories, and | |
| 1613 | -** with names of the form "*.fossil" then the a prefix of the URL pathname | |
| 1614 | -** selects from among the various repositories. If the pathname does | |
| 1615 | -** not select a valid repository and the --notfound option is available, | |
| 1616 | -** then the server redirects (HTTP code 302) to the URL of --notfound. | |
| 1617 | -** When REPOSITORY is a directory, the pathname must contain only | |
| 1618 | -** alphanumerics, "_", "/", "-" and "." and no "-" may occur after a "/" | |
| 1619 | -** and every "." must be surrounded on both sides by alphanumerics or else | |
| 1620 | -** a 404 error is returned. Static content files in the directory are | |
| 1621 | -** returned if they match comma-separate GLOB pattern specified by --files | |
| 1622 | -** and do not match "*.fossil*" and have a well-known suffix. | |
| 1623 | -** | |
| 1624 | -** The --host option can be used to specify the hostname for the server. | |
| 1625 | -** The --https option indicates that the request came from HTTPS rather | |
| 1626 | -** than HTTP. If --nossl is given, then SSL connections will not be available, | |
| 1627 | -** thus also no redirecting from http: to https: will take place. | |
| 1628 | -** | |
| 1629 | -** If the --localauth option is given, then automatic login is performed | |
| 1630 | -** for requests coming from localhost, if the "localauth" setting is not | |
| 1631 | -** enabled. | |
| 1632 | -** | |
| 1633 | -** Options: | |
| 1634 | -** --localauth enable automatic login for local connections | |
| 1635 | -** --host NAME specify hostname of the server | |
| 1636 | -** --https signal a request coming in via https | |
| 1637 | -** --nossl signal that no SSL connections are available | |
| 1638 | -** --notfound URL use URL as "HTTP 404, object not found" page. | |
| 1639 | -** --files GLOB comma-separate glob patterns for static file to serve | |
| 1640 | -** --baseurl URL base URL (useful with reverse proxies) | |
| 1641 | -** | |
| 1642 | -** See also: cgi, server, winsrv | |
| 1643 | -*/ | |
| 1644 | -void cmd_http(void){ | |
| 1645 | - const char *zIpAddr; | |
| 1646 | - const char *zNotFound; | |
| 1647 | - const char *zHost; | |
| 1648 | - const char *zAltBase; | |
| 1649 | - const char *zFileGlob; | |
| 1650 | - | |
| 1651 | - /* The winhttp module passes the --files option as --files-urlenc with | |
| 1652 | - ** the argument being URL encoded, to avoid wildcard expansion in the | |
| 1653 | - ** shell. This option is for internal use and is undocumented. | |
| 1654 | - */ | |
| 1655 | - zFileGlob = find_option("files-urlenc",0,1); | |
| 1656 | - if( zFileGlob ){ | |
| 1657 | - char *z = mprintf("%s", zFileGlob); | |
| 1658 | - dehttpize(z); | |
| 1659 | - zFileGlob = z; | |
| 1660 | - }else{ | |
| 1661 | - zFileGlob = find_option("files",0,1); | |
| 1662 | - } | |
| 1663 | - zNotFound = find_option("notfound", 0, 1); | |
| 1664 | - g.useLocalauth = find_option("localauth", 0, 0)!=0; | |
| 1665 | - g.sslNotAvailable = find_option("nossl", 0, 0)!=0; | |
| 1666 | - zAltBase = find_option("baseurl", 0, 1); | |
| 1667 | - if( zAltBase ) set_base_url(zAltBase); | |
| 1668 | - if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on"); | |
| 1669 | - zHost = find_option("host", 0, 1); | |
| 1670 | - if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost); | |
| 1671 | - g.cgiOutput = 1; | |
| 1672 | - if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ | |
| 1673 | - fossil_fatal("no repository specified"); | |
| 1674 | - } | |
| 1675 | - g.fullHttpReply = 1; | |
| 1676 | - if( g.argc==6 ){ | |
| 1677 | - g.httpIn = fossil_fopen(g.argv[3], "rb"); | |
| 1678 | - g.httpOut = fossil_fopen(g.argv[4], "wb"); | |
| 1679 | - zIpAddr = g.argv[5]; | |
| 1680 | - }else{ | |
| 1681 | - g.httpIn = stdin; | |
| 1682 | - g.httpOut = stdout; | |
| 1683 | - zIpAddr = 0; | |
| 1684 | - } | |
| 1685 | - find_server_repository(0); | |
| 1686 | - g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); | |
| 1687 | - cgi_handle_http_request(zIpAddr); | |
| 1688 | - process_one_web_page(zNotFound, glob_create(zFileGlob)); | |
| 1689 | -} | |
| 1690 | - | |
| 1691 | -/* | |
| 1692 | -** Note that the following command is used by ssh:// processing. | |
| 1693 | -** | |
| 1694 | -** COMMAND: test-http | |
| 1695 | -** Works like the http command but gives setup permission to all users. | |
| 1696 | -*/ | |
| 1697 | -void cmd_test_http(void){ | |
| 1698 | - Th_InitTraceLog(); | |
| 1699 | - login_set_capabilities("sx", 0); | |
| 1700 | - g.useLocalauth = 1; | |
| 1701 | - cgi_set_parameter("REMOTE_ADDR", "127.0.0.1"); | |
| 1702 | - g.httpIn = stdin; | |
| 1703 | - g.httpOut = stdout; | |
| 1704 | - find_server_repository(0); | |
| 1705 | - g.cgiOutput = 1; | |
| 1706 | - g.fullHttpReply = 1; | |
| 1707 | - cgi_handle_http_request(0); | |
| 1708 | - process_one_web_page(0, 0); | |
| 1709 | -} | |
| 1710 | - | |
| 1711 | -#if !defined(_WIN32) | |
| 1712 | -#if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) | |
| 1713 | -/* | |
| 1714 | -** Search for an executable on the PATH environment variable. | |
| 1715 | -** Return true (1) if found and false (0) if not found. | |
| 1716 | -*/ | |
| 1717 | -static int binaryOnPath(const char *zBinary){ | |
| 1718 | - const char *zPath = fossil_getenv("PATH"); | |
| 1719 | - char *zFull; | |
| 1720 | - int i; | |
| 1721 | - int bExists; | |
| 1722 | - while( zPath && zPath[0] ){ | |
| 1723 | - while( zPath[0]==':' ) zPath++; | |
| 1724 | - for(i=0; zPath[i] && zPath[i]!=':'; i++){} | |
| 1725 | - zFull = mprintf("%.*s/%s", i, zPath, zBinary); | |
| 1726 | - bExists = file_access(zFull, X_OK); | |
| 1727 | - fossil_free(zFull); | |
| 1728 | - if( bExists==0 ) return 1; | |
| 1729 | - zPath += i; | |
| 1730 | - } | |
| 1731 | - return 0; | |
| 1732 | -} | |
| 1733 | -#endif | |
| 1734 | -#endif | |
| 1735 | - | |
| 1736 | -/* | |
| 1737 | -** COMMAND: server* | |
| 1738 | -** COMMAND: ui | |
| 1739 | -** | |
| 1740 | -** Usage: %fossil server ?OPTIONS? ?REPOSITORY? | |
| 1741 | -** Or: %fossil ui ?OPTIONS? ?REPOSITORY? | |
| 1742 | -** | |
| 1743 | -** Open a socket and begin listening and responding to HTTP requests on | |
| 1744 | -** TCP port 8080, or on any other TCP port defined by the -P or | |
| 1745 | -** --port option. The optional argument is the name of the repository. | |
| 1746 | -** The repository argument may be omitted if the working directory is | |
| 1747 | -** within an open checkout. | |
| 1748 | -** | |
| 1749 | -** The "ui" command automatically starts a web browser after initializing | |
| 1750 | -** the web server. The "ui" command also binds to 127.0.0.1 and so will | |
| 1751 | -** only process HTTP traffic from the local machine. | |
| 1752 | -** | |
| 1753 | -** The REPOSITORY can be a directory (aka folder) that contains one or | |
| 1754 | -** more repositories with names ending in ".fossil". In this case, the | |
| 1755 | -** a prefix of the URL pathname is used to search the directory for an | |
| 1756 | -** appropriate repository. To thwart mischief, the pathname in the URL must | |
| 1757 | -** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may | |
| 1758 | -** occur after "/", and every "." must be surrounded on both sides by | |
| 1759 | -** alphanumerics. Any pathname that does not satisfy these constraints | |
| 1760 | -** results in a 404 error. Files in REPOSITORY that match the comma-separated | |
| 1761 | -** list of glob patterns given by --files and that have known suffixes | |
| 1762 | -** such as ".txt" or ".html" or ".jpeg" and do not match the pattern | |
| 1763 | -** "*.fossil*" will be served as static content. With the "ui" command, | |
| 1764 | -** the REPOSITORY can only be a directory if the --notfound option is | |
| 1765 | -** also present. | |
| 1766 | -** | |
| 1767 | -** By default, the "ui" command provides full administrative access without | |
| 1768 | -** having to log in. This can be disabled by setting turning off the | |
| 1769 | -** "localauth" setting. Automatic login for the "server" command is available | |
| 1770 | -** if the --localauth option is present and the "localauth" setting is off | |
| 1771 | -** and the connection is from localhost. The optional REPOSITORY argument | |
| 1772 | -** to "ui" may be a directory and will function as "server" if and only if | |
| 1773 | -** the --notfound option is used. | |
| 1774 | -** | |
| 1775 | -** Options: | |
| 1776 | -** --localauth enable automatic login for requests from localhost | |
| 1777 | -** --localhost listen on 127.0.0.1 only (always true for "ui") | |
| 1778 | -** -P|--port TCPPORT listen to request on port TCPPORT | |
| 1779 | -** --th-trace trace TH1 execution (for debugging purposes) | |
| 1780 | -** --baseurl URL Use URL as the base (useful for reverse proxies) | |
| 1781 | -** --notfound URL Redirect | |
| 1782 | -** --files GLOBLIST Comma-separated list of glob patterns for static files | |
| 1783 | -** | |
| 1784 | -** See also: cgi, http, winsrv | |
| 1785 | -*/ | |
| 1786 | -void cmd_webserver(void){ | |
| 1787 | - int iPort, mxPort; /* Range of TCP ports allowed */ | |
| 1788 | - const char *zPort; /* Value of the --port option */ | |
| 1789 | - const char *zBrowser; /* Name of web browser program */ | |
| 1790 | - char *zBrowserCmd = 0; /* Command to launch the web browser */ | |
| 1791 | - int isUiCmd; /* True if command is "ui", not "server' */ | |
| 1792 | - const char *zNotFound; /* The --notfound option or NULL */ | |
| 1793 | - int flags = 0; /* Server flags */ | |
| 1794 | - const char *zAltBase; /* Argument to the --baseurl option */ | |
| 1795 | - const char *zFileGlob; /* Static content must match this */ | |
| 1796 | - char *zIpAddr = 0; /* Bind to this IP address */ | |
| 1797 | - | |
| 1798 | -#if defined(_WIN32) | |
| 1799 | - const char *zStopperFile; /* Name of file used to terminate server */ | |
| 1800 | - zStopperFile = find_option("stopper", 0, 1); | |
| 1801 | -#endif | |
| 1802 | - | |
| 1803 | - zFileGlob = find_option("files", 0, 1); | |
| 1804 | - g.useLocalauth = find_option("localauth", 0, 0)!=0; | |
| 1805 | - Th_InitTraceLog(); | |
| 1806 | - zPort = find_option("port", "P", 1); | |
| 1807 | - zNotFound = find_option("notfound", 0, 1); | |
| 1808 | - zAltBase = find_option("baseurl", 0, 1); | |
| 1809 | - if( zAltBase ){ | |
| 1810 | - set_base_url(zAltBase); | |
| 1811 | - } | |
| 1812 | - if ( find_option("localhost", 0, 0)!=0 ){ | |
| 1813 | - flags |= HTTP_SERVER_LOCALHOST; | |
| 1814 | - } | |
| 1815 | - if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); | |
| 1816 | - isUiCmd = g.argv[1][0]=='u'; | |
| 1817 | - if( isUiCmd ){ | |
| 1818 | - flags |= HTTP_SERVER_LOCALHOST; | |
| 1819 | - g.useLocalauth = 1; | |
| 1820 | - } | |
| 1821 | - find_server_repository(isUiCmd && zNotFound==0); | |
| 1822 | - if( zPort ){ | |
| 1823 | - int i; | |
| 1824 | - for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} | |
| 1825 | - if( i>0 ){ | |
| 1826 | - zIpAddr = mprintf("%.*s", i, zPort); | |
| 1827 | - zPort += i+1; | |
| 1828 | - } | |
| 1829 | - iPort = mxPort = atoi(zPort); | |
| 1830 | - }else{ | |
| 1831 | - iPort = db_get_int("http-port", 8080); | |
| 1832 | - mxPort = iPort+100; | |
| 1833 | - } | |
| 1834 | -#if !defined(_WIN32) | |
| 1835 | - /* Unix implementation */ | |
| 1836 | - if( isUiCmd ){ | |
| 1837 | -#if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) | |
| 1838 | - zBrowser = db_get("web-browser", 0); | |
| 1839 | - if( zBrowser==0 ){ | |
| 1840 | - static const char *const azBrowserProg[] = | |
| 1841 | - { "xdg-open", "gnome-open", "firefox", "google-chrome" }; | |
| 1842 | - int i; | |
| 1843 | - zBrowser = "echo"; | |
| 1844 | - for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ | |
| 1845 | - if( binaryOnPath(azBrowserProg[i]) ){ | |
| 1846 | - zBrowser = azBrowserProg[i]; | |
| 1847 | - break; | |
| 1848 | - } | |
| 1849 | - } | |
| 1850 | - } | |
| 1851 | -#else | |
| 1852 | - zBrowser = db_get("web-browser", "open"); | |
| 1853 | -#endif | |
| 1854 | - if( zIpAddr ){ | |
| 1855 | - zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr); | |
| 1856 | - }else{ | |
| 1857 | - zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); | |
| 1858 | - } | |
| 1859 | - } | |
| 1860 | - db_close(1); | |
| 1861 | - if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ | |
| 1862 | - fossil_fatal("unable to listen on TCP socket %d", iPort); | |
| 1863 | - } | |
| 1864 | - g.sslNotAvailable = 1; | |
| 1865 | - g.httpIn = stdin; | |
| 1866 | - g.httpOut = stdout; | |
| 1867 | - if( g.fHttpTrace || g.fSqlTrace ){ | |
| 1868 | - fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); | |
| 1869 | - } | |
| 1870 | - g.cgiOutput = 1; | |
| 1871 | - find_server_repository(isUiCmd && zNotFound==0); | |
| 1872 | - g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); | |
| 1873 | - cgi_handle_http_request(0); | |
| 1874 | - process_one_web_page(zNotFound, glob_create(zFileGlob)); | |
| 1875 | -#else | |
| 1876 | - /* Win32 implementation */ | |
| 1877 | - if( isUiCmd ){ | |
| 1878 | - zBrowser = db_get("web-browser", "start"); | |
| 1879 | - if( zIpAddr ){ | |
| 1880 | - zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr); | |
| 1881 | - }else{ | |
| 1882 | - zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); | |
| 1883 | - } | |
| 1884 | - } | |
| 1885 | - db_close(1); | |
| 1886 | - if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){ | |
| 1887 | - win32_http_server(iPort, mxPort, zBrowserCmd, | |
| 1888 | - zStopperFile, zNotFound, zFileGlob, zIpAddr, flags); | |
| 1889 | - } | |
| 1890 | -#endif | |
| 1891 | -} | |
| 1892 | - | |
| 1893 | 1350 | /* |
| 1894 | 1351 | ** COMMAND: test-echo |
| 1895 | 1352 | ** |
| 1896 | 1353 | ** Usage: %fossil test-echo [--hex] ARGS... |
| 1897 | 1354 | ** |
| 1898 | 1355 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -21,18 +21,11 @@ | |
| 21 | #include "config.h" |
| 22 | #include "main.h" |
| 23 | #include <string.h> |
| 24 | #include <time.h> |
| 25 | #include <fcntl.h> |
| 26 | #include <sys/types.h> |
| 27 | #include <sys/stat.h> |
| 28 | #include <stdlib.h> /* atexit() */ |
| 29 | #if defined(_WIN32) |
| 30 | # include <windows.h> |
| 31 | #else |
| 32 | # include <errno.h> /* errno global */ |
| 33 | #endif |
| 34 | #include "zlib.h" |
| 35 | #ifdef FOSSIL_ENABLE_SSL |
| 36 | # include "openssl/opensslv.h" |
| 37 | #endif |
| 38 | #if INTERFACE |
| @@ -1023,11 +1016,11 @@ | |
| 1023 | ** The g.zBaseURL is normally set based on HTTP_HOST and SCRIPT_NAME |
| 1024 | ** environment variables. However, if zAltBase is not NULL then it |
| 1025 | ** is the argument to the --baseurl option command-line option and |
| 1026 | ** g.zBaseURL and g.zTop is set from that instead. |
| 1027 | */ |
| 1028 | static void set_base_url(const char *zAltBase){ |
| 1029 | int i; |
| 1030 | const char *zHost; |
| 1031 | const char *zMode; |
| 1032 | const char *zCur; |
| 1033 | |
| @@ -1085,65 +1078,10 @@ | |
| 1085 | */ |
| 1086 | NORETURN void fossil_redirect_home(void){ |
| 1087 | cgi_redirectf("%s%s", g.zTop, db_get("index-page", "/index")); |
| 1088 | } |
| 1089 | |
| 1090 | /* |
| 1091 | ** If running as root, chroot to the directory containing the |
| 1092 | ** repository zRepo and then drop root privileges. Return the |
| 1093 | ** new repository name. |
| 1094 | ** |
| 1095 | ** zRepo might be a directory itself. In that case chroot into |
| 1096 | ** the directory zRepo. |
| 1097 | ** |
| 1098 | ** Assume the user-id and group-id of the repository, or if zRepo |
| 1099 | ** is a directory, of that directory. |
| 1100 | */ |
| 1101 | static char *enter_chroot_jail(char *zRepo){ |
| 1102 | #if !defined(_WIN32) |
| 1103 | if( getuid()==0 ){ |
| 1104 | int i; |
| 1105 | struct stat sStat; |
| 1106 | Blob dir; |
| 1107 | char *zDir; |
| 1108 | |
| 1109 | file_canonical_name(zRepo, &dir, 0); |
| 1110 | zDir = blob_str(&dir); |
| 1111 | if( file_isdir(zDir)==1 ){ |
| 1112 | if( file_chdir(zDir, 1) ){ |
| 1113 | fossil_fatal("unable to chroot into %s", zDir); |
| 1114 | } |
| 1115 | zRepo = "/"; |
| 1116 | }else{ |
| 1117 | for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){} |
| 1118 | if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo); |
| 1119 | if( i>0 ){ |
| 1120 | zDir[i] = 0; |
| 1121 | if( file_chdir(zDir, 1) ){ |
| 1122 | fossil_fatal("unable to chroot into %s", zDir); |
| 1123 | } |
| 1124 | zDir[i] = '/'; |
| 1125 | } |
| 1126 | zRepo = &zDir[i]; |
| 1127 | } |
| 1128 | if( stat(zRepo, &sStat)!=0 ){ |
| 1129 | fossil_fatal("cannot stat() repository: %s", zRepo); |
| 1130 | } |
| 1131 | i = setgid(sStat.st_gid); |
| 1132 | i = i || setuid(sStat.st_uid); |
| 1133 | if(i){ |
| 1134 | fossil_fatal("setgid/uid() failed with errno %d", errno); |
| 1135 | } |
| 1136 | if( g.db!=0 ){ |
| 1137 | db_close(1); |
| 1138 | db_open_repository(zRepo); |
| 1139 | } |
| 1140 | } |
| 1141 | #endif |
| 1142 | return zRepo; |
| 1143 | } |
| 1144 | |
| 1145 | /* |
| 1146 | ** Preconditions: |
| 1147 | ** |
| 1148 | ** * Environment variables are set up according to the CGI standard. |
| 1149 | ** |
| @@ -1162,11 +1100,11 @@ | |
| 1162 | ** $prefix can be determined from its suffix, then the file $prefix is |
| 1163 | ** returned as static text. |
| 1164 | ** |
| 1165 | ** If no suitable webpage is found, try to redirect to zNotFound. |
| 1166 | */ |
| 1167 | static void process_one_web_page(const char *zNotFound, Glob *pFileGlob){ |
| 1168 | const char *zPathInfo; |
| 1169 | char *zPath = NULL; |
| 1170 | int idx; |
| 1171 | int i; |
| 1172 | |
| @@ -1407,491 +1345,10 @@ | |
| 1407 | /* Return the result. |
| 1408 | */ |
| 1409 | cgi_reply(); |
| 1410 | } |
| 1411 | |
| 1412 | /* If the CGI program contains one or more lines of the form |
| 1413 | ** |
| 1414 | ** redirect: repository-filename http://hostname/path/%s |
| 1415 | ** |
| 1416 | ** then control jumps here. Search each repository for an artifact ID |
| 1417 | ** that matches the "name" CGI parameter and for the first match, |
| 1418 | ** redirect to the corresponding URL with the "name" CGI parameter |
| 1419 | ** inserted. Paint an error page if no match is found. |
| 1420 | ** |
| 1421 | ** If there is a line of the form: |
| 1422 | ** |
| 1423 | ** redirect: * URL |
| 1424 | ** |
| 1425 | ** Then a redirect is made to URL if no match is found. Otherwise a |
| 1426 | ** very primitive error message is returned. |
| 1427 | */ |
| 1428 | static void redirect_web_page(int nRedirect, char **azRedirect){ |
| 1429 | int i; /* Loop counter */ |
| 1430 | const char *zNotFound = 0; /* Not found URL */ |
| 1431 | const char *zName = P("name"); |
| 1432 | set_base_url(0); |
| 1433 | if( zName==0 ){ |
| 1434 | zName = P("SCRIPT_NAME"); |
| 1435 | if( zName && zName[0]=='/' ) zName++; |
| 1436 | } |
| 1437 | if( zName && validate16(zName, strlen(zName)) ){ |
| 1438 | for(i=0; i<nRedirect; i++){ |
| 1439 | if( fossil_strcmp(azRedirect[i*2],"*")==0 ){ |
| 1440 | zNotFound = azRedirect[i*2+1]; |
| 1441 | continue; |
| 1442 | } |
| 1443 | db_open_repository(azRedirect[i*2]); |
| 1444 | if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){ |
| 1445 | cgi_redirectf(azRedirect[i*2+1], zName); |
| 1446 | return; |
| 1447 | } |
| 1448 | db_close(1); |
| 1449 | } |
| 1450 | } |
| 1451 | if( zNotFound ){ |
| 1452 | cgi_redirectf(zNotFound, zName); |
| 1453 | }else{ |
| 1454 | @ <html> |
| 1455 | @ <head><title>No Such Object</title></head> |
| 1456 | @ <body> |
| 1457 | @ <p>No such object: <b>%h(zName)</b></p> |
| 1458 | @ </body> |
| 1459 | cgi_reply(); |
| 1460 | } |
| 1461 | } |
| 1462 | |
| 1463 | /* |
| 1464 | ** COMMAND: cgi* |
| 1465 | ** |
| 1466 | ** Usage: %fossil ?cgi? SCRIPT |
| 1467 | ** |
| 1468 | ** The SCRIPT argument is the name of a file that is the CGI script |
| 1469 | ** that is being run. The command name, "cgi", may be omitted if |
| 1470 | ** the GATEWAY_INTERFACE environment variable is set to "CGI" (which |
| 1471 | ** should always be the case for CGI scripts run by a webserver.) The |
| 1472 | ** SCRIPT file should look something like this: |
| 1473 | ** |
| 1474 | ** #!/usr/bin/fossil |
| 1475 | ** repository: /home/somebody/project.db |
| 1476 | ** |
| 1477 | ** The second line defines the name of the repository. After locating |
| 1478 | ** the repository, fossil will generate a webpage on stdout based on |
| 1479 | ** the values of standard CGI environment variables. |
| 1480 | ** |
| 1481 | ** See also: http, server, winsrv |
| 1482 | */ |
| 1483 | void cmd_cgi(void){ |
| 1484 | const char *zFile; |
| 1485 | const char *zNotFound = 0; |
| 1486 | char **azRedirect = 0; /* List of repositories to redirect to */ |
| 1487 | int nRedirect = 0; /* Number of entries in azRedirect */ |
| 1488 | Glob *pFileGlob = 0; /* Pattern for files */ |
| 1489 | Blob config, line, key, value, value2; |
| 1490 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 1491 | zFile = g.argv[2]; |
| 1492 | }else{ |
| 1493 | zFile = g.argv[1]; |
| 1494 | } |
| 1495 | g.httpOut = stdout; |
| 1496 | g.httpIn = stdin; |
| 1497 | fossil_binary_mode(g.httpOut); |
| 1498 | fossil_binary_mode(g.httpIn); |
| 1499 | g.cgiOutput = 1; |
| 1500 | blob_read_from_file(&config, zFile); |
| 1501 | while( blob_line(&config, &line) ){ |
| 1502 | if( !blob_token(&line, &key) ) continue; |
| 1503 | if( blob_buffer(&key)[0]=='#' ) continue; |
| 1504 | if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ |
| 1505 | g.fDebug = fossil_fopen(blob_str(&value), "ab"); |
| 1506 | blob_reset(&value); |
| 1507 | continue; |
| 1508 | } |
| 1509 | if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){ |
| 1510 | cgi_setenv("HOME", blob_str(&value)); |
| 1511 | blob_reset(&value); |
| 1512 | continue; |
| 1513 | } |
| 1514 | if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){ |
| 1515 | blob_trim(&value); |
| 1516 | db_open_repository(blob_str(&value)); |
| 1517 | blob_reset(&value); |
| 1518 | continue; |
| 1519 | } |
| 1520 | if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){ |
| 1521 | db_close(1); |
| 1522 | g.zRepositoryName = mprintf("%s", blob_str(&value)); |
| 1523 | blob_reset(&value); |
| 1524 | continue; |
| 1525 | } |
| 1526 | if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){ |
| 1527 | zNotFound = mprintf("%s", blob_str(&value)); |
| 1528 | blob_reset(&value); |
| 1529 | continue; |
| 1530 | } |
| 1531 | if( blob_eq(&key, "localauth") ){ |
| 1532 | g.useLocalauth = 1; |
| 1533 | continue; |
| 1534 | } |
| 1535 | if( blob_eq(&key, "redirect:") && blob_token(&line, &value) |
| 1536 | && blob_token(&line, &value2) ){ |
| 1537 | nRedirect++; |
| 1538 | azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*)); |
| 1539 | azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value)); |
| 1540 | azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2)); |
| 1541 | blob_reset(&value); |
| 1542 | blob_reset(&value2); |
| 1543 | continue; |
| 1544 | } |
| 1545 | if( blob_eq(&key, "files:") && blob_token(&line, &value) ){ |
| 1546 | pFileGlob = glob_create(blob_str(&value)); |
| 1547 | continue; |
| 1548 | } |
| 1549 | } |
| 1550 | blob_reset(&config); |
| 1551 | if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){ |
| 1552 | cgi_panic("Unable to find or open the project repository"); |
| 1553 | } |
| 1554 | cgi_init(); |
| 1555 | if( nRedirect ){ |
| 1556 | redirect_web_page(nRedirect, azRedirect); |
| 1557 | }else{ |
| 1558 | process_one_web_page(zNotFound, pFileGlob); |
| 1559 | } |
| 1560 | } |
| 1561 | |
| 1562 | /* |
| 1563 | ** If g.argv[2] exists then it is either the name of a repository |
| 1564 | ** that will be used by a server, or else it is a directory that |
| 1565 | ** contains multiple repositories that can be served. If g.argv[2] |
| 1566 | ** is a directory, the repositories it contains must be named |
| 1567 | ** "*.fossil". If g.argv[2] does not exists, then we must be within |
| 1568 | ** a check-out and the repository to be served is the repository of |
| 1569 | ** that check-out. |
| 1570 | ** |
| 1571 | ** Open the repository to be served if it is known. If g.argv[2] is |
| 1572 | ** a directory full of repositories, then set g.zRepositoryName to |
| 1573 | ** the name of that directory and the specific repository will be |
| 1574 | ** opened later by process_one_web_page() based on the content of |
| 1575 | ** the PATH_INFO variable. |
| 1576 | ** |
| 1577 | ** If disallowDir is set, then the directory full of repositories method |
| 1578 | ** is disallowed. |
| 1579 | */ |
| 1580 | static void find_server_repository(int disallowDir){ |
| 1581 | if( g.argc<3 ){ |
| 1582 | db_must_be_within_tree(); |
| 1583 | }else if( file_isdir(g.argv[2])==1 ){ |
| 1584 | if( disallowDir ){ |
| 1585 | fossil_fatal("\"%s\" is a directory, not a repository file", g.argv[2]); |
| 1586 | }else{ |
| 1587 | g.zRepositoryName = mprintf("%s", g.argv[2]); |
| 1588 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 1589 | } |
| 1590 | }else{ |
| 1591 | db_open_repository(g.argv[2]); |
| 1592 | } |
| 1593 | } |
| 1594 | |
| 1595 | /* |
| 1596 | ** undocumented format: |
| 1597 | ** |
| 1598 | ** fossil http REPOSITORY INFILE OUTFILE IPADDR |
| 1599 | ** |
| 1600 | ** The argv==6 form is used by the win32 server only. |
| 1601 | ** |
| 1602 | ** COMMAND: http* |
| 1603 | ** |
| 1604 | ** Usage: %fossil http REPOSITORY ?OPTIONS? |
| 1605 | ** |
| 1606 | ** Handle a single HTTP request appearing on stdin. The resulting webpage |
| 1607 | ** is delivered on stdout. This method is used to launch an HTTP request |
| 1608 | ** handler from inetd, for example. The argument is the name of the |
| 1609 | ** repository. |
| 1610 | ** |
| 1611 | ** If REPOSITORY is a directory that contains one or more repositories, |
| 1612 | ** either directly in REPOSITORY itself, or in subdirectories, and |
| 1613 | ** with names of the form "*.fossil" then the a prefix of the URL pathname |
| 1614 | ** selects from among the various repositories. If the pathname does |
| 1615 | ** not select a valid repository and the --notfound option is available, |
| 1616 | ** then the server redirects (HTTP code 302) to the URL of --notfound. |
| 1617 | ** When REPOSITORY is a directory, the pathname must contain only |
| 1618 | ** alphanumerics, "_", "/", "-" and "." and no "-" may occur after a "/" |
| 1619 | ** and every "." must be surrounded on both sides by alphanumerics or else |
| 1620 | ** a 404 error is returned. Static content files in the directory are |
| 1621 | ** returned if they match comma-separate GLOB pattern specified by --files |
| 1622 | ** and do not match "*.fossil*" and have a well-known suffix. |
| 1623 | ** |
| 1624 | ** The --host option can be used to specify the hostname for the server. |
| 1625 | ** The --https option indicates that the request came from HTTPS rather |
| 1626 | ** than HTTP. If --nossl is given, then SSL connections will not be available, |
| 1627 | ** thus also no redirecting from http: to https: will take place. |
| 1628 | ** |
| 1629 | ** If the --localauth option is given, then automatic login is performed |
| 1630 | ** for requests coming from localhost, if the "localauth" setting is not |
| 1631 | ** enabled. |
| 1632 | ** |
| 1633 | ** Options: |
| 1634 | ** --localauth enable automatic login for local connections |
| 1635 | ** --host NAME specify hostname of the server |
| 1636 | ** --https signal a request coming in via https |
| 1637 | ** --nossl signal that no SSL connections are available |
| 1638 | ** --notfound URL use URL as "HTTP 404, object not found" page. |
| 1639 | ** --files GLOB comma-separate glob patterns for static file to serve |
| 1640 | ** --baseurl URL base URL (useful with reverse proxies) |
| 1641 | ** |
| 1642 | ** See also: cgi, server, winsrv |
| 1643 | */ |
| 1644 | void cmd_http(void){ |
| 1645 | const char *zIpAddr; |
| 1646 | const char *zNotFound; |
| 1647 | const char *zHost; |
| 1648 | const char *zAltBase; |
| 1649 | const char *zFileGlob; |
| 1650 | |
| 1651 | /* The winhttp module passes the --files option as --files-urlenc with |
| 1652 | ** the argument being URL encoded, to avoid wildcard expansion in the |
| 1653 | ** shell. This option is for internal use and is undocumented. |
| 1654 | */ |
| 1655 | zFileGlob = find_option("files-urlenc",0,1); |
| 1656 | if( zFileGlob ){ |
| 1657 | char *z = mprintf("%s", zFileGlob); |
| 1658 | dehttpize(z); |
| 1659 | zFileGlob = z; |
| 1660 | }else{ |
| 1661 | zFileGlob = find_option("files",0,1); |
| 1662 | } |
| 1663 | zNotFound = find_option("notfound", 0, 1); |
| 1664 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 1665 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0; |
| 1666 | zAltBase = find_option("baseurl", 0, 1); |
| 1667 | if( zAltBase ) set_base_url(zAltBase); |
| 1668 | if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on"); |
| 1669 | zHost = find_option("host", 0, 1); |
| 1670 | if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost); |
| 1671 | g.cgiOutput = 1; |
| 1672 | if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ |
| 1673 | fossil_fatal("no repository specified"); |
| 1674 | } |
| 1675 | g.fullHttpReply = 1; |
| 1676 | if( g.argc==6 ){ |
| 1677 | g.httpIn = fossil_fopen(g.argv[3], "rb"); |
| 1678 | g.httpOut = fossil_fopen(g.argv[4], "wb"); |
| 1679 | zIpAddr = g.argv[5]; |
| 1680 | }else{ |
| 1681 | g.httpIn = stdin; |
| 1682 | g.httpOut = stdout; |
| 1683 | zIpAddr = 0; |
| 1684 | } |
| 1685 | find_server_repository(0); |
| 1686 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); |
| 1687 | cgi_handle_http_request(zIpAddr); |
| 1688 | process_one_web_page(zNotFound, glob_create(zFileGlob)); |
| 1689 | } |
| 1690 | |
| 1691 | /* |
| 1692 | ** Note that the following command is used by ssh:// processing. |
| 1693 | ** |
| 1694 | ** COMMAND: test-http |
| 1695 | ** Works like the http command but gives setup permission to all users. |
| 1696 | */ |
| 1697 | void cmd_test_http(void){ |
| 1698 | Th_InitTraceLog(); |
| 1699 | login_set_capabilities("sx", 0); |
| 1700 | g.useLocalauth = 1; |
| 1701 | cgi_set_parameter("REMOTE_ADDR", "127.0.0.1"); |
| 1702 | g.httpIn = stdin; |
| 1703 | g.httpOut = stdout; |
| 1704 | find_server_repository(0); |
| 1705 | g.cgiOutput = 1; |
| 1706 | g.fullHttpReply = 1; |
| 1707 | cgi_handle_http_request(0); |
| 1708 | process_one_web_page(0, 0); |
| 1709 | } |
| 1710 | |
| 1711 | #if !defined(_WIN32) |
| 1712 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1713 | /* |
| 1714 | ** Search for an executable on the PATH environment variable. |
| 1715 | ** Return true (1) if found and false (0) if not found. |
| 1716 | */ |
| 1717 | static int binaryOnPath(const char *zBinary){ |
| 1718 | const char *zPath = fossil_getenv("PATH"); |
| 1719 | char *zFull; |
| 1720 | int i; |
| 1721 | int bExists; |
| 1722 | while( zPath && zPath[0] ){ |
| 1723 | while( zPath[0]==':' ) zPath++; |
| 1724 | for(i=0; zPath[i] && zPath[i]!=':'; i++){} |
| 1725 | zFull = mprintf("%.*s/%s", i, zPath, zBinary); |
| 1726 | bExists = file_access(zFull, X_OK); |
| 1727 | fossil_free(zFull); |
| 1728 | if( bExists==0 ) return 1; |
| 1729 | zPath += i; |
| 1730 | } |
| 1731 | return 0; |
| 1732 | } |
| 1733 | #endif |
| 1734 | #endif |
| 1735 | |
| 1736 | /* |
| 1737 | ** COMMAND: server* |
| 1738 | ** COMMAND: ui |
| 1739 | ** |
| 1740 | ** Usage: %fossil server ?OPTIONS? ?REPOSITORY? |
| 1741 | ** Or: %fossil ui ?OPTIONS? ?REPOSITORY? |
| 1742 | ** |
| 1743 | ** Open a socket and begin listening and responding to HTTP requests on |
| 1744 | ** TCP port 8080, or on any other TCP port defined by the -P or |
| 1745 | ** --port option. The optional argument is the name of the repository. |
| 1746 | ** The repository argument may be omitted if the working directory is |
| 1747 | ** within an open checkout. |
| 1748 | ** |
| 1749 | ** The "ui" command automatically starts a web browser after initializing |
| 1750 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 1751 | ** only process HTTP traffic from the local machine. |
| 1752 | ** |
| 1753 | ** The REPOSITORY can be a directory (aka folder) that contains one or |
| 1754 | ** more repositories with names ending in ".fossil". In this case, the |
| 1755 | ** a prefix of the URL pathname is used to search the directory for an |
| 1756 | ** appropriate repository. To thwart mischief, the pathname in the URL must |
| 1757 | ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may |
| 1758 | ** occur after "/", and every "." must be surrounded on both sides by |
| 1759 | ** alphanumerics. Any pathname that does not satisfy these constraints |
| 1760 | ** results in a 404 error. Files in REPOSITORY that match the comma-separated |
| 1761 | ** list of glob patterns given by --files and that have known suffixes |
| 1762 | ** such as ".txt" or ".html" or ".jpeg" and do not match the pattern |
| 1763 | ** "*.fossil*" will be served as static content. With the "ui" command, |
| 1764 | ** the REPOSITORY can only be a directory if the --notfound option is |
| 1765 | ** also present. |
| 1766 | ** |
| 1767 | ** By default, the "ui" command provides full administrative access without |
| 1768 | ** having to log in. This can be disabled by setting turning off the |
| 1769 | ** "localauth" setting. Automatic login for the "server" command is available |
| 1770 | ** if the --localauth option is present and the "localauth" setting is off |
| 1771 | ** and the connection is from localhost. The optional REPOSITORY argument |
| 1772 | ** to "ui" may be a directory and will function as "server" if and only if |
| 1773 | ** the --notfound option is used. |
| 1774 | ** |
| 1775 | ** Options: |
| 1776 | ** --localauth enable automatic login for requests from localhost |
| 1777 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 1778 | ** -P|--port TCPPORT listen to request on port TCPPORT |
| 1779 | ** --th-trace trace TH1 execution (for debugging purposes) |
| 1780 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 1781 | ** --notfound URL Redirect |
| 1782 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 1783 | ** |
| 1784 | ** See also: cgi, http, winsrv |
| 1785 | */ |
| 1786 | void cmd_webserver(void){ |
| 1787 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1788 | const char *zPort; /* Value of the --port option */ |
| 1789 | const char *zBrowser; /* Name of web browser program */ |
| 1790 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1791 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1792 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1793 | int flags = 0; /* Server flags */ |
| 1794 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 1795 | const char *zFileGlob; /* Static content must match this */ |
| 1796 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 1797 | |
| 1798 | #if defined(_WIN32) |
| 1799 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 1800 | zStopperFile = find_option("stopper", 0, 1); |
| 1801 | #endif |
| 1802 | |
| 1803 | zFileGlob = find_option("files", 0, 1); |
| 1804 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 1805 | Th_InitTraceLog(); |
| 1806 | zPort = find_option("port", "P", 1); |
| 1807 | zNotFound = find_option("notfound", 0, 1); |
| 1808 | zAltBase = find_option("baseurl", 0, 1); |
| 1809 | if( zAltBase ){ |
| 1810 | set_base_url(zAltBase); |
| 1811 | } |
| 1812 | if ( find_option("localhost", 0, 0)!=0 ){ |
| 1813 | flags |= HTTP_SERVER_LOCALHOST; |
| 1814 | } |
| 1815 | if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); |
| 1816 | isUiCmd = g.argv[1][0]=='u'; |
| 1817 | if( isUiCmd ){ |
| 1818 | flags |= HTTP_SERVER_LOCALHOST; |
| 1819 | g.useLocalauth = 1; |
| 1820 | } |
| 1821 | find_server_repository(isUiCmd && zNotFound==0); |
| 1822 | if( zPort ){ |
| 1823 | int i; |
| 1824 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 1825 | if( i>0 ){ |
| 1826 | zIpAddr = mprintf("%.*s", i, zPort); |
| 1827 | zPort += i+1; |
| 1828 | } |
| 1829 | iPort = mxPort = atoi(zPort); |
| 1830 | }else{ |
| 1831 | iPort = db_get_int("http-port", 8080); |
| 1832 | mxPort = iPort+100; |
| 1833 | } |
| 1834 | #if !defined(_WIN32) |
| 1835 | /* Unix implementation */ |
| 1836 | if( isUiCmd ){ |
| 1837 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1838 | zBrowser = db_get("web-browser", 0); |
| 1839 | if( zBrowser==0 ){ |
| 1840 | static const char *const azBrowserProg[] = |
| 1841 | { "xdg-open", "gnome-open", "firefox", "google-chrome" }; |
| 1842 | int i; |
| 1843 | zBrowser = "echo"; |
| 1844 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1845 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1846 | zBrowser = azBrowserProg[i]; |
| 1847 | break; |
| 1848 | } |
| 1849 | } |
| 1850 | } |
| 1851 | #else |
| 1852 | zBrowser = db_get("web-browser", "open"); |
| 1853 | #endif |
| 1854 | if( zIpAddr ){ |
| 1855 | zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr); |
| 1856 | }else{ |
| 1857 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 1858 | } |
| 1859 | } |
| 1860 | db_close(1); |
| 1861 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ |
| 1862 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 1863 | } |
| 1864 | g.sslNotAvailable = 1; |
| 1865 | g.httpIn = stdin; |
| 1866 | g.httpOut = stdout; |
| 1867 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 1868 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 1869 | } |
| 1870 | g.cgiOutput = 1; |
| 1871 | find_server_repository(isUiCmd && zNotFound==0); |
| 1872 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); |
| 1873 | cgi_handle_http_request(0); |
| 1874 | process_one_web_page(zNotFound, glob_create(zFileGlob)); |
| 1875 | #else |
| 1876 | /* Win32 implementation */ |
| 1877 | if( isUiCmd ){ |
| 1878 | zBrowser = db_get("web-browser", "start"); |
| 1879 | if( zIpAddr ){ |
| 1880 | zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr); |
| 1881 | }else{ |
| 1882 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 1883 | } |
| 1884 | } |
| 1885 | db_close(1); |
| 1886 | if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){ |
| 1887 | win32_http_server(iPort, mxPort, zBrowserCmd, |
| 1888 | zStopperFile, zNotFound, zFileGlob, zIpAddr, flags); |
| 1889 | } |
| 1890 | #endif |
| 1891 | } |
| 1892 | |
| 1893 | /* |
| 1894 | ** COMMAND: test-echo |
| 1895 | ** |
| 1896 | ** Usage: %fossil test-echo [--hex] ARGS... |
| 1897 | ** |
| 1898 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -21,18 +21,11 @@ | |
| 21 | #include "config.h" |
| 22 | #include "main.h" |
| 23 | #include <string.h> |
| 24 | #include <time.h> |
| 25 | #include <fcntl.h> |
| 26 | #include <stdlib.h> /* atexit() */ |
| 27 | #include "zlib.h" |
| 28 | #ifdef FOSSIL_ENABLE_SSL |
| 29 | # include "openssl/opensslv.h" |
| 30 | #endif |
| 31 | #if INTERFACE |
| @@ -1023,11 +1016,11 @@ | |
| 1016 | ** The g.zBaseURL is normally set based on HTTP_HOST and SCRIPT_NAME |
| 1017 | ** environment variables. However, if zAltBase is not NULL then it |
| 1018 | ** is the argument to the --baseurl option command-line option and |
| 1019 | ** g.zBaseURL and g.zTop is set from that instead. |
| 1020 | */ |
| 1021 | void set_base_url(const char *zAltBase){ |
| 1022 | int i; |
| 1023 | const char *zHost; |
| 1024 | const char *zMode; |
| 1025 | const char *zCur; |
| 1026 | |
| @@ -1085,65 +1078,10 @@ | |
| 1078 | */ |
| 1079 | NORETURN void fossil_redirect_home(void){ |
| 1080 | cgi_redirectf("%s%s", g.zTop, db_get("index-page", "/index")); |
| 1081 | } |
| 1082 | |
| 1083 | /* |
| 1084 | ** Preconditions: |
| 1085 | ** |
| 1086 | ** * Environment variables are set up according to the CGI standard. |
| 1087 | ** |
| @@ -1162,11 +1100,11 @@ | |
| 1100 | ** $prefix can be determined from its suffix, then the file $prefix is |
| 1101 | ** returned as static text. |
| 1102 | ** |
| 1103 | ** If no suitable webpage is found, try to redirect to zNotFound. |
| 1104 | */ |
| 1105 | void process_one_web_page(const char *zNotFound, Glob *pFileGlob){ |
| 1106 | const char *zPathInfo; |
| 1107 | char *zPath = NULL; |
| 1108 | int idx; |
| 1109 | int i; |
| 1110 | |
| @@ -1407,491 +1345,10 @@ | |
| 1345 | /* Return the result. |
| 1346 | */ |
| 1347 | cgi_reply(); |
| 1348 | } |
| 1349 | |
| 1350 | /* |
| 1351 | ** COMMAND: test-echo |
| 1352 | ** |
| 1353 | ** Usage: %fossil test-echo [--hex] ARGS... |
| 1354 | ** |
| 1355 |
+11
-1
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -88,10 +88,11 @@ | ||
| 88 | 88 | $(SRCDIR)/regexp.c \ |
| 89 | 89 | $(SRCDIR)/report.c \ |
| 90 | 90 | $(SRCDIR)/rss.c \ |
| 91 | 91 | $(SRCDIR)/schema.c \ |
| 92 | 92 | $(SRCDIR)/search.c \ |
| 93 | + $(SRCDIR)/server.c \ | |
| 93 | 94 | $(SRCDIR)/setup.c \ |
| 94 | 95 | $(SRCDIR)/sha1.c \ |
| 95 | 96 | $(SRCDIR)/shun.c \ |
| 96 | 97 | $(SRCDIR)/skins.c \ |
| 97 | 98 | $(SRCDIR)/sqlcmd.c \ |
| @@ -197,10 +198,11 @@ | ||
| 197 | 198 | $(OBJDIR)/regexp_.c \ |
| 198 | 199 | $(OBJDIR)/report_.c \ |
| 199 | 200 | $(OBJDIR)/rss_.c \ |
| 200 | 201 | $(OBJDIR)/schema_.c \ |
| 201 | 202 | $(OBJDIR)/search_.c \ |
| 203 | + $(OBJDIR)/server_.c \ | |
| 202 | 204 | $(OBJDIR)/setup_.c \ |
| 203 | 205 | $(OBJDIR)/sha1_.c \ |
| 204 | 206 | $(OBJDIR)/shun_.c \ |
| 205 | 207 | $(OBJDIR)/skins_.c \ |
| 206 | 208 | $(OBJDIR)/sqlcmd_.c \ |
| @@ -306,10 +308,11 @@ | ||
| 306 | 308 | $(OBJDIR)/regexp.o \ |
| 307 | 309 | $(OBJDIR)/report.o \ |
| 308 | 310 | $(OBJDIR)/rss.o \ |
| 309 | 311 | $(OBJDIR)/schema.o \ |
| 310 | 312 | $(OBJDIR)/search.o \ |
| 313 | + $(OBJDIR)/server.o \ | |
| 311 | 314 | $(OBJDIR)/setup.o \ |
| 312 | 315 | $(OBJDIR)/sha1.o \ |
| 313 | 316 | $(OBJDIR)/shun.o \ |
| 314 | 317 | $(OBJDIR)/skins.o \ |
| 315 | 318 | $(OBJDIR)/sqlcmd.o \ |
| @@ -405,11 +408,11 @@ | ||
| 405 | 408 | |
| 406 | 409 | |
| 407 | 410 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 408 | 411 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 409 | 412 | $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h |
| 410 | - $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/util_.c:$(OBJDIR)/util.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h | |
| 413 | + $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/server_.c:$(OBJDIR)/server.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/util_.c:$(OBJDIR)/util.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h | |
| 411 | 414 | touch $(OBJDIR)/headers |
| 412 | 415 | $(OBJDIR)/headers: Makefile |
| 413 | 416 | $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/json_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h |
| 414 | 417 | Makefile: |
| 415 | 418 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| @@ -942,10 +945,17 @@ | ||
| 942 | 945 | |
| 943 | 946 | $(OBJDIR)/search.o: $(OBJDIR)/search_.c $(OBJDIR)/search.h $(SRCDIR)/config.h |
| 944 | 947 | $(XTCC) -o $(OBJDIR)/search.o -c $(OBJDIR)/search_.c |
| 945 | 948 | |
| 946 | 949 | $(OBJDIR)/search.h: $(OBJDIR)/headers |
| 950 | +$(OBJDIR)/server_.c: $(SRCDIR)/server.c $(OBJDIR)/translate | |
| 951 | + $(OBJDIR)/translate $(SRCDIR)/server.c >$(OBJDIR)/server_.c | |
| 952 | + | |
| 953 | +$(OBJDIR)/server.o: $(OBJDIR)/server_.c $(OBJDIR)/server.h $(SRCDIR)/config.h | |
| 954 | + $(XTCC) -o $(OBJDIR)/server.o -c $(OBJDIR)/server_.c | |
| 955 | + | |
| 956 | +$(OBJDIR)/server.h: $(OBJDIR)/headers | |
| 947 | 957 | $(OBJDIR)/setup_.c: $(SRCDIR)/setup.c $(OBJDIR)/translate |
| 948 | 958 | $(OBJDIR)/translate $(SRCDIR)/setup.c >$(OBJDIR)/setup_.c |
| 949 | 959 | |
| 950 | 960 | $(OBJDIR)/setup.o: $(OBJDIR)/setup_.c $(OBJDIR)/setup.h $(SRCDIR)/config.h |
| 951 | 961 | $(XTCC) -o $(OBJDIR)/setup.o -c $(OBJDIR)/setup_.c |
| 952 | 962 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -88,10 +88,11 @@ | |
| 88 | $(SRCDIR)/regexp.c \ |
| 89 | $(SRCDIR)/report.c \ |
| 90 | $(SRCDIR)/rss.c \ |
| 91 | $(SRCDIR)/schema.c \ |
| 92 | $(SRCDIR)/search.c \ |
| 93 | $(SRCDIR)/setup.c \ |
| 94 | $(SRCDIR)/sha1.c \ |
| 95 | $(SRCDIR)/shun.c \ |
| 96 | $(SRCDIR)/skins.c \ |
| 97 | $(SRCDIR)/sqlcmd.c \ |
| @@ -197,10 +198,11 @@ | |
| 197 | $(OBJDIR)/regexp_.c \ |
| 198 | $(OBJDIR)/report_.c \ |
| 199 | $(OBJDIR)/rss_.c \ |
| 200 | $(OBJDIR)/schema_.c \ |
| 201 | $(OBJDIR)/search_.c \ |
| 202 | $(OBJDIR)/setup_.c \ |
| 203 | $(OBJDIR)/sha1_.c \ |
| 204 | $(OBJDIR)/shun_.c \ |
| 205 | $(OBJDIR)/skins_.c \ |
| 206 | $(OBJDIR)/sqlcmd_.c \ |
| @@ -306,10 +308,11 @@ | |
| 306 | $(OBJDIR)/regexp.o \ |
| 307 | $(OBJDIR)/report.o \ |
| 308 | $(OBJDIR)/rss.o \ |
| 309 | $(OBJDIR)/schema.o \ |
| 310 | $(OBJDIR)/search.o \ |
| 311 | $(OBJDIR)/setup.o \ |
| 312 | $(OBJDIR)/sha1.o \ |
| 313 | $(OBJDIR)/shun.o \ |
| 314 | $(OBJDIR)/skins.o \ |
| 315 | $(OBJDIR)/sqlcmd.o \ |
| @@ -405,11 +408,11 @@ | |
| 405 | |
| 406 | |
| 407 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 408 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 409 | $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h |
| 410 | $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/util_.c:$(OBJDIR)/util.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h |
| 411 | touch $(OBJDIR)/headers |
| 412 | $(OBJDIR)/headers: Makefile |
| 413 | $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/json_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h |
| 414 | Makefile: |
| 415 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| @@ -942,10 +945,17 @@ | |
| 942 | |
| 943 | $(OBJDIR)/search.o: $(OBJDIR)/search_.c $(OBJDIR)/search.h $(SRCDIR)/config.h |
| 944 | $(XTCC) -o $(OBJDIR)/search.o -c $(OBJDIR)/search_.c |
| 945 | |
| 946 | $(OBJDIR)/search.h: $(OBJDIR)/headers |
| 947 | $(OBJDIR)/setup_.c: $(SRCDIR)/setup.c $(OBJDIR)/translate |
| 948 | $(OBJDIR)/translate $(SRCDIR)/setup.c >$(OBJDIR)/setup_.c |
| 949 | |
| 950 | $(OBJDIR)/setup.o: $(OBJDIR)/setup_.c $(OBJDIR)/setup.h $(SRCDIR)/config.h |
| 951 | $(XTCC) -o $(OBJDIR)/setup.o -c $(OBJDIR)/setup_.c |
| 952 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -88,10 +88,11 @@ | |
| 88 | $(SRCDIR)/regexp.c \ |
| 89 | $(SRCDIR)/report.c \ |
| 90 | $(SRCDIR)/rss.c \ |
| 91 | $(SRCDIR)/schema.c \ |
| 92 | $(SRCDIR)/search.c \ |
| 93 | $(SRCDIR)/server.c \ |
| 94 | $(SRCDIR)/setup.c \ |
| 95 | $(SRCDIR)/sha1.c \ |
| 96 | $(SRCDIR)/shun.c \ |
| 97 | $(SRCDIR)/skins.c \ |
| 98 | $(SRCDIR)/sqlcmd.c \ |
| @@ -197,10 +198,11 @@ | |
| 198 | $(OBJDIR)/regexp_.c \ |
| 199 | $(OBJDIR)/report_.c \ |
| 200 | $(OBJDIR)/rss_.c \ |
| 201 | $(OBJDIR)/schema_.c \ |
| 202 | $(OBJDIR)/search_.c \ |
| 203 | $(OBJDIR)/server_.c \ |
| 204 | $(OBJDIR)/setup_.c \ |
| 205 | $(OBJDIR)/sha1_.c \ |
| 206 | $(OBJDIR)/shun_.c \ |
| 207 | $(OBJDIR)/skins_.c \ |
| 208 | $(OBJDIR)/sqlcmd_.c \ |
| @@ -306,10 +308,11 @@ | |
| 308 | $(OBJDIR)/regexp.o \ |
| 309 | $(OBJDIR)/report.o \ |
| 310 | $(OBJDIR)/rss.o \ |
| 311 | $(OBJDIR)/schema.o \ |
| 312 | $(OBJDIR)/search.o \ |
| 313 | $(OBJDIR)/server.o \ |
| 314 | $(OBJDIR)/setup.o \ |
| 315 | $(OBJDIR)/sha1.o \ |
| 316 | $(OBJDIR)/shun.o \ |
| 317 | $(OBJDIR)/skins.o \ |
| 318 | $(OBJDIR)/sqlcmd.o \ |
| @@ -405,11 +408,11 @@ | |
| 408 | |
| 409 | |
| 410 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 411 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 412 | $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h |
| 413 | $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/server_.c:$(OBJDIR)/server.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/util_.c:$(OBJDIR)/util.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h |
| 414 | touch $(OBJDIR)/headers |
| 415 | $(OBJDIR)/headers: Makefile |
| 416 | $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/json_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h |
| 417 | Makefile: |
| 418 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| @@ -942,10 +945,17 @@ | |
| 945 | |
| 946 | $(OBJDIR)/search.o: $(OBJDIR)/search_.c $(OBJDIR)/search.h $(SRCDIR)/config.h |
| 947 | $(XTCC) -o $(OBJDIR)/search.o -c $(OBJDIR)/search_.c |
| 948 | |
| 949 | $(OBJDIR)/search.h: $(OBJDIR)/headers |
| 950 | $(OBJDIR)/server_.c: $(SRCDIR)/server.c $(OBJDIR)/translate |
| 951 | $(OBJDIR)/translate $(SRCDIR)/server.c >$(OBJDIR)/server_.c |
| 952 | |
| 953 | $(OBJDIR)/server.o: $(OBJDIR)/server_.c $(OBJDIR)/server.h $(SRCDIR)/config.h |
| 954 | $(XTCC) -o $(OBJDIR)/server.o -c $(OBJDIR)/server_.c |
| 955 | |
| 956 | $(OBJDIR)/server.h: $(OBJDIR)/headers |
| 957 | $(OBJDIR)/setup_.c: $(SRCDIR)/setup.c $(OBJDIR)/translate |
| 958 | $(OBJDIR)/translate $(SRCDIR)/setup.c >$(OBJDIR)/setup_.c |
| 959 | |
| 960 | $(OBJDIR)/setup.o: $(OBJDIR)/setup_.c $(OBJDIR)/setup.h $(SRCDIR)/config.h |
| 961 | $(XTCC) -o $(OBJDIR)/setup.o -c $(OBJDIR)/setup_.c |
| 962 |
+1
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -91,10 +91,11 @@ | ||
| 91 | 91 | regexp |
| 92 | 92 | report |
| 93 | 93 | rss |
| 94 | 94 | schema |
| 95 | 95 | search |
| 96 | + server | |
| 96 | 97 | setup |
| 97 | 98 | sha1 |
| 98 | 99 | shun |
| 99 | 100 | skins |
| 100 | 101 | sqlcmd |
| 101 | 102 | |
| 102 | 103 | ADDED src/server.c |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -91,10 +91,11 @@ | |
| 91 | regexp |
| 92 | report |
| 93 | rss |
| 94 | schema |
| 95 | search |
| 96 | setup |
| 97 | sha1 |
| 98 | shun |
| 99 | skins |
| 100 | sqlcmd |
| 101 | |
| 102 | DDED src/server.c |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -91,10 +91,11 @@ | |
| 91 | regexp |
| 92 | report |
| 93 | rss |
| 94 | schema |
| 95 | search |
| 96 | server |
| 97 | setup |
| 98 | sha1 |
| 99 | shun |
| 100 | skins |
| 101 | sqlcmd |
| 102 | |
| 103 | DDED src/server.c |
+567
| --- a/src/server.c | ||
| +++ b/src/server.c | ||
| @@ -0,0 +1,567 @@ | ||
| 1 | +/* | |
| 2 | +** Copyright (c) 2006 D. Richard Hipp | |
| 3 | +** | |
| 4 | +** This program is free software; you can redistribute it and/or | |
| 5 | +** modify it under the terms of the Simplified BSD License (also | |
| 6 | +** known as the "2-Clause License" or "FreeBSD License".) | |
| 7 | +** | |
| 8 | +** This program is distributed in the hope that it will be useful, | |
| 9 | +** but without any warranty; without even the implied warranty of | |
| 10 | +** merchantability or fitness for a particular purpose. | |
| 11 | +** | |
| 12 | +** Author contact information: | |
| 13 | +** [email protected] | |
| 14 | +** http://www.hwaci.com/drh/ | |
| 15 | +** | |
| 16 | +******************************************************************************* | |
| 17 | +** | |
| 18 | +** This module contains code to implement CGI, HTTP, SCGI, and FastCGI | |
| 19 | +** servers. | |
| 20 | +*/ | |
| 21 | +#include "config.h" | |
| 22 | +#include "server.h" | |
| 23 | +#include <sys/types.h> | |
| 24 | +#include <sys/stat.h> | |
| 25 | +#if defined(_WIN32) | |
| 26 | +# include <windows.h> | |
| 27 | +#else | |
| 28 | +# include <errno.h> /* errno global */ | |
| 29 | +#endif | |
| 30 | + | |
| 31 | +/* | |
| 32 | +** If g.argv[2] exists then it is either the name of a repository | |
| 33 | +** that will be used by a server, or else it is a directory that | |
| 34 | +** contains multiple repositories that can be served. If g.argv[2] | |
| 35 | +** is a directory, the repositories it contains must be named | |
| 36 | +** "*.fossil". If g.argv[2] does not exists, then we must be within | |
| 37 | +** a check-out and the repository to be served is the repository of | |
| 38 | +** that check-out. | |
| 39 | +** | |
| 40 | +** Open the repository to be served if it is known. If g.argv[2] is | |
| 41 | +** a directory full of repositories, then set g.zRepositoryName to | |
| 42 | +** the name of that directory and the specific repository will be | |
| 43 | +** opened later by process_one_web_page() based on the content of | |
| 44 | +** the PATH_INFO variable. | |
| 45 | +** | |
| 46 | +** If disallowDir is set, then the directory full of repositories method | |
| 47 | +** is disallowed. | |
| 48 | +*/ | |
| 49 | +static void find_server_repository(int disallowDir){ | |
| 50 | + if( g.argc<3 ){ | |
| 51 | + db_must_be_within_tree(); | |
| 52 | + }else if( file_isdir(g.argv[2])==1 ){ | |
| 53 | + if( disallowDir ){ | |
| 54 | + fossil_fatal("\"%s\" is a directory, not a repository file", g.argv[2]); | |
| 55 | + }else{ | |
| 56 | + g.zRepositoryName = mprintf("%s", g.argv[2]); | |
| 57 | + file_simplify_name(g.zRepositoryName, -1, 0); | |
| 58 | + } | |
| 59 | + }else{ | |
| 60 | + db_open_repository(g.argv[2]); | |
| 61 | + } | |
| 62 | +} | |
| 63 | + | |
| 64 | +#if !defined(_WIN32) | |
| 65 | +#if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) | |
| 66 | +/* | |
| 67 | +** Search for an executable on the PATH environment variable. | |
| 68 | +** Return true (1) if found and false (0) if not found. | |
| 69 | +*/ | |
| 70 | +static int binaryOnPath(const char *zBinary){ | |
| 71 | + const char *zPath = fossil_getenv("PATH"); | |
| 72 | + char *zFull; | |
| 73 | + int i; | |
| 74 | + int bExists; | |
| 75 | + while( zPath && zPath[0] ){ | |
| 76 | + while( zPath[0]==':' ) zPath++; | |
| 77 | + for(i=0; zPath[i] && zPath[i]!=':'; i++){} | |
| 78 | + zFull = mprintf("%.*s/%s", i, zPath, zBinary); | |
| 79 | + bExists = file_access(zFull, X_OK); | |
| 80 | + fossil_free(zFull); | |
| 81 | + if( bExists==0 ) return 1; | |
| 82 | + zPath += i; | |
| 83 | + } | |
| 84 | + return 0; | |
| 85 | +} | |
| 86 | +#endif | |
| 87 | +#endif | |
| 88 | + | |
| 89 | +/* | |
| 90 | +** If running as root, chroot to the directory containing the | |
| 91 | +** repository zRepo and then drop root privileges. Return the | |
| 92 | +** new repository name. | |
| 93 | +** | |
| 94 | +** zRepo might be a directory itself. In that case chroot into | |
| 95 | +** the directory zRepo. | |
| 96 | +** | |
| 97 | +** Assume the user-id and group-id of the repository, or if zRepo | |
| 98 | +** is a directory, of that directory. | |
| 99 | +*/ | |
| 100 | +char *enter_chroot_jail(char *zRepo){ | |
| 101 | +#if !defined(_WIN32) | |
| 102 | + if( getuid()==0 ){ | |
| 103 | + int i; | |
| 104 | + struct stat sStat; | |
| 105 | + Blob dir; | |
| 106 | + char *zDir; | |
| 107 | + | |
| 108 | + file_canonical_name(zRepo, &dir, 0); | |
| 109 | + zDir = blob_str(&dir); | |
| 110 | + if( file_isdir(zDir)==1 ){ | |
| 111 | + if( file_chdir(zDir, 1) ){ | |
| 112 | + fossil_fatal("unable to chroot into %s", zDir); | |
| 113 | + } | |
| 114 | + zRepo = "/"; | |
| 115 | + }else{ | |
| 116 | + for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){} | |
| 117 | + if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo); | |
| 118 | + if( i>0 ){ | |
| 119 | + zDir[i] = 0; | |
| 120 | + if( file_chdir(zDir, 1) ){ | |
| 121 | + fossil_fatal("unable to chroot into %s", zDir); | |
| 122 | + } | |
| 123 | + zDir[i] = '/'; | |
| 124 | + } | |
| 125 | + zRepo = &zDir[i]; | |
| 126 | + } | |
| 127 | + if( stat(zRepo, &sStat)!=0 ){ | |
| 128 | + fossil_fatal("cannot stat() repository: %s", zRepo); | |
| 129 | + } | |
| 130 | + i = setgid(sStat.st_gid); | |
| 131 | + i = i || setuid(sStat.st_uid); | |
| 132 | + if(i){ | |
| 133 | + fossil_fatal("setgid/uid() failed with errno %d", errno); | |
| 134 | + } | |
| 135 | + if( g.db!=0 ){ | |
| 136 | + db_close(1); | |
| 137 | + db_open_repository(zRepo); | |
| 138 | + } | |
| 139 | + } | |
| 140 | +#endif | |
| 141 | + return zRepo; | |
| 142 | +} | |
| 143 | + | |
| 144 | +/* If the CGI program contains one or more lines of the form | |
| 145 | +** | |
| 146 | +** redirect: repository-filename http://hostname/path/%s | |
| 147 | +** | |
| 148 | +** then control jumps here. Search each repository for an artifact ID | |
| 149 | +** that matches the "name" CGI parameter and for the first match, | |
| 150 | +** redirect to the corresponding URL with the "name" CGI parameter | |
| 151 | +** inserted. Paint an error page if no match is found. | |
| 152 | +** | |
| 153 | +** If there is a line of the form: | |
| 154 | +** | |
| 155 | +** redirect: * URL | |
| 156 | +** | |
| 157 | +** Then a redirect is made to URL if no match is found. Otherwise a | |
| 158 | +** very primitive error message is returned. | |
| 159 | +*/ | |
| 160 | +static void redirect_web_page(int nRedirect, char **azRedirect){ | |
| 161 | + int i; /* Loop counter */ | |
| 162 | + const char *zNotFound = 0; /* Not found URL */ | |
| 163 | + const char *zName = P("name"); | |
| 164 | + set_base_url(0); | |
| 165 | + if( zName==0 ){ | |
| 166 | + zName = P("SCRIPT_NAME"); | |
| 167 | + if( zName && zName[0]=='/' ) zName++; | |
| 168 | + } | |
| 169 | + if( zName && validate16(zName, strlen(zName)) ){ | |
| 170 | + for(i=0; i<nRedirect; i++){ | |
| 171 | + if( fossil_strcmp(azRedirect[i*2],"*")==0 ){ | |
| 172 | + zNotFound = azRedirect[i*2+1]; | |
| 173 | + continue; | |
| 174 | + } | |
| 175 | + db_open_repository(azRedirect[i*2]); | |
| 176 | + if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){ | |
| 177 | + cgi_redirectf(azRedirect[i*2+1], zName); | |
| 178 | + return; | |
| 179 | + } | |
| 180 | + db_close(1); | |
| 181 | + } | |
| 182 | + } | |
| 183 | + if( zNotFound ){ | |
| 184 | + cgi_redirectf(zNotFound, zName); | |
| 185 | + }else{ | |
| 186 | + @ <html> | |
| 187 | + @ <head><title>No Such Object</title></head> | |
| 188 | + @ <body> | |
| 189 | + @ <p>No such object: <b>%h(zName)</b></p> | |
| 190 | + @ </body> | |
| 191 | + cgi_reply(); | |
| 192 | + } | |
| 193 | +} | |
| 194 | + | |
| 195 | +/* | |
| 196 | +** COMMAND: cgi* | |
| 197 | +** | |
| 198 | +** Usage: %fossil ?cgi? SCRIPT | |
| 199 | +** | |
| 200 | +** The SCRIPT argument is the name of a file that is the CGI script | |
| 201 | +** that is being run. The command name, "cgi", may be omitted if | |
| 202 | +** the GATEWAY_INTERFACE environment variable is set to "CGI" (which | |
| 203 | +** should always be the case for CGI scripts run by a webserver.) The | |
| 204 | +** SCRIPT file should look something like this: | |
| 205 | +** | |
| 206 | +** #!/usr/bin/fossil | |
| 207 | +** repository: /home/somebody/project.db | |
| 208 | +** | |
| 209 | +** The second line defines the name of the repository. After locating | |
| 210 | +** the repository, fossil will generate a webpage on stdout based on | |
| 211 | +** the values of standard CGI environment variables. | |
| 212 | +** | |
| 213 | +** See also: http, server, winsrv | |
| 214 | +*/ | |
| 215 | +void cmd_cgi(void){ | |
| 216 | + const char *zFile; | |
| 217 | + const char *zNotFound = 0; | |
| 218 | + char **azRedirect = 0; /* List of repositories to redirect to */ | |
| 219 | + int nRedirect = 0; /* Number of entries in azRedirect */ | |
| 220 | + Glob *pFileGlob = 0; /* Pattern for files */ | |
| 221 | + Blob config, line, key, value, value2; | |
| 222 | + if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ | |
| 223 | + zFile = g.argv[2]; | |
| 224 | + }else{ | |
| 225 | + zFile = g.argv[1]; | |
| 226 | + } | |
| 227 | + g.httpOut = stdout; | |
| 228 | + g.httpIn = stdin; | |
| 229 | + fossil_binary_mode(g.httpOut); | |
| 230 | + fossil_binary_mode(g.httpIn); | |
| 231 | + g.cgiOutput = 1; | |
| 232 | + blob_read_from_file(&config, zFile); | |
| 233 | + while( blob_line(&config, &line) ){ | |
| 234 | + if( !blob_token(&line, &key) ) continue; | |
| 235 | + if( blob_buffer(&key)[0]=='#' ) continue; | |
| 236 | + if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ | |
| 237 | + g.fDebug = fossil_fopen(blob_str(&value), "ab"); | |
| 238 | + blob_reset(&value); | |
| 239 | + continue; | |
| 240 | + } | |
| 241 | + if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){ | |
| 242 | + cgi_setenv("HOME", blob_str(&value)); | |
| 243 | + blob_reset(&value); | |
| 244 | + continue; | |
| 245 | + } | |
| 246 | + if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){ | |
| 247 | + blob_trim(&value); | |
| 248 | + db_open_repository(blob_str(&value)); | |
| 249 | + blob_reset(&value); | |
| 250 | + continue; | |
| 251 | + } | |
| 252 | + if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){ | |
| 253 | + db_close(1); | |
| 254 | + g.zRepositoryName = mprintf("%s", blob_str(&value)); | |
| 255 | + blob_reset(&value); | |
| 256 | + continue; | |
| 257 | + } | |
| 258 | + if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){ | |
| 259 | + zNotFound = mprintf("%s", blob_str(&value)); | |
| 260 | + blob_reset(&value); | |
| 261 | + continue; | |
| 262 | + } | |
| 263 | + if( blob_eq(&key, "localauth") ){ | |
| 264 | + g.useLocalauth = 1; | |
| 265 | + continue; | |
| 266 | + } | |
| 267 | + if( blob_eq(&key, "redirect:") && blob_token(&line, &value) | |
| 268 | + && blob_token(&line, &value2) ){ | |
| 269 | + nRedirect++; | |
| 270 | + azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*)); | |
| 271 | + azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value)); | |
| 272 | + azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2)); | |
| 273 | + blob_reset(&value); | |
| 274 | + blob_reset(&value2); | |
| 275 | + continue; | |
| 276 | + } | |
| 277 | + if( blob_eq(&key, "files:") && blob_token(&line, &value) ){ | |
| 278 | + pFileGlob = glob_create(blob_str(&value)); | |
| 279 | + continue; | |
| 280 | + } | |
| 281 | + } | |
| 282 | + blob_reset(&config); | |
| 283 | + if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){ | |
| 284 | + cgi_panic("Unable to find or open the project repository"); | |
| 285 | + } | |
| 286 | + cgi_init(); | |
| 287 | + if( nRedirect ){ | |
| 288 | + redirect_web_page(nRedirect, azRedirect); | |
| 289 | + }else{ | |
| 290 | + process_one_web_page(zNotFound, pFileGlob); | |
| 291 | + } | |
| 292 | +} | |
| 293 | + | |
| 294 | + | |
| 295 | +/* | |
| 296 | +** undocumented format: | |
| 297 | +** | |
| 298 | +** fossil http REPOSITORY INFILE OUTFILE IPADDR | |
| 299 | +** | |
| 300 | +** The argv==6 form is used by the win32 server only. | |
| 301 | +** | |
| 302 | +** COMMAND: http* | |
| 303 | +** | |
| 304 | +** Usage: %fossil http REPOSITORY ?OPTIONS? | |
| 305 | +** | |
| 306 | +** Handle a single HTTP request appearing on stdin. The resulting webpage | |
| 307 | +** is delivered on stdout. This method is used to launch an HTTP request | |
| 308 | +** handler from inetd, for example. The argument is the name of the | |
| 309 | +** repository. | |
| 310 | +** | |
| 311 | +** If REPOSITORY is a directory that contains one or more repositories, | |
| 312 | +** either directly in REPOSITORY itself, or in subdirectories, and | |
| 313 | +** with names of the form "*.fossil" then the a prefix of the URL pathname | |
| 314 | +** selects from among the various repositories. If the pathname does | |
| 315 | +** not select a valid repository and the --notfound option is available, | |
| 316 | +** then the server redirects (HTTP code 302) to the URL of --notfound. | |
| 317 | +** When REPOSITORY is a directory, the pathname must contain only | |
| 318 | +** alphanumerics, "_", "/", "-" and "." and no "-" may occur after a "/" | |
| 319 | +** and every "." must be surrounded on both sides by alphanumerics or else | |
| 320 | +** a 404 error is returned. Static content files in the directory are | |
| 321 | +** returned if they match comma-separate GLOB pattern specified by --files | |
| 322 | +** and do not match "*.fossil*" and have a well-known suffix. | |
| 323 | +** | |
| 324 | +** The --host option can be used to specify the hostname for the server. | |
| 325 | +** The --https option indicates that the request came from HTTPS rather | |
| 326 | +** than HTTP. If --nossl is given, then SSL connections will not be available, | |
| 327 | +** thus also no redirecting from http: to https: will take place. | |
| 328 | +** | |
| 329 | +** If the --localauth option is given, then automatic login is performed | |
| 330 | +** for requests coming from localhost, if the "localauth" setting is not | |
| 331 | +** enabled. | |
| 332 | +** | |
| 333 | +** Options: | |
| 334 | +** --localauth enable automatic login for local connections | |
| 335 | +** --host NAME specify hostname of the server | |
| 336 | +** --https signal a request coming in via https | |
| 337 | +** --nossl signal that no SSL connections are available | |
| 338 | +** --notfound URL use URL as "HTTP 404, object not found" page. | |
| 339 | +** --files GLOB comma-separate glob patterns for static file to serve | |
| 340 | +** --baseurl URL base URL (useful with reverse proxies) | |
| 341 | +** | |
| 342 | +** See also: cgi, server, winsrv | |
| 343 | +*/ | |
| 344 | +void cmd_http(void){ | |
| 345 | + const char *zIpAddr; | |
| 346 | + const char *zNotFound; | |
| 347 | + const char *zHost; | |
| 348 | + const char *zAltBase; | |
| 349 | + const char *zFileGlob; | |
| 350 | + | |
| 351 | + /* The winhttp module passes the --files option as --files-urlenc with | |
| 352 | + ** the argument being URL encoded, to avoid wildcard expansion in the | |
| 353 | + ** shell. This option is for internal use and is undocumented. | |
| 354 | + */ | |
| 355 | + zFileGlob = find_option("files-urlenc",0,1); | |
| 356 | + if( zFileGlob ){ | |
| 357 | + char *z = mprintf("%s", zFileGlob); | |
| 358 | + dehttpize(z); | |
| 359 | + zFileGlob = z; | |
| 360 | + }else{ | |
| 361 | + zFileGlob = find_option("files",0,1); | |
| 362 | + } | |
| 363 | + zNotFound = find_option("notfound", 0, 1); | |
| 364 | + g.useLocalauth = find_option("localauth", 0, 0)!=0; | |
| 365 | + g.sslNotAvailable = find_option("nossl", 0, 0)!=0; | |
| 366 | + zAltBase = find_option("baseurl", 0, 1); | |
| 367 | + if( zAltBase ) set_base_url(zAltBase); | |
| 368 | + if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on"); | |
| 369 | + zHost = find_option("host", 0, 1); | |
| 370 | + if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost); | |
| 371 | + g.cgiOutput = 1; | |
| 372 | + if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ | |
| 373 | + fossil_fatal("no repository specified"); | |
| 374 | + } | |
| 375 | + g.fullHttpReply = 1; | |
| 376 | + if( g.argc==6 ){ | |
| 377 | + g.httpIn = fossil_fopen(g.argv[3], "rb"); | |
| 378 | + g.httpOut = fossil_fopen(g.argv[4], "wb"); | |
| 379 | + zIpAddr = g.argv[5]; | |
| 380 | + }else{ | |
| 381 | + g.httpIn = stdin; | |
| 382 | + g.httpOut = stdout; | |
| 383 | + zIpAddr = 0; | |
| 384 | + } | |
| 385 | + find_server_repository(0); | |
| 386 | + g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); | |
| 387 | + cgi_handle_http_request(zIpAddr); | |
| 388 | + process_one_web_page(zNotFound, glob_create(zFileGlob)); | |
| 389 | +} | |
| 390 | + | |
| 391 | +/* | |
| 392 | +** Note that the following command is used by ssh:// processing. | |
| 393 | +** | |
| 394 | +** COMMAND: test-http | |
| 395 | +** Works like the http command but gives setup permission to all users. | |
| 396 | +*/ | |
| 397 | +void cmd_test_http(void){ | |
| 398 | + Th_InitTraceLog(); | |
| 399 | + login_set_capabilities("sx", 0); | |
| 400 | + g.useLocalauth = 1; | |
| 401 | + cgi_set_parameter("REMOTE_ADDR", "127.0.0.1"); | |
| 402 | + g.httpIn = stdin; | |
| 403 | + g.httpOut = stdout; | |
| 404 | + find_server_repository(0); | |
| 405 | + g.cgiOutput = 1; | |
| 406 | + g.fullHttpReply = 1; | |
| 407 | + cgi_handle_http_request(0); | |
| 408 | + process_one_web_page(0, 0); | |
| 409 | +} | |
| 410 | + | |
| 411 | + | |
| 412 | +/* | |
| 413 | +** COMMAND: server* | |
| 414 | +** COMMAND: ui | |
| 415 | +** | |
| 416 | +** Usage: %fossil server ?OPTIONS? ?REPOSITORY? | |
| 417 | +** Or: %fossil ui ?OPTIONS? ?REPOSITORY? | |
| 418 | +** | |
| 419 | +** Open a socket and begin listening and responding to HTTP requests on | |
| 420 | +** TCP port 8080, or on any other TCP port defined by the -P or | |
| 421 | +** --port option. The optional argument is the name of the repository. | |
| 422 | +** The repository argument may be omitted if the working directory is | |
| 423 | +** within an open checkout. | |
| 424 | +** | |
| 425 | +** The "ui" command automatically starts a web browser after initializing | |
| 426 | +** the web server. The "ui" command also binds to 127.0.0.1 and so will | |
| 427 | +** only process HTTP traffic from the local machine. | |
| 428 | +** | |
| 429 | +** The REPOSITORY can be a directory (aka folder) that contains one or | |
| 430 | +** more repositories with names ending in ".fossil". In this case, the | |
| 431 | +** a prefix of the URL pathname is used to search the directory for an | |
| 432 | +** appropriate repository. To thwart mischief, the pathname in the URL must | |
| 433 | +** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may | |
| 434 | +** occur after "/", and every "." must be surrounded on both sides by | |
| 435 | +** alphanumerics. Any pathname that does not satisfy these constraints | |
| 436 | +** results in a 404 error. Files in REPOSITORY that match the comma-separated | |
| 437 | +** list of glob patterns given by --files and that have known suffixes | |
| 438 | +** such as ".txt" or ".html" or ".jpeg" and do not match the pattern | |
| 439 | +** "*.fossil*" will be served as static content. With the "ui" command, | |
| 440 | +** the REPOSITORY can only be a directory if the --notfound option is | |
| 441 | +** also present. | |
| 442 | +** | |
| 443 | +** By default, the "ui" command provides full administrative access without | |
| 444 | +** having to log in. This can be disabled by setting turning off the | |
| 445 | +** "localauth" setting. Automatic login for the "server" command is available | |
| 446 | +** if the --localauth option is present and the "localauth" setting is off | |
| 447 | +** and the connection is from localhost. The optional REPOSITORY argument | |
| 448 | +** to "ui" may be a directory and will function as "server" if and only if | |
| 449 | +** the --notfound option is used. | |
| 450 | +** | |
| 451 | +** Options: | |
| 452 | +** --localauth enable automatic login for requests from localhost | |
| 453 | +** --localhost listen on 127.0.0.1 only (always true for "ui") | |
| 454 | +** -P|--port TCPPORT listen to request on port TCPPORT | |
| 455 | +** --th-trace trace TH1 execution (for debugging purposes) | |
| 456 | +** --baseurl URL Use URL as the base (useful for reverse proxies) | |
| 457 | +** --notfound URL Redirect | |
| 458 | +** --files GLOBLIST Comma-separated list of glob patterns for static files | |
| 459 | +** | |
| 460 | +** See also: cgi, http, winsrv | |
| 461 | +*/ | |
| 462 | +void cmd_webserver(void){ | |
| 463 | + int iPort, mxPort; /* Range of TCP ports allowed */ | |
| 464 | + const char *zPort; /* Value of the --port option */ | |
| 465 | + const char *zBrowser; /* Name of web browser program */ | |
| 466 | + char *zBrowserCmd = 0; /* Command to launch the web browser */ | |
| 467 | + int isUiCmd; /* True if command is "ui", not "server' */ | |
| 468 | + const char *zNotFound; /* The --notfound option or NULL */ | |
| 469 | + int flags = 0; /* Server flags */ | |
| 470 | + const char *zAltBase; /* Argument to the --baseurl option */ | |
| 471 | + const char *zFileGlob; /* Static content must match this */ | |
| 472 | + char *zIpAddr = 0; /* Bind to this IP address */ | |
| 473 | + | |
| 474 | +#if defined(_WIN32) | |
| 475 | + const char *zStopperFile; /* Name of file used to terminate server */ | |
| 476 | + zStopperFile = find_option("stopper", 0, 1); | |
| 477 | +#endif | |
| 478 | + | |
| 479 | + zFileGlob = find_option("files", 0, 1); | |
| 480 | + g.useLocalauth = find_option("localauth", 0, 0)!=0; | |
| 481 | + Th_InitTraceLog(); | |
| 482 | + zPort = find_option("port", "P", 1); | |
| 483 | + zNotFound = find_option("notfound", 0, 1); | |
| 484 | + zAltBase = find_option("baseurl", 0, 1); | |
| 485 | + if( zAltBase ){ | |
| 486 | + set_base_url(zAltBase); | |
| 487 | + } | |
| 488 | + if ( find_option("localhost", 0, 0)!=0 ){ | |
| 489 | + flags |= HTTP_SERVER_LOCALHOST; | |
| 490 | + } | |
| 491 | + if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); | |
| 492 | + isUiCmd = g.argv[1][0]=='u'; | |
| 493 | + if( isUiCmd ){ | |
| 494 | + flags |= HTTP_SERVER_LOCALHOST; | |
| 495 | + g.useLocalauth = 1; | |
| 496 | + } | |
| 497 | + find_server_repository(isUiCmd && zNotFound==0); | |
| 498 | + if( zPort ){ | |
| 499 | + int i; | |
| 500 | + for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} | |
| 501 | + if( i>0 ){ | |
| 502 | + zIpAddr = mprintf("%.*s", i, zPort); | |
| 503 | + zPort += i+1; | |
| 504 | + } | |
| 505 | + iPort = mxPort = atoi(zPort); | |
| 506 | + }else{ | |
| 507 | + iPort = db_get_int("http-port", 8080); | |
| 508 | + mxPort = iPort+100; | |
| 509 | + } | |
| 510 | +#if !defined(_WIN32) | |
| 511 | + /* Unix implementation */ | |
| 512 | + if( isUiCmd ){ | |
| 513 | +#if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) | |
| 514 | + zBrowser = db_get("web-browser", 0); | |
| 515 | + if( zBrowser==0 ){ | |
| 516 | + static const char *const azBrowserProg[] = | |
| 517 | + { "xdg-open", "gnome-open", "firefox", "google-chrome" }; | |
| 518 | + int i; | |
| 519 | + zBrowser = "echo"; | |
| 520 | + for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ | |
| 521 | + if( binaryOnPath(azBrowserProg[i]) ){ | |
| 522 | + zBrowser = azBrowserProg[i]; | |
| 523 | + break; | |
| 524 | + } | |
| 525 | + } | |
| 526 | + } | |
| 527 | +#else | |
| 528 | + zBrowser = db_get("web-browser", "open"); | |
| 529 | +#endif | |
| 530 | + if( zIpAddr ){ | |
| 531 | + zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr); | |
| 532 | + }else{ | |
| 533 | + zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); | |
| 534 | + } | |
| 535 | + } | |
| 536 | + db_close(1); | |
| 537 | + if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ | |
| 538 | + fossil_fatal("unable to listen on TCP socket %d", iPort); | |
| 539 | + } | |
| 540 | + g.sslNotAvailable = 1; | |
| 541 | + g.httpIn = stdin; | |
| 542 | + g.httpOut = stdout; | |
| 543 | + if( g.fHttpTrace || g.fSqlTrace ){ | |
| 544 | + fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); | |
| 545 | + } | |
| 546 | + g.cgiOutput = 1; | |
| 547 | + find_server_repository(isUiCmd && zNotFound==0); | |
| 548 | + g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); | |
| 549 | + cgi_handle_http_request(0); | |
| 550 | + process_one_web_page(zNotFound, glob_create(zFileGlob)); | |
| 551 | +#else | |
| 552 | + /* Win32 implementation */ | |
| 553 | + if( isUiCmd ){ | |
| 554 | + zBrowser = db_get("web-browser", "start"); | |
| 555 | + if( zIpAddr ){ | |
| 556 | + zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr); | |
| 557 | + }else{ | |
| 558 | + zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); | |
| 559 | + } | |
| 560 | + } | |
| 561 | + db_close(1); | |
| 562 | + if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){ | |
| 563 | + win32_http_server(iPort, mxPort, zBrowserCmd, | |
| 564 | + zStopperFile, zNotFound, zFileGlob, zIpAddr, flags); | |
| 565 | + } | |
| 566 | +#endif | |
| 567 | +} |
| --- a/src/server.c | |
| +++ b/src/server.c | |
| @@ -0,0 +1,567 @@ | |
| --- a/src/server.c | |
| +++ b/src/server.c | |
| @@ -0,0 +1,567 @@ | |
| 1 | /* |
| 2 | ** Copyright (c) 2006 D. Richard Hipp |
| 3 | ** |
| 4 | ** This program is free software; you can redistribute it and/or |
| 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | ** |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but without any warranty; without even the implied warranty of |
| 10 | ** merchantability or fitness for a particular purpose. |
| 11 | ** |
| 12 | ** Author contact information: |
| 13 | ** [email protected] |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This module contains code to implement CGI, HTTP, SCGI, and FastCGI |
| 19 | ** servers. |
| 20 | */ |
| 21 | #include "config.h" |
| 22 | #include "server.h" |
| 23 | #include <sys/types.h> |
| 24 | #include <sys/stat.h> |
| 25 | #if defined(_WIN32) |
| 26 | # include <windows.h> |
| 27 | #else |
| 28 | # include <errno.h> /* errno global */ |
| 29 | #endif |
| 30 | |
| 31 | /* |
| 32 | ** If g.argv[2] exists then it is either the name of a repository |
| 33 | ** that will be used by a server, or else it is a directory that |
| 34 | ** contains multiple repositories that can be served. If g.argv[2] |
| 35 | ** is a directory, the repositories it contains must be named |
| 36 | ** "*.fossil". If g.argv[2] does not exists, then we must be within |
| 37 | ** a check-out and the repository to be served is the repository of |
| 38 | ** that check-out. |
| 39 | ** |
| 40 | ** Open the repository to be served if it is known. If g.argv[2] is |
| 41 | ** a directory full of repositories, then set g.zRepositoryName to |
| 42 | ** the name of that directory and the specific repository will be |
| 43 | ** opened later by process_one_web_page() based on the content of |
| 44 | ** the PATH_INFO variable. |
| 45 | ** |
| 46 | ** If disallowDir is set, then the directory full of repositories method |
| 47 | ** is disallowed. |
| 48 | */ |
| 49 | static void find_server_repository(int disallowDir){ |
| 50 | if( g.argc<3 ){ |
| 51 | db_must_be_within_tree(); |
| 52 | }else if( file_isdir(g.argv[2])==1 ){ |
| 53 | if( disallowDir ){ |
| 54 | fossil_fatal("\"%s\" is a directory, not a repository file", g.argv[2]); |
| 55 | }else{ |
| 56 | g.zRepositoryName = mprintf("%s", g.argv[2]); |
| 57 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 58 | } |
| 59 | }else{ |
| 60 | db_open_repository(g.argv[2]); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | #if !defined(_WIN32) |
| 65 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 66 | /* |
| 67 | ** Search for an executable on the PATH environment variable. |
| 68 | ** Return true (1) if found and false (0) if not found. |
| 69 | */ |
| 70 | static int binaryOnPath(const char *zBinary){ |
| 71 | const char *zPath = fossil_getenv("PATH"); |
| 72 | char *zFull; |
| 73 | int i; |
| 74 | int bExists; |
| 75 | while( zPath && zPath[0] ){ |
| 76 | while( zPath[0]==':' ) zPath++; |
| 77 | for(i=0; zPath[i] && zPath[i]!=':'; i++){} |
| 78 | zFull = mprintf("%.*s/%s", i, zPath, zBinary); |
| 79 | bExists = file_access(zFull, X_OK); |
| 80 | fossil_free(zFull); |
| 81 | if( bExists==0 ) return 1; |
| 82 | zPath += i; |
| 83 | } |
| 84 | return 0; |
| 85 | } |
| 86 | #endif |
| 87 | #endif |
| 88 | |
| 89 | /* |
| 90 | ** If running as root, chroot to the directory containing the |
| 91 | ** repository zRepo and then drop root privileges. Return the |
| 92 | ** new repository name. |
| 93 | ** |
| 94 | ** zRepo might be a directory itself. In that case chroot into |
| 95 | ** the directory zRepo. |
| 96 | ** |
| 97 | ** Assume the user-id and group-id of the repository, or if zRepo |
| 98 | ** is a directory, of that directory. |
| 99 | */ |
| 100 | char *enter_chroot_jail(char *zRepo){ |
| 101 | #if !defined(_WIN32) |
| 102 | if( getuid()==0 ){ |
| 103 | int i; |
| 104 | struct stat sStat; |
| 105 | Blob dir; |
| 106 | char *zDir; |
| 107 | |
| 108 | file_canonical_name(zRepo, &dir, 0); |
| 109 | zDir = blob_str(&dir); |
| 110 | if( file_isdir(zDir)==1 ){ |
| 111 | if( file_chdir(zDir, 1) ){ |
| 112 | fossil_fatal("unable to chroot into %s", zDir); |
| 113 | } |
| 114 | zRepo = "/"; |
| 115 | }else{ |
| 116 | for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){} |
| 117 | if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo); |
| 118 | if( i>0 ){ |
| 119 | zDir[i] = 0; |
| 120 | if( file_chdir(zDir, 1) ){ |
| 121 | fossil_fatal("unable to chroot into %s", zDir); |
| 122 | } |
| 123 | zDir[i] = '/'; |
| 124 | } |
| 125 | zRepo = &zDir[i]; |
| 126 | } |
| 127 | if( stat(zRepo, &sStat)!=0 ){ |
| 128 | fossil_fatal("cannot stat() repository: %s", zRepo); |
| 129 | } |
| 130 | i = setgid(sStat.st_gid); |
| 131 | i = i || setuid(sStat.st_uid); |
| 132 | if(i){ |
| 133 | fossil_fatal("setgid/uid() failed with errno %d", errno); |
| 134 | } |
| 135 | if( g.db!=0 ){ |
| 136 | db_close(1); |
| 137 | db_open_repository(zRepo); |
| 138 | } |
| 139 | } |
| 140 | #endif |
| 141 | return zRepo; |
| 142 | } |
| 143 | |
| 144 | /* If the CGI program contains one or more lines of the form |
| 145 | ** |
| 146 | ** redirect: repository-filename http://hostname/path/%s |
| 147 | ** |
| 148 | ** then control jumps here. Search each repository for an artifact ID |
| 149 | ** that matches the "name" CGI parameter and for the first match, |
| 150 | ** redirect to the corresponding URL with the "name" CGI parameter |
| 151 | ** inserted. Paint an error page if no match is found. |
| 152 | ** |
| 153 | ** If there is a line of the form: |
| 154 | ** |
| 155 | ** redirect: * URL |
| 156 | ** |
| 157 | ** Then a redirect is made to URL if no match is found. Otherwise a |
| 158 | ** very primitive error message is returned. |
| 159 | */ |
| 160 | static void redirect_web_page(int nRedirect, char **azRedirect){ |
| 161 | int i; /* Loop counter */ |
| 162 | const char *zNotFound = 0; /* Not found URL */ |
| 163 | const char *zName = P("name"); |
| 164 | set_base_url(0); |
| 165 | if( zName==0 ){ |
| 166 | zName = P("SCRIPT_NAME"); |
| 167 | if( zName && zName[0]=='/' ) zName++; |
| 168 | } |
| 169 | if( zName && validate16(zName, strlen(zName)) ){ |
| 170 | for(i=0; i<nRedirect; i++){ |
| 171 | if( fossil_strcmp(azRedirect[i*2],"*")==0 ){ |
| 172 | zNotFound = azRedirect[i*2+1]; |
| 173 | continue; |
| 174 | } |
| 175 | db_open_repository(azRedirect[i*2]); |
| 176 | if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){ |
| 177 | cgi_redirectf(azRedirect[i*2+1], zName); |
| 178 | return; |
| 179 | } |
| 180 | db_close(1); |
| 181 | } |
| 182 | } |
| 183 | if( zNotFound ){ |
| 184 | cgi_redirectf(zNotFound, zName); |
| 185 | }else{ |
| 186 | @ <html> |
| 187 | @ <head><title>No Such Object</title></head> |
| 188 | @ <body> |
| 189 | @ <p>No such object: <b>%h(zName)</b></p> |
| 190 | @ </body> |
| 191 | cgi_reply(); |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | /* |
| 196 | ** COMMAND: cgi* |
| 197 | ** |
| 198 | ** Usage: %fossil ?cgi? SCRIPT |
| 199 | ** |
| 200 | ** The SCRIPT argument is the name of a file that is the CGI script |
| 201 | ** that is being run. The command name, "cgi", may be omitted if |
| 202 | ** the GATEWAY_INTERFACE environment variable is set to "CGI" (which |
| 203 | ** should always be the case for CGI scripts run by a webserver.) The |
| 204 | ** SCRIPT file should look something like this: |
| 205 | ** |
| 206 | ** #!/usr/bin/fossil |
| 207 | ** repository: /home/somebody/project.db |
| 208 | ** |
| 209 | ** The second line defines the name of the repository. After locating |
| 210 | ** the repository, fossil will generate a webpage on stdout based on |
| 211 | ** the values of standard CGI environment variables. |
| 212 | ** |
| 213 | ** See also: http, server, winsrv |
| 214 | */ |
| 215 | void cmd_cgi(void){ |
| 216 | const char *zFile; |
| 217 | const char *zNotFound = 0; |
| 218 | char **azRedirect = 0; /* List of repositories to redirect to */ |
| 219 | int nRedirect = 0; /* Number of entries in azRedirect */ |
| 220 | Glob *pFileGlob = 0; /* Pattern for files */ |
| 221 | Blob config, line, key, value, value2; |
| 222 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 223 | zFile = g.argv[2]; |
| 224 | }else{ |
| 225 | zFile = g.argv[1]; |
| 226 | } |
| 227 | g.httpOut = stdout; |
| 228 | g.httpIn = stdin; |
| 229 | fossil_binary_mode(g.httpOut); |
| 230 | fossil_binary_mode(g.httpIn); |
| 231 | g.cgiOutput = 1; |
| 232 | blob_read_from_file(&config, zFile); |
| 233 | while( blob_line(&config, &line) ){ |
| 234 | if( !blob_token(&line, &key) ) continue; |
| 235 | if( blob_buffer(&key)[0]=='#' ) continue; |
| 236 | if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ |
| 237 | g.fDebug = fossil_fopen(blob_str(&value), "ab"); |
| 238 | blob_reset(&value); |
| 239 | continue; |
| 240 | } |
| 241 | if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){ |
| 242 | cgi_setenv("HOME", blob_str(&value)); |
| 243 | blob_reset(&value); |
| 244 | continue; |
| 245 | } |
| 246 | if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){ |
| 247 | blob_trim(&value); |
| 248 | db_open_repository(blob_str(&value)); |
| 249 | blob_reset(&value); |
| 250 | continue; |
| 251 | } |
| 252 | if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){ |
| 253 | db_close(1); |
| 254 | g.zRepositoryName = mprintf("%s", blob_str(&value)); |
| 255 | blob_reset(&value); |
| 256 | continue; |
| 257 | } |
| 258 | if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){ |
| 259 | zNotFound = mprintf("%s", blob_str(&value)); |
| 260 | blob_reset(&value); |
| 261 | continue; |
| 262 | } |
| 263 | if( blob_eq(&key, "localauth") ){ |
| 264 | g.useLocalauth = 1; |
| 265 | continue; |
| 266 | } |
| 267 | if( blob_eq(&key, "redirect:") && blob_token(&line, &value) |
| 268 | && blob_token(&line, &value2) ){ |
| 269 | nRedirect++; |
| 270 | azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*)); |
| 271 | azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value)); |
| 272 | azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2)); |
| 273 | blob_reset(&value); |
| 274 | blob_reset(&value2); |
| 275 | continue; |
| 276 | } |
| 277 | if( blob_eq(&key, "files:") && blob_token(&line, &value) ){ |
| 278 | pFileGlob = glob_create(blob_str(&value)); |
| 279 | continue; |
| 280 | } |
| 281 | } |
| 282 | blob_reset(&config); |
| 283 | if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){ |
| 284 | cgi_panic("Unable to find or open the project repository"); |
| 285 | } |
| 286 | cgi_init(); |
| 287 | if( nRedirect ){ |
| 288 | redirect_web_page(nRedirect, azRedirect); |
| 289 | }else{ |
| 290 | process_one_web_page(zNotFound, pFileGlob); |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | |
| 295 | /* |
| 296 | ** undocumented format: |
| 297 | ** |
| 298 | ** fossil http REPOSITORY INFILE OUTFILE IPADDR |
| 299 | ** |
| 300 | ** The argv==6 form is used by the win32 server only. |
| 301 | ** |
| 302 | ** COMMAND: http* |
| 303 | ** |
| 304 | ** Usage: %fossil http REPOSITORY ?OPTIONS? |
| 305 | ** |
| 306 | ** Handle a single HTTP request appearing on stdin. The resulting webpage |
| 307 | ** is delivered on stdout. This method is used to launch an HTTP request |
| 308 | ** handler from inetd, for example. The argument is the name of the |
| 309 | ** repository. |
| 310 | ** |
| 311 | ** If REPOSITORY is a directory that contains one or more repositories, |
| 312 | ** either directly in REPOSITORY itself, or in subdirectories, and |
| 313 | ** with names of the form "*.fossil" then the a prefix of the URL pathname |
| 314 | ** selects from among the various repositories. If the pathname does |
| 315 | ** not select a valid repository and the --notfound option is available, |
| 316 | ** then the server redirects (HTTP code 302) to the URL of --notfound. |
| 317 | ** When REPOSITORY is a directory, the pathname must contain only |
| 318 | ** alphanumerics, "_", "/", "-" and "." and no "-" may occur after a "/" |
| 319 | ** and every "." must be surrounded on both sides by alphanumerics or else |
| 320 | ** a 404 error is returned. Static content files in the directory are |
| 321 | ** returned if they match comma-separate GLOB pattern specified by --files |
| 322 | ** and do not match "*.fossil*" and have a well-known suffix. |
| 323 | ** |
| 324 | ** The --host option can be used to specify the hostname for the server. |
| 325 | ** The --https option indicates that the request came from HTTPS rather |
| 326 | ** than HTTP. If --nossl is given, then SSL connections will not be available, |
| 327 | ** thus also no redirecting from http: to https: will take place. |
| 328 | ** |
| 329 | ** If the --localauth option is given, then automatic login is performed |
| 330 | ** for requests coming from localhost, if the "localauth" setting is not |
| 331 | ** enabled. |
| 332 | ** |
| 333 | ** Options: |
| 334 | ** --localauth enable automatic login for local connections |
| 335 | ** --host NAME specify hostname of the server |
| 336 | ** --https signal a request coming in via https |
| 337 | ** --nossl signal that no SSL connections are available |
| 338 | ** --notfound URL use URL as "HTTP 404, object not found" page. |
| 339 | ** --files GLOB comma-separate glob patterns for static file to serve |
| 340 | ** --baseurl URL base URL (useful with reverse proxies) |
| 341 | ** |
| 342 | ** See also: cgi, server, winsrv |
| 343 | */ |
| 344 | void cmd_http(void){ |
| 345 | const char *zIpAddr; |
| 346 | const char *zNotFound; |
| 347 | const char *zHost; |
| 348 | const char *zAltBase; |
| 349 | const char *zFileGlob; |
| 350 | |
| 351 | /* The winhttp module passes the --files option as --files-urlenc with |
| 352 | ** the argument being URL encoded, to avoid wildcard expansion in the |
| 353 | ** shell. This option is for internal use and is undocumented. |
| 354 | */ |
| 355 | zFileGlob = find_option("files-urlenc",0,1); |
| 356 | if( zFileGlob ){ |
| 357 | char *z = mprintf("%s", zFileGlob); |
| 358 | dehttpize(z); |
| 359 | zFileGlob = z; |
| 360 | }else{ |
| 361 | zFileGlob = find_option("files",0,1); |
| 362 | } |
| 363 | zNotFound = find_option("notfound", 0, 1); |
| 364 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 365 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0; |
| 366 | zAltBase = find_option("baseurl", 0, 1); |
| 367 | if( zAltBase ) set_base_url(zAltBase); |
| 368 | if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on"); |
| 369 | zHost = find_option("host", 0, 1); |
| 370 | if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost); |
| 371 | g.cgiOutput = 1; |
| 372 | if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ |
| 373 | fossil_fatal("no repository specified"); |
| 374 | } |
| 375 | g.fullHttpReply = 1; |
| 376 | if( g.argc==6 ){ |
| 377 | g.httpIn = fossil_fopen(g.argv[3], "rb"); |
| 378 | g.httpOut = fossil_fopen(g.argv[4], "wb"); |
| 379 | zIpAddr = g.argv[5]; |
| 380 | }else{ |
| 381 | g.httpIn = stdin; |
| 382 | g.httpOut = stdout; |
| 383 | zIpAddr = 0; |
| 384 | } |
| 385 | find_server_repository(0); |
| 386 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); |
| 387 | cgi_handle_http_request(zIpAddr); |
| 388 | process_one_web_page(zNotFound, glob_create(zFileGlob)); |
| 389 | } |
| 390 | |
| 391 | /* |
| 392 | ** Note that the following command is used by ssh:// processing. |
| 393 | ** |
| 394 | ** COMMAND: test-http |
| 395 | ** Works like the http command but gives setup permission to all users. |
| 396 | */ |
| 397 | void cmd_test_http(void){ |
| 398 | Th_InitTraceLog(); |
| 399 | login_set_capabilities("sx", 0); |
| 400 | g.useLocalauth = 1; |
| 401 | cgi_set_parameter("REMOTE_ADDR", "127.0.0.1"); |
| 402 | g.httpIn = stdin; |
| 403 | g.httpOut = stdout; |
| 404 | find_server_repository(0); |
| 405 | g.cgiOutput = 1; |
| 406 | g.fullHttpReply = 1; |
| 407 | cgi_handle_http_request(0); |
| 408 | process_one_web_page(0, 0); |
| 409 | } |
| 410 | |
| 411 | |
| 412 | /* |
| 413 | ** COMMAND: server* |
| 414 | ** COMMAND: ui |
| 415 | ** |
| 416 | ** Usage: %fossil server ?OPTIONS? ?REPOSITORY? |
| 417 | ** Or: %fossil ui ?OPTIONS? ?REPOSITORY? |
| 418 | ** |
| 419 | ** Open a socket and begin listening and responding to HTTP requests on |
| 420 | ** TCP port 8080, or on any other TCP port defined by the -P or |
| 421 | ** --port option. The optional argument is the name of the repository. |
| 422 | ** The repository argument may be omitted if the working directory is |
| 423 | ** within an open checkout. |
| 424 | ** |
| 425 | ** The "ui" command automatically starts a web browser after initializing |
| 426 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 427 | ** only process HTTP traffic from the local machine. |
| 428 | ** |
| 429 | ** The REPOSITORY can be a directory (aka folder) that contains one or |
| 430 | ** more repositories with names ending in ".fossil". In this case, the |
| 431 | ** a prefix of the URL pathname is used to search the directory for an |
| 432 | ** appropriate repository. To thwart mischief, the pathname in the URL must |
| 433 | ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may |
| 434 | ** occur after "/", and every "." must be surrounded on both sides by |
| 435 | ** alphanumerics. Any pathname that does not satisfy these constraints |
| 436 | ** results in a 404 error. Files in REPOSITORY that match the comma-separated |
| 437 | ** list of glob patterns given by --files and that have known suffixes |
| 438 | ** such as ".txt" or ".html" or ".jpeg" and do not match the pattern |
| 439 | ** "*.fossil*" will be served as static content. With the "ui" command, |
| 440 | ** the REPOSITORY can only be a directory if the --notfound option is |
| 441 | ** also present. |
| 442 | ** |
| 443 | ** By default, the "ui" command provides full administrative access without |
| 444 | ** having to log in. This can be disabled by setting turning off the |
| 445 | ** "localauth" setting. Automatic login for the "server" command is available |
| 446 | ** if the --localauth option is present and the "localauth" setting is off |
| 447 | ** and the connection is from localhost. The optional REPOSITORY argument |
| 448 | ** to "ui" may be a directory and will function as "server" if and only if |
| 449 | ** the --notfound option is used. |
| 450 | ** |
| 451 | ** Options: |
| 452 | ** --localauth enable automatic login for requests from localhost |
| 453 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 454 | ** -P|--port TCPPORT listen to request on port TCPPORT |
| 455 | ** --th-trace trace TH1 execution (for debugging purposes) |
| 456 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 457 | ** --notfound URL Redirect |
| 458 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 459 | ** |
| 460 | ** See also: cgi, http, winsrv |
| 461 | */ |
| 462 | void cmd_webserver(void){ |
| 463 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 464 | const char *zPort; /* Value of the --port option */ |
| 465 | const char *zBrowser; /* Name of web browser program */ |
| 466 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 467 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 468 | const char *zNotFound; /* The --notfound option or NULL */ |
| 469 | int flags = 0; /* Server flags */ |
| 470 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 471 | const char *zFileGlob; /* Static content must match this */ |
| 472 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 473 | |
| 474 | #if defined(_WIN32) |
| 475 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 476 | zStopperFile = find_option("stopper", 0, 1); |
| 477 | #endif |
| 478 | |
| 479 | zFileGlob = find_option("files", 0, 1); |
| 480 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 481 | Th_InitTraceLog(); |
| 482 | zPort = find_option("port", "P", 1); |
| 483 | zNotFound = find_option("notfound", 0, 1); |
| 484 | zAltBase = find_option("baseurl", 0, 1); |
| 485 | if( zAltBase ){ |
| 486 | set_base_url(zAltBase); |
| 487 | } |
| 488 | if ( find_option("localhost", 0, 0)!=0 ){ |
| 489 | flags |= HTTP_SERVER_LOCALHOST; |
| 490 | } |
| 491 | if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); |
| 492 | isUiCmd = g.argv[1][0]=='u'; |
| 493 | if( isUiCmd ){ |
| 494 | flags |= HTTP_SERVER_LOCALHOST; |
| 495 | g.useLocalauth = 1; |
| 496 | } |
| 497 | find_server_repository(isUiCmd && zNotFound==0); |
| 498 | if( zPort ){ |
| 499 | int i; |
| 500 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 501 | if( i>0 ){ |
| 502 | zIpAddr = mprintf("%.*s", i, zPort); |
| 503 | zPort += i+1; |
| 504 | } |
| 505 | iPort = mxPort = atoi(zPort); |
| 506 | }else{ |
| 507 | iPort = db_get_int("http-port", 8080); |
| 508 | mxPort = iPort+100; |
| 509 | } |
| 510 | #if !defined(_WIN32) |
| 511 | /* Unix implementation */ |
| 512 | if( isUiCmd ){ |
| 513 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 514 | zBrowser = db_get("web-browser", 0); |
| 515 | if( zBrowser==0 ){ |
| 516 | static const char *const azBrowserProg[] = |
| 517 | { "xdg-open", "gnome-open", "firefox", "google-chrome" }; |
| 518 | int i; |
| 519 | zBrowser = "echo"; |
| 520 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 521 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 522 | zBrowser = azBrowserProg[i]; |
| 523 | break; |
| 524 | } |
| 525 | } |
| 526 | } |
| 527 | #else |
| 528 | zBrowser = db_get("web-browser", "open"); |
| 529 | #endif |
| 530 | if( zIpAddr ){ |
| 531 | zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr); |
| 532 | }else{ |
| 533 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 534 | } |
| 535 | } |
| 536 | db_close(1); |
| 537 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ |
| 538 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 539 | } |
| 540 | g.sslNotAvailable = 1; |
| 541 | g.httpIn = stdin; |
| 542 | g.httpOut = stdout; |
| 543 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 544 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 545 | } |
| 546 | g.cgiOutput = 1; |
| 547 | find_server_repository(isUiCmd && zNotFound==0); |
| 548 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); |
| 549 | cgi_handle_http_request(0); |
| 550 | process_one_web_page(zNotFound, glob_create(zFileGlob)); |
| 551 | #else |
| 552 | /* Win32 implementation */ |
| 553 | if( isUiCmd ){ |
| 554 | zBrowser = db_get("web-browser", "start"); |
| 555 | if( zIpAddr ){ |
| 556 | zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr); |
| 557 | }else{ |
| 558 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 559 | } |
| 560 | } |
| 561 | db_close(1); |
| 562 | if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){ |
| 563 | win32_http_server(iPort, mxPort, zBrowserCmd, |
| 564 | zStopperFile, zNotFound, zFileGlob, zIpAddr, flags); |
| 565 | } |
| 566 | #endif |
| 567 | } |
+10
-4
| --- win/Makefile.dmc | ||
| +++ win/Makefile.dmc | ||
| @@ -26,13 +26,13 @@ | ||
| 26 | 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 27 | 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 |
| 28 | 28 | |
| 29 | 29 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 30 | 30 | |
| 31 | -SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c | |
| 31 | +SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c server_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c | |
| 32 | 32 | |
| 33 | -OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O | |
| 33 | +OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\server$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O | |
| 34 | 34 | |
| 35 | 35 | |
| 36 | 36 | RC=$(DMDIR)\bin\rcc |
| 37 | 37 | RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ |
| 38 | 38 | |
| @@ -46,11 +46,11 @@ | ||
| 46 | 46 | |
| 47 | 47 | $(OBJDIR)\fossil.res: $B\win\fossil.rc |
| 48 | 48 | $(RC) $(RCFLAGS) -o$@ $** |
| 49 | 49 | |
| 50 | 50 | $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res |
| 51 | - +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path pivot popen pqueue printf rebuild regexp report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ | |
| 51 | + +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path pivot popen pqueue printf rebuild regexp report rss schema search server setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ | |
| 52 | 52 | +echo fossil >> $@ |
| 53 | 53 | +echo fossil >> $@ |
| 54 | 54 | +echo $(LIBS) >> $@ |
| 55 | 55 | +echo. >> $@ |
| 56 | 56 | +echo fossil >> $@ |
| @@ -566,10 +566,16 @@ | ||
| 566 | 566 | $(OBJDIR)\search$O : search_.c search.h |
| 567 | 567 | $(TCC) -o$@ -c search_.c |
| 568 | 568 | |
| 569 | 569 | search_.c : $(SRCDIR)\search.c |
| 570 | 570 | +translate$E $** > $@ |
| 571 | + | |
| 572 | +$(OBJDIR)\server$O : server_.c server.h | |
| 573 | + $(TCC) -o$@ -c server_.c | |
| 574 | + | |
| 575 | +server_.c : $(SRCDIR)\server.c | |
| 576 | + +translate$E $** > $@ | |
| 571 | 577 | |
| 572 | 578 | $(OBJDIR)\setup$O : setup_.c setup.h |
| 573 | 579 | $(TCC) -o$@ -c setup_.c |
| 574 | 580 | |
| 575 | 581 | setup_.c : $(SRCDIR)\setup.c |
| @@ -754,7 +760,7 @@ | ||
| 754 | 760 | |
| 755 | 761 | zip_.c : $(SRCDIR)\zip.c |
| 756 | 762 | +translate$E $** > $@ |
| 757 | 763 | |
| 758 | 764 | headers: makeheaders$E page_index.h VERSION.h |
| 759 | - +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h | |
| 765 | + +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h server_.c:server.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h | |
| 760 | 766 | @copy /Y nul: headers |
| 761 | 767 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -26,13 +26,13 @@ | |
| 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 |
| 28 | |
| 29 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 30 | |
| 31 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c |
| 32 | |
| 33 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 34 | |
| 35 | |
| 36 | RC=$(DMDIR)\bin\rcc |
| 37 | RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ |
| 38 | |
| @@ -46,11 +46,11 @@ | |
| 46 | |
| 47 | $(OBJDIR)\fossil.res: $B\win\fossil.rc |
| 48 | $(RC) $(RCFLAGS) -o$@ $** |
| 49 | |
| 50 | $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res |
| 51 | +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path pivot popen pqueue printf rebuild regexp report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ |
| 52 | +echo fossil >> $@ |
| 53 | +echo fossil >> $@ |
| 54 | +echo $(LIBS) >> $@ |
| 55 | +echo. >> $@ |
| 56 | +echo fossil >> $@ |
| @@ -566,10 +566,16 @@ | |
| 566 | $(OBJDIR)\search$O : search_.c search.h |
| 567 | $(TCC) -o$@ -c search_.c |
| 568 | |
| 569 | search_.c : $(SRCDIR)\search.c |
| 570 | +translate$E $** > $@ |
| 571 | |
| 572 | $(OBJDIR)\setup$O : setup_.c setup.h |
| 573 | $(TCC) -o$@ -c setup_.c |
| 574 | |
| 575 | setup_.c : $(SRCDIR)\setup.c |
| @@ -754,7 +760,7 @@ | |
| 754 | |
| 755 | zip_.c : $(SRCDIR)\zip.c |
| 756 | +translate$E $** > $@ |
| 757 | |
| 758 | headers: makeheaders$E page_index.h VERSION.h |
| 759 | +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h |
| 760 | @copy /Y nul: headers |
| 761 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -26,13 +26,13 @@ | |
| 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 |
| 28 | |
| 29 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 30 | |
| 31 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c server_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c |
| 32 | |
| 33 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\server$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 34 | |
| 35 | |
| 36 | RC=$(DMDIR)\bin\rcc |
| 37 | RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ |
| 38 | |
| @@ -46,11 +46,11 @@ | |
| 46 | |
| 47 | $(OBJDIR)\fossil.res: $B\win\fossil.rc |
| 48 | $(RC) $(RCFLAGS) -o$@ $** |
| 49 | |
| 50 | $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res |
| 51 | +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path pivot popen pqueue printf rebuild regexp report rss schema search server setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ |
| 52 | +echo fossil >> $@ |
| 53 | +echo fossil >> $@ |
| 54 | +echo $(LIBS) >> $@ |
| 55 | +echo. >> $@ |
| 56 | +echo fossil >> $@ |
| @@ -566,10 +566,16 @@ | |
| 566 | $(OBJDIR)\search$O : search_.c search.h |
| 567 | $(TCC) -o$@ -c search_.c |
| 568 | |
| 569 | search_.c : $(SRCDIR)\search.c |
| 570 | +translate$E $** > $@ |
| 571 | |
| 572 | $(OBJDIR)\server$O : server_.c server.h |
| 573 | $(TCC) -o$@ -c server_.c |
| 574 | |
| 575 | server_.c : $(SRCDIR)\server.c |
| 576 | +translate$E $** > $@ |
| 577 | |
| 578 | $(OBJDIR)\setup$O : setup_.c setup.h |
| 579 | $(TCC) -o$@ -c setup_.c |
| 580 | |
| 581 | setup_.c : $(SRCDIR)\setup.c |
| @@ -754,7 +760,7 @@ | |
| 760 | |
| 761 | zip_.c : $(SRCDIR)\zip.c |
| 762 | +translate$E $** > $@ |
| 763 | |
| 764 | headers: makeheaders$E page_index.h VERSION.h |
| 765 | +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h server_.c:server.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h |
| 766 | @copy /Y nul: headers |
| 767 |
+12
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -319,10 +319,11 @@ | ||
| 319 | 319 | $(SRCDIR)/regexp.c \ |
| 320 | 320 | $(SRCDIR)/report.c \ |
| 321 | 321 | $(SRCDIR)/rss.c \ |
| 322 | 322 | $(SRCDIR)/schema.c \ |
| 323 | 323 | $(SRCDIR)/search.c \ |
| 324 | + $(SRCDIR)/server.c \ | |
| 324 | 325 | $(SRCDIR)/setup.c \ |
| 325 | 326 | $(SRCDIR)/sha1.c \ |
| 326 | 327 | $(SRCDIR)/shun.c \ |
| 327 | 328 | $(SRCDIR)/skins.c \ |
| 328 | 329 | $(SRCDIR)/sqlcmd.c \ |
| @@ -428,10 +429,11 @@ | ||
| 428 | 429 | $(OBJDIR)/regexp_.c \ |
| 429 | 430 | $(OBJDIR)/report_.c \ |
| 430 | 431 | $(OBJDIR)/rss_.c \ |
| 431 | 432 | $(OBJDIR)/schema_.c \ |
| 432 | 433 | $(OBJDIR)/search_.c \ |
| 434 | + $(OBJDIR)/server_.c \ | |
| 433 | 435 | $(OBJDIR)/setup_.c \ |
| 434 | 436 | $(OBJDIR)/sha1_.c \ |
| 435 | 437 | $(OBJDIR)/shun_.c \ |
| 436 | 438 | $(OBJDIR)/skins_.c \ |
| 437 | 439 | $(OBJDIR)/sqlcmd_.c \ |
| @@ -537,10 +539,11 @@ | ||
| 537 | 539 | $(OBJDIR)/regexp.o \ |
| 538 | 540 | $(OBJDIR)/report.o \ |
| 539 | 541 | $(OBJDIR)/rss.o \ |
| 540 | 542 | $(OBJDIR)/schema.o \ |
| 541 | 543 | $(OBJDIR)/search.o \ |
| 544 | + $(OBJDIR)/server.o \ | |
| 542 | 545 | $(OBJDIR)/setup.o \ |
| 543 | 546 | $(OBJDIR)/sha1.o \ |
| 544 | 547 | $(OBJDIR)/shun.o \ |
| 545 | 548 | $(OBJDIR)/skins.o \ |
| 546 | 549 | $(OBJDIR)/sqlcmd.o \ |
| @@ -759,10 +762,11 @@ | ||
| 759 | 762 | $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ |
| 760 | 763 | $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ |
| 761 | 764 | $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ |
| 762 | 765 | $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ |
| 763 | 766 | $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ |
| 767 | + $(OBJDIR)/server_.c:$(OBJDIR)/server.h \ | |
| 764 | 768 | $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ |
| 765 | 769 | $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ |
| 766 | 770 | $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h \ |
| 767 | 771 | $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \ |
| 768 | 772 | $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \ |
| @@ -1406,10 +1410,18 @@ | ||
| 1406 | 1410 | |
| 1407 | 1411 | $(OBJDIR)/search.o: $(OBJDIR)/search_.c $(OBJDIR)/search.h $(SRCDIR)/config.h |
| 1408 | 1412 | $(XTCC) -o $(OBJDIR)/search.o -c $(OBJDIR)/search_.c |
| 1409 | 1413 | |
| 1410 | 1414 | $(OBJDIR)/search.h: $(OBJDIR)/headers |
| 1415 | + | |
| 1416 | +$(OBJDIR)/server_.c: $(SRCDIR)/server.c $(OBJDIR)/translate | |
| 1417 | + $(TRANSLATE) $(SRCDIR)/server.c >$(OBJDIR)/server_.c | |
| 1418 | + | |
| 1419 | +$(OBJDIR)/server.o: $(OBJDIR)/server_.c $(OBJDIR)/server.h $(SRCDIR)/config.h | |
| 1420 | + $(XTCC) -o $(OBJDIR)/server.o -c $(OBJDIR)/server_.c | |
| 1421 | + | |
| 1422 | +$(OBJDIR)/server.h: $(OBJDIR)/headers | |
| 1411 | 1423 | |
| 1412 | 1424 | $(OBJDIR)/setup_.c: $(SRCDIR)/setup.c $(OBJDIR)/translate |
| 1413 | 1425 | $(TRANSLATE) $(SRCDIR)/setup.c >$(OBJDIR)/setup_.c |
| 1414 | 1426 | |
| 1415 | 1427 | $(OBJDIR)/setup.o: $(OBJDIR)/setup_.c $(OBJDIR)/setup.h $(SRCDIR)/config.h |
| 1416 | 1428 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -319,10 +319,11 @@ | |
| 319 | $(SRCDIR)/regexp.c \ |
| 320 | $(SRCDIR)/report.c \ |
| 321 | $(SRCDIR)/rss.c \ |
| 322 | $(SRCDIR)/schema.c \ |
| 323 | $(SRCDIR)/search.c \ |
| 324 | $(SRCDIR)/setup.c \ |
| 325 | $(SRCDIR)/sha1.c \ |
| 326 | $(SRCDIR)/shun.c \ |
| 327 | $(SRCDIR)/skins.c \ |
| 328 | $(SRCDIR)/sqlcmd.c \ |
| @@ -428,10 +429,11 @@ | |
| 428 | $(OBJDIR)/regexp_.c \ |
| 429 | $(OBJDIR)/report_.c \ |
| 430 | $(OBJDIR)/rss_.c \ |
| 431 | $(OBJDIR)/schema_.c \ |
| 432 | $(OBJDIR)/search_.c \ |
| 433 | $(OBJDIR)/setup_.c \ |
| 434 | $(OBJDIR)/sha1_.c \ |
| 435 | $(OBJDIR)/shun_.c \ |
| 436 | $(OBJDIR)/skins_.c \ |
| 437 | $(OBJDIR)/sqlcmd_.c \ |
| @@ -537,10 +539,11 @@ | |
| 537 | $(OBJDIR)/regexp.o \ |
| 538 | $(OBJDIR)/report.o \ |
| 539 | $(OBJDIR)/rss.o \ |
| 540 | $(OBJDIR)/schema.o \ |
| 541 | $(OBJDIR)/search.o \ |
| 542 | $(OBJDIR)/setup.o \ |
| 543 | $(OBJDIR)/sha1.o \ |
| 544 | $(OBJDIR)/shun.o \ |
| 545 | $(OBJDIR)/skins.o \ |
| 546 | $(OBJDIR)/sqlcmd.o \ |
| @@ -759,10 +762,11 @@ | |
| 759 | $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ |
| 760 | $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ |
| 761 | $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ |
| 762 | $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ |
| 763 | $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ |
| 764 | $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ |
| 765 | $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ |
| 766 | $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h \ |
| 767 | $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \ |
| 768 | $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \ |
| @@ -1406,10 +1410,18 @@ | |
| 1406 | |
| 1407 | $(OBJDIR)/search.o: $(OBJDIR)/search_.c $(OBJDIR)/search.h $(SRCDIR)/config.h |
| 1408 | $(XTCC) -o $(OBJDIR)/search.o -c $(OBJDIR)/search_.c |
| 1409 | |
| 1410 | $(OBJDIR)/search.h: $(OBJDIR)/headers |
| 1411 | |
| 1412 | $(OBJDIR)/setup_.c: $(SRCDIR)/setup.c $(OBJDIR)/translate |
| 1413 | $(TRANSLATE) $(SRCDIR)/setup.c >$(OBJDIR)/setup_.c |
| 1414 | |
| 1415 | $(OBJDIR)/setup.o: $(OBJDIR)/setup_.c $(OBJDIR)/setup.h $(SRCDIR)/config.h |
| 1416 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -319,10 +319,11 @@ | |
| 319 | $(SRCDIR)/regexp.c \ |
| 320 | $(SRCDIR)/report.c \ |
| 321 | $(SRCDIR)/rss.c \ |
| 322 | $(SRCDIR)/schema.c \ |
| 323 | $(SRCDIR)/search.c \ |
| 324 | $(SRCDIR)/server.c \ |
| 325 | $(SRCDIR)/setup.c \ |
| 326 | $(SRCDIR)/sha1.c \ |
| 327 | $(SRCDIR)/shun.c \ |
| 328 | $(SRCDIR)/skins.c \ |
| 329 | $(SRCDIR)/sqlcmd.c \ |
| @@ -428,10 +429,11 @@ | |
| 429 | $(OBJDIR)/regexp_.c \ |
| 430 | $(OBJDIR)/report_.c \ |
| 431 | $(OBJDIR)/rss_.c \ |
| 432 | $(OBJDIR)/schema_.c \ |
| 433 | $(OBJDIR)/search_.c \ |
| 434 | $(OBJDIR)/server_.c \ |
| 435 | $(OBJDIR)/setup_.c \ |
| 436 | $(OBJDIR)/sha1_.c \ |
| 437 | $(OBJDIR)/shun_.c \ |
| 438 | $(OBJDIR)/skins_.c \ |
| 439 | $(OBJDIR)/sqlcmd_.c \ |
| @@ -537,10 +539,11 @@ | |
| 539 | $(OBJDIR)/regexp.o \ |
| 540 | $(OBJDIR)/report.o \ |
| 541 | $(OBJDIR)/rss.o \ |
| 542 | $(OBJDIR)/schema.o \ |
| 543 | $(OBJDIR)/search.o \ |
| 544 | $(OBJDIR)/server.o \ |
| 545 | $(OBJDIR)/setup.o \ |
| 546 | $(OBJDIR)/sha1.o \ |
| 547 | $(OBJDIR)/shun.o \ |
| 548 | $(OBJDIR)/skins.o \ |
| 549 | $(OBJDIR)/sqlcmd.o \ |
| @@ -759,10 +762,11 @@ | |
| 762 | $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ |
| 763 | $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ |
| 764 | $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ |
| 765 | $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ |
| 766 | $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ |
| 767 | $(OBJDIR)/server_.c:$(OBJDIR)/server.h \ |
| 768 | $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ |
| 769 | $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ |
| 770 | $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h \ |
| 771 | $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \ |
| 772 | $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \ |
| @@ -1406,10 +1410,18 @@ | |
| 1410 | |
| 1411 | $(OBJDIR)/search.o: $(OBJDIR)/search_.c $(OBJDIR)/search.h $(SRCDIR)/config.h |
| 1412 | $(XTCC) -o $(OBJDIR)/search.o -c $(OBJDIR)/search_.c |
| 1413 | |
| 1414 | $(OBJDIR)/search.h: $(OBJDIR)/headers |
| 1415 | |
| 1416 | $(OBJDIR)/server_.c: $(SRCDIR)/server.c $(OBJDIR)/translate |
| 1417 | $(TRANSLATE) $(SRCDIR)/server.c >$(OBJDIR)/server_.c |
| 1418 | |
| 1419 | $(OBJDIR)/server.o: $(OBJDIR)/server_.c $(OBJDIR)/server.h $(SRCDIR)/config.h |
| 1420 | $(XTCC) -o $(OBJDIR)/server.o -c $(OBJDIR)/server_.c |
| 1421 | |
| 1422 | $(OBJDIR)/server.h: $(OBJDIR)/headers |
| 1423 | |
| 1424 | $(OBJDIR)/setup_.c: $(SRCDIR)/setup.c $(OBJDIR)/translate |
| 1425 | $(TRANSLATE) $(SRCDIR)/setup.c >$(OBJDIR)/setup_.c |
| 1426 | |
| 1427 | $(OBJDIR)/setup.o: $(OBJDIR)/setup_.c $(OBJDIR)/setup.h $(SRCDIR)/config.h |
| 1428 |
+10
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -137,10 +137,11 @@ | ||
| 137 | 137 | regexp_.c \ |
| 138 | 138 | report_.c \ |
| 139 | 139 | rss_.c \ |
| 140 | 140 | schema_.c \ |
| 141 | 141 | search_.c \ |
| 142 | + server_.c \ | |
| 142 | 143 | setup_.c \ |
| 143 | 144 | sha1_.c \ |
| 144 | 145 | shun_.c \ |
| 145 | 146 | skins_.c \ |
| 146 | 147 | sqlcmd_.c \ |
| @@ -246,10 +247,11 @@ | ||
| 246 | 247 | $(OX)\regexp$O \ |
| 247 | 248 | $(OX)\report$O \ |
| 248 | 249 | $(OX)\rss$O \ |
| 249 | 250 | $(OX)\schema$O \ |
| 250 | 251 | $(OX)\search$O \ |
| 252 | + $(OX)\server$O \ | |
| 251 | 253 | $(OX)\setup$O \ |
| 252 | 254 | $(OX)\sha1$O \ |
| 253 | 255 | $(OX)\shell$O \ |
| 254 | 256 | $(OX)\shun$O \ |
| 255 | 257 | $(OX)\skins$O \ |
| @@ -373,10 +375,11 @@ | ||
| 373 | 375 | echo $(OX)\regexp.obj >> $@ |
| 374 | 376 | echo $(OX)\report.obj >> $@ |
| 375 | 377 | echo $(OX)\rss.obj >> $@ |
| 376 | 378 | echo $(OX)\schema.obj >> $@ |
| 377 | 379 | echo $(OX)\search.obj >> $@ |
| 380 | + echo $(OX)\server.obj >> $@ | |
| 378 | 381 | echo $(OX)\setup.obj >> $@ |
| 379 | 382 | echo $(OX)\sha1.obj >> $@ |
| 380 | 383 | echo $(OX)\shell.obj >> $@ |
| 381 | 384 | echo $(OX)\shun.obj >> $@ |
| 382 | 385 | echo $(OX)\skins.obj >> $@ |
| @@ -938,10 +941,16 @@ | ||
| 938 | 941 | $(OX)\search$O : search_.c search.h |
| 939 | 942 | $(TCC) /Fo$@ -c search_.c |
| 940 | 943 | |
| 941 | 944 | search_.c : $(SRCDIR)\search.c |
| 942 | 945 | translate$E $** > $@ |
| 946 | + | |
| 947 | +$(OX)\server$O : server_.c server.h | |
| 948 | + $(TCC) /Fo$@ -c server_.c | |
| 949 | + | |
| 950 | +server_.c : $(SRCDIR)\server.c | |
| 951 | + translate$E $** > $@ | |
| 943 | 952 | |
| 944 | 953 | $(OX)\setup$O : setup_.c setup.h |
| 945 | 954 | $(TCC) /Fo$@ -c setup_.c |
| 946 | 955 | |
| 947 | 956 | setup_.c : $(SRCDIR)\setup.c |
| @@ -1204,10 +1213,11 @@ | ||
| 1204 | 1213 | regexp_.c:regexp.h \ |
| 1205 | 1214 | report_.c:report.h \ |
| 1206 | 1215 | rss_.c:rss.h \ |
| 1207 | 1216 | schema_.c:schema.h \ |
| 1208 | 1217 | search_.c:search.h \ |
| 1218 | + server_.c:server.h \ | |
| 1209 | 1219 | setup_.c:setup.h \ |
| 1210 | 1220 | sha1_.c:sha1.h \ |
| 1211 | 1221 | shun_.c:shun.h \ |
| 1212 | 1222 | skins_.c:skins.h \ |
| 1213 | 1223 | sqlcmd_.c:sqlcmd.h \ |
| 1214 | 1224 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -137,10 +137,11 @@ | |
| 137 | regexp_.c \ |
| 138 | report_.c \ |
| 139 | rss_.c \ |
| 140 | schema_.c \ |
| 141 | search_.c \ |
| 142 | setup_.c \ |
| 143 | sha1_.c \ |
| 144 | shun_.c \ |
| 145 | skins_.c \ |
| 146 | sqlcmd_.c \ |
| @@ -246,10 +247,11 @@ | |
| 246 | $(OX)\regexp$O \ |
| 247 | $(OX)\report$O \ |
| 248 | $(OX)\rss$O \ |
| 249 | $(OX)\schema$O \ |
| 250 | $(OX)\search$O \ |
| 251 | $(OX)\setup$O \ |
| 252 | $(OX)\sha1$O \ |
| 253 | $(OX)\shell$O \ |
| 254 | $(OX)\shun$O \ |
| 255 | $(OX)\skins$O \ |
| @@ -373,10 +375,11 @@ | |
| 373 | echo $(OX)\regexp.obj >> $@ |
| 374 | echo $(OX)\report.obj >> $@ |
| 375 | echo $(OX)\rss.obj >> $@ |
| 376 | echo $(OX)\schema.obj >> $@ |
| 377 | echo $(OX)\search.obj >> $@ |
| 378 | echo $(OX)\setup.obj >> $@ |
| 379 | echo $(OX)\sha1.obj >> $@ |
| 380 | echo $(OX)\shell.obj >> $@ |
| 381 | echo $(OX)\shun.obj >> $@ |
| 382 | echo $(OX)\skins.obj >> $@ |
| @@ -938,10 +941,16 @@ | |
| 938 | $(OX)\search$O : search_.c search.h |
| 939 | $(TCC) /Fo$@ -c search_.c |
| 940 | |
| 941 | search_.c : $(SRCDIR)\search.c |
| 942 | translate$E $** > $@ |
| 943 | |
| 944 | $(OX)\setup$O : setup_.c setup.h |
| 945 | $(TCC) /Fo$@ -c setup_.c |
| 946 | |
| 947 | setup_.c : $(SRCDIR)\setup.c |
| @@ -1204,10 +1213,11 @@ | |
| 1204 | regexp_.c:regexp.h \ |
| 1205 | report_.c:report.h \ |
| 1206 | rss_.c:rss.h \ |
| 1207 | schema_.c:schema.h \ |
| 1208 | search_.c:search.h \ |
| 1209 | setup_.c:setup.h \ |
| 1210 | sha1_.c:sha1.h \ |
| 1211 | shun_.c:shun.h \ |
| 1212 | skins_.c:skins.h \ |
| 1213 | sqlcmd_.c:sqlcmd.h \ |
| 1214 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -137,10 +137,11 @@ | |
| 137 | regexp_.c \ |
| 138 | report_.c \ |
| 139 | rss_.c \ |
| 140 | schema_.c \ |
| 141 | search_.c \ |
| 142 | server_.c \ |
| 143 | setup_.c \ |
| 144 | sha1_.c \ |
| 145 | shun_.c \ |
| 146 | skins_.c \ |
| 147 | sqlcmd_.c \ |
| @@ -246,10 +247,11 @@ | |
| 247 | $(OX)\regexp$O \ |
| 248 | $(OX)\report$O \ |
| 249 | $(OX)\rss$O \ |
| 250 | $(OX)\schema$O \ |
| 251 | $(OX)\search$O \ |
| 252 | $(OX)\server$O \ |
| 253 | $(OX)\setup$O \ |
| 254 | $(OX)\sha1$O \ |
| 255 | $(OX)\shell$O \ |
| 256 | $(OX)\shun$O \ |
| 257 | $(OX)\skins$O \ |
| @@ -373,10 +375,11 @@ | |
| 375 | echo $(OX)\regexp.obj >> $@ |
| 376 | echo $(OX)\report.obj >> $@ |
| 377 | echo $(OX)\rss.obj >> $@ |
| 378 | echo $(OX)\schema.obj >> $@ |
| 379 | echo $(OX)\search.obj >> $@ |
| 380 | echo $(OX)\server.obj >> $@ |
| 381 | echo $(OX)\setup.obj >> $@ |
| 382 | echo $(OX)\sha1.obj >> $@ |
| 383 | echo $(OX)\shell.obj >> $@ |
| 384 | echo $(OX)\shun.obj >> $@ |
| 385 | echo $(OX)\skins.obj >> $@ |
| @@ -938,10 +941,16 @@ | |
| 941 | $(OX)\search$O : search_.c search.h |
| 942 | $(TCC) /Fo$@ -c search_.c |
| 943 | |
| 944 | search_.c : $(SRCDIR)\search.c |
| 945 | translate$E $** > $@ |
| 946 | |
| 947 | $(OX)\server$O : server_.c server.h |
| 948 | $(TCC) /Fo$@ -c server_.c |
| 949 | |
| 950 | server_.c : $(SRCDIR)\server.c |
| 951 | translate$E $** > $@ |
| 952 | |
| 953 | $(OX)\setup$O : setup_.c setup.h |
| 954 | $(TCC) /Fo$@ -c setup_.c |
| 955 | |
| 956 | setup_.c : $(SRCDIR)\setup.c |
| @@ -1204,10 +1213,11 @@ | |
| 1213 | regexp_.c:regexp.h \ |
| 1214 | report_.c:report.h \ |
| 1215 | rss_.c:rss.h \ |
| 1216 | schema_.c:schema.h \ |
| 1217 | search_.c:search.h \ |
| 1218 | server_.c:server.h \ |
| 1219 | setup_.c:setup.h \ |
| 1220 | sha1_.c:sha1.h \ |
| 1221 | shun_.c:shun.h \ |
| 1222 | skins_.c:skins.h \ |
| 1223 | sqlcmd_.c:sqlcmd.h \ |
| 1224 |