Merge branch 'ef/mingw-daemon'
* ef/mingw-daemon: daemon: opt-out on features that require posix daemon: make --inetd and --detach incompatible daemon: use socklen_t mingw: use poll-emulation from gnulib mingw: import poll-emulation from gnulib daemon: get remote host address from root-process Improve the mingw getaddrinfo stub to handle more use cases daemon: use full buffered mode for stderr daemon: use run-command api for async serving mingw: add kill emulation mingw: support waitpid with pid > 0 and WNOHANG mingw: use real pid inet_ntop: fix a couple of old-style decls compat: add inet_pton and inet_ntop prototypes mingw: implement syslog mingw: add network-wrappers for daemon
This commit is contained in:
@ -78,7 +78,8 @@ OPTIONS
|
|||||||
|
|
||||||
--inetd::
|
--inetd::
|
||||||
Have the server run as an inetd service. Implies --syslog.
|
Have the server run as an inetd service. Implies --syslog.
|
||||||
Incompatible with --port, --listen, --user and --group options.
|
Incompatible with --detach, --port, --listen, --user and --group
|
||||||
|
options.
|
||||||
|
|
||||||
--listen=<host_or_ipaddr>::
|
--listen=<host_or_ipaddr>::
|
||||||
Listen on a specific IP address or hostname. IP addresses can
|
Listen on a specific IP address or hostname. IP addresses can
|
||||||
|
23
Makefile
23
Makefile
@ -401,6 +401,7 @@ EXTRA_PROGRAMS =
|
|||||||
# ... and all the rest that could be moved out of bindir to gitexecdir
|
# ... and all the rest that could be moved out of bindir to gitexecdir
|
||||||
PROGRAMS += $(EXTRA_PROGRAMS)
|
PROGRAMS += $(EXTRA_PROGRAMS)
|
||||||
|
|
||||||
|
PROGRAM_OBJS += daemon.o
|
||||||
PROGRAM_OBJS += fast-import.o
|
PROGRAM_OBJS += fast-import.o
|
||||||
PROGRAM_OBJS += imap-send.o
|
PROGRAM_OBJS += imap-send.o
|
||||||
PROGRAM_OBJS += shell.o
|
PROGRAM_OBJS += shell.o
|
||||||
@ -496,6 +497,8 @@ LIB_H += compat/bswap.h
|
|||||||
LIB_H += compat/cygwin.h
|
LIB_H += compat/cygwin.h
|
||||||
LIB_H += compat/mingw.h
|
LIB_H += compat/mingw.h
|
||||||
LIB_H += compat/win32/pthread.h
|
LIB_H += compat/win32/pthread.h
|
||||||
|
LIB_H += compat/win32/syslog.h
|
||||||
|
LIB_H += compat/win32/sys/poll.h
|
||||||
LIB_H += csum-file.h
|
LIB_H += csum-file.h
|
||||||
LIB_H += decorate.h
|
LIB_H += decorate.h
|
||||||
LIB_H += delta.h
|
LIB_H += delta.h
|
||||||
@ -1064,7 +1067,6 @@ ifeq ($(uname_S),Windows)
|
|||||||
NO_SVN_TESTS = YesPlease
|
NO_SVN_TESTS = YesPlease
|
||||||
NO_PERL_MAKEMAKER = YesPlease
|
NO_PERL_MAKEMAKER = YesPlease
|
||||||
RUNTIME_PREFIX = YesPlease
|
RUNTIME_PREFIX = YesPlease
|
||||||
NO_POSIX_ONLY_PROGRAMS = YesPlease
|
|
||||||
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
||||||
NO_NSEC = YesPlease
|
NO_NSEC = YesPlease
|
||||||
USE_WIN32_MMAP = YesPlease
|
USE_WIN32_MMAP = YesPlease
|
||||||
@ -1075,13 +1077,14 @@ ifeq ($(uname_S),Windows)
|
|||||||
NO_CURL = YesPlease
|
NO_CURL = YesPlease
|
||||||
NO_PYTHON = YesPlease
|
NO_PYTHON = YesPlease
|
||||||
BLK_SHA1 = YesPlease
|
BLK_SHA1 = YesPlease
|
||||||
|
NO_POSIX_GOODIES = UnfortunatelyYes
|
||||||
NATIVE_CRLF = YesPlease
|
NATIVE_CRLF = YesPlease
|
||||||
|
|
||||||
CC = compat/vcbuild/scripts/clink.pl
|
CC = compat/vcbuild/scripts/clink.pl
|
||||||
AR = compat/vcbuild/scripts/lib.pl
|
AR = compat/vcbuild/scripts/lib.pl
|
||||||
CFLAGS =
|
CFLAGS =
|
||||||
BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
|
BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
|
||||||
COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o
|
COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o compat/win32/syslog.o compat/win32/sys/poll.o
|
||||||
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
|
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
|
||||||
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
|
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
|
||||||
EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib
|
EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib
|
||||||
@ -1117,7 +1120,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
|
|||||||
NO_SVN_TESTS = YesPlease
|
NO_SVN_TESTS = YesPlease
|
||||||
NO_PERL_MAKEMAKER = YesPlease
|
NO_PERL_MAKEMAKER = YesPlease
|
||||||
RUNTIME_PREFIX = YesPlease
|
RUNTIME_PREFIX = YesPlease
|
||||||
NO_POSIX_ONLY_PROGRAMS = YesPlease
|
|
||||||
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
||||||
NO_NSEC = YesPlease
|
NO_NSEC = YesPlease
|
||||||
USE_WIN32_MMAP = YesPlease
|
USE_WIN32_MMAP = YesPlease
|
||||||
@ -1128,10 +1130,14 @@ ifneq (,$(findstring MINGW,$(uname_S)))
|
|||||||
NO_PYTHON = YesPlease
|
NO_PYTHON = YesPlease
|
||||||
BLK_SHA1 = YesPlease
|
BLK_SHA1 = YesPlease
|
||||||
ETAGS_TARGET = ETAGS
|
ETAGS_TARGET = ETAGS
|
||||||
|
NO_INET_PTON = YesPlease
|
||||||
|
NO_INET_NTOP = YesPlease
|
||||||
|
NO_POSIX_GOODIES = UnfortunatelyYes
|
||||||
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/win32
|
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/win32
|
||||||
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
|
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
|
||||||
COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
|
COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
|
||||||
compat/win32/pthread.o
|
compat/win32/pthread.o compat/win32/syslog.o \
|
||||||
|
compat/win32/sys/poll.o
|
||||||
EXTLIBS += -lws2_32
|
EXTLIBS += -lws2_32
|
||||||
PTHREAD_LIBS =
|
PTHREAD_LIBS =
|
||||||
X = .exe
|
X = .exe
|
||||||
@ -1246,9 +1252,6 @@ ifdef ZLIB_PATH
|
|||||||
endif
|
endif
|
||||||
EXTLIBS += -lz
|
EXTLIBS += -lz
|
||||||
|
|
||||||
ifndef NO_POSIX_ONLY_PROGRAMS
|
|
||||||
PROGRAM_OBJS += daemon.o
|
|
||||||
endif
|
|
||||||
ifndef NO_OPENSSL
|
ifndef NO_OPENSSL
|
||||||
OPENSSL_LIBSSL = -lssl
|
OPENSSL_LIBSSL = -lssl
|
||||||
ifdef OPENSSLDIR
|
ifdef OPENSSLDIR
|
||||||
@ -1397,9 +1400,11 @@ endif
|
|||||||
endif
|
endif
|
||||||
ifdef NO_INET_NTOP
|
ifdef NO_INET_NTOP
|
||||||
LIB_OBJS += compat/inet_ntop.o
|
LIB_OBJS += compat/inet_ntop.o
|
||||||
|
BASIC_CFLAGS += -DNO_INET_NTOP
|
||||||
endif
|
endif
|
||||||
ifdef NO_INET_PTON
|
ifdef NO_INET_PTON
|
||||||
LIB_OBJS += compat/inet_pton.o
|
LIB_OBJS += compat/inet_pton.o
|
||||||
|
BASIC_CFLAGS += -DNO_INET_PTON
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef NO_ICONV
|
ifdef NO_ICONV
|
||||||
@ -1414,6 +1419,10 @@ ifdef NO_DEFLATE_BOUND
|
|||||||
BASIC_CFLAGS += -DNO_DEFLATE_BOUND
|
BASIC_CFLAGS += -DNO_DEFLATE_BOUND
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef NO_POSIX_GOODIES
|
||||||
|
BASIC_CFLAGS += -DNO_POSIX_GOODIES
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef BLK_SHA1
|
ifdef BLK_SHA1
|
||||||
SHA1_HEADER = "block-sha1/sha1.h"
|
SHA1_HEADER = "block-sha1/sha1.h"
|
||||||
LIB_OBJS += block-sha1/sha1.o
|
LIB_OBJS += block-sha1/sha1.o
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
#include "../git-compat-util.h"
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -50,10 +50,7 @@
|
|||||||
* Paul Vixie, 1996.
|
* Paul Vixie, 1996.
|
||||||
*/
|
*/
|
||||||
static const char *
|
static const char *
|
||||||
inet_ntop4(src, dst, size)
|
inet_ntop4(const u_char *src, char *dst, size_t size)
|
||||||
const u_char *src;
|
|
||||||
char *dst;
|
|
||||||
size_t size;
|
|
||||||
{
|
{
|
||||||
static const char fmt[] = "%u.%u.%u.%u";
|
static const char fmt[] = "%u.%u.%u.%u";
|
||||||
char tmp[sizeof "255.255.255.255"];
|
char tmp[sizeof "255.255.255.255"];
|
||||||
@ -78,10 +75,7 @@ inet_ntop4(src, dst, size)
|
|||||||
* Paul Vixie, 1996.
|
* Paul Vixie, 1996.
|
||||||
*/
|
*/
|
||||||
static const char *
|
static const char *
|
||||||
inet_ntop6(src, dst, size)
|
inet_ntop6(const u_char *src, char *dst, size_t size)
|
||||||
const u_char *src;
|
|
||||||
char *dst;
|
|
||||||
size_t size;
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Note that int32_t and int16_t need only be "at least" large enough
|
* Note that int32_t and int16_t need only be "at least" large enough
|
||||||
@ -178,11 +172,7 @@ inet_ntop6(src, dst, size)
|
|||||||
* Paul Vixie, 1996.
|
* Paul Vixie, 1996.
|
||||||
*/
|
*/
|
||||||
const char *
|
const char *
|
||||||
inet_ntop(af, src, dst, size)
|
inet_ntop(int af, const void *src, char *dst, size_t size)
|
||||||
int af;
|
|
||||||
const void *src;
|
|
||||||
char *dst;
|
|
||||||
size_t size;
|
|
||||||
{
|
{
|
||||||
switch (af) {
|
switch (af) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
#include "../git-compat-util.h"
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -41,7 +41,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static int inet_pton4(const char *src, unsigned char *dst);
|
static int inet_pton4(const char *src, unsigned char *dst);
|
||||||
|
#ifndef NO_IPV6
|
||||||
static int inet_pton6(const char *src, unsigned char *dst);
|
static int inet_pton6(const char *src, unsigned char *dst);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* int
|
/* int
|
||||||
* inet_pton4(src, dst)
|
* inet_pton4(src, dst)
|
||||||
|
237
compat/mingw.c
237
compat/mingw.c
@ -408,71 +408,6 @@ int pipe(int filedes[2])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int poll(struct pollfd *ufds, unsigned int nfds, int timeout)
|
|
||||||
{
|
|
||||||
int i, pending;
|
|
||||||
|
|
||||||
if (timeout >= 0) {
|
|
||||||
if (nfds == 0) {
|
|
||||||
Sleep(timeout);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return errno = EINVAL, error("poll timeout not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When there is only one fd to wait for, then we pretend that
|
|
||||||
* input is available and let the actual wait happen when the
|
|
||||||
* caller invokes read().
|
|
||||||
*/
|
|
||||||
if (nfds == 1) {
|
|
||||||
if (!(ufds[0].events & POLLIN))
|
|
||||||
return errno = EINVAL, error("POLLIN not set");
|
|
||||||
ufds[0].revents = POLLIN;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
repeat:
|
|
||||||
pending = 0;
|
|
||||||
for (i = 0; i < nfds; i++) {
|
|
||||||
DWORD avail = 0;
|
|
||||||
HANDLE h = (HANDLE) _get_osfhandle(ufds[i].fd);
|
|
||||||
if (h == INVALID_HANDLE_VALUE)
|
|
||||||
return -1; /* errno was set */
|
|
||||||
|
|
||||||
if (!(ufds[i].events & POLLIN))
|
|
||||||
return errno = EINVAL, error("POLLIN not set");
|
|
||||||
|
|
||||||
/* this emulation works only for pipes */
|
|
||||||
if (!PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL)) {
|
|
||||||
int err = GetLastError();
|
|
||||||
if (err == ERROR_BROKEN_PIPE) {
|
|
||||||
ufds[i].revents = POLLHUP;
|
|
||||||
pending++;
|
|
||||||
} else {
|
|
||||||
errno = EINVAL;
|
|
||||||
return error("PeekNamedPipe failed,"
|
|
||||||
" GetLastError: %u", err);
|
|
||||||
}
|
|
||||||
} else if (avail) {
|
|
||||||
ufds[i].revents = POLLIN;
|
|
||||||
pending++;
|
|
||||||
} else
|
|
||||||
ufds[i].revents = 0;
|
|
||||||
}
|
|
||||||
if (!pending) {
|
|
||||||
/* The only times that we spin here is when the process
|
|
||||||
* that is connected through the pipes is waiting for
|
|
||||||
* its own input data to become available. But since
|
|
||||||
* the process (pack-objects) is itself CPU intensive,
|
|
||||||
* it will happily pick up the time slice that we are
|
|
||||||
* relinquishing here.
|
|
||||||
*/
|
|
||||||
Sleep(0);
|
|
||||||
goto repeat;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tm *gmtime_r(const time_t *timep, struct tm *result)
|
struct tm *gmtime_r(const time_t *timep, struct tm *result)
|
||||||
{
|
{
|
||||||
/* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
|
/* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
|
||||||
@ -702,6 +637,14 @@ static int env_compare(const void *a, const void *b)
|
|||||||
return strcasecmp(*ea, *eb);
|
return strcasecmp(*ea, *eb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pinfo_t {
|
||||||
|
struct pinfo_t *next;
|
||||||
|
pid_t pid;
|
||||||
|
HANDLE proc;
|
||||||
|
} pinfo_t;
|
||||||
|
struct pinfo_t *pinfo = NULL;
|
||||||
|
CRITICAL_SECTION pinfo_cs;
|
||||||
|
|
||||||
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
|
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
|
||||||
const char *dir,
|
const char *dir,
|
||||||
int prepend_cmd, int fhin, int fhout, int fherr)
|
int prepend_cmd, int fhin, int fhout, int fherr)
|
||||||
@ -794,7 +737,26 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
return (pid_t)pi.hProcess;
|
|
||||||
|
/*
|
||||||
|
* The process ID is the human-readable identifier of the process
|
||||||
|
* that we want to present in log and error messages. The handle
|
||||||
|
* is not useful for this purpose. But we cannot close it, either,
|
||||||
|
* because it is not possible to turn a process ID into a process
|
||||||
|
* handle after the process terminated.
|
||||||
|
* Keep the handle in a list for waitpid.
|
||||||
|
*/
|
||||||
|
EnterCriticalSection(&pinfo_cs);
|
||||||
|
{
|
||||||
|
struct pinfo_t *info = xmalloc(sizeof(struct pinfo_t));
|
||||||
|
info->pid = pi.dwProcessId;
|
||||||
|
info->proc = pi.hProcess;
|
||||||
|
info->next = pinfo;
|
||||||
|
pinfo = info;
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&pinfo_cs);
|
||||||
|
|
||||||
|
return (pid_t)pi.dwProcessId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
|
static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
|
||||||
@ -909,6 +871,25 @@ void mingw_execv(const char *cmd, char *const *argv)
|
|||||||
mingw_execve(cmd, argv, environ);
|
mingw_execve(cmd, argv, environ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mingw_kill(pid_t pid, int sig)
|
||||||
|
{
|
||||||
|
if (pid > 0 && sig == SIGTERM) {
|
||||||
|
HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||||
|
|
||||||
|
if (TerminateProcess(h, -1)) {
|
||||||
|
CloseHandle(h);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = err_win_to_posix(GetLastError());
|
||||||
|
CloseHandle(h);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static char **copy_environ(void)
|
static char **copy_environ(void)
|
||||||
{
|
{
|
||||||
char **env;
|
char **env;
|
||||||
@ -993,19 +974,22 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
|
|||||||
const struct addrinfo *hints,
|
const struct addrinfo *hints,
|
||||||
struct addrinfo **res)
|
struct addrinfo **res)
|
||||||
{
|
{
|
||||||
struct hostent *h = gethostbyname(node);
|
struct hostent *h = NULL;
|
||||||
struct addrinfo *ai;
|
struct addrinfo *ai;
|
||||||
struct sockaddr_in *sin;
|
struct sockaddr_in *sin;
|
||||||
|
|
||||||
if (!h)
|
if (node) {
|
||||||
return WSAGetLastError();
|
h = gethostbyname(node);
|
||||||
|
if (!h)
|
||||||
|
return WSAGetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
ai = xmalloc(sizeof(struct addrinfo));
|
ai = xmalloc(sizeof(struct addrinfo));
|
||||||
*res = ai;
|
*res = ai;
|
||||||
ai->ai_flags = 0;
|
ai->ai_flags = 0;
|
||||||
ai->ai_family = AF_INET;
|
ai->ai_family = AF_INET;
|
||||||
ai->ai_socktype = hints->ai_socktype;
|
ai->ai_socktype = hints ? hints->ai_socktype : 0;
|
||||||
switch (hints->ai_socktype) {
|
switch (ai->ai_socktype) {
|
||||||
case SOCK_STREAM:
|
case SOCK_STREAM:
|
||||||
ai->ai_protocol = IPPROTO_TCP;
|
ai->ai_protocol = IPPROTO_TCP;
|
||||||
break;
|
break;
|
||||||
@ -1017,14 +1001,25 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||||
ai->ai_canonname = strdup(h->h_name);
|
if (hints && (hints->ai_flags & AI_CANONNAME))
|
||||||
|
ai->ai_canonname = h ? strdup(h->h_name) : NULL;
|
||||||
|
else
|
||||||
|
ai->ai_canonname = NULL;
|
||||||
|
|
||||||
sin = xmalloc(ai->ai_addrlen);
|
sin = xmalloc(ai->ai_addrlen);
|
||||||
memset(sin, 0, ai->ai_addrlen);
|
memset(sin, 0, ai->ai_addrlen);
|
||||||
sin->sin_family = AF_INET;
|
sin->sin_family = AF_INET;
|
||||||
|
/* Note: getaddrinfo is supposed to allow service to be a string,
|
||||||
|
* which should be looked up using getservbyname. This is
|
||||||
|
* currently not implemented */
|
||||||
if (service)
|
if (service)
|
||||||
sin->sin_port = htons(atoi(service));
|
sin->sin_port = htons(atoi(service));
|
||||||
sin->sin_addr = *(struct in_addr *)h->h_addr;
|
if (h)
|
||||||
|
sin->sin_addr = *(struct in_addr *)h->h_addr;
|
||||||
|
else if (hints && (hints->ai_flags & AI_PASSIVE))
|
||||||
|
sin->sin_addr.s_addr = INADDR_ANY;
|
||||||
|
else
|
||||||
|
sin->sin_addr.s_addr = INADDR_LOOPBACK;
|
||||||
ai->ai_addr = (struct sockaddr *)sin;
|
ai->ai_addr = (struct sockaddr *)sin;
|
||||||
ai->ai_next = 0;
|
ai->ai_next = 0;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1175,7 +1170,10 @@ int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
|||||||
int mingw_socket(int domain, int type, int protocol)
|
int mingw_socket(int domain, int type, int protocol)
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd;
|
||||||
SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0);
|
SOCKET s;
|
||||||
|
|
||||||
|
ensure_socket_initialization();
|
||||||
|
s = WSASocket(domain, type, protocol, NULL, 0, 0);
|
||||||
if (s == INVALID_SOCKET) {
|
if (s == INVALID_SOCKET) {
|
||||||
/*
|
/*
|
||||||
* WSAGetLastError() values are regular BSD error codes
|
* WSAGetLastError() values are regular BSD error codes
|
||||||
@ -1205,6 +1203,45 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
|
|||||||
return connect(s, sa, sz);
|
return connect(s, sa, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef bind
|
||||||
|
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
|
||||||
|
{
|
||||||
|
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
|
||||||
|
return bind(s, sa, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef setsockopt
|
||||||
|
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
|
||||||
|
{
|
||||||
|
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
|
||||||
|
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef listen
|
||||||
|
int mingw_listen(int sockfd, int backlog)
|
||||||
|
{
|
||||||
|
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
|
||||||
|
return listen(s, backlog);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef accept
|
||||||
|
int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
|
||||||
|
{
|
||||||
|
int sockfd2;
|
||||||
|
|
||||||
|
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
|
||||||
|
SOCKET s2 = accept(s1, sa, sz);
|
||||||
|
|
||||||
|
/* convert into a file descriptor */
|
||||||
|
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
|
||||||
|
int err = errno;
|
||||||
|
closesocket(s2);
|
||||||
|
return error("unable to make a socket file descriptor: %s",
|
||||||
|
strerror(err));
|
||||||
|
}
|
||||||
|
return sockfd2;
|
||||||
|
}
|
||||||
|
|
||||||
#undef rename
|
#undef rename
|
||||||
int mingw_rename(const char *pold, const char *pnew)
|
int mingw_rename(const char *pold, const char *pnew)
|
||||||
{
|
{
|
||||||
@ -1476,6 +1513,58 @@ char *getpass(const char *prompt)
|
|||||||
return strbuf_detach(&buf, NULL);
|
return strbuf_detach(&buf, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid_t waitpid(pid_t pid, int *status, unsigned options)
|
||||||
|
{
|
||||||
|
HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
|
||||||
|
FALSE, pid);
|
||||||
|
if (!h) {
|
||||||
|
errno = ECHILD;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid > 0 && options & WNOHANG) {
|
||||||
|
if (WAIT_OBJECT_0 != WaitForSingleObject(h, 0)) {
|
||||||
|
CloseHandle(h);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
options &= ~WNOHANG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options == 0) {
|
||||||
|
struct pinfo_t **ppinfo;
|
||||||
|
if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
|
||||||
|
CloseHandle(h);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
GetExitCodeProcess(h, (LPDWORD)status);
|
||||||
|
|
||||||
|
EnterCriticalSection(&pinfo_cs);
|
||||||
|
|
||||||
|
ppinfo = &pinfo;
|
||||||
|
while (*ppinfo) {
|
||||||
|
struct pinfo_t *info = *ppinfo;
|
||||||
|
if (info->pid == pid) {
|
||||||
|
CloseHandle(info->proc);
|
||||||
|
*ppinfo = info->next;
|
||||||
|
free(info);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ppinfo = &info->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&pinfo_cs);
|
||||||
|
|
||||||
|
CloseHandle(h);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
CloseHandle(h);
|
||||||
|
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NO_MINGW_REPLACE_READDIR
|
#ifndef NO_MINGW_REPLACE_READDIR
|
||||||
/* MinGW readdir implementation to avoid extra lstats for Git */
|
/* MinGW readdir implementation to avoid extra lstats for Git */
|
||||||
struct mingw_DIR
|
struct mingw_DIR
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
typedef int pid_t;
|
typedef int pid_t;
|
||||||
typedef int uid_t;
|
typedef int uid_t;
|
||||||
|
typedef int socklen_t;
|
||||||
#define hstrerror strerror
|
#define hstrerror strerror
|
||||||
|
|
||||||
#define S_IFLNK 0120000 /* Symbolic link */
|
#define S_IFLNK 0120000 /* Symbolic link */
|
||||||
@ -47,6 +48,9 @@ typedef int uid_t;
|
|||||||
#define F_SETFD 2
|
#define F_SETFD 2
|
||||||
#define FD_CLOEXEC 0x1
|
#define FD_CLOEXEC 0x1
|
||||||
|
|
||||||
|
#define EAFNOSUPPORT WSAEAFNOSUPPORT
|
||||||
|
#define ECONNABORTED WSAECONNABORTED
|
||||||
|
|
||||||
struct passwd {
|
struct passwd {
|
||||||
char *pw_name;
|
char *pw_name;
|
||||||
char *pw_gecos;
|
char *pw_gecos;
|
||||||
@ -55,16 +59,6 @@ struct passwd {
|
|||||||
|
|
||||||
extern char *getpass(const char *prompt);
|
extern char *getpass(const char *prompt);
|
||||||
|
|
||||||
#ifndef POLLIN
|
|
||||||
struct pollfd {
|
|
||||||
int fd; /* file descriptor */
|
|
||||||
short events; /* requested events */
|
|
||||||
short revents; /* returned events */
|
|
||||||
};
|
|
||||||
#define POLLIN 1
|
|
||||||
#define POLLHUP 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef void (__cdecl *sig_handler_t)(int);
|
typedef void (__cdecl *sig_handler_t)(int);
|
||||||
struct sigaction {
|
struct sigaction {
|
||||||
sig_handler_t sa_handler;
|
sig_handler_t sa_handler;
|
||||||
@ -136,13 +130,11 @@ static inline int mingw_unlink(const char *pathname)
|
|||||||
}
|
}
|
||||||
#define unlink mingw_unlink
|
#define unlink mingw_unlink
|
||||||
|
|
||||||
static inline pid_t waitpid(pid_t pid, int *status, unsigned options)
|
#define WNOHANG 1
|
||||||
{
|
pid_t waitpid(pid_t pid, int *status, unsigned options);
|
||||||
if (options == 0)
|
|
||||||
return _cwait(status, pid, 0);
|
#define kill mingw_kill
|
||||||
errno = EINVAL;
|
int mingw_kill(pid_t pid, int sig);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NO_OPENSSL
|
#ifndef NO_OPENSSL
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
@ -173,7 +165,6 @@ int pipe(int filedes[2]);
|
|||||||
unsigned int sleep (unsigned int seconds);
|
unsigned int sleep (unsigned int seconds);
|
||||||
int mkstemp(char *template);
|
int mkstemp(char *template);
|
||||||
int gettimeofday(struct timeval *tv, void *tz);
|
int gettimeofday(struct timeval *tv, void *tz);
|
||||||
int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
|
|
||||||
struct tm *gmtime_r(const time_t *timep, struct tm *result);
|
struct tm *gmtime_r(const time_t *timep, struct tm *result);
|
||||||
struct tm *localtime_r(const time_t *timep, struct tm *result);
|
struct tm *localtime_r(const time_t *timep, struct tm *result);
|
||||||
int getpagesize(void); /* defined in MinGW's libgcc.a */
|
int getpagesize(void); /* defined in MinGW's libgcc.a */
|
||||||
@ -225,6 +216,18 @@ int mingw_socket(int domain, int type, int protocol);
|
|||||||
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
|
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
|
||||||
#define connect mingw_connect
|
#define connect mingw_connect
|
||||||
|
|
||||||
|
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
|
||||||
|
#define bind mingw_bind
|
||||||
|
|
||||||
|
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
|
||||||
|
#define setsockopt mingw_setsockopt
|
||||||
|
|
||||||
|
int mingw_listen(int sockfd, int backlog);
|
||||||
|
#define listen mingw_listen
|
||||||
|
|
||||||
|
int mingw_accept(int sockfd, struct sockaddr *sa, socklen_t *sz);
|
||||||
|
#define accept mingw_accept
|
||||||
|
|
||||||
int mingw_rename(const char*, const char*);
|
int mingw_rename(const char*, const char*);
|
||||||
#define rename mingw_rename
|
#define rename mingw_rename
|
||||||
|
|
||||||
@ -305,11 +308,13 @@ void free_environ(char **env);
|
|||||||
static int mingw_main(); \
|
static int mingw_main(); \
|
||||||
int main(int argc, const char **argv) \
|
int main(int argc, const char **argv) \
|
||||||
{ \
|
{ \
|
||||||
|
extern CRITICAL_SECTION pinfo_cs; \
|
||||||
_fmode = _O_BINARY; \
|
_fmode = _O_BINARY; \
|
||||||
_setmode(_fileno(stdin), _O_BINARY); \
|
_setmode(_fileno(stdin), _O_BINARY); \
|
||||||
_setmode(_fileno(stdout), _O_BINARY); \
|
_setmode(_fileno(stdout), _O_BINARY); \
|
||||||
_setmode(_fileno(stderr), _O_BINARY); \
|
_setmode(_fileno(stderr), _O_BINARY); \
|
||||||
argv[0] = xstrdup(_pgmptr); \
|
argv[0] = xstrdup(_pgmptr); \
|
||||||
|
InitializeCriticalSection(&pinfo_cs); \
|
||||||
return mingw_main(argc, argv); \
|
return mingw_main(argc, argv); \
|
||||||
} \
|
} \
|
||||||
static int mingw_main(c,v)
|
static int mingw_main(c,v)
|
||||||
|
596
compat/win32/sys/poll.c
Normal file
596
compat/win32/sys/poll.c
Normal file
@ -0,0 +1,596 @@
|
|||||||
|
/* Emulation for poll(2)
|
||||||
|
Contributed by Paolo Bonzini.
|
||||||
|
|
||||||
|
Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of gnulib.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation,
|
||||||
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||||
|
|
||||||
|
/* Tell gcc not to warn about the (nfd < 0) tests, below. */
|
||||||
|
#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
|
||||||
|
# pragma GCC diagnostic ignored "-Wtype-limits"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "poll.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
|
||||||
|
# define WIN32_NATIVE
|
||||||
|
# include <winsock2.h>
|
||||||
|
# include <windows.h>
|
||||||
|
# include <io.h>
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <conio.h>
|
||||||
|
#else
|
||||||
|
# include <sys/time.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <sys/select.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_IOCTL_H
|
||||||
|
# include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SYS_FILIO_H
|
||||||
|
# include <sys/filio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifndef INFTIM
|
||||||
|
# define INFTIM (-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* BeOS does not have MSG_PEEK. */
|
||||||
|
#ifndef MSG_PEEK
|
||||||
|
# define MSG_PEEK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32_NATIVE
|
||||||
|
|
||||||
|
#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
IsSocketHandle (HANDLE h)
|
||||||
|
{
|
||||||
|
WSANETWORKEVENTS ev;
|
||||||
|
|
||||||
|
if (IsConsoleHandle (h))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Under Wine, it seems that getsockopt returns 0 for pipes too.
|
||||||
|
WSAEnumNetworkEvents instead distinguishes the two correctly. */
|
||||||
|
ev.lNetworkEvents = 0xDEADBEEF;
|
||||||
|
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
|
||||||
|
return ev.lNetworkEvents != 0xDEADBEEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Declare data structures for ntdll functions. */
|
||||||
|
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
|
||||||
|
ULONG NamedPipeType;
|
||||||
|
ULONG NamedPipeConfiguration;
|
||||||
|
ULONG MaximumInstances;
|
||||||
|
ULONG CurrentInstances;
|
||||||
|
ULONG InboundQuota;
|
||||||
|
ULONG ReadDataAvailable;
|
||||||
|
ULONG OutboundQuota;
|
||||||
|
ULONG WriteQuotaAvailable;
|
||||||
|
ULONG NamedPipeState;
|
||||||
|
ULONG NamedPipeEnd;
|
||||||
|
} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
|
||||||
|
|
||||||
|
typedef struct _IO_STATUS_BLOCK
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
DWORD Status;
|
||||||
|
PVOID Pointer;
|
||||||
|
} u;
|
||||||
|
ULONG_PTR Information;
|
||||||
|
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
||||||
|
|
||||||
|
typedef enum _FILE_INFORMATION_CLASS {
|
||||||
|
FilePipeLocalInformation = 24
|
||||||
|
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
typedef DWORD (WINAPI *PNtQueryInformationFile)
|
||||||
|
(HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
|
||||||
|
|
||||||
|
# ifndef PIPE_BUF
|
||||||
|
# define PIPE_BUF 512
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* Compute revents values for file handle H. If some events cannot happen
|
||||||
|
for the handle, eliminate them from *P_SOUGHT. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
win32_compute_revents (HANDLE h, int *p_sought)
|
||||||
|
{
|
||||||
|
int i, ret, happened;
|
||||||
|
INPUT_RECORD *irbuffer;
|
||||||
|
DWORD avail, nbuffer;
|
||||||
|
BOOL bRet;
|
||||||
|
IO_STATUS_BLOCK iosb;
|
||||||
|
FILE_PIPE_LOCAL_INFORMATION fpli;
|
||||||
|
static PNtQueryInformationFile NtQueryInformationFile;
|
||||||
|
static BOOL once_only;
|
||||||
|
|
||||||
|
switch (GetFileType (h))
|
||||||
|
{
|
||||||
|
case FILE_TYPE_PIPE:
|
||||||
|
if (!once_only)
|
||||||
|
{
|
||||||
|
NtQueryInformationFile = (PNtQueryInformationFile)
|
||||||
|
GetProcAddress (GetModuleHandle ("ntdll.dll"),
|
||||||
|
"NtQueryInformationFile");
|
||||||
|
once_only = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
happened = 0;
|
||||||
|
if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
|
||||||
|
{
|
||||||
|
if (avail)
|
||||||
|
happened |= *p_sought & (POLLIN | POLLRDNORM);
|
||||||
|
}
|
||||||
|
else if (GetLastError () == ERROR_BROKEN_PIPE)
|
||||||
|
happened |= POLLHUP;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* It was the write-end of the pipe. Check if it is writable.
|
||||||
|
If NtQueryInformationFile fails, optimistically assume the pipe is
|
||||||
|
writable. This could happen on Win9x, where NtQueryInformationFile
|
||||||
|
is not available, or if we inherit a pipe that doesn't permit
|
||||||
|
FILE_READ_ATTRIBUTES access on the write end (I think this should
|
||||||
|
not happen since WinXP SP2; WINE seems fine too). Otherwise,
|
||||||
|
ensure that enough space is available for atomic writes. */
|
||||||
|
memset (&iosb, 0, sizeof (iosb));
|
||||||
|
memset (&fpli, 0, sizeof (fpli));
|
||||||
|
|
||||||
|
if (!NtQueryInformationFile
|
||||||
|
|| NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
|
||||||
|
FilePipeLocalInformation)
|
||||||
|
|| fpli.WriteQuotaAvailable >= PIPE_BUF
|
||||||
|
|| (fpli.OutboundQuota < PIPE_BUF &&
|
||||||
|
fpli.WriteQuotaAvailable == fpli.OutboundQuota))
|
||||||
|
happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
|
||||||
|
}
|
||||||
|
return happened;
|
||||||
|
|
||||||
|
case FILE_TYPE_CHAR:
|
||||||
|
ret = WaitForSingleObject (h, 0);
|
||||||
|
if (!IsConsoleHandle (h))
|
||||||
|
return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
|
||||||
|
|
||||||
|
nbuffer = avail = 0;
|
||||||
|
bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
|
||||||
|
if (bRet)
|
||||||
|
{
|
||||||
|
/* Input buffer. */
|
||||||
|
*p_sought &= POLLIN | POLLRDNORM;
|
||||||
|
if (nbuffer == 0)
|
||||||
|
return POLLHUP;
|
||||||
|
if (!*p_sought)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
|
||||||
|
bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
|
||||||
|
if (!bRet || avail == 0)
|
||||||
|
return POLLHUP;
|
||||||
|
|
||||||
|
for (i = 0; i < avail; i++)
|
||||||
|
if (irbuffer[i].EventType == KEY_EVENT)
|
||||||
|
return *p_sought;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Screen buffer. */
|
||||||
|
*p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
|
||||||
|
return *p_sought;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = WaitForSingleObject (h, 0);
|
||||||
|
if (ret == WAIT_OBJECT_0)
|
||||||
|
return *p_sought & ~(POLLPRI | POLLRDBAND);
|
||||||
|
|
||||||
|
return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert fd_sets returned by select into revents values. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
|
||||||
|
{
|
||||||
|
int happened = 0;
|
||||||
|
|
||||||
|
if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
|
||||||
|
happened |= (POLLIN | POLLRDNORM) & sought;
|
||||||
|
|
||||||
|
else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
|
||||||
|
{
|
||||||
|
int r, error;
|
||||||
|
|
||||||
|
char data[64];
|
||||||
|
WSASetLastError (0);
|
||||||
|
r = recv (h, data, sizeof (data), MSG_PEEK);
|
||||||
|
error = WSAGetLastError ();
|
||||||
|
WSASetLastError (0);
|
||||||
|
|
||||||
|
if (r > 0 || error == WSAENOTCONN)
|
||||||
|
happened |= (POLLIN | POLLRDNORM) & sought;
|
||||||
|
|
||||||
|
/* Distinguish hung-up sockets from other errors. */
|
||||||
|
else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
|
||||||
|
|| error == WSAECONNABORTED || error == WSAENETRESET)
|
||||||
|
happened |= POLLHUP;
|
||||||
|
|
||||||
|
else
|
||||||
|
happened |= POLLERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
|
||||||
|
happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
|
||||||
|
|
||||||
|
if (lNetworkEvents & FD_OOB)
|
||||||
|
happened |= (POLLPRI | POLLRDBAND) & sought;
|
||||||
|
|
||||||
|
return happened;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !MinGW */
|
||||||
|
|
||||||
|
/* Convert select(2) returned fd_sets into poll(2) revents values. */
|
||||||
|
static int
|
||||||
|
compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
|
||||||
|
{
|
||||||
|
int happened = 0;
|
||||||
|
if (FD_ISSET (fd, rfds))
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
int socket_errno;
|
||||||
|
|
||||||
|
# if defined __MACH__ && defined __APPLE__
|
||||||
|
/* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
|
||||||
|
for some kinds of descriptors. Detect if this descriptor is a
|
||||||
|
connected socket, a server socket, or something else using a
|
||||||
|
0-byte recv, and use ioctl(2) to detect POLLHUP. */
|
||||||
|
r = recv (fd, NULL, 0, MSG_PEEK);
|
||||||
|
socket_errno = (r < 0) ? errno : 0;
|
||||||
|
if (r == 0 || socket_errno == ENOTSOCK)
|
||||||
|
ioctl (fd, FIONREAD, &r);
|
||||||
|
# else
|
||||||
|
char data[64];
|
||||||
|
r = recv (fd, data, sizeof (data), MSG_PEEK);
|
||||||
|
socket_errno = (r < 0) ? errno : 0;
|
||||||
|
# endif
|
||||||
|
if (r == 0)
|
||||||
|
happened |= POLLHUP;
|
||||||
|
|
||||||
|
/* If the event happened on an unconnected server socket,
|
||||||
|
that's fine. */
|
||||||
|
else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
|
||||||
|
happened |= (POLLIN | POLLRDNORM) & sought;
|
||||||
|
|
||||||
|
/* Distinguish hung-up sockets from other errors. */
|
||||||
|
else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
|
||||||
|
|| socket_errno == ECONNABORTED || socket_errno == ENETRESET)
|
||||||
|
happened |= POLLHUP;
|
||||||
|
|
||||||
|
else
|
||||||
|
happened |= POLLERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET (fd, wfds))
|
||||||
|
happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
|
||||||
|
|
||||||
|
if (FD_ISSET (fd, efds))
|
||||||
|
happened |= (POLLPRI | POLLRDBAND) & sought;
|
||||||
|
|
||||||
|
return happened;
|
||||||
|
}
|
||||||
|
#endif /* !MinGW */
|
||||||
|
|
||||||
|
int
|
||||||
|
poll (pfd, nfd, timeout)
|
||||||
|
struct pollfd *pfd;
|
||||||
|
nfds_t nfd;
|
||||||
|
int timeout;
|
||||||
|
{
|
||||||
|
#ifndef WIN32_NATIVE
|
||||||
|
fd_set rfds, wfds, efds;
|
||||||
|
struct timeval tv;
|
||||||
|
struct timeval *ptv;
|
||||||
|
int maxfd, rc;
|
||||||
|
nfds_t i;
|
||||||
|
|
||||||
|
# ifdef _SC_OPEN_MAX
|
||||||
|
static int sc_open_max = -1;
|
||||||
|
|
||||||
|
if (nfd < 0
|
||||||
|
|| (nfd > sc_open_max
|
||||||
|
&& (sc_open_max != -1
|
||||||
|
|| nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
# else /* !_SC_OPEN_MAX */
|
||||||
|
# ifdef OPEN_MAX
|
||||||
|
if (nfd < 0 || nfd > OPEN_MAX)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
# endif /* OPEN_MAX -- else, no check is needed */
|
||||||
|
# endif /* !_SC_OPEN_MAX */
|
||||||
|
|
||||||
|
/* EFAULT is not necessary to implement, but let's do it in the
|
||||||
|
simplest case. */
|
||||||
|
if (!pfd)
|
||||||
|
{
|
||||||
|
errno = EFAULT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert timeout number into a timeval structure */
|
||||||
|
if (timeout == 0)
|
||||||
|
{
|
||||||
|
ptv = &tv;
|
||||||
|
ptv->tv_sec = 0;
|
||||||
|
ptv->tv_usec = 0;
|
||||||
|
}
|
||||||
|
else if (timeout > 0)
|
||||||
|
{
|
||||||
|
ptv = &tv;
|
||||||
|
ptv->tv_sec = timeout / 1000;
|
||||||
|
ptv->tv_usec = (timeout % 1000) * 1000;
|
||||||
|
}
|
||||||
|
else if (timeout == INFTIM)
|
||||||
|
/* wait forever */
|
||||||
|
ptv = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create fd sets and determine max fd */
|
||||||
|
maxfd = -1;
|
||||||
|
FD_ZERO (&rfds);
|
||||||
|
FD_ZERO (&wfds);
|
||||||
|
FD_ZERO (&efds);
|
||||||
|
for (i = 0; i < nfd; i++)
|
||||||
|
{
|
||||||
|
if (pfd[i].fd < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pfd[i].events & (POLLIN | POLLRDNORM))
|
||||||
|
FD_SET (pfd[i].fd, &rfds);
|
||||||
|
|
||||||
|
/* see select(2): "the only exceptional condition detectable
|
||||||
|
is out-of-band data received on a socket", hence we push
|
||||||
|
POLLWRBAND events onto wfds instead of efds. */
|
||||||
|
if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
|
||||||
|
FD_SET (pfd[i].fd, &wfds);
|
||||||
|
if (pfd[i].events & (POLLPRI | POLLRDBAND))
|
||||||
|
FD_SET (pfd[i].fd, &efds);
|
||||||
|
if (pfd[i].fd >= maxfd
|
||||||
|
&& (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
|
||||||
|
| POLLRDNORM | POLLRDBAND
|
||||||
|
| POLLWRNORM | POLLWRBAND)))
|
||||||
|
{
|
||||||
|
maxfd = pfd[i].fd;
|
||||||
|
if (maxfd > FD_SETSIZE)
|
||||||
|
{
|
||||||
|
errno = EOVERFLOW;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* examine fd sets */
|
||||||
|
rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* establish results */
|
||||||
|
rc = 0;
|
||||||
|
for (i = 0; i < nfd; i++)
|
||||||
|
if (pfd[i].fd < 0)
|
||||||
|
pfd[i].revents = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int happened = compute_revents (pfd[i].fd, pfd[i].events,
|
||||||
|
&rfds, &wfds, &efds);
|
||||||
|
if (happened)
|
||||||
|
{
|
||||||
|
pfd[i].revents = happened;
|
||||||
|
rc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
#else
|
||||||
|
static struct timeval tv0;
|
||||||
|
static HANDLE hEvent;
|
||||||
|
WSANETWORKEVENTS ev;
|
||||||
|
HANDLE h, handle_array[FD_SETSIZE + 2];
|
||||||
|
DWORD ret, wait_timeout, nhandles;
|
||||||
|
fd_set rfds, wfds, xfds;
|
||||||
|
BOOL poll_again;
|
||||||
|
MSG msg;
|
||||||
|
int rc = 0;
|
||||||
|
nfds_t i;
|
||||||
|
|
||||||
|
if (nfd < 0 || timeout < -1)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hEvent)
|
||||||
|
hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
|
handle_array[0] = hEvent;
|
||||||
|
nhandles = 1;
|
||||||
|
FD_ZERO (&rfds);
|
||||||
|
FD_ZERO (&wfds);
|
||||||
|
FD_ZERO (&xfds);
|
||||||
|
|
||||||
|
/* Classify socket handles and create fd sets. */
|
||||||
|
for (i = 0; i < nfd; i++)
|
||||||
|
{
|
||||||
|
int sought = pfd[i].events;
|
||||||
|
pfd[i].revents = 0;
|
||||||
|
if (pfd[i].fd < 0)
|
||||||
|
continue;
|
||||||
|
if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
|
||||||
|
| POLLPRI | POLLRDBAND)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
h = (HANDLE) _get_osfhandle (pfd[i].fd);
|
||||||
|
assert (h != NULL);
|
||||||
|
if (IsSocketHandle (h))
|
||||||
|
{
|
||||||
|
int requested = FD_CLOSE;
|
||||||
|
|
||||||
|
/* see above; socket handles are mapped onto select. */
|
||||||
|
if (sought & (POLLIN | POLLRDNORM))
|
||||||
|
{
|
||||||
|
requested |= FD_READ | FD_ACCEPT;
|
||||||
|
FD_SET ((SOCKET) h, &rfds);
|
||||||
|
}
|
||||||
|
if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
|
||||||
|
{
|
||||||
|
requested |= FD_WRITE | FD_CONNECT;
|
||||||
|
FD_SET ((SOCKET) h, &wfds);
|
||||||
|
}
|
||||||
|
if (sought & (POLLPRI | POLLRDBAND))
|
||||||
|
{
|
||||||
|
requested |= FD_OOB;
|
||||||
|
FD_SET ((SOCKET) h, &xfds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requested)
|
||||||
|
WSAEventSelect ((SOCKET) h, hEvent, requested);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Poll now. If we get an event, do not poll again. Also,
|
||||||
|
screen buffer handles are waitable, and they'll block until
|
||||||
|
a character is available. win32_compute_revents eliminates
|
||||||
|
bits for the "wrong" direction. */
|
||||||
|
pfd[i].revents = win32_compute_revents (h, &sought);
|
||||||
|
if (sought)
|
||||||
|
handle_array[nhandles++] = h;
|
||||||
|
if (pfd[i].revents)
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
|
||||||
|
{
|
||||||
|
/* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
|
||||||
|
no need to call select again. */
|
||||||
|
poll_again = FALSE;
|
||||||
|
wait_timeout = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
poll_again = TRUE;
|
||||||
|
if (timeout == INFTIM)
|
||||||
|
wait_timeout = INFINITE;
|
||||||
|
else
|
||||||
|
wait_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
|
||||||
|
wait_timeout, QS_ALLINPUT);
|
||||||
|
|
||||||
|
if (ret == WAIT_OBJECT_0 + nhandles)
|
||||||
|
{
|
||||||
|
/* new input of some other kind */
|
||||||
|
BOOL bRet;
|
||||||
|
while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
|
||||||
|
{
|
||||||
|
TranslateMessage (&msg);
|
||||||
|
DispatchMessage (&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poll_again)
|
||||||
|
select (0, &rfds, &wfds, &xfds, &tv0);
|
||||||
|
|
||||||
|
/* Place a sentinel at the end of the array. */
|
||||||
|
handle_array[nhandles] = NULL;
|
||||||
|
nhandles = 1;
|
||||||
|
for (i = 0; i < nfd; i++)
|
||||||
|
{
|
||||||
|
int happened;
|
||||||
|
|
||||||
|
if (pfd[i].fd < 0)
|
||||||
|
continue;
|
||||||
|
if (!(pfd[i].events & (POLLIN | POLLRDNORM |
|
||||||
|
POLLOUT | POLLWRNORM | POLLWRBAND)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
h = (HANDLE) _get_osfhandle (pfd[i].fd);
|
||||||
|
if (h != handle_array[nhandles])
|
||||||
|
{
|
||||||
|
/* It's a socket. */
|
||||||
|
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
|
||||||
|
WSAEventSelect ((SOCKET) h, 0, 0);
|
||||||
|
|
||||||
|
/* If we're lucky, WSAEnumNetworkEvents already provided a way
|
||||||
|
to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
|
||||||
|
if (FD_ISSET ((SOCKET) h, &rfds)
|
||||||
|
&& !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
|
||||||
|
ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
|
||||||
|
if (FD_ISSET ((SOCKET) h, &wfds))
|
||||||
|
ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
|
||||||
|
if (FD_ISSET ((SOCKET) h, &xfds))
|
||||||
|
ev.lNetworkEvents |= FD_OOB;
|
||||||
|
|
||||||
|
happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
|
||||||
|
ev.lNetworkEvents);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Not a socket. */
|
||||||
|
int sought = pfd[i].events;
|
||||||
|
happened = win32_compute_revents (h, &sought);
|
||||||
|
nhandles++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pfd[i].revents |= happened) != 0)
|
||||||
|
rc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
#endif
|
||||||
|
}
|
53
compat/win32/sys/poll.h
Normal file
53
compat/win32/sys/poll.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/* Header for poll(2) emulation
|
||||||
|
Contributed by Paolo Bonzini.
|
||||||
|
|
||||||
|
Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of gnulib.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation,
|
||||||
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||||
|
|
||||||
|
#ifndef _GL_POLL_H
|
||||||
|
#define _GL_POLL_H
|
||||||
|
|
||||||
|
/* fake a poll(2) environment */
|
||||||
|
#define POLLIN 0x0001 /* any readable data available */
|
||||||
|
#define POLLPRI 0x0002 /* OOB/Urgent readable data */
|
||||||
|
#define POLLOUT 0x0004 /* file descriptor is writeable */
|
||||||
|
#define POLLERR 0x0008 /* some poll error occurred */
|
||||||
|
#define POLLHUP 0x0010 /* file descriptor was "hung up" */
|
||||||
|
#define POLLNVAL 0x0020 /* requested events "invalid" */
|
||||||
|
#define POLLRDNORM 0x0040
|
||||||
|
#define POLLRDBAND 0x0080
|
||||||
|
#define POLLWRNORM 0x0100
|
||||||
|
#define POLLWRBAND 0x0200
|
||||||
|
|
||||||
|
struct pollfd
|
||||||
|
{
|
||||||
|
int fd; /* which file descriptor to poll */
|
||||||
|
short events; /* events we are interested in */
|
||||||
|
short revents; /* events found on return */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef unsigned long nfds_t;
|
||||||
|
|
||||||
|
extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);
|
||||||
|
|
||||||
|
/* Define INFTIM only if doing so conforms to POSIX. */
|
||||||
|
#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)
|
||||||
|
#define INFTIM (-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _GL_POLL_H */
|
72
compat/win32/syslog.c
Normal file
72
compat/win32/syslog.c
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include "../../git-compat-util.h"
|
||||||
|
#include "../../strbuf.h"
|
||||||
|
|
||||||
|
static HANDLE ms_eventlog;
|
||||||
|
|
||||||
|
void openlog(const char *ident, int logopt, int facility)
|
||||||
|
{
|
||||||
|
if (ms_eventlog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ms_eventlog = RegisterEventSourceA(NULL, ident);
|
||||||
|
|
||||||
|
if (!ms_eventlog)
|
||||||
|
warning("RegisterEventSource() failed: %lu", GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
void syslog(int priority, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
struct strbuf_expand_dict_entry dict[] = {
|
||||||
|
{"1", "% 1"},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
WORD logtype;
|
||||||
|
char *str;
|
||||||
|
int str_len;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (!ms_eventlog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
str_len = vsnprintf(NULL, 0, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (str_len < 0) {
|
||||||
|
warning("vsnprintf failed: '%s'", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = malloc(str_len + 1);
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(str, str_len + 1, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
strbuf_expand(&sb, str, strbuf_expand_dict_cb, &dict);
|
||||||
|
free(str);
|
||||||
|
|
||||||
|
switch (priority) {
|
||||||
|
case LOG_EMERG:
|
||||||
|
case LOG_ALERT:
|
||||||
|
case LOG_CRIT:
|
||||||
|
case LOG_ERR:
|
||||||
|
logtype = EVENTLOG_ERROR_TYPE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LOG_WARNING:
|
||||||
|
logtype = EVENTLOG_WARNING_TYPE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LOG_NOTICE:
|
||||||
|
case LOG_INFO:
|
||||||
|
case LOG_DEBUG:
|
||||||
|
default:
|
||||||
|
logtype = EVENTLOG_INFORMATION_TYPE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportEventA(ms_eventlog, logtype, 0, 0, NULL, 1, 0,
|
||||||
|
(const char **)&sb.buf, NULL);
|
||||||
|
|
||||||
|
strbuf_release(&sb);
|
||||||
|
}
|
20
compat/win32/syslog.h
Normal file
20
compat/win32/syslog.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef SYSLOG_H
|
||||||
|
#define SYSLOG_H
|
||||||
|
|
||||||
|
#define LOG_PID 0x01
|
||||||
|
|
||||||
|
#define LOG_EMERG 0
|
||||||
|
#define LOG_ALERT 1
|
||||||
|
#define LOG_CRIT 2
|
||||||
|
#define LOG_ERR 3
|
||||||
|
#define LOG_WARNING 4
|
||||||
|
#define LOG_NOTICE 5
|
||||||
|
#define LOG_INFO 6
|
||||||
|
#define LOG_DEBUG 7
|
||||||
|
|
||||||
|
#define LOG_DAEMON (3<<3)
|
||||||
|
|
||||||
|
void openlog(const char *ident, int logopt, int facility);
|
||||||
|
void syslog(int priority, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif /* SYSLOG_H */
|
262
daemon.c
262
daemon.c
@ -5,8 +5,6 @@
|
|||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
#include "string-list.h"
|
#include "string-list.h"
|
||||||
|
|
||||||
#include <syslog.h>
|
|
||||||
|
|
||||||
#ifndef HOST_NAME_MAX
|
#ifndef HOST_NAME_MAX
|
||||||
#define HOST_NAME_MAX 256
|
#define HOST_NAME_MAX 256
|
||||||
#endif
|
#endif
|
||||||
@ -25,10 +23,10 @@ static const char daemon_usage[] =
|
|||||||
" [--strict-paths] [--base-path=<path>] [--base-path-relaxed]\n"
|
" [--strict-paths] [--base-path=<path>] [--base-path-relaxed]\n"
|
||||||
" [--user-path | --user-path=<path>]\n"
|
" [--user-path | --user-path=<path>]\n"
|
||||||
" [--interpolated-path=<path>]\n"
|
" [--interpolated-path=<path>]\n"
|
||||||
" [--reuseaddr] [--detach] [--pid-file=<file>]\n"
|
" [--reuseaddr] [--pid-file=<file>]\n"
|
||||||
" [--(enable|disable|allow-override|forbid-override)=<service>]\n"
|
" [--(enable|disable|allow-override|forbid-override)=<service>]\n"
|
||||||
" [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
|
" [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
|
||||||
" [--user=<user> [--group=<group>]]\n"
|
" [--detach] [--user=<user> [--group=<group>]]\n"
|
||||||
" [<directory>...]";
|
" [<directory>...]";
|
||||||
|
|
||||||
/* List of acceptable pathname prefixes */
|
/* List of acceptable pathname prefixes */
|
||||||
@ -69,12 +67,14 @@ static void logreport(int priority, const char *err, va_list params)
|
|||||||
syslog(priority, "%s", buf);
|
syslog(priority, "%s", buf);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Since stderr is set to linebuffered mode, the
|
* Since stderr is set to buffered mode, the
|
||||||
* logging of different processes will not overlap
|
* logging of different processes will not overlap
|
||||||
|
* unless they overflow the (rather big) buffers.
|
||||||
*/
|
*/
|
||||||
fprintf(stderr, "[%"PRIuMAX"] ", (uintmax_t)getpid());
|
fprintf(stderr, "[%"PRIuMAX"] ", (uintmax_t)getpid());
|
||||||
vfprintf(stderr, err, params);
|
vfprintf(stderr, err, params);
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
|
fflush(stderr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,37 +516,14 @@ static void parse_host_arg(char *extra_args, int buflen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int execute(struct sockaddr *addr)
|
static int execute(void)
|
||||||
{
|
{
|
||||||
static char line[1000];
|
static char line[1000];
|
||||||
int pktlen, len, i;
|
int pktlen, len, i;
|
||||||
|
char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT");
|
||||||
|
|
||||||
if (addr) {
|
if (addr)
|
||||||
char addrbuf[256] = "";
|
loginfo("Connection from %s:%s", addr, port);
|
||||||
int port = -1;
|
|
||||||
|
|
||||||
if (addr->sa_family == AF_INET) {
|
|
||||||
struct sockaddr_in *sin_addr = (void *) addr;
|
|
||||||
inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
|
|
||||||
port = ntohs(sin_addr->sin_port);
|
|
||||||
#ifndef NO_IPV6
|
|
||||||
} else if (addr && addr->sa_family == AF_INET6) {
|
|
||||||
struct sockaddr_in6 *sin6_addr = (void *) addr;
|
|
||||||
|
|
||||||
char *buf = addrbuf;
|
|
||||||
*buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
|
|
||||||
inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
|
|
||||||
strcat(buf, "]");
|
|
||||||
|
|
||||||
port = ntohs(sin6_addr->sin6_port);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
loginfo("Connection from %s:%d", addrbuf, port);
|
|
||||||
setenv("REMOTE_ADDR", addrbuf, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unsetenv("REMOTE_ADDR");
|
|
||||||
}
|
|
||||||
|
|
||||||
alarm(init_timeout ? init_timeout : timeout);
|
alarm(init_timeout ? init_timeout : timeout);
|
||||||
pktlen = packet_read_line(0, line, sizeof(line));
|
pktlen = packet_read_line(0, line, sizeof(line));
|
||||||
@ -616,17 +593,17 @@ static unsigned int live_children;
|
|||||||
|
|
||||||
static struct child {
|
static struct child {
|
||||||
struct child *next;
|
struct child *next;
|
||||||
pid_t pid;
|
struct child_process cld;
|
||||||
struct sockaddr_storage address;
|
struct sockaddr_storage address;
|
||||||
} *firstborn;
|
} *firstborn;
|
||||||
|
|
||||||
static void add_child(pid_t pid, struct sockaddr *addr, int addrlen)
|
static void add_child(struct child_process *cld, struct sockaddr *addr, socklen_t addrlen)
|
||||||
{
|
{
|
||||||
struct child *newborn, **cradle;
|
struct child *newborn, **cradle;
|
||||||
|
|
||||||
newborn = xcalloc(1, sizeof(*newborn));
|
newborn = xcalloc(1, sizeof(*newborn));
|
||||||
live_children++;
|
live_children++;
|
||||||
newborn->pid = pid;
|
memcpy(&newborn->cld, cld, sizeof(*cld));
|
||||||
memcpy(&newborn->address, addr, addrlen);
|
memcpy(&newborn->address, addr, addrlen);
|
||||||
for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next)
|
for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next)
|
||||||
if (!addrcmp(&(*cradle)->address, &newborn->address))
|
if (!addrcmp(&(*cradle)->address, &newborn->address))
|
||||||
@ -635,19 +612,6 @@ static void add_child(pid_t pid, struct sockaddr *addr, int addrlen)
|
|||||||
*cradle = newborn;
|
*cradle = newborn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_child(pid_t pid)
|
|
||||||
{
|
|
||||||
struct child **cradle, *blanket;
|
|
||||||
|
|
||||||
for (cradle = &firstborn; (blanket = *cradle); cradle = &blanket->next)
|
|
||||||
if (blanket->pid == pid) {
|
|
||||||
*cradle = blanket->next;
|
|
||||||
live_children--;
|
|
||||||
free(blanket);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This gets called if the number of connections grows
|
* This gets called if the number of connections grows
|
||||||
* past "max_connections".
|
* past "max_connections".
|
||||||
@ -663,7 +627,7 @@ static void kill_some_child(void)
|
|||||||
|
|
||||||
for (; (next = blanket->next); blanket = next)
|
for (; (next = blanket->next); blanket = next)
|
||||||
if (!addrcmp(&blanket->address, &next->address)) {
|
if (!addrcmp(&blanket->address, &next->address)) {
|
||||||
kill(blanket->pid, SIGTERM);
|
kill(blanket->cld.pid, SIGTERM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -673,18 +637,28 @@ static void check_dead_children(void)
|
|||||||
int status;
|
int status;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
|
struct child **cradle, *blanket;
|
||||||
const char *dead = "";
|
for (cradle = &firstborn; (blanket = *cradle);)
|
||||||
remove_child(pid);
|
if ((pid = waitpid(blanket->cld.pid, &status, WNOHANG)) > 1) {
|
||||||
if (!WIFEXITED(status) || (WEXITSTATUS(status) > 0))
|
const char *dead = "";
|
||||||
dead = " (with error)";
|
if (status)
|
||||||
loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead);
|
dead = " (with error)";
|
||||||
}
|
loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead);
|
||||||
|
|
||||||
|
/* remove the child */
|
||||||
|
*cradle = blanket->next;
|
||||||
|
live_children--;
|
||||||
|
free(blanket);
|
||||||
|
} else
|
||||||
|
cradle = &blanket->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle(int incoming, struct sockaddr *addr, int addrlen)
|
static char **cld_argv;
|
||||||
|
static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
struct child_process cld = { 0 };
|
||||||
|
char addrbuf[300] = "REMOTE_ADDR=", portbuf[300];
|
||||||
|
char *env[] = { addrbuf, portbuf, NULL };
|
||||||
|
|
||||||
if (max_connections && live_children >= max_connections) {
|
if (max_connections && live_children >= max_connections) {
|
||||||
kill_some_child();
|
kill_some_child();
|
||||||
@ -697,22 +671,37 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pid = fork())) {
|
if (addr->sa_family == AF_INET) {
|
||||||
close(incoming);
|
struct sockaddr_in *sin_addr = (void *) addr;
|
||||||
if (pid < 0) {
|
inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf + 12,
|
||||||
logerror("Couldn't fork %s", strerror(errno));
|
sizeof(addrbuf) - 12);
|
||||||
return;
|
snprintf(portbuf, sizeof(portbuf), "REMOTE_PORT=%d",
|
||||||
}
|
ntohs(sin_addr->sin_port));
|
||||||
|
#ifndef NO_IPV6
|
||||||
|
} else if (addr && addr->sa_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *sin6_addr = (void *) addr;
|
||||||
|
|
||||||
add_child(pid, addr, addrlen);
|
char *buf = addrbuf + 12;
|
||||||
return;
|
*buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
|
||||||
|
inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf,
|
||||||
|
sizeof(addrbuf) - 13);
|
||||||
|
strcat(buf, "]");
|
||||||
|
|
||||||
|
snprintf(portbuf, sizeof(portbuf), "REMOTE_PORT=%d",
|
||||||
|
ntohs(sin6_addr->sin6_port));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
dup2(incoming, 0);
|
cld.env = (const char **)env;
|
||||||
dup2(incoming, 1);
|
cld.argv = (const char **)cld_argv;
|
||||||
close(incoming);
|
cld.in = incoming;
|
||||||
|
cld.out = dup(incoming);
|
||||||
|
|
||||||
exit(execute(addr));
|
if (start_command(&cld))
|
||||||
|
logerror("unable to fork");
|
||||||
|
else
|
||||||
|
add_child(&cld, addr, addrlen);
|
||||||
|
close(incoming);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void child_handler(int signo)
|
static void child_handler(int signo)
|
||||||
@ -914,9 +903,15 @@ static int service_loop(struct socketlist *socklist)
|
|||||||
|
|
||||||
for (i = 0; i < socklist->nr; i++) {
|
for (i = 0; i < socklist->nr; i++) {
|
||||||
if (pfd[i].revents & POLLIN) {
|
if (pfd[i].revents & POLLIN) {
|
||||||
struct sockaddr_storage ss;
|
union {
|
||||||
unsigned int sslen = sizeof(ss);
|
struct sockaddr sa;
|
||||||
int incoming = accept(pfd[i].fd, (struct sockaddr *)&ss, &sslen);
|
struct sockaddr_in sai;
|
||||||
|
#ifndef NO_IPV6
|
||||||
|
struct sockaddr_in6 sai6;
|
||||||
|
#endif
|
||||||
|
} ss;
|
||||||
|
socklen_t sslen = sizeof(ss);
|
||||||
|
int incoming = accept(pfd[i].fd, &ss.sa, &sslen);
|
||||||
if (incoming < 0) {
|
if (incoming < 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
@ -927,7 +922,7 @@ static int service_loop(struct socketlist *socklist)
|
|||||||
die_errno("accept returned");
|
die_errno("accept returned");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handle(incoming, (struct sockaddr *)&ss, sslen);
|
handle(incoming, &ss.sa, sslen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -945,6 +940,62 @@ static void sanitize_stdfds(void)
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NO_POSIX_GOODIES
|
||||||
|
|
||||||
|
struct credentials;
|
||||||
|
|
||||||
|
static void drop_privileges(struct credentials *cred)
|
||||||
|
{
|
||||||
|
/* nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void daemonize(void)
|
||||||
|
{
|
||||||
|
die("--detach not supported on this platform");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct credentials *prepare_credentials(const char *user_name,
|
||||||
|
const char *group_name)
|
||||||
|
{
|
||||||
|
die("--user not supported on this platform");
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
struct credentials {
|
||||||
|
struct passwd *pass;
|
||||||
|
gid_t gid;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void drop_privileges(struct credentials *cred)
|
||||||
|
{
|
||||||
|
if (cred && (initgroups(cred->pass->pw_name, cred->gid) ||
|
||||||
|
setgid (cred->gid) || setuid(cred->pass->pw_uid)))
|
||||||
|
die("cannot drop privileges");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct credentials *prepare_credentials(const char *user_name,
|
||||||
|
const char *group_name)
|
||||||
|
{
|
||||||
|
static struct credentials c;
|
||||||
|
|
||||||
|
c.pass = getpwnam(user_name);
|
||||||
|
if (!c.pass)
|
||||||
|
die("user not found - %s", user_name);
|
||||||
|
|
||||||
|
if (!group_name)
|
||||||
|
c.gid = c.pass->pw_gid;
|
||||||
|
else {
|
||||||
|
struct group *group = getgrnam(group_name);
|
||||||
|
if (!group)
|
||||||
|
die("group not found - %s", group_name);
|
||||||
|
|
||||||
|
c.gid = group->gr_gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &c;
|
||||||
|
}
|
||||||
|
|
||||||
static void daemonize(void)
|
static void daemonize(void)
|
||||||
{
|
{
|
||||||
switch (fork()) {
|
switch (fork()) {
|
||||||
@ -962,6 +1013,7 @@ static void daemonize(void)
|
|||||||
close(2);
|
close(2);
|
||||||
sanitize_stdfds();
|
sanitize_stdfds();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void store_pid(const char *path)
|
static void store_pid(const char *path)
|
||||||
{
|
{
|
||||||
@ -972,7 +1024,8 @@ static void store_pid(const char *path)
|
|||||||
die_errno("failed to write pid file '%s'", path);
|
die_errno("failed to write pid file '%s'", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int serve(struct string_list *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
|
static int serve(struct string_list *listen_addr, int listen_port,
|
||||||
|
struct credentials *cred)
|
||||||
{
|
{
|
||||||
struct socketlist socklist = { NULL, 0, 0 };
|
struct socketlist socklist = { NULL, 0, 0 };
|
||||||
|
|
||||||
@ -981,10 +1034,7 @@ static int serve(struct string_list *listen_addr, int listen_port, struct passwd
|
|||||||
die("unable to allocate any listen sockets on port %u",
|
die("unable to allocate any listen sockets on port %u",
|
||||||
listen_port);
|
listen_port);
|
||||||
|
|
||||||
if (pass && gid &&
|
drop_privileges(cred);
|
||||||
(initgroups(pass->pw_name, gid) || setgid (gid) ||
|
|
||||||
setuid(pass->pw_uid)))
|
|
||||||
die("cannot drop privileges");
|
|
||||||
|
|
||||||
return service_loop(&socklist);
|
return service_loop(&socklist);
|
||||||
}
|
}
|
||||||
@ -993,12 +1043,10 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int listen_port = 0;
|
int listen_port = 0;
|
||||||
struct string_list listen_addr = STRING_LIST_INIT_NODUP;
|
struct string_list listen_addr = STRING_LIST_INIT_NODUP;
|
||||||
int inetd_mode = 0;
|
int serve_mode = 0, inetd_mode = 0;
|
||||||
const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
|
const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
|
||||||
int detach = 0;
|
int detach = 0;
|
||||||
struct passwd *pass = NULL;
|
struct credentials *cred = NULL;
|
||||||
struct group *group;
|
|
||||||
gid_t gid = 0;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
git_extract_argv0_path(argv[0]);
|
git_extract_argv0_path(argv[0]);
|
||||||
@ -1019,6 +1067,10 @@ int main(int argc, char **argv)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!strcmp(arg, "--serve")) {
|
||||||
|
serve_mode = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strcmp(arg, "--inetd")) {
|
if (!strcmp(arg, "--inetd")) {
|
||||||
inetd_mode = 1;
|
inetd_mode = 1;
|
||||||
log_syslog = 1;
|
log_syslog = 1;
|
||||||
@ -1127,10 +1179,10 @@ int main(int argc, char **argv)
|
|||||||
set_die_routine(daemon_die);
|
set_die_routine(daemon_die);
|
||||||
} else
|
} else
|
||||||
/* avoid splitting a message in the middle */
|
/* avoid splitting a message in the middle */
|
||||||
setvbuf(stderr, NULL, _IOLBF, 0);
|
setvbuf(stderr, NULL, _IOFBF, 4096);
|
||||||
|
|
||||||
if (inetd_mode && (group_name || user_name))
|
if (inetd_mode && (detach || group_name || user_name))
|
||||||
die("--user and --group are incompatible with --inetd");
|
die("--detach, --user and --group are incompatible with --inetd");
|
||||||
|
|
||||||
if (inetd_mode && (listen_port || (listen_addr.nr > 0)))
|
if (inetd_mode && (listen_port || (listen_addr.nr > 0)))
|
||||||
die("--listen= and --port= are incompatible with --inetd");
|
die("--listen= and --port= are incompatible with --inetd");
|
||||||
@ -1140,21 +1192,8 @@ int main(int argc, char **argv)
|
|||||||
if (group_name && !user_name)
|
if (group_name && !user_name)
|
||||||
die("--group supplied without --user");
|
die("--group supplied without --user");
|
||||||
|
|
||||||
if (user_name) {
|
if (user_name)
|
||||||
pass = getpwnam(user_name);
|
cred = prepare_credentials(user_name, group_name);
|
||||||
if (!pass)
|
|
||||||
die("user not found - %s", user_name);
|
|
||||||
|
|
||||||
if (!group_name)
|
|
||||||
gid = pass->pw_gid;
|
|
||||||
else {
|
|
||||||
group = getgrnam(group_name);
|
|
||||||
if (!group)
|
|
||||||
die("group not found - %s", group_name);
|
|
||||||
|
|
||||||
gid = group->gr_gid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strict_paths && (!ok_paths || !*ok_paths))
|
if (strict_paths && (!ok_paths || !*ok_paths))
|
||||||
die("option --strict-paths requires a whitelist");
|
die("option --strict-paths requires a whitelist");
|
||||||
@ -1164,19 +1203,13 @@ int main(int argc, char **argv)
|
|||||||
base_path);
|
base_path);
|
||||||
|
|
||||||
if (inetd_mode) {
|
if (inetd_mode) {
|
||||||
struct sockaddr_storage ss;
|
|
||||||
struct sockaddr *peer = (struct sockaddr *)&ss;
|
|
||||||
socklen_t slen = sizeof(ss);
|
|
||||||
|
|
||||||
if (!freopen("/dev/null", "w", stderr))
|
if (!freopen("/dev/null", "w", stderr))
|
||||||
die_errno("failed to redirect stderr to /dev/null");
|
die_errno("failed to redirect stderr to /dev/null");
|
||||||
|
|
||||||
if (getpeername(0, peer, &slen))
|
|
||||||
peer = NULL;
|
|
||||||
|
|
||||||
return execute(peer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inetd_mode || serve_mode)
|
||||||
|
return execute();
|
||||||
|
|
||||||
if (detach) {
|
if (detach) {
|
||||||
daemonize();
|
daemonize();
|
||||||
loginfo("Ready to rumble");
|
loginfo("Ready to rumble");
|
||||||
@ -1187,5 +1220,12 @@ int main(int argc, char **argv)
|
|||||||
if (pid_file)
|
if (pid_file)
|
||||||
store_pid(pid_file);
|
store_pid(pid_file);
|
||||||
|
|
||||||
return serve(&listen_addr, listen_port, pass, gid);
|
/* prepare argv for serving-processes */
|
||||||
|
cld_argv = xmalloc(sizeof (char *) * (argc + 2));
|
||||||
|
for (i = 0; i < argc; ++i)
|
||||||
|
cld_argv[i] = argv[i];
|
||||||
|
cld_argv[argc] = "--serve";
|
||||||
|
cld_argv[argc+1] = NULL;
|
||||||
|
|
||||||
|
return serve(&listen_addr, listen_port, cred);
|
||||||
}
|
}
|
||||||
|
@ -104,9 +104,10 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
@ -386,6 +387,14 @@ static inline void *gitmempcpy(void *dest, const void *src, size_t n)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_INET_PTON
|
||||||
|
int inet_pton(int af, const char *src, void *dst);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_INET_NTOP
|
||||||
|
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void release_pack_memory(size_t, int);
|
extern void release_pack_memory(size_t, int);
|
||||||
|
|
||||||
typedef void (*try_to_free_t)(size_t);
|
typedef void (*try_to_free_t)(size_t);
|
||||||
|
Reference in New Issue
Block a user