Fossil SCM

Enhancements to unix-domain socket support for "fossil server": (1) Change the command-line option to "--socket-name FILENAME" for creating the unix socket. (It was formerly --unix-socket.) (2) Add new command-line options "--socket-mode MODE" and "--socket-owner USER" or "... USER:GROUP" to set permissions and ownership on the new socket. (3) Attempt to unlink the socket from the filesystem upon exit.

drh 2024-08-06 20:39 trunk merge
Commit effdadadd0cbef4ef987e87b51d8962f64575753e3561a9161c77f3d1347ca68
3 files changed +46 -19 +67 +39 -10
+46 -19
--- src/cgi.c
+++ src/cgi.c
@@ -2477,11 +2477,11 @@
24772477
#define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
24782478
#define HTTP_SERVER_HAD_REPOSITORY 0x0004 /* Was the repository open? */
24792479
#define HTTP_SERVER_HAD_CHECKOUT 0x0008 /* Was a checkout open? */
24802480
#define HTTP_SERVER_REPOLIST 0x0010 /* Allow repo listing */
24812481
#define HTTP_SERVER_NOFORK 0x0020 /* Do not call fork() */
2482
-#define HTTP_SERVER_UNIXDOMAINSOCK 0x0040 /* Use a unix-domain socket */
2482
+#define HTTP_SERVER_UNIXSOCKET 0x0040 /* Use a unix-domain socket */
24832483
24842484
#endif /* INTERFACE */
24852485
24862486
/*
24872487
** Maximum number of child processes that we can have running
@@ -2524,23 +2524,43 @@
25242524
int opt = 1; /* setsockopt flag */
25252525
int rc; /* Result code from system calls */
25262526
int iPort = mnPort; /* Port to try to use */
25272527
25282528
while( iPort<=mxPort ){
2529
- if( flags & HTTP_SERVER_UNIXDOMAINSOCK ){
2529
+ if( flags & HTTP_SERVER_UNIXSOCKET ){
2530
+ /* Initialize a Unix socket named g.zSockName */
2531
+ assert( g.zSockName!=0 );
25302532
memset(&uxaddr, 0, sizeof(uxaddr));
2531
- if( strlen(zIpAddr)>sizeof(uxaddr.sun_path) ){
2532
- fossil_fatal("name of unix-domain socket too big: %s\n"
2533
- "max size: %d\n", zIpAddr, (int)sizeof(uxaddr.sun_path));
2533
+ if( strlen(g.zSockName)>sizeof(uxaddr.sun_path) ){
2534
+ fossil_fatal("name of unix socket too big: %s\nmax size: %d\n",
2535
+ g.zSockName, (int)sizeof(uxaddr.sun_path));
25342536
}
2535
- if( unlink(zIpAddr)==-1 && errno!=ENOENT ){
2536
- fossil_fatal("Cannot remove existing file at %s\n", zIpAddr);
2537
+ if( file_isdir(g.zSockName, ExtFILE)!=0 ){
2538
+ if( !file_issocket(g.zSockName) ){
2539
+ fossil_fatal("cannot name socket \"%s\" because another object"
2540
+ " with that name already exists", g.zSockName);
2541
+ }else{
2542
+ unlink(g.zSockName);
2543
+ }
25372544
}
25382545
uxaddr.sun_family = AF_UNIX;
2539
- strncpy(uxaddr.sun_path, zIpAddr, sizeof(uxaddr.sun_path)-1);
2546
+ strncpy(uxaddr.sun_path, g.zSockName, sizeof(uxaddr.sun_path)-1);
25402547
listener = socket(AF_UNIX, SOCK_STREAM, 0);
2548
+ if( listener<0 ){
2549
+ fossil_fatal("unable to create a unix socket named %s",
2550
+ g.zSockName);
2551
+ }
2552
+ /* Set the access permission for the new socket. Default to 0660.
2553
+ ** But use an alternative specified by --socket-mode if available.
2554
+ ** Do this before bind() to avoid a race condition. */
2555
+ if( g.zSockMode ){
2556
+ file_set_mode(g.zSockName, listener, g.zSockMode, 0);
2557
+ }else{
2558
+ file_set_mode(g.zSockName, listener, "0660", 1);
2559
+ }
25412560
}else{
2561
+ /* Initialize a TCP/IP socket on port iPort */
25422562
memset(&inaddr, 0, sizeof(inaddr));
25432563
inaddr.sin_family = AF_INET;
25442564
if( zIpAddr ){
25452565
inaddr.sin_addr.s_addr = inet_addr(zIpAddr);
25462566
if( inaddr.sin_addr.s_addr == INADDR_NONE ){
@@ -2551,21 +2571,28 @@
25512571
}else{
25522572
inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
25532573
}
25542574
inaddr.sin_port = htons(iPort);
25552575
listener = socket(AF_INET, SOCK_STREAM, 0);
2556
- }
2557
- if( listener<0 ){
2558
- iPort++;
2559
- continue;
2576
+ if( listener<0 ){
2577
+ iPort++;
2578
+ continue;
2579
+ }
25602580
}
25612581
25622582
/* if we can't terminate nicely, at least allow the socket to be reused */
25632583
setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
25642584
2565
- if( flags & HTTP_SERVER_UNIXDOMAINSOCK ){
2585
+ if( flags & HTTP_SERVER_UNIXSOCKET ){
25662586
rc = bind(listener, (struct sockaddr*)&uxaddr, sizeof(uxaddr));
2587
+ /* Set the owner of the socket if requested by --socket-owner. This
2588
+ ** must wait until after bind(), after the filesystem object has been
2589
+ ** created. See https://lkml.org/lkml/2004/11/1/84 and
2590
+ ** https://fossil-scm.org/forum/forumpost/7517680ef9684c57 */
2591
+ if( g.zSockOwner ){
2592
+ file_set_owner(g.zSockName, listener, g.zSockOwner);
2593
+ }
25672594
}else{
25682595
rc = bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr));
25692596
}
25702597
if( rc<0 ){
25712598
close(listener);
@@ -2573,32 +2600,32 @@
25732600
continue;
25742601
}
25752602
break;
25762603
}
25772604
if( iPort>mxPort ){
2578
- if( flags & HTTP_SERVER_UNIXDOMAINSOCK ){
2579
- fossil_fatal("unable to listen on unix-domain socket %s", zIpAddr);
2605
+ if( flags & HTTP_SERVER_UNIXSOCKET ){
2606
+ fossil_fatal("unable to listen on unix socket %s", zIpAddr);
25802607
}else if( mnPort==mxPort ){
25812608
fossil_fatal("unable to open listening socket on port %d", mnPort);
25822609
}else{
25832610
fossil_fatal("unable to open listening socket on any"
25842611
" port in the range %d..%d", mnPort, mxPort);
25852612
}
25862613
}
25872614
if( iPort>mxPort ) return 1;
25882615
listen(listener,10);
2589
- if( flags & HTTP_SERVER_UNIXDOMAINSOCK ){
2590
- fossil_print("Listening for %s requests on unix-domain socket %s\n",
2616
+ if( flags & HTTP_SERVER_UNIXSOCKET ){
2617
+ fossil_print("Listening for %s requests on unix socket %s\n",
25912618
(flags & HTTP_SERVER_SCGI)!=0 ? "SCGI" :
2592
- g.httpUseSSL?"TLS-encrypted HTTPS":"HTTP", zIpAddr);
2619
+ g.httpUseSSL?"TLS-encrypted HTTPS":"HTTP", g.zSockName);
25932620
}else{
25942621
fossil_print("Listening for %s requests on TCP port %d\n",
25952622
(flags & HTTP_SERVER_SCGI)!=0 ? "SCGI" :
25962623
g.httpUseSSL?"TLS-encrypted HTTPS":"HTTP", iPort);
25972624
}
25982625
fflush(stdout);
2599
- if( zBrowser && (flags & HTTP_SERVER_UNIXDOMAINSOCK)==0 ){
2626
+ if( zBrowser && (flags & HTTP_SERVER_UNIXSOCKET)==0 ){
26002627
assert( strstr(zBrowser,"%d")!=0 );
26012628
zBrowser = mprintf(zBrowser /*works-like:"%d"*/, iPort);
26022629
#if defined(__CYGWIN__)
26032630
/* On Cygwin, we can do better than "echo" */
26042631
if( fossil_strncmp(zBrowser, "echo ", 5)==0 ){
26052632
--- src/cgi.c
+++ src/cgi.c
@@ -2477,11 +2477,11 @@
2477 #define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
2478 #define HTTP_SERVER_HAD_REPOSITORY 0x0004 /* Was the repository open? */
2479 #define HTTP_SERVER_HAD_CHECKOUT 0x0008 /* Was a checkout open? */
2480 #define HTTP_SERVER_REPOLIST 0x0010 /* Allow repo listing */
2481 #define HTTP_SERVER_NOFORK 0x0020 /* Do not call fork() */
2482 #define HTTP_SERVER_UNIXDOMAINSOCK 0x0040 /* Use a unix-domain socket */
2483
2484 #endif /* INTERFACE */
2485
2486 /*
2487 ** Maximum number of child processes that we can have running
@@ -2524,23 +2524,43 @@
2524 int opt = 1; /* setsockopt flag */
2525 int rc; /* Result code from system calls */
2526 int iPort = mnPort; /* Port to try to use */
2527
2528 while( iPort<=mxPort ){
2529 if( flags & HTTP_SERVER_UNIXDOMAINSOCK ){
 
 
2530 memset(&uxaddr, 0, sizeof(uxaddr));
2531 if( strlen(zIpAddr)>sizeof(uxaddr.sun_path) ){
2532 fossil_fatal("name of unix-domain socket too big: %s\n"
2533 "max size: %d\n", zIpAddr, (int)sizeof(uxaddr.sun_path));
2534 }
2535 if( unlink(zIpAddr)==-1 && errno!=ENOENT ){
2536 fossil_fatal("Cannot remove existing file at %s\n", zIpAddr);
 
 
 
 
 
2537 }
2538 uxaddr.sun_family = AF_UNIX;
2539 strncpy(uxaddr.sun_path, zIpAddr, sizeof(uxaddr.sun_path)-1);
2540 listener = socket(AF_UNIX, SOCK_STREAM, 0);
 
 
 
 
 
 
 
 
 
 
 
 
2541 }else{
 
2542 memset(&inaddr, 0, sizeof(inaddr));
2543 inaddr.sin_family = AF_INET;
2544 if( zIpAddr ){
2545 inaddr.sin_addr.s_addr = inet_addr(zIpAddr);
2546 if( inaddr.sin_addr.s_addr == INADDR_NONE ){
@@ -2551,21 +2571,28 @@
2551 }else{
2552 inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
2553 }
2554 inaddr.sin_port = htons(iPort);
2555 listener = socket(AF_INET, SOCK_STREAM, 0);
2556 }
2557 if( listener<0 ){
2558 iPort++;
2559 continue;
2560 }
2561
2562 /* if we can't terminate nicely, at least allow the socket to be reused */
2563 setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
2564
2565 if( flags & HTTP_SERVER_UNIXDOMAINSOCK ){
2566 rc = bind(listener, (struct sockaddr*)&uxaddr, sizeof(uxaddr));
 
 
 
 
 
 
 
2567 }else{
2568 rc = bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr));
2569 }
2570 if( rc<0 ){
2571 close(listener);
@@ -2573,32 +2600,32 @@
2573 continue;
2574 }
2575 break;
2576 }
2577 if( iPort>mxPort ){
2578 if( flags & HTTP_SERVER_UNIXDOMAINSOCK ){
2579 fossil_fatal("unable to listen on unix-domain socket %s", zIpAddr);
2580 }else if( mnPort==mxPort ){
2581 fossil_fatal("unable to open listening socket on port %d", mnPort);
2582 }else{
2583 fossil_fatal("unable to open listening socket on any"
2584 " port in the range %d..%d", mnPort, mxPort);
2585 }
2586 }
2587 if( iPort>mxPort ) return 1;
2588 listen(listener,10);
2589 if( flags & HTTP_SERVER_UNIXDOMAINSOCK ){
2590 fossil_print("Listening for %s requests on unix-domain socket %s\n",
2591 (flags & HTTP_SERVER_SCGI)!=0 ? "SCGI" :
2592 g.httpUseSSL?"TLS-encrypted HTTPS":"HTTP", zIpAddr);
2593 }else{
2594 fossil_print("Listening for %s requests on TCP port %d\n",
2595 (flags & HTTP_SERVER_SCGI)!=0 ? "SCGI" :
2596 g.httpUseSSL?"TLS-encrypted HTTPS":"HTTP", iPort);
2597 }
2598 fflush(stdout);
2599 if( zBrowser && (flags & HTTP_SERVER_UNIXDOMAINSOCK)==0 ){
2600 assert( strstr(zBrowser,"%d")!=0 );
2601 zBrowser = mprintf(zBrowser /*works-like:"%d"*/, iPort);
2602 #if defined(__CYGWIN__)
2603 /* On Cygwin, we can do better than "echo" */
2604 if( fossil_strncmp(zBrowser, "echo ", 5)==0 ){
2605
--- src/cgi.c
+++ src/cgi.c
@@ -2477,11 +2477,11 @@
2477 #define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
2478 #define HTTP_SERVER_HAD_REPOSITORY 0x0004 /* Was the repository open? */
2479 #define HTTP_SERVER_HAD_CHECKOUT 0x0008 /* Was a checkout open? */
2480 #define HTTP_SERVER_REPOLIST 0x0010 /* Allow repo listing */
2481 #define HTTP_SERVER_NOFORK 0x0020 /* Do not call fork() */
2482 #define HTTP_SERVER_UNIXSOCKET 0x0040 /* Use a unix-domain socket */
2483
2484 #endif /* INTERFACE */
2485
2486 /*
2487 ** Maximum number of child processes that we can have running
@@ -2524,23 +2524,43 @@
2524 int opt = 1; /* setsockopt flag */
2525 int rc; /* Result code from system calls */
2526 int iPort = mnPort; /* Port to try to use */
2527
2528 while( iPort<=mxPort ){
2529 if( flags & HTTP_SERVER_UNIXSOCKET ){
2530 /* Initialize a Unix socket named g.zSockName */
2531 assert( g.zSockName!=0 );
2532 memset(&uxaddr, 0, sizeof(uxaddr));
2533 if( strlen(g.zSockName)>sizeof(uxaddr.sun_path) ){
2534 fossil_fatal("name of unix socket too big: %s\nmax size: %d\n",
2535 g.zSockName, (int)sizeof(uxaddr.sun_path));
2536 }
2537 if( file_isdir(g.zSockName, ExtFILE)!=0 ){
2538 if( !file_issocket(g.zSockName) ){
2539 fossil_fatal("cannot name socket \"%s\" because another object"
2540 " with that name already exists", g.zSockName);
2541 }else{
2542 unlink(g.zSockName);
2543 }
2544 }
2545 uxaddr.sun_family = AF_UNIX;
2546 strncpy(uxaddr.sun_path, g.zSockName, sizeof(uxaddr.sun_path)-1);
2547 listener = socket(AF_UNIX, SOCK_STREAM, 0);
2548 if( listener<0 ){
2549 fossil_fatal("unable to create a unix socket named %s",
2550 g.zSockName);
2551 }
2552 /* Set the access permission for the new socket. Default to 0660.
2553 ** But use an alternative specified by --socket-mode if available.
2554 ** Do this before bind() to avoid a race condition. */
2555 if( g.zSockMode ){
2556 file_set_mode(g.zSockName, listener, g.zSockMode, 0);
2557 }else{
2558 file_set_mode(g.zSockName, listener, "0660", 1);
2559 }
2560 }else{
2561 /* Initialize a TCP/IP socket on port iPort */
2562 memset(&inaddr, 0, sizeof(inaddr));
2563 inaddr.sin_family = AF_INET;
2564 if( zIpAddr ){
2565 inaddr.sin_addr.s_addr = inet_addr(zIpAddr);
2566 if( inaddr.sin_addr.s_addr == INADDR_NONE ){
@@ -2551,21 +2571,28 @@
2571 }else{
2572 inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
2573 }
2574 inaddr.sin_port = htons(iPort);
2575 listener = socket(AF_INET, SOCK_STREAM, 0);
2576 if( listener<0 ){
2577 iPort++;
2578 continue;
2579 }
2580 }
2581
2582 /* if we can't terminate nicely, at least allow the socket to be reused */
2583 setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
2584
2585 if( flags & HTTP_SERVER_UNIXSOCKET ){
2586 rc = bind(listener, (struct sockaddr*)&uxaddr, sizeof(uxaddr));
2587 /* Set the owner of the socket if requested by --socket-owner. This
2588 ** must wait until after bind(), after the filesystem object has been
2589 ** created. See https://lkml.org/lkml/2004/11/1/84 and
2590 ** https://fossil-scm.org/forum/forumpost/7517680ef9684c57 */
2591 if( g.zSockOwner ){
2592 file_set_owner(g.zSockName, listener, g.zSockOwner);
2593 }
2594 }else{
2595 rc = bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr));
2596 }
2597 if( rc<0 ){
2598 close(listener);
@@ -2573,32 +2600,32 @@
2600 continue;
2601 }
2602 break;
2603 }
2604 if( iPort>mxPort ){
2605 if( flags & HTTP_SERVER_UNIXSOCKET ){
2606 fossil_fatal("unable to listen on unix socket %s", zIpAddr);
2607 }else if( mnPort==mxPort ){
2608 fossil_fatal("unable to open listening socket on port %d", mnPort);
2609 }else{
2610 fossil_fatal("unable to open listening socket on any"
2611 " port in the range %d..%d", mnPort, mxPort);
2612 }
2613 }
2614 if( iPort>mxPort ) return 1;
2615 listen(listener,10);
2616 if( flags & HTTP_SERVER_UNIXSOCKET ){
2617 fossil_print("Listening for %s requests on unix socket %s\n",
2618 (flags & HTTP_SERVER_SCGI)!=0 ? "SCGI" :
2619 g.httpUseSSL?"TLS-encrypted HTTPS":"HTTP", g.zSockName);
2620 }else{
2621 fossil_print("Listening for %s requests on TCP port %d\n",
2622 (flags & HTTP_SERVER_SCGI)!=0 ? "SCGI" :
2623 g.httpUseSSL?"TLS-encrypted HTTPS":"HTTP", iPort);
2624 }
2625 fflush(stdout);
2626 if( zBrowser && (flags & HTTP_SERVER_UNIXSOCKET)==0 ){
2627 assert( strstr(zBrowser,"%d")!=0 );
2628 zBrowser = mprintf(zBrowser /*works-like:"%d"*/, iPort);
2629 #if defined(__CYGWIN__)
2630 /* On Cygwin, we can do better than "echo" */
2631 if( fossil_strncmp(zBrowser, "echo ", 5)==0 ){
2632
+67
--- src/file.c
+++ src/file.c
@@ -34,10 +34,12 @@
3434
# include <direct.h>
3535
# include <windows.h>
3636
# include <sys/utime.h>
3737
#else
3838
# include <sys/time.h>
39
+# include <pwd.h>
40
+# include <grp.h>
3941
#endif
4042
4143
#if INTERFACE
4244
4345
/* Many APIs take an eFType argument which must be one of ExtFILE, RepoFILE,
@@ -229,10 +231,20 @@
229231
** for directories, devices, fifos, symlinks, etc.
230232
*/
231233
int file_isfile(const char *zFilename, int eFType){
232234
return getStat(zFilename, eFType) ? 0 : S_ISREG(fx.fileStat.st_mode);
233235
}
236
+
237
+/*
238
+** Return TRUE if zFilename is a socket.
239
+*/
240
+int file_issocket(const char *zFilename){
241
+ if( getStat(zFilename, ExtFILE) ){
242
+ return 0; /* stat() failed. Return false. */
243
+ }
244
+ return S_ISSOCK(fx.fileStat.st_mode);
245
+}
234246
235247
/*
236248
** Create a symbolic link named zLinkFile that points to zTargetFile.
237249
**
238250
** If allow-symlinks is off, create an ordinary file named zLinkFile
@@ -713,10 +725,64 @@
713725
file_set_mtime(zFile, iMTime);
714726
iMTime = file_mtime(zFile, RepoFILE);
715727
zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
716728
fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
717729
}
730
+
731
+/*
732
+** Change access permissions on a file.
733
+*/
734
+void file_set_mode(const char *zFN, int fd, const char *zMode, int bNoErr){
735
+#if !defined(_WIN32)
736
+ mode_t m;
737
+ char *zEnd = 0;
738
+ m = strtol(zMode, &zEnd, 0);
739
+ if( (zEnd[0] || fchmod(fd, m)) && !bNoErr ){
740
+ fossil_fatal("cannot change permissions on %s to \"%s\"",
741
+ zFN, zMode);
742
+ }
743
+#endif
744
+}
745
+
746
+/* Change the owner of a file to zOwner. zOwner can be of the form
747
+** USER:GROUP.
748
+*/
749
+void file_set_owner(const char *zFN, int fd, const char *zOwner){
750
+#if !defined(_WIN32)
751
+ const char *zGrp;
752
+ const char *zUsr = zOwner;
753
+ struct passwd *pw;
754
+ struct group *grp;
755
+ uid_t uid = -1;
756
+ gid_t gid = -1;
757
+ zGrp = strchr(zUsr, ':');
758
+ if( zGrp ){
759
+ int n = (int)(zGrp - zUsr);
760
+ zUsr = fossil_strndup(zUsr, n);
761
+ zGrp++;
762
+ }
763
+ pw = getpwnam(zUsr);
764
+ if( pw==0 ){
765
+ fossil_fatal("no such user: \"%s\"", zUsr);
766
+ }
767
+ uid = pw->pw_uid;
768
+ if( zGrp ){
769
+ grp = getgrnam(zGrp);
770
+ if( grp==0 ){
771
+ fossil_fatal("no such group: \"%s\"", zGrp);
772
+ }
773
+ gid = grp->gr_gid;
774
+ }
775
+ if( chown(zFN, uid, gid) ){
776
+ fossil_fatal("cannot change ownership of %s to %s",zFN, zOwner);
777
+ }
778
+ if( zOwner!=zUsr ){
779
+ fossil_free((char*)zUsr);
780
+ }
781
+#endif
782
+}
783
+
718784
719785
/*
720786
** Delete a file.
721787
**
722788
** If zFilename is a symbolic link, then it is the link itself that is
@@ -1514,10 +1580,11 @@
15141580
fossil_free(z);
15151581
fossil_print(" file_mtime(ExtFILE) = %s\n", zBuf);
15161582
fossil_print(" file_mode(ExtFILE) = 0%o\n", file_mode(zPath,ExtFILE));
15171583
fossil_print(" file_isfile(ExtFILE) = %d\n", file_isfile(zPath,ExtFILE));
15181584
fossil_print(" file_isdir(ExtFILE) = %d\n", file_isdir(zPath,ExtFILE));
1585
+ fossil_print(" file_issocket() = %d\n", file_issocket(zPath));
15191586
if( reset ) resetStat();
15201587
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zPath,RepoFILE));
15211588
fossil_print(" file_size(RepoFILE) = %s\n", zBuf);
15221589
iMtime = file_mtime(zPath,RepoFILE);
15231590
z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMtime);
15241591
--- src/file.c
+++ src/file.c
@@ -34,10 +34,12 @@
34 # include <direct.h>
35 # include <windows.h>
36 # include <sys/utime.h>
37 #else
38 # include <sys/time.h>
 
 
39 #endif
40
41 #if INTERFACE
42
43 /* Many APIs take an eFType argument which must be one of ExtFILE, RepoFILE,
@@ -229,10 +231,20 @@
229 ** for directories, devices, fifos, symlinks, etc.
230 */
231 int file_isfile(const char *zFilename, int eFType){
232 return getStat(zFilename, eFType) ? 0 : S_ISREG(fx.fileStat.st_mode);
233 }
 
 
 
 
 
 
 
 
 
 
234
235 /*
236 ** Create a symbolic link named zLinkFile that points to zTargetFile.
237 **
238 ** If allow-symlinks is off, create an ordinary file named zLinkFile
@@ -713,10 +725,64 @@
713 file_set_mtime(zFile, iMTime);
714 iMTime = file_mtime(zFile, RepoFILE);
715 zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
716 fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
717 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
718
719 /*
720 ** Delete a file.
721 **
722 ** If zFilename is a symbolic link, then it is the link itself that is
@@ -1514,10 +1580,11 @@
1514 fossil_free(z);
1515 fossil_print(" file_mtime(ExtFILE) = %s\n", zBuf);
1516 fossil_print(" file_mode(ExtFILE) = 0%o\n", file_mode(zPath,ExtFILE));
1517 fossil_print(" file_isfile(ExtFILE) = %d\n", file_isfile(zPath,ExtFILE));
1518 fossil_print(" file_isdir(ExtFILE) = %d\n", file_isdir(zPath,ExtFILE));
 
1519 if( reset ) resetStat();
1520 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zPath,RepoFILE));
1521 fossil_print(" file_size(RepoFILE) = %s\n", zBuf);
1522 iMtime = file_mtime(zPath,RepoFILE);
1523 z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMtime);
1524
--- src/file.c
+++ src/file.c
@@ -34,10 +34,12 @@
34 # include <direct.h>
35 # include <windows.h>
36 # include <sys/utime.h>
37 #else
38 # include <sys/time.h>
39 # include <pwd.h>
40 # include <grp.h>
41 #endif
42
43 #if INTERFACE
44
45 /* Many APIs take an eFType argument which must be one of ExtFILE, RepoFILE,
@@ -229,10 +231,20 @@
231 ** for directories, devices, fifos, symlinks, etc.
232 */
233 int file_isfile(const char *zFilename, int eFType){
234 return getStat(zFilename, eFType) ? 0 : S_ISREG(fx.fileStat.st_mode);
235 }
236
237 /*
238 ** Return TRUE if zFilename is a socket.
239 */
240 int file_issocket(const char *zFilename){
241 if( getStat(zFilename, ExtFILE) ){
242 return 0; /* stat() failed. Return false. */
243 }
244 return S_ISSOCK(fx.fileStat.st_mode);
245 }
246
247 /*
248 ** Create a symbolic link named zLinkFile that points to zTargetFile.
249 **
250 ** If allow-symlinks is off, create an ordinary file named zLinkFile
@@ -713,10 +725,64 @@
725 file_set_mtime(zFile, iMTime);
726 iMTime = file_mtime(zFile, RepoFILE);
727 zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
728 fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
729 }
730
731 /*
732 ** Change access permissions on a file.
733 */
734 void file_set_mode(const char *zFN, int fd, const char *zMode, int bNoErr){
735 #if !defined(_WIN32)
736 mode_t m;
737 char *zEnd = 0;
738 m = strtol(zMode, &zEnd, 0);
739 if( (zEnd[0] || fchmod(fd, m)) && !bNoErr ){
740 fossil_fatal("cannot change permissions on %s to \"%s\"",
741 zFN, zMode);
742 }
743 #endif
744 }
745
746 /* Change the owner of a file to zOwner. zOwner can be of the form
747 ** USER:GROUP.
748 */
749 void file_set_owner(const char *zFN, int fd, const char *zOwner){
750 #if !defined(_WIN32)
751 const char *zGrp;
752 const char *zUsr = zOwner;
753 struct passwd *pw;
754 struct group *grp;
755 uid_t uid = -1;
756 gid_t gid = -1;
757 zGrp = strchr(zUsr, ':');
758 if( zGrp ){
759 int n = (int)(zGrp - zUsr);
760 zUsr = fossil_strndup(zUsr, n);
761 zGrp++;
762 }
763 pw = getpwnam(zUsr);
764 if( pw==0 ){
765 fossil_fatal("no such user: \"%s\"", zUsr);
766 }
767 uid = pw->pw_uid;
768 if( zGrp ){
769 grp = getgrnam(zGrp);
770 if( grp==0 ){
771 fossil_fatal("no such group: \"%s\"", zGrp);
772 }
773 gid = grp->gr_gid;
774 }
775 if( chown(zFN, uid, gid) ){
776 fossil_fatal("cannot change ownership of %s to %s",zFN, zOwner);
777 }
778 if( zOwner!=zUsr ){
779 fossil_free((char*)zUsr);
780 }
781 #endif
782 }
783
784
785 /*
786 ** Delete a file.
787 **
788 ** If zFilename is a symbolic link, then it is the link itself that is
@@ -1514,10 +1580,11 @@
1580 fossil_free(z);
1581 fossil_print(" file_mtime(ExtFILE) = %s\n", zBuf);
1582 fossil_print(" file_mode(ExtFILE) = 0%o\n", file_mode(zPath,ExtFILE));
1583 fossil_print(" file_isfile(ExtFILE) = %d\n", file_isfile(zPath,ExtFILE));
1584 fossil_print(" file_isdir(ExtFILE) = %d\n", file_isdir(zPath,ExtFILE));
1585 fossil_print(" file_issocket() = %d\n", file_issocket(zPath));
1586 if( reset ) resetStat();
1587 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zPath,RepoFILE));
1588 fossil_print(" file_size(RepoFILE) = %s\n", zBuf);
1589 iMtime = file_mtime(zPath,RepoFILE);
1590 z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMtime);
1591
+39 -10
--- src/main.c
+++ src/main.c
@@ -238,10 +238,13 @@
238238
int noPswd; /* Logged in without password (on 127.0.0.1) */
239239
int userUid; /* Integer user id */
240240
int isHuman; /* True if access by a human, not a spider or bot */
241241
int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be
242242
** accessed through get_comment_format(). */
243
+ const char *zSockName; /* Name of the unix-domain socket file */
244
+ const char *zSockMode; /* File permissions for unix-domain socket */
245
+ const char *zSockOwner; /* Owner, or owner:group for unix-domain socket */
243246
244247
/* Information used to populate the RCVFROM table */
245248
int rcvid; /* The rcvid. 0 if not yet defined. */
246249
char *zIpAddr; /* The remote IP address */
247250
char *zNonce; /* The nonce used for login */
@@ -391,10 +394,15 @@
391394
unloadTcl(g.interp, &g.tcl);
392395
#endif
393396
#ifdef FOSSIL_ENABLE_JSON
394397
cson_value_free(g.json.gc.v);
395398
memset(&g.json, 0, sizeof(g.json));
399
+#endif
400
+#if !defined(_WIN32)
401
+ if( g.zSockName && file_issocket(g.zSockName) ){
402
+ unlink(g.zSockName);
403
+ }
396404
#endif
397405
free(g.zErrMsg);
398406
if(g.db){
399407
db_close(0);
400408
}
@@ -1507,30 +1515,44 @@
15071515
if( getuid()==0 ){
15081516
int i;
15091517
struct stat sStat;
15101518
Blob dir;
15111519
char *zDir;
1520
+ size_t nDir;
15121521
if( g.db!=0 ){
15131522
db_close(1);
15141523
}
15151524
15161525
file_canonical_name(zRepo, &dir, 0);
15171526
zDir = blob_str(&dir);
1527
+ nDir = blob_size(&dir);
15181528
if( !noJail ){
15191529
if( file_isdir(zDir, ExtFILE)==1 ){
1530
+ /* Translate the repository name to the new root */
15201531
if( g.zRepositoryName ){
1521
- size_t n = strlen(zDir);
15221532
Blob repo;
15231533
file_canonical_name(g.zRepositoryName, &repo, 0);
15241534
zRepo = blob_str(&repo);
1525
- if( strncmp(zRepo, zDir, n)!=0 ){
1535
+ if( strncmp(zRepo, zDir, nDir)!=0 ){
15261536
fossil_fatal("repo %s not under chroot dir %s", zRepo, zDir);
15271537
}
1528
- zRepo += n;
1538
+ zRepo += nDir;
15291539
if( *zRepo == '\0' ) zRepo = "/";
15301540
}else {
15311541
zRepo = "/";
1542
+ }
1543
+ /* If a unix socket is defined, try to translate its name into
1544
+ ** the new root so that it can be delete by atexit(). If unable,
1545
+ ** just zero out the socket name. */
1546
+ if( g.zSockName ){
1547
+ if( strncmp(g.zSockName, zDir, nDir)==0
1548
+ && g.zSockName[nDir]=='/'
1549
+ ){
1550
+ g.zSockName += nDir;
1551
+ }else{
1552
+ g.zSockName = 0;
1553
+ }
15321554
}
15331555
if( file_chdir(zDir, 1) ){
15341556
fossil_panic("unable to chroot into %s", zDir);
15351557
}
15361558
}else{
@@ -3185,13 +3207,18 @@
31853207
** -P|--port [IP:]PORT Listen on the given IP (optional) and port
31863208
** --repolist If REPOSITORY is dir, URL "/" lists repos
31873209
** --scgi Accept SCGI rather than HTTP
31883210
** --skin LABEL Use override skin LABEL, or the site's default skin if
31893211
** LABEL is an empty string.
3212
+** --socket-mode MODE File permissions to set for the unix socket created
3213
+** by the --socket-name option.
3214
+** --socket-name NAME Use a unix-domain socket called NAME instead of a
3215
+** TCP/IP socket.
3216
+** --socket-owner USR Try to set the owner of the unix socket to USR.
3217
+** USR can be of the form USER:GROUP to set both
3218
+** user and group.
31903219
** --th-trace Trace TH1 execution (for debugging purposes)
3191
-** --unix-socket NAME Listen on unix-domain socket NAME rather than on a
3192
-** TCP/IP port.
31933220
** --usepidkey Use saved encryption key from parent process. This is
31943221
** only necessary when using SEE on Windows or Linux.
31953222
**
31963223
** See also: [[cgi]], [[http]], [[winsrv]]
31973224
*/
@@ -3285,22 +3312,24 @@
32853312
g.zMainMenuFile = find_option("mainmenu",0,1);
32863313
if( g.zMainMenuFile!=0 && file_size(g.zMainMenuFile,ExtFILE)<0 ){
32873314
fossil_fatal("Cannot read --mainmenu file %s", g.zMainMenuFile);
32883315
}
32893316
if( find_option("acme",0,0)!=0 ) g.fAllowACME = 1;
3290
- zIpAddr = (char*)find_option("unix-socket",0,1);
3291
- if( zIpAddr ){
3317
+ g.zSockMode = find_option("socket-mode",0,1);
3318
+ g.zSockName = find_option("socket-name",0,1);
3319
+ g.zSockOwner = find_option("socket-owner",0,1);
3320
+ if( g.zSockName ){
32923321
#if defined(_WIN32)
32933322
fossil_fatal("unix sockets are not supported on Windows");
32943323
#endif
32953324
if( zPort ){
32963325
fossil_fatal("cannot specify a port number for a unix socket");
32973326
}
32983327
if( isUiCmd && !fNoBrowser ){
32993328
fossil_fatal("cannot start a web-browser on a unix socket");
33003329
}
3301
- flags |= HTTP_SERVER_UNIXDOMAINSOCK;
3330
+ flags |= HTTP_SERVER_UNIXSOCKET;
33023331
}
33033332
33043333
/* Undocumented option: --debug-nofork
33053334
**
33063335
** This sets the HTTP_SERVER_NOFORK flag, which causes only the
@@ -3467,11 +3496,11 @@
34673496
}
34683497
if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY;
34693498
if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
34703499
db_close(1);
34713500
#if !defined(_WIN32)
3472
- if( getpid()==1 ){
3501
+ if( 1 ){
34733502
/* Modern kernels suppress SIGTERM to PID 1 to prevent root from
34743503
** rebooting the system by nuking the init system. The only way
34753504
** Fossil becomes that PID 1 is when it's running solo in a Linux
34763505
** container or similar, so we do want to exit immediately, to
34773506
** allow the container to shut down quickly.
@@ -3490,11 +3519,11 @@
34903519
fossil_setenv("SERVER_SOFTWARE", "fossil version " RELEASE_VERSION
34913520
" " MANIFEST_VERSION " " MANIFEST_DATE);
34923521
#if !defined(_WIN32)
34933522
/* Unix implementation */
34943523
if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
3495
- fossil_fatal("unable to listen on TCP socket %d", iPort);
3524
+ fossil_fatal("unable to listen on CGI socket");
34963525
}
34973526
/* For the parent process, the cgi_http_server() command above never
34983527
** returns (except in the case of an error). Instead, for each incoming
34993528
** client connection, a child process is created, file descriptors 0
35003529
** and 1 are bound to that connection, and the child returns.
35013530
--- src/main.c
+++ src/main.c
@@ -238,10 +238,13 @@
238 int noPswd; /* Logged in without password (on 127.0.0.1) */
239 int userUid; /* Integer user id */
240 int isHuman; /* True if access by a human, not a spider or bot */
241 int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be
242 ** accessed through get_comment_format(). */
 
 
 
243
244 /* Information used to populate the RCVFROM table */
245 int rcvid; /* The rcvid. 0 if not yet defined. */
246 char *zIpAddr; /* The remote IP address */
247 char *zNonce; /* The nonce used for login */
@@ -391,10 +394,15 @@
391 unloadTcl(g.interp, &g.tcl);
392 #endif
393 #ifdef FOSSIL_ENABLE_JSON
394 cson_value_free(g.json.gc.v);
395 memset(&g.json, 0, sizeof(g.json));
 
 
 
 
 
396 #endif
397 free(g.zErrMsg);
398 if(g.db){
399 db_close(0);
400 }
@@ -1507,30 +1515,44 @@
1507 if( getuid()==0 ){
1508 int i;
1509 struct stat sStat;
1510 Blob dir;
1511 char *zDir;
 
1512 if( g.db!=0 ){
1513 db_close(1);
1514 }
1515
1516 file_canonical_name(zRepo, &dir, 0);
1517 zDir = blob_str(&dir);
 
1518 if( !noJail ){
1519 if( file_isdir(zDir, ExtFILE)==1 ){
 
1520 if( g.zRepositoryName ){
1521 size_t n = strlen(zDir);
1522 Blob repo;
1523 file_canonical_name(g.zRepositoryName, &repo, 0);
1524 zRepo = blob_str(&repo);
1525 if( strncmp(zRepo, zDir, n)!=0 ){
1526 fossil_fatal("repo %s not under chroot dir %s", zRepo, zDir);
1527 }
1528 zRepo += n;
1529 if( *zRepo == '\0' ) zRepo = "/";
1530 }else {
1531 zRepo = "/";
 
 
 
 
 
 
 
 
 
 
 
 
1532 }
1533 if( file_chdir(zDir, 1) ){
1534 fossil_panic("unable to chroot into %s", zDir);
1535 }
1536 }else{
@@ -3185,13 +3207,18 @@
3185 ** -P|--port [IP:]PORT Listen on the given IP (optional) and port
3186 ** --repolist If REPOSITORY is dir, URL "/" lists repos
3187 ** --scgi Accept SCGI rather than HTTP
3188 ** --skin LABEL Use override skin LABEL, or the site's default skin if
3189 ** LABEL is an empty string.
 
 
 
 
 
 
 
3190 ** --th-trace Trace TH1 execution (for debugging purposes)
3191 ** --unix-socket NAME Listen on unix-domain socket NAME rather than on a
3192 ** TCP/IP port.
3193 ** --usepidkey Use saved encryption key from parent process. This is
3194 ** only necessary when using SEE on Windows or Linux.
3195 **
3196 ** See also: [[cgi]], [[http]], [[winsrv]]
3197 */
@@ -3285,22 +3312,24 @@
3285 g.zMainMenuFile = find_option("mainmenu",0,1);
3286 if( g.zMainMenuFile!=0 && file_size(g.zMainMenuFile,ExtFILE)<0 ){
3287 fossil_fatal("Cannot read --mainmenu file %s", g.zMainMenuFile);
3288 }
3289 if( find_option("acme",0,0)!=0 ) g.fAllowACME = 1;
3290 zIpAddr = (char*)find_option("unix-socket",0,1);
3291 if( zIpAddr ){
 
 
3292 #if defined(_WIN32)
3293 fossil_fatal("unix sockets are not supported on Windows");
3294 #endif
3295 if( zPort ){
3296 fossil_fatal("cannot specify a port number for a unix socket");
3297 }
3298 if( isUiCmd && !fNoBrowser ){
3299 fossil_fatal("cannot start a web-browser on a unix socket");
3300 }
3301 flags |= HTTP_SERVER_UNIXDOMAINSOCK;
3302 }
3303
3304 /* Undocumented option: --debug-nofork
3305 **
3306 ** This sets the HTTP_SERVER_NOFORK flag, which causes only the
@@ -3467,11 +3496,11 @@
3467 }
3468 if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY;
3469 if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
3470 db_close(1);
3471 #if !defined(_WIN32)
3472 if( getpid()==1 ){
3473 /* Modern kernels suppress SIGTERM to PID 1 to prevent root from
3474 ** rebooting the system by nuking the init system. The only way
3475 ** Fossil becomes that PID 1 is when it's running solo in a Linux
3476 ** container or similar, so we do want to exit immediately, to
3477 ** allow the container to shut down quickly.
@@ -3490,11 +3519,11 @@
3490 fossil_setenv("SERVER_SOFTWARE", "fossil version " RELEASE_VERSION
3491 " " MANIFEST_VERSION " " MANIFEST_DATE);
3492 #if !defined(_WIN32)
3493 /* Unix implementation */
3494 if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
3495 fossil_fatal("unable to listen on TCP socket %d", iPort);
3496 }
3497 /* For the parent process, the cgi_http_server() command above never
3498 ** returns (except in the case of an error). Instead, for each incoming
3499 ** client connection, a child process is created, file descriptors 0
3500 ** and 1 are bound to that connection, and the child returns.
3501
--- src/main.c
+++ src/main.c
@@ -238,10 +238,13 @@
238 int noPswd; /* Logged in without password (on 127.0.0.1) */
239 int userUid; /* Integer user id */
240 int isHuman; /* True if access by a human, not a spider or bot */
241 int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be
242 ** accessed through get_comment_format(). */
243 const char *zSockName; /* Name of the unix-domain socket file */
244 const char *zSockMode; /* File permissions for unix-domain socket */
245 const char *zSockOwner; /* Owner, or owner:group for unix-domain socket */
246
247 /* Information used to populate the RCVFROM table */
248 int rcvid; /* The rcvid. 0 if not yet defined. */
249 char *zIpAddr; /* The remote IP address */
250 char *zNonce; /* The nonce used for login */
@@ -391,10 +394,15 @@
394 unloadTcl(g.interp, &g.tcl);
395 #endif
396 #ifdef FOSSIL_ENABLE_JSON
397 cson_value_free(g.json.gc.v);
398 memset(&g.json, 0, sizeof(g.json));
399 #endif
400 #if !defined(_WIN32)
401 if( g.zSockName && file_issocket(g.zSockName) ){
402 unlink(g.zSockName);
403 }
404 #endif
405 free(g.zErrMsg);
406 if(g.db){
407 db_close(0);
408 }
@@ -1507,30 +1515,44 @@
1515 if( getuid()==0 ){
1516 int i;
1517 struct stat sStat;
1518 Blob dir;
1519 char *zDir;
1520 size_t nDir;
1521 if( g.db!=0 ){
1522 db_close(1);
1523 }
1524
1525 file_canonical_name(zRepo, &dir, 0);
1526 zDir = blob_str(&dir);
1527 nDir = blob_size(&dir);
1528 if( !noJail ){
1529 if( file_isdir(zDir, ExtFILE)==1 ){
1530 /* Translate the repository name to the new root */
1531 if( g.zRepositoryName ){
 
1532 Blob repo;
1533 file_canonical_name(g.zRepositoryName, &repo, 0);
1534 zRepo = blob_str(&repo);
1535 if( strncmp(zRepo, zDir, nDir)!=0 ){
1536 fossil_fatal("repo %s not under chroot dir %s", zRepo, zDir);
1537 }
1538 zRepo += nDir;
1539 if( *zRepo == '\0' ) zRepo = "/";
1540 }else {
1541 zRepo = "/";
1542 }
1543 /* If a unix socket is defined, try to translate its name into
1544 ** the new root so that it can be delete by atexit(). If unable,
1545 ** just zero out the socket name. */
1546 if( g.zSockName ){
1547 if( strncmp(g.zSockName, zDir, nDir)==0
1548 && g.zSockName[nDir]=='/'
1549 ){
1550 g.zSockName += nDir;
1551 }else{
1552 g.zSockName = 0;
1553 }
1554 }
1555 if( file_chdir(zDir, 1) ){
1556 fossil_panic("unable to chroot into %s", zDir);
1557 }
1558 }else{
@@ -3185,13 +3207,18 @@
3207 ** -P|--port [IP:]PORT Listen on the given IP (optional) and port
3208 ** --repolist If REPOSITORY is dir, URL "/" lists repos
3209 ** --scgi Accept SCGI rather than HTTP
3210 ** --skin LABEL Use override skin LABEL, or the site's default skin if
3211 ** LABEL is an empty string.
3212 ** --socket-mode MODE File permissions to set for the unix socket created
3213 ** by the --socket-name option.
3214 ** --socket-name NAME Use a unix-domain socket called NAME instead of a
3215 ** TCP/IP socket.
3216 ** --socket-owner USR Try to set the owner of the unix socket to USR.
3217 ** USR can be of the form USER:GROUP to set both
3218 ** user and group.
3219 ** --th-trace Trace TH1 execution (for debugging purposes)
 
 
3220 ** --usepidkey Use saved encryption key from parent process. This is
3221 ** only necessary when using SEE on Windows or Linux.
3222 **
3223 ** See also: [[cgi]], [[http]], [[winsrv]]
3224 */
@@ -3285,22 +3312,24 @@
3312 g.zMainMenuFile = find_option("mainmenu",0,1);
3313 if( g.zMainMenuFile!=0 && file_size(g.zMainMenuFile,ExtFILE)<0 ){
3314 fossil_fatal("Cannot read --mainmenu file %s", g.zMainMenuFile);
3315 }
3316 if( find_option("acme",0,0)!=0 ) g.fAllowACME = 1;
3317 g.zSockMode = find_option("socket-mode",0,1);
3318 g.zSockName = find_option("socket-name",0,1);
3319 g.zSockOwner = find_option("socket-owner",0,1);
3320 if( g.zSockName ){
3321 #if defined(_WIN32)
3322 fossil_fatal("unix sockets are not supported on Windows");
3323 #endif
3324 if( zPort ){
3325 fossil_fatal("cannot specify a port number for a unix socket");
3326 }
3327 if( isUiCmd && !fNoBrowser ){
3328 fossil_fatal("cannot start a web-browser on a unix socket");
3329 }
3330 flags |= HTTP_SERVER_UNIXSOCKET;
3331 }
3332
3333 /* Undocumented option: --debug-nofork
3334 **
3335 ** This sets the HTTP_SERVER_NOFORK flag, which causes only the
@@ -3467,11 +3496,11 @@
3496 }
3497 if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY;
3498 if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
3499 db_close(1);
3500 #if !defined(_WIN32)
3501 if( 1 ){
3502 /* Modern kernels suppress SIGTERM to PID 1 to prevent root from
3503 ** rebooting the system by nuking the init system. The only way
3504 ** Fossil becomes that PID 1 is when it's running solo in a Linux
3505 ** container or similar, so we do want to exit immediately, to
3506 ** allow the container to shut down quickly.
@@ -3490,11 +3519,11 @@
3519 fossil_setenv("SERVER_SOFTWARE", "fossil version " RELEASE_VERSION
3520 " " MANIFEST_VERSION " " MANIFEST_DATE);
3521 #if !defined(_WIN32)
3522 /* Unix implementation */
3523 if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
3524 fossil_fatal("unable to listen on CGI socket");
3525 }
3526 /* For the parent process, the cgi_http_server() command above never
3527 ** returns (except in the case of an error). Instead, for each incoming
3528 ** client connection, a child process is created, file descriptors 0
3529 ** and 1 are bound to that connection, and the child returns.
3530

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button