|
From: <ale...@us...> - 2014-12-17 14:31:16
|
Revision: 60379
http://sourceforge.net/p/firebird/code/60379
Author: alexpeshkoff
Date: 2014-12-17 14:31:02 +0000 (Wed, 17 Dec 2014)
Log Message:
-----------
Work in progress on CORE-3632: make all file descriptors, opened by firebird, close on exec()
Modified Paths:
--------------
firebird/trunk/configure.ac
firebird/trunk/src/burp/burp.cpp
firebird/trunk/src/burp/mvol.cpp
firebird/trunk/src/burp/split/spit.cpp
firebird/trunk/src/common/classes/TempFile.cpp
firebird/trunk/src/common/classes/alloc.cpp
firebird/trunk/src/common/config/config_file.cpp
firebird/trunk/src/common/isc_file.cpp
firebird/trunk/src/common/os/os_utils.h
firebird/trunk/src/common/os/posix/divorce.cpp
firebird/trunk/src/common/os/posix/guid.cpp
firebird/trunk/src/common/os/posix/os_utils.cpp
firebird/trunk/src/common/os/win32/os_utils.cpp
firebird/trunk/src/common/utils.cpp
firebird/trunk/src/jrd/Optimizer.cpp
firebird/trunk/src/jrd/ext.cpp
firebird/trunk/src/jrd/jrd.cpp
firebird/trunk/src/jrd/opt.cpp
firebird/trunk/src/jrd/os/posix/unix.cpp
firebird/trunk/src/jrd/svc.cpp
firebird/trunk/src/jrd/trace/TraceConfigStorage.cpp
firebird/trunk/src/lock/lock.cpp
firebird/trunk/src/remote/SockAddr.h
firebird/trunk/src/remote/inet.cpp
firebird/trunk/src/remote/remote.h
firebird/trunk/src/remote/server/os/posix/inet_server.cpp
firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp
firebird/trunk/src/remote/server/server.cpp
firebird/trunk/src/utilities/analyse.cpp
firebird/trunk/src/utilities/gstat/dba.epp
firebird/trunk/src/utilities/nbackup/nbackup.cpp
firebird/trunk/src/yvalve/gds.cpp
firebird/trunk/src/yvalve/utl.cpp
Modified: firebird/trunk/configure.ac
===================================================================
--- firebird/trunk/configure.ac 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/configure.ac 2014-12-17 14:31:02 UTC (rev 60379)
@@ -883,6 +883,9 @@
dnl Check for fallocate() system call
AC_CHECK_FUNCS(fallocate)
+dnl Check for close_on_exec support
+AC_CHECK_FUNCS(accept4)
+
dnl Semaphores
if test "$ac_cv_header_semaphore_h" = "yes"; then
AC_SEARCH_LIBS(sem_init, rt pthread)
Modified: firebird/trunk/src/burp/burp.cpp
===================================================================
--- firebird/trunk/src/burp/burp.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/burp/burp.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -58,6 +58,7 @@
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/Switches.h"
#include "../common/IntlUtil.h"
+#include "../common/os/os_utils.h"
#include "../burp/burpswi.h"
#ifdef HAVE_CTYPE_H
@@ -768,7 +769,7 @@
if (tdgbl->sw_redirect == REDIRECT) // not NOREDIRECT, and not NOOUTPUT
{
// Make sure the status file doesn't already exist
- FILE* tmp_outfile = fopen(redirect, fopen_read_type);
+ FILE* tmp_outfile = os_utils::fopen(redirect, fopen_read_type);
if (tmp_outfile)
{
BURP_print(true, 66, redirect);
@@ -776,7 +777,7 @@
fclose(tmp_outfile);
BURP_exit_local(FINI_ERROR, tdgbl);
}
- if (! (tdgbl->output_file = fopen(redirect, fopen_write_type)))
+ if (! (tdgbl->output_file = os_utils::fopen(redirect, fopen_write_type)))
{
BURP_print(true, 66, redirect);
// msg 66 can't open status and error output file %s
@@ -1862,7 +1863,7 @@
if ((fil->fil_fd = MVOL_open(nm.c_str(), MODE_WRITE, CREATE_ALWAYS)) ==
INVALID_HANDLE_VALUE)
#else
- if ((fil->fil_fd = open(nm.c_str(), MODE_WRITE, open_mask)) == -1)
+ if ((fil->fil_fd = os_utils::open(nm.c_str(), MODE_WRITE, open_mask)) == -1)
#endif // WIN_NT
{
@@ -1970,7 +1971,7 @@
if ((fil->fil_fd = MVOL_open(nm.c_str(), MODE_READ, OPEN_EXISTING)) ==
INVALID_HANDLE_VALUE)
#else
- if ((fil->fil_fd = open(nm.c_str(), MODE_READ)) == INVALID_HANDLE_VALUE)
+ if ((fil->fil_fd = os_utils::open(nm.c_str(), MODE_READ)) == INVALID_HANDLE_VALUE)
#endif
{
BURP_error(65, true, fil->fil_name.c_str());
@@ -2019,7 +2020,7 @@
if ((fil->fil_fd = MVOL_open(nm.c_str(), MODE_READ, OPEN_EXISTING)) ==
INVALID_HANDLE_VALUE)
#else
- if ((fil->fil_fd = open(nm.c_str(), MODE_READ)) == INVALID_HANDLE_VALUE)
+ if ((fil->fil_fd = os_utils::open(nm.c_str(), MODE_READ)) == INVALID_HANDLE_VALUE)
#endif
{
BURP_error(65, false, fil->fil_name.c_str());
Modified: firebird/trunk/src/burp/mvol.cpp
===================================================================
--- firebird/trunk/src/burp/mvol.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/burp/mvol.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -44,6 +44,7 @@
#include "../burp/mvol_proto.h"
#include "../yvalve/gds_proto.h"
#include "../common/gdsassert.h"
+#include "../common/os/os_utils.h"
#include <fcntl.h>
#include <sys/types.h>
@@ -905,7 +906,7 @@
new_desc = MVOL_open(new_file, mode, OPEN_ALWAYS);
if (new_desc == INVALID_HANDLE_VALUE)
#else
- new_desc = open(new_file, mode, open_mask);
+ new_desc = os_utils::open(new_file, mode, open_mask);
if (new_desc < 0)
#endif // WIN_NT
{
@@ -975,12 +976,12 @@
// Get a location to read from.
fb_assert(!tdgbl->uSvc->isService());
- if (isatty(fileno(stdout)) || !(term_out = fopen(TERM_OUTPUT, "w")))
+ if (isatty(fileno(stdout)) || !(term_out = os_utils::fopen(TERM_OUTPUT, "w")))
{
term_out = stdout;
}
- if (isatty(fileno(stdin)) || !(term_in = fopen(TERM_INPUT, "r")))
+ if (isatty(fileno(stdin)) || !(term_in = os_utils::fopen(TERM_INPUT, "r")))
{
term_in = stdin;
}
Modified: firebird/trunk/src/burp/split/spit.cpp
===================================================================
--- firebird/trunk/src/burp/split/spit.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/burp/split/spit.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -49,6 +49,7 @@
#include "../common/classes/Switches.h"
#include "../burp/std_desc.h"
#include "../burp/burpswi.h"
+#include "../common/os/os_utils.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -68,7 +69,7 @@
return CreateFile(name, (writeFlag ? GENERIC_WRITE : GENERIC_READ), 0, NULL,
(writeFlag ? CREATE_ALWAYS : OPEN_EXISTING), FILE_ATTRIBUTE_NORMAL, 0);
#else
- return open(name, (writeFlag ? mode_write : mode_read), mask);
+ return os_utils::open(name, (writeFlag ? mode_write : mode_read), mask);
#endif
}
Modified: firebird/trunk/src/common/classes/TempFile.cpp
===================================================================
--- firebird/trunk/src/common/classes/TempFile.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/classes/TempFile.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -216,9 +216,7 @@
system_error::raise("mktemp");
}
- do {
- handle = open(filename.c_str(), O_RDWR | O_EXCL | O_CREAT);
- } while (handle == -1 && errno == EINTR);
+ handle = os_utils::open(filename.c_str(), O_RDWR | O_EXCL | O_CREAT);
#endif
if (handle == -1)
Modified: firebird/trunk/src/common/classes/alloc.cpp
===================================================================
--- firebird/trunk/src/common/classes/alloc.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/classes/alloc.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -52,6 +52,7 @@
#include "../common/classes/locks.h"
#include "../common/classes/init.h"
#include "../common/classes/vector.h"
+#include "../common/os/os_utils.h"
#include "gen/iberror.h"
#ifdef USE_VALGRIND
@@ -828,7 +829,7 @@
#else // MAP_ANONYMOUS
if (dev_zero_fd < 0)
- dev_zero_fd = open("/dev/zero", O_RDWR);
+ dev_zero_fd = os_utils::open("/dev/zero", O_RDWR);
void* result = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero_fd, 0);
#endif // MAP_ANONYMOUS
@@ -1015,7 +1016,7 @@
void MemoryPool::print_contents(const char* filename, bool used_only, const char* filter_path) throw ()
{
- FILE* out = fopen(filename, "w");
+ FILE* out = os_utils::fopen(filename, "w");
if (!out)
return;
Modified: firebird/trunk/src/common/config/config_file.cpp
===================================================================
--- firebird/trunk/src/common/config/config_file.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/config/config_file.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -28,6 +28,7 @@
#include "../common/config/config.h"
#include "../common/config/ConfigCache.h"
#include "../common/os/path_utils.h"
+#include "../common/os/os_utils.h"
#include "../common/ScanDir.h"
#include "../common/utils_proto.h"
#include <stdio.h>
@@ -49,7 +50,7 @@
{
public:
MainStream(const char* fname, bool errorWhenMissing)
- : file(fopen(fname, "rt")), fileName(fname), l(0)
+ : file(os_utils::fopen(fname, "rt")), fileName(fname), l(0)
{
if (errorWhenMissing && !file)
{
Modified: firebird/trunk/src/common/isc_file.cpp
===================================================================
--- firebird/trunk/src/common/isc_file.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/isc_file.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -116,7 +116,7 @@
#define MTAB_OPEN(path, type) setmntent(path, "r")
#define MTAB_CLOSE(stream) endmntent(stream)
#else
-#define MTAB_OPEN(path, type) fopen(path, type)
+#define MTAB_OPEN(path, type) os_utils::fopen(path, type)
#define MTAB_CLOSE(stream) fclose(stream)
#endif
Modified: firebird/trunk/src/common/os/os_utils.h
===================================================================
--- firebird/trunk/src/common/os/os_utils.h 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/os/os_utils.h 2014-12-17 14:31:02 UTC (rev 60379)
@@ -28,9 +28,7 @@
#ifndef INCLUDE_OS_FILE_UTILS_H
#define INCLUDE_OS_FILE_UTILS_H
-#ifdef SFIO
#include <stdio.h>
-#endif
#include "../common/classes/fb_string.h"
#include "../common/StatusArg.h"
@@ -47,6 +45,11 @@
bool touchFile(const char* pathname);
bool isIPv6supported();
+
+ // force descriptor to have O_CLOEXEC set
+ int open(const char *pathname, int flags, mode_t mode = 0666);
+ void setCloseOnExec(int fd); // posix only
+ FILE* fopen(const char *pathname, const char *mode);
} // namespace os_utils
#endif // INCLUDE_OS_FILE_UTILS_H
Modified: firebird/trunk/src/common/os/posix/divorce.cpp
===================================================================
--- firebird/trunk/src/common/os/posix/divorce.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/os/posix/divorce.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -52,6 +52,7 @@
#include "firebird.h"
#include "../common/os/divorce.h"
#include "../common/classes/semaphore.h"
+#include "../common/os/os_utils.h"
#ifdef HAVE_IO_H
#include <io.h>
@@ -123,7 +124,7 @@
// Perform terminal divorce
// this is in case of BSD systems
- fid = open("/dev/tty", 2);
+ fid = os_utils::open("/dev/tty", 2);
if (fid >= 0) {
ioctl(fid, TIOCNOTTY, 0);
Modified: firebird/trunk/src/common/os/posix/guid.cpp
===================================================================
--- firebird/trunk/src/common/os/posix/guid.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/os/posix/guid.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -30,6 +30,7 @@
#include "../common/os/guid.h"
#include "fb_exception.h"
+#include "../common/os/os_utils.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -43,15 +44,7 @@
void GenerateRandomBytes(void* buffer, FB_SIZE_T size)
{
// do not use /dev/random because it may return lesser data than we need.
- int fd = -1;
- for (;;)
- {
- fd = open("/dev/urandom", O_RDONLY);
- if (fd >= 0)
- break;
- if (errno != EINTR)
- Firebird::system_call_failed::raise("open");
- }
+ int fd = os_utils::open("/dev/urandom", O_RDONLY);
for (FB_SIZE_T offset = 0; offset < size; )
{
int rc = read(fd, static_cast<char*>(buffer) + offset, size - offset);
Modified: firebird/trunk/src/common/os/posix/os_utils.cpp
===================================================================
--- firebird/trunk/src/common/os/posix/os_utils.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/os/posix/os_utils.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -58,6 +58,14 @@
#include <pwd.h>
#endif
+#ifdef HAVE_ACCEPT4
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+
using namespace Firebird;
namespace os_utils
@@ -117,6 +125,7 @@
}
} // anonymous namespace
+
// create directory for lock files and set appropriate access rights
void createLockDirectory(const char* pathname)
{
@@ -173,11 +182,7 @@
// open (or create if missing) and set appropriate access rights
int openCreateSharedFile(const char* pathname, int flags)
{
- int fd;
- do {
- fd = ::open(pathname, flags | O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
- } while (fd < 0 && SYSCALL_INTERRUPTED(errno));
-
+ int fd = os_utils::open(pathname, flags | O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
if (fd < 0)
raiseError(fd, pathname);
@@ -235,4 +240,41 @@
return true;
}
+// setting flag is not absolutely required, therefore ignore errors here
+void setCloseOnExec(int fd)
+{
+ if (fd >= 0)
+ {
+ while (fcntl(fd, F_SETFD, O_CLOEXEC) < 0 && SYSCALL_INTERRUPTED(errno))
+ ;
+ }
+}
+
+// force file descriptor to have O_CLOEXEC set
+int open(const char *pathname, int flags, mode_t mode)
+{
+ int fd;
+ do {
+ fd = ::open(pathname, flags | O_CLOEXEC, mode);
+ } while (fd < 0 && SYSCALL_INTERRUPTED(errno));
+
+ if (fd < 0 && errno == EINVAL) // probably O_CLOEXEC not accepted
+ {
+ do {
+ fd = ::open(pathname, flags | O_CLOEXEC, mode);
+ } while (fd < 0 && SYSCALL_INTERRUPTED(errno));
+ }
+
+ setCloseOnExec(fd);
+ return fd;
+}
+
+FILE* fopen(const char *pathname, const char *mode)
+{
+ FILE* f = ::fopen(pathname, mode); // TODO: use open + fdopen to avoid races
+ if (f)
+ setCloseOnExec(fileno(f));
+ return f;
+}
+
} // namespace os_utils
Modified: firebird/trunk/src/common/os/win32/os_utils.cpp
===================================================================
--- firebird/trunk/src/common/os/win32/os_utils.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/os/win32/os_utils.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -303,4 +303,14 @@
return false;
}
+int open(const char *pathname, int flags, mode_t mode = 0666)
+{
+ return ::_open(char *pathname, flags, mode);
+}
+
+FILE* fopen(const char *pathname, const char *mode)
+{
+ return ::fopen(pathname, mode);
+}
+
} // namespace os_utils
Modified: firebird/trunk/src/common/utils.cpp
===================================================================
--- firebird/trunk/src/common/utils.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/common/utils.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -49,6 +49,7 @@
#include "../common/os/path_utils.h"
#include "../common/os/fbsyslog.h"
#include "../common/StatusArg.h"
+#include "../common/os/os_utils.h"
#include "../dsql/sqlda_pub.h"
#ifdef WIN_NT
@@ -734,7 +735,7 @@
f = stdin;
}
else {
- f = fopen(name.c_str(), "rt");
+ f = os_utils::fopen(name.c_str(), "rt");
}
if (f && isatty(fileno(f)))
{
Modified: firebird/trunk/src/jrd/Optimizer.cpp
===================================================================
--- firebird/trunk/src/jrd/Optimizer.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/jrd/Optimizer.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -2255,7 +2255,7 @@
*
**************************************/
- FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
+ FILE *opt_debug_file = os_utils::fopen(OPTIMIZER_DEBUG_FILE, "a");
fprintf(opt_debug_file, " cost(%1.2f), selectivity(%1.10f), indexes(%d), matched(%d, %d)",
candidate->cost, candidate->selectivity, candidate->indexes, candidate->matchedSegments,
candidate->nonFullMatchedSegments);
@@ -2289,7 +2289,7 @@
*
**************************************/
- FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
+ FILE *opt_debug_file = os_utils::fopen(OPTIMIZER_DEBUG_FILE, "a");
fprintf(opt_debug_file, " retrieval candidates:\n");
fclose(opt_debug_file);
const InversionCandidate* const* inversion = inversions->begin();
@@ -2314,7 +2314,7 @@
if (candidate)
{
- FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
+ FILE *opt_debug_file = os_utils::fopen(OPTIMIZER_DEBUG_FILE, "a");
fprintf(opt_debug_file, " final candidate: ");
fclose(opt_debug_file);
printCandidate(candidate);
@@ -3037,7 +3037,7 @@
*
**************************************/
- FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
+ FILE *opt_debug_file = os_utils::fopen(OPTIMIZER_DEBUG_FILE, "a");
fprintf(opt_debug_file, " best order, streams: ");
for (StreamType i = 0; i < optimizer->opt_best_count; i++)
{
@@ -3064,7 +3064,7 @@
*
**************************************/
- FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
+ FILE *opt_debug_file = os_utils::fopen(OPTIMIZER_DEBUG_FILE, "a");
fprintf(opt_debug_file, " position %2.2d:", position);
fprintf(opt_debug_file, " pos. cardinality(%10.2f) pos. cost(%10.2f)", positionCardinality, positionCost);
fprintf(opt_debug_file, " cardinality(%10.2f) cost(%10.2f)", cardinality, cost);
@@ -3095,7 +3095,7 @@
*
**************************************/
- FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
+ FILE *opt_debug_file = os_utils::fopen(OPTIMIZER_DEBUG_FILE, "a");
fprintf(opt_debug_file, " basestream %d, relationships: stream(cost)", stream);
const IndexRelationship* const* relationships = processList->begin();
for (int i = 0; i < processList->getCount(); i++)
@@ -3116,7 +3116,7 @@
*
**************************************/
- FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
+ FILE *opt_debug_file = os_utils::fopen(OPTIMIZER_DEBUG_FILE, "a");
fprintf(opt_debug_file, "Start join order: with stream(baseCost)");
bool firstStream = true;
for (int i = 0; i < innerStreams.getCount(); i++)
Modified: firebird/trunk/src/jrd/ext.cpp
===================================================================
--- firebird/trunk/src/jrd/ext.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/jrd/ext.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -59,6 +59,7 @@
#include "../common/os/path_utils.h"
#include "../common/classes/init.h"
#include "../common/isc_f_proto.h"
+#include "../common/os/os_utils.h"
#if defined _MSC_VER && _MSC_VER < 1400
// NS: in VS2003 these only work with static CRT
@@ -135,12 +136,12 @@
// RW mode. If the DB is ReadOnly, then open the external files only in
// ReadOnly mode, thus being consistent.
if (!dbb->readOnly())
- ext_file->ext_ifi = fopen(file_name, FOPEN_TYPE);
+ ext_file->ext_ifi = os_utils::fopen(file_name, FOPEN_TYPE);
if (!ext_file->ext_ifi)
{
// could not open the file as read write attempt as read only
- if (!(ext_file->ext_ifi = fopen(file_name, FOPEN_READ_ONLY)))
+ if (!(ext_file->ext_ifi = os_utils::fopen(file_name, FOPEN_READ_ONLY)))
{
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("fopen") << Arg::Str(file_name) <<
Arg::Gds(isc_io_open_err) << SYS_ERR(errno));
Modified: firebird/trunk/src/jrd/jrd.cpp
===================================================================
--- firebird/trunk/src/jrd/jrd.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/jrd/jrd.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -5196,7 +5196,7 @@
TEXT fname[MAXPATHLEN];
Firebird::string fname = fb_utils::getPrefix(IConfigManager::FB_DIR_LOG, "proc_info.log");
- FILE* fptr = fopen(fname.c_str(), "a+");
+ FILE* fptr = os_utils::fopen(fname.c_str(), "a+");
if (!fptr)
{
gds__log("Failed to open %s\n", fname.c_str());
Modified: firebird/trunk/src/jrd/opt.cpp
===================================================================
--- firebird/trunk/src/jrd/opt.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/jrd/opt.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -82,6 +82,7 @@
#include "../jrd/UserManagement.h"
#include "../common/classes/array.h"
#include "../common/classes/objects_array.h"
+#include "../common/os/os_utils.h"
#include "../jrd/recsrc/RecordSource.h"
#include "../jrd/recsrc/Cursor.h"
#include "../jrd/Mapping.h"
@@ -466,7 +467,7 @@
#ifdef OPT_DEBUG
if (opt_debug_flag != DEBUG_NONE && !opt_debug_file)
- opt_debug_file = fopen("opt_debug.out", "w");
+ opt_debug_file = os_utils::fopen("opt_debug.out", "w");
#endif
// If there is a boolean, there is some work to be done. First,
Modified: firebird/trunk/src/jrd/os/posix/unix.cpp
===================================================================
--- firebird/trunk/src/jrd/os/posix/unix.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/jrd/os/posix/unix.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -67,6 +67,7 @@
#include "../jrd/ods_proto.h"
#include "../jrd/os/pio_proto.h"
#include "../common/classes/init.h"
+#include "../common/os/os_utils.h"
using namespace Jrd;
using namespace Firebird;
@@ -215,7 +216,7 @@
#endif
#endif
- const int desc = open(file_name.c_str(), flag, 0666);
+ const int desc = os_utils::open(file_name.c_str(), flag, 0666);
if (desc == -1)
{
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("open O_CREAT") << Arg::Str(file_name) <<
@@ -891,16 +892,7 @@
flag |= O_DIRECT;
#endif
- for (int i = 0; i < IO_RETRY; i++)
- {
- int desc = open(name, flag);
- if (desc != -1)
- return desc;
- if (!SYSCALL_INTERRUPTED(errno))
- break;
- }
-
- return -1;
+ return os_utils::open(name, flag);
}
@@ -1213,18 +1205,12 @@
static int raw_devices_unlink_database(const PathName& file_name)
{
char header[MIN_PAGE_SIZE];
- int desc = -1;
- for (int i = 0; i < IO_RETRY; i++)
+ int desc = os_utils::open(file_name.c_str(), O_RDWR | O_BINARY);
+ if (desc < 0)
{
- if ((desc = open (file_name.c_str(), O_RDWR | O_BINARY)) != -1)
- break;
-
- if (!SYSCALL_INTERRUPTED(errno))
- {
- ERR_post(Arg::Gds(isc_io_error) << Arg::Str("open") << Arg::Str(file_name) <<
- Arg::Gds(isc_io_open_err) << Arg::Unix(errno));
- }
+ ERR_post(Arg::Gds(isc_io_error) << Arg::Str("open") << Arg::Str(file_name) <<
+ Arg::Gds(isc_io_open_err) << Arg::Unix(errno));
}
memset(header, 0xa5, sizeof(header));
Modified: firebird/trunk/src/jrd/svc.cpp
===================================================================
--- firebird/trunk/src/jrd/svc.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/jrd/svc.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -63,6 +63,7 @@
#include "../jrd/EngineInterface.h"
#include "../jrd/Mapping.h"
#include "../common/classes/RefMutex.h"
+#include "../common/os/os_utils.h"
#include "../common/classes/DbImplementation.h"
@@ -2194,7 +2195,7 @@
bool svc_started = false;
Firebird::PathName name = fb_utils::getPrefix(IConfigManager::FB_DIR_LOG, LOGFILE);
- FILE* file = fopen(name.c_str(), "r");
+ FILE* file = os_utils::fopen(name.c_str(), "r");
try
{
Modified: firebird/trunk/src/jrd/trace/TraceConfigStorage.cpp
===================================================================
--- firebird/trunk/src/jrd/trace/TraceConfigStorage.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/jrd/trace/TraceConfigStorage.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -208,7 +208,7 @@
}
else
{
- m_cfg_file = ::open(cfg_file_name, O_RDWR | O_BINARY);
+ m_cfg_file = os_utils::open(cfg_file_name, O_RDWR | O_BINARY);
if (m_cfg_file < 0)
checkFileError(cfg_file_name, "open", isc_io_open_err);
@@ -244,7 +244,7 @@
configFileName.insert(0, root);
}
- cfgFile = fopen(configFileName.c_str(), "rb");
+ cfgFile = os_utils::fopen(configFileName.c_str(), "rb");
if (!cfgFile) {
checkFileError(configFileName.c_str(), "fopen", isc_io_open_err);
}
Modified: firebird/trunk/src/lock/lock.cpp
===================================================================
--- firebird/trunk/src/lock/lock.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/lock/lock.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -54,6 +54,7 @@
#include "../common/classes/semaphore.h"
#include "../common/classes/init.h"
#include "../common/classes/timestamp.h"
+#include "../common/os/os_utils.h"
#include <stdio.h>
#include <errno.h>
@@ -1621,7 +1622,7 @@
TEXT buffer[MAXPATHLEN];
gds__prefix_lock(buffer, "fb_lock_table.dump");
const TEXT* const lock_file = buffer;
- FILE* const fd = fopen(lock_file, "wb");
+ FILE* const fd = os_utils::fopen(lock_file, "wb");
if (fd)
{
FB_UNUSED(fwrite(header, 1, header->lhb_used, fd));
Modified: firebird/trunk/src/remote/SockAddr.h
===================================================================
--- firebird/trunk/src/remote/SockAddr.h 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/remote/SockAddr.h 2014-12-17 14:31:02 UTC (rev 60379)
@@ -45,7 +45,6 @@
#include "../remote/remote.h"
-
class SockAddr
{
private:
@@ -111,7 +110,7 @@
inline int SockAddr::accept(SOCKET s)
{
- return ::accept(s, (struct sockaddr*) data, &len);
+ return os_utils::accept(s, (struct sockaddr*) data, &len);
}
Modified: firebird/trunk/src/remote/inet.cpp
===================================================================
--- firebird/trunk/src/remote/inet.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/remote/inet.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -54,6 +54,7 @@
#include "../common/classes/timestamp.h"
#include "../common/classes/init.h"
#include "../common/ThreadStart.h"
+#include "../common/os/os_utils.h"
#ifdef HAVE_PWD_H
#include <pwd.h>
@@ -111,7 +112,6 @@
#include "../common/config/config.h"
#include "../common/utils_proto.h"
#include "../common/classes/ClumpletWriter.h"
-#include "../common/os/os_utils.h"
// Please review. Maybe not needed. See H_ERRNO in common.h.
#if defined HPUX
@@ -842,7 +842,7 @@
for (const addrinfo* pai = gai_result; pai; pai = pai->ai_next)
{
// Allocate a port block and initialize a socket for communications
- port->port_handle = socket(pai->ai_family, pai->ai_socktype, pai->ai_protocol);
+ port->port_handle = os_utils::socket(pai->ai_family, pai->ai_socktype, pai->ai_protocol);
if (port->port_handle == INVALID_SOCKET)
{
@@ -997,7 +997,7 @@
while (true)
{
- SOCKET s = accept(port->port_handle, NULL, NULL);
+ SOCKET s = os_utils::accept(port->port_handle, NULL, NULL);
const int inetErrNo = INET_ERRNO;
if (s == INVALID_SOCKET)
{
@@ -1371,7 +1371,7 @@
}
}
- const SOCKET n = accept(port->port_channel, NULL, NULL);
+ const SOCKET n = os_utils::accept(port->port_channel, NULL, NULL);
inetErrNo = INET_ERRNO;
if (n == INVALID_SOCKET)
@@ -1416,7 +1416,7 @@
// Set up new socket
- SOCKET n = socket(address.family(), SOCK_STREAM, 0);
+ SOCKET n = os_utils::socket(address.family(), SOCK_STREAM, 0);
if (n == INVALID_SOCKET)
{
int savedError = INET_ERRNO;
@@ -1465,7 +1465,7 @@
unsigned short aux_port = port->getPortConfig()->getRemoteAuxPort();
our_address.setPort(aux_port); // may be 0
- SOCKET n = socket(our_address.family(), SOCK_STREAM, 0);
+ SOCKET n = os_utils::socket(our_address.family(), SOCK_STREAM, 0);
if (n == INVALID_SOCKET)
{
inet_error(false, port, "socket", isc_net_event_listen_err, INET_ERRNO);
@@ -1966,7 +1966,7 @@
rem_port* const port = alloc_port(main_port);
inet_ports->registerPort(port);
- port->port_handle = accept(main_port->port_handle, NULL, NULL);
+ port->port_handle = os_utils::accept(main_port->port_handle, NULL, NULL);
if (port->port_handle == INVALID_SOCKET)
{
inet_error(true, port, "accept", isc_net_connect_err, INET_ERRNO);
@@ -3081,3 +3081,58 @@
**************************************/
tryStopMainThread = func;
}
+
+namespace os_utils
+{
+
+// force socket descriptor to have O_CLOEXEC set
+int socket(int domain, int type, int protocol)
+{
+#ifdef WIN_NT
+ return ::socket(domain, type, protocol);
+#else
+ int fd;
+ do {
+ fd = ::socket(domain, type | O_CLOEXEC, protocol);
+ } while (fd < 0 && SYSCALL_INTERRUPTED(errno));
+
+ if (fd < 0 && errno == EINVAL) // probably O_CLOEXEC not accepted
+ {
+ do {
+ fd = ::socket(domain, type, protocol);
+ } while (fd < 0 && SYSCALL_INTERRUPTED(errno));
+ }
+
+ setCloseOnExec(fd);
+ return fd;
+#endif
+}
+
+// force socket descriptor to have O_CLOEXEC set
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
+{
+#ifdef WIN_NT
+ return ::accept(sockfd, addr, addrlen);
+#else
+ int fd;
+#ifdef HAVE_ACCEPT4
+ do {
+ fd = ::accept4(sockfd, addr, addrlen, O_CLOEXEC);
+ } while (fd < 0 && SYSCALL_INTERRUPTED(errno));
+
+ if (fd < 0 && errno == EINVAL) // probably O_CLOEXEC not accepted
+ {
+#endif
+ do {
+ fd = ::accept(sockfd, addr, addrlen);
+ } while (fd < 0 && SYSCALL_INTERRUPTED(errno));
+#ifdef HAVE_ACCEPT4
+ }
+#endif
+
+ setCloseOnExec(fd);
+ return fd;
+#endif
+}
+
+} // namespace os_utils
Modified: firebird/trunk/src/remote/remote.h
===================================================================
--- firebird/trunk/src/remote/remote.h 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/remote/remote.h 2014-12-17 14:31:02 UTC (rev 60379)
@@ -105,6 +105,17 @@
class Exception;
}
+#ifndef WIN_NT
+typedef int SOCKET;
+#endif
+
+namespace os_utils
+{
+ // force descriptor to have O_CLOEXEC set
+ SOCKET socket(int domain, int type, int protocol);
+ SOCKET accept(SOCKET sockfd, sockaddr *addr, socklen_t *addrlen);
+}
+
struct rem_port;
typedef Firebird::AutoPtr<UCHAR, Firebird::ArrayDelete<UCHAR> > UCharArrayAutoPtr;
@@ -586,11 +597,6 @@
// Generalized port definition.
-#ifndef WIN_NT
-typedef int SOCKET;
-#endif
-
-
//////////////////////////////////////////////////////////////////
// fwd. decl.
struct p_cnct;
Modified: firebird/trunk/src/remote/server/os/posix/inet_server.cpp
===================================================================
--- firebird/trunk/src/remote/server/os/posix/inet_server.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/remote/server/os/posix/inet_server.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -40,6 +40,7 @@
#include "../common/classes/init.h"
#include "../common/config/config.h"
#include "../common/os/fbsyslog.h"
+#include "../common/os/os_utils.h"
#include <sys/param.h>
#ifdef HAVE_SYS_TYPES_H
@@ -425,7 +426,7 @@
//gds_alloc_report(0, __FILE__, __LINE__);
Firebird::PathName name = fb_utils::getPrefix(
Firebird::IConfigManager::FB_DIR_LOG, "memdebug.log");
- FILE* file = fopen(name.c_str(), "w+t");
+ FILE* file = os_utils::fopen(name.c_str(), "w+t");
if (file)
{
fprintf(file, "Global memory pool allocated objects\n");
Modified: firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp
===================================================================
--- firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -109,6 +109,7 @@
#include "firebird/Interface.h"
#include "../common/classes/ImplementHelper.h"
+#include "../common/os/os_utils.h"
#include "../auth/trusted/AuthSspi.h"
#include "../auth/SecurityDatabase/LegacyServer.h"
#include "../auth/SecureRemotePassword/server/SrpServer.h"
@@ -346,7 +347,7 @@
//gds_alloc_report(0, __FILE__, __LINE__);
PathName name = fb_utils::getPrefix(IConfigManager::FB_DIR_LOG, "memdebug.log");
- FILE* file = fopen(name.c_str(), "w+t");
+ FILE* file = os_utils::fopen(name.c_str(), "w+t");
if (file)
{
fprintf(file, "Global memory pool allocated objects\n");
Modified: firebird/trunk/src/remote/server/server.cpp
===================================================================
--- firebird/trunk/src/remote/server/server.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/remote/server/server.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -73,6 +73,7 @@
#include "../auth/SecurityDatabase/LegacyHash.h"
#include "../common/enc_proto.h"
#include "../common/classes/InternalMessageBuffer.h"
+#include "../common/os/os_utils.h"
using namespace Firebird;
@@ -637,12 +638,10 @@
firebirdPortMutex.printf(PORT_FILE, id);
TEXT filename[MAXPATHLEN];
gds__prefix_lock(filename, firebirdPortMutex.c_str());
- while ((fd = open(filename, O_WRONLY | O_CREAT, 0666)) < 0)
+ fd = os_utils::open(filename, O_WRONLY | O_CREAT, 0666);
+ if (fd < 0)
{
- if (errno != EINTR)
- {
- system_call_failed::raise("open");
- }
+ system_call_failed::raise("open");
}
struct flock lock;
Modified: firebird/trunk/src/utilities/analyse.cpp
===================================================================
--- firebird/trunk/src/utilities/analyse.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/utilities/analyse.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -329,7 +329,7 @@
*
**************************************/
- if ((file = open(file_name, 2)) == -1)
+ if ((file = os_utils::open(file_name, 2)) == -1)
db_error(errno);
}
Modified: firebird/trunk/src/utilities/gstat/dba.epp
===================================================================
--- firebird/trunk/src/utilities/gstat/dba.epp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/utilities/gstat/dba.epp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -54,6 +54,7 @@
#include "../jrd/ods_proto.h"
#include "../common/classes/MsgPrint.h"
#include "../common/classes/UserBlob.h"
+#include "../common/os/os_utils.h"
using MsgFormat::SafeArg;
@@ -1949,7 +1950,7 @@
fil->fil_fudge = 0;
fil->fil_max_page = 0L;
- if ((fil->fil_desc = open(file_name, O_RDONLY)) == -1)
+ if ((fil->fil_desc = os_utils::open(file_name, O_RDONLY)) == -1)
{
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name);
// msg 29: Can't open database file %s
Modified: firebird/trunk/src/utilities/nbackup/nbackup.cpp
===================================================================
--- firebird/trunk/src/utilities/nbackup/nbackup.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/utilities/nbackup/nbackup.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -53,6 +53,7 @@
#include "../common/isc_f_proto.h"
#include "../common/StatusArg.h"
#include "../common/classes/objects_array.h"
+#include "../common/os/os_utils.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -457,7 +458,7 @@
if (dbase != INVALID_HANDLE_VALUE)
return;
#else
- dbase = open(dbname.c_str(), O_RDWR | O_LARGEFILE);
+ dbase = os_utils::open(dbname.c_str(), O_RDWR | O_LARGEFILE);
if (dbase >= 0)
return;
#endif
@@ -497,11 +498,11 @@
#define O_DIRECT 0
#endif // O_DIRECT
- dbase = open(dbname.c_str(), O_RDONLY | O_LARGEFILE | O_NOATIME | (direct_io ? O_DIRECT : 0));
+ dbase = os_utils::open(dbname.c_str(), O_RDONLY | O_LARGEFILE | O_NOATIME | (direct_io ? O_DIRECT : 0));
if (dbase < 0)
{
// Non-root may fail when opening file of another user with O_NOATIME
- dbase = open(dbname.c_str(), O_RDONLY | O_LARGEFILE | (direct_io ? O_DIRECT : 0));
+ dbase = os_utils::open(dbname.c_str(), O_RDONLY | O_LARGEFILE | (direct_io ? O_DIRECT : 0));
}
if (dbase < 0)
{
@@ -540,7 +541,7 @@
if (dbase != INVALID_HANDLE_VALUE)
return;
#else
- dbase = open(dbname.c_str(), O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, 0660);
+ dbase = os_utils::open(dbname.c_str(), O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, 0660);
if (dbase >= 0)
return;
#endif
@@ -655,7 +656,7 @@
}
else
{
- backup = open(nm.c_str(), O_RDONLY | O_LARGEFILE);
+ backup = os_utils::open(nm.c_str(), O_RDONLY | O_LARGEFILE);
if (backup >= 0)
return;
}
@@ -684,7 +685,7 @@
backup = 1; // Posix file handle for stdout
return;
}
- backup = open(nm.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, 0660);
+ backup = os_utils::open(nm.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, 0660);
if (backup >= 0)
return;
#endif
Modified: firebird/trunk/src/yvalve/gds.cpp
===================================================================
--- firebird/trunk/src/yvalve/gds.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/yvalve/gds.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -1077,7 +1077,7 @@
ReleaseMutex(CleanupTraceHandles::trace_mutex_handle);
#else
Firebird::PathName name = fb_utils::getPrefix(Firebird::IConfigManager::FB_DIR_LOG, LOGFILE);
- int file = open(name.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0660);
+ int file = os_utils::open(name.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0660);
if (file == -1)
return;
@@ -1186,7 +1186,7 @@
#ifdef WIN_NT
WaitForSingleObject(CleanupTraceHandles::trace_mutex_handle, INFINITE);
#endif
- FILE* file = fopen(name.c_str(), "a");
+ FILE* file = os_utils::fopen(name.c_str(), "a");
if (file != NULL)
{
#ifndef WIN_NT
@@ -1252,7 +1252,7 @@
#ifdef WIN_NT
WaitForSingleObject(CleanupTraceHandles::trace_mutex_handle, INFINITE);
#endif
- FILE* file = fopen(name.c_str(), "a");
+ FILE* file = os_utils::fopen(name.c_str(), "a");
if (file != NULL)
{
TEXT buffer[MAXPATHLEN];
@@ -1585,7 +1585,7 @@
* and update a message handle.
*
**************************************/
- const int n = open(filename, O_RDONLY | O_BINARY, 0);
+ const int n = os_utils::open(filename, O_RDONLY | O_BINARY, 0);
if (n < 0)
return -2;
@@ -2414,11 +2414,11 @@
if (stdio_flag)
{
- FILE* result = fopen(filename.c_str(), "w+b");
+ FILE* result = os_utils::fopen(filename.c_str(), "w+b");
return result ? result : (void*) (IPTR) (-1);
}
- return (void*) (IPTR) open(filename.c_str(), O_RDWR | O_EXCL | O_TRUNC);
+ return (void*) (IPTR) os_utils::open(filename.c_str(), O_RDWR | O_EXCL | O_TRUNC);
}
catch (const Firebird::Exception&)
{
Modified: firebird/trunk/src/yvalve/utl.cpp
===================================================================
--- firebird/trunk/src/yvalve/utl.cpp 2014-12-17 11:56:48 UTC (rev 60378)
+++ firebird/trunk/src/yvalve/utl.cpp 2014-12-17 14:31:02 UTC (rev 60379)
@@ -66,6 +66,7 @@
#include "../common/isc_f_proto.h"
#include "../common/StatusHolder.h"
#include "../common/classes/ImplementHelper.h"
+#include "../common/os/os_utils.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -316,7 +317,7 @@
if (status->getStatus() & Firebird::IStatus::FB_HAS_ERRORS)
return FB_FALSE;
- FILE* file = fopen(tmpf.c_str(), FOPEN_WRITE_TYPE_TEXT);
+ FILE* file = os_utils::fopen(tmpf.c_str(), FOPEN_WRITE_TYPE_TEXT);
if (!file)
{
unlink(tmpf.c_str());
@@ -338,7 +339,7 @@
if (gds__edit(tmpf.c_str(), type))
{
- if (!(file = fopen(tmpf.c_str(), FOPEN_READ_TYPE_TEXT)))
+ if (!(file = os_utils::fopen(tmpf.c_str(), FOPEN_READ_TYPE_TEXT)))
{
unlink(tmpf.c_str());
system_error::raise("fopen");
@@ -364,7 +365,7 @@
void UtlInterface::dumpBlob(IStatus* status, ISC_QUAD* blobId,
IAttachment* att, ITransaction* tra, const char* file_name, FB_BOOLEAN txt)
{
- FILE* file = fopen(file_name, txt ? FOPEN_WRITE_TYPE_TEXT : FOPEN_WRITE_TYPE);
+ FILE* file = os_utils::fopen(file_name, txt ? FOPEN_WRITE_TYPE_TEXT : FOPEN_WRITE_TYPE);
try
{
if (!file)
@@ -397,7 +398,7 @@
* Load a blob with the contents of a file.
*
**************************************/
- FILE* file = fopen(file_name, txt ? FOPEN_READ_TYPE_TEXT : FOPEN_READ_TYPE);
+ FILE* file = os_utils::fopen(file_name, txt ? FOPEN_READ_TYPE_TEXT : FOPEN_READ_TYPE);
try
{
if (!file)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|