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:
commit
89ba4e7c7f
@ -78,7 +78,8 @@ OPTIONS
|
||||
|
||||
--inetd::
|
||||
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 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
|
||||
PROGRAMS += $(EXTRA_PROGRAMS)
|
||||
|
||||
PROGRAM_OBJS += daemon.o
|
||||
PROGRAM_OBJS += fast-import.o
|
||||
PROGRAM_OBJS += imap-send.o
|
||||
PROGRAM_OBJS += shell.o
|
||||
@ -496,6 +497,8 @@ LIB_H += compat/bswap.h
|
||||
LIB_H += compat/cygwin.h
|
||||
LIB_H += compat/mingw.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 += decorate.h
|
||||
LIB_H += delta.h
|
||||
@ -1064,7 +1067,6 @@ ifeq ($(uname_S),Windows)
|
||||
NO_SVN_TESTS = YesPlease
|
||||
NO_PERL_MAKEMAKER = YesPlease
|
||||
RUNTIME_PREFIX = YesPlease
|
||||
NO_POSIX_ONLY_PROGRAMS = YesPlease
|
||||
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
||||
NO_NSEC = YesPlease
|
||||
USE_WIN32_MMAP = YesPlease
|
||||
@ -1075,13 +1077,14 @@ ifeq ($(uname_S),Windows)
|
||||
NO_CURL = YesPlease
|
||||
NO_PYTHON = YesPlease
|
||||
BLK_SHA1 = YesPlease
|
||||
NO_POSIX_GOODIES = UnfortunatelyYes
|
||||
NATIVE_CRLF = YesPlease
|
||||
|
||||
CC = compat/vcbuild/scripts/clink.pl
|
||||
AR = compat/vcbuild/scripts/lib.pl
|
||||
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
|
||||
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\"
|
||||
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.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_PERL_MAKEMAKER = YesPlease
|
||||
RUNTIME_PREFIX = YesPlease
|
||||
NO_POSIX_ONLY_PROGRAMS = YesPlease
|
||||
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
||||
NO_NSEC = YesPlease
|
||||
USE_WIN32_MMAP = YesPlease
|
||||
@ -1128,10 +1130,14 @@ ifneq (,$(findstring MINGW,$(uname_S)))
|
||||
NO_PYTHON = YesPlease
|
||||
BLK_SHA1 = YesPlease
|
||||
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 += -DSTRIP_EXTENSION=\".exe\"
|
||||
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
|
||||
PTHREAD_LIBS =
|
||||
X = .exe
|
||||
@ -1246,9 +1252,6 @@ ifdef ZLIB_PATH
|
||||
endif
|
||||
EXTLIBS += -lz
|
||||
|
||||
ifndef NO_POSIX_ONLY_PROGRAMS
|
||||
PROGRAM_OBJS += daemon.o
|
||||
endif
|
||||
ifndef NO_OPENSSL
|
||||
OPENSSL_LIBSSL = -lssl
|
||||
ifdef OPENSSLDIR
|
||||
@ -1397,9 +1400,11 @@ endif
|
||||
endif
|
||||
ifdef NO_INET_NTOP
|
||||
LIB_OBJS += compat/inet_ntop.o
|
||||
BASIC_CFLAGS += -DNO_INET_NTOP
|
||||
endif
|
||||
ifdef NO_INET_PTON
|
||||
LIB_OBJS += compat/inet_pton.o
|
||||
BASIC_CFLAGS += -DNO_INET_PTON
|
||||
endif
|
||||
|
||||
ifdef NO_ICONV
|
||||
@ -1414,6 +1419,10 @@ ifdef NO_DEFLATE_BOUND
|
||||
BASIC_CFLAGS += -DNO_DEFLATE_BOUND
|
||||
endif
|
||||
|
||||
ifdef NO_POSIX_GOODIES
|
||||
BASIC_CFLAGS += -DNO_POSIX_GOODIES
|
||||
endif
|
||||
|
||||
ifdef BLK_SHA1
|
||||
SHA1_HEADER = "block-sha1/sha1.h"
|
||||
LIB_OBJS += block-sha1/sha1.o
|
||||
|
@ -17,9 +17,9 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -50,10 +50,7 @@
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static const char *
|
||||
inet_ntop4(src, dst, size)
|
||||
const u_char *src;
|
||||
char *dst;
|
||||
size_t size;
|
||||
inet_ntop4(const u_char *src, char *dst, size_t size)
|
||||
{
|
||||
static const char fmt[] = "%u.%u.%u.%u";
|
||||
char tmp[sizeof "255.255.255.255"];
|
||||
@ -78,10 +75,7 @@ inet_ntop4(src, dst, size)
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static const char *
|
||||
inet_ntop6(src, dst, size)
|
||||
const u_char *src;
|
||||
char *dst;
|
||||
size_t size;
|
||||
inet_ntop6(const u_char *src, char *dst, size_t size)
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
const char *
|
||||
inet_ntop(af, src, dst, size)
|
||||
int af;
|
||||
const void *src;
|
||||
char *dst;
|
||||
size_t size;
|
||||
inet_ntop(int af, const void *src, char *dst, size_t size)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
|
@ -17,9 +17,9 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -41,7 +41,9 @@
|
||||
*/
|
||||
|
||||
static int inet_pton4(const char *src, unsigned char *dst);
|
||||
#ifndef NO_IPV6
|
||||
static int inet_pton6(const char *src, unsigned char *dst);
|
||||
#endif
|
||||
|
||||
/* int
|
||||
* inet_pton4(src, dst)
|
||||
|
231
compat/mingw.c
231
compat/mingw.c
@ -408,71 +408,6 @@ int pipe(int filedes[2])
|
||||
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)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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,
|
||||
const char *dir,
|
||||
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;
|
||||
}
|
||||
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,
|
||||
@ -909,6 +871,25 @@ void mingw_execv(const char *cmd, char *const *argv)
|
||||
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)
|
||||
{
|
||||
char **env;
|
||||
@ -993,19 +974,22 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
|
||||
const struct addrinfo *hints,
|
||||
struct addrinfo **res)
|
||||
{
|
||||
struct hostent *h = gethostbyname(node);
|
||||
struct hostent *h = NULL;
|
||||
struct addrinfo *ai;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
if (node) {
|
||||
h = gethostbyname(node);
|
||||
if (!h)
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
ai = xmalloc(sizeof(struct addrinfo));
|
||||
*res = ai;
|
||||
ai->ai_flags = 0;
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_socktype = hints->ai_socktype;
|
||||
switch (hints->ai_socktype) {
|
||||
ai->ai_socktype = hints ? hints->ai_socktype : 0;
|
||||
switch (ai->ai_socktype) {
|
||||
case SOCK_STREAM:
|
||||
ai->ai_protocol = IPPROTO_TCP;
|
||||
break;
|
||||
@ -1017,14 +1001,25 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
|
||||
break;
|
||||
}
|
||||
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);
|
||||
memset(sin, 0, ai->ai_addrlen);
|
||||
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)
|
||||
sin->sin_port = htons(atoi(service));
|
||||
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_next = 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 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) {
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
#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
|
||||
int mingw_rename(const char *pold, const char *pnew)
|
||||
{
|
||||
@ -1476,6 +1513,58 @@ char *getpass(const char *prompt)
|
||||
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
|
||||
/* MinGW readdir implementation to avoid extra lstats for Git */
|
||||
struct mingw_DIR
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
typedef int pid_t;
|
||||
typedef int uid_t;
|
||||
typedef int socklen_t;
|
||||
#define hstrerror strerror
|
||||
|
||||
#define S_IFLNK 0120000 /* Symbolic link */
|
||||
@ -47,6 +48,9 @@ typedef int uid_t;
|
||||
#define F_SETFD 2
|
||||
#define FD_CLOEXEC 0x1
|
||||
|
||||
#define EAFNOSUPPORT WSAEAFNOSUPPORT
|
||||
#define ECONNABORTED WSAECONNABORTED
|
||||
|
||||
struct passwd {
|
||||
char *pw_name;
|
||||
char *pw_gecos;
|
||||
@ -55,16 +59,6 @@ struct passwd {
|
||||
|
||||
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);
|
||||
struct sigaction {
|
||||
sig_handler_t sa_handler;
|
||||
@ -136,13 +130,11 @@ static inline int mingw_unlink(const char *pathname)
|
||||
}
|
||||
#define unlink mingw_unlink
|
||||
|
||||
static inline pid_t waitpid(pid_t pid, int *status, unsigned options)
|
||||
{
|
||||
if (options == 0)
|
||||
return _cwait(status, pid, 0);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#define WNOHANG 1
|
||||
pid_t waitpid(pid_t pid, int *status, unsigned options);
|
||||
|
||||
#define kill mingw_kill
|
||||
int mingw_kill(pid_t pid, int sig);
|
||||
|
||||
#ifndef NO_OPENSSL
|
||||
#include <openssl/ssl.h>
|
||||
@ -173,7 +165,6 @@ int pipe(int filedes[2]);
|
||||
unsigned int sleep (unsigned int seconds);
|
||||
int mkstemp(char *template);
|
||||
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 *localtime_r(const time_t *timep, struct tm *result);
|
||||
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);
|
||||
#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*);
|
||||
#define rename mingw_rename
|
||||
|
||||
@ -305,11 +308,13 @@ void free_environ(char **env);
|
||||
static int mingw_main(); \
|
||||
int main(int argc, const char **argv) \
|
||||
{ \
|
||||
extern CRITICAL_SECTION pinfo_cs; \
|
||||
_fmode = _O_BINARY; \
|
||||
_setmode(_fileno(stdin), _O_BINARY); \
|
||||
_setmode(_fileno(stdout), _O_BINARY); \
|
||||
_setmode(_fileno(stderr), _O_BINARY); \
|
||||
argv[0] = xstrdup(_pgmptr); \
|
||||
InitializeCriticalSection(&pinfo_cs); \
|
||||
return mingw_main(argc, argv); \
|
||||
} \
|
||||
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 */
|
256
daemon.c
256
daemon.c
@ -5,8 +5,6 @@
|
||||
#include "strbuf.h"
|
||||
#include "string-list.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#ifndef HOST_NAME_MAX
|
||||
#define HOST_NAME_MAX 256
|
||||
#endif
|
||||
@ -25,10 +23,10 @@ static const char daemon_usage[] =
|
||||
" [--strict-paths] [--base-path=<path>] [--base-path-relaxed]\n"
|
||||
" [--user-path | --user-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"
|
||||
" [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
|
||||
" [--user=<user> [--group=<group>]]\n"
|
||||
" [--detach] [--user=<user> [--group=<group>]]\n"
|
||||
" [<directory>...]";
|
||||
|
||||
/* List of acceptable pathname prefixes */
|
||||
@ -69,12 +67,14 @@ static void logreport(int priority, const char *err, va_list params)
|
||||
syslog(priority, "%s", buf);
|
||||
} else {
|
||||
/*
|
||||
* Since stderr is set to linebuffered mode, the
|
||||
* Since stderr is set to buffered mode, the
|
||||
* logging of different processes will not overlap
|
||||
* unless they overflow the (rather big) buffers.
|
||||
*/
|
||||
fprintf(stderr, "[%"PRIuMAX"] ", (uintmax_t)getpid());
|
||||
vfprintf(stderr, err, params);
|
||||
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];
|
||||
int pktlen, len, i;
|
||||
char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT");
|
||||
|
||||
if (addr) {
|
||||
char addrbuf[256] = "";
|
||||
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");
|
||||
}
|
||||
if (addr)
|
||||
loginfo("Connection from %s:%s", addr, port);
|
||||
|
||||
alarm(init_timeout ? init_timeout : timeout);
|
||||
pktlen = packet_read_line(0, line, sizeof(line));
|
||||
@ -616,17 +593,17 @@ static unsigned int live_children;
|
||||
|
||||
static struct child {
|
||||
struct child *next;
|
||||
pid_t pid;
|
||||
struct child_process cld;
|
||||
struct sockaddr_storage address;
|
||||
} *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;
|
||||
|
||||
newborn = xcalloc(1, sizeof(*newborn));
|
||||
live_children++;
|
||||
newborn->pid = pid;
|
||||
memcpy(&newborn->cld, cld, sizeof(*cld));
|
||||
memcpy(&newborn->address, addr, addrlen);
|
||||
for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next)
|
||||
if (!addrcmp(&(*cradle)->address, &newborn->address))
|
||||
@ -635,19 +612,6 @@ static void add_child(pid_t pid, struct sockaddr *addr, int addrlen)
|
||||
*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
|
||||
* past "max_connections".
|
||||
@ -663,7 +627,7 @@ static void kill_some_child(void)
|
||||
|
||||
for (; (next = blanket->next); blanket = next)
|
||||
if (!addrcmp(&blanket->address, &next->address)) {
|
||||
kill(blanket->pid, SIGTERM);
|
||||
kill(blanket->cld.pid, SIGTERM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -673,18 +637,28 @@ static void check_dead_children(void)
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
|
||||
struct child **cradle, *blanket;
|
||||
for (cradle = &firstborn; (blanket = *cradle);)
|
||||
if ((pid = waitpid(blanket->cld.pid, &status, WNOHANG)) > 1) {
|
||||
const char *dead = "";
|
||||
remove_child(pid);
|
||||
if (!WIFEXITED(status) || (WEXITSTATUS(status) > 0))
|
||||
if (status)
|
||||
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) {
|
||||
kill_some_child();
|
||||
@ -697,22 +671,37 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)
|
||||
}
|
||||
}
|
||||
|
||||
if ((pid = fork())) {
|
||||
close(incoming);
|
||||
if (pid < 0) {
|
||||
logerror("Couldn't fork %s", strerror(errno));
|
||||
return;
|
||||
if (addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sin_addr = (void *) addr;
|
||||
inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf + 12,
|
||||
sizeof(addrbuf) - 12);
|
||||
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;
|
||||
|
||||
char *buf = addrbuf + 12;
|
||||
*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
|
||||
}
|
||||
|
||||
add_child(pid, addr, addrlen);
|
||||
return;
|
||||
}
|
||||
cld.env = (const char **)env;
|
||||
cld.argv = (const char **)cld_argv;
|
||||
cld.in = incoming;
|
||||
cld.out = dup(incoming);
|
||||
|
||||
dup2(incoming, 0);
|
||||
dup2(incoming, 1);
|
||||
if (start_command(&cld))
|
||||
logerror("unable to fork");
|
||||
else
|
||||
add_child(&cld, addr, addrlen);
|
||||
close(incoming);
|
||||
|
||||
exit(execute(addr));
|
||||
}
|
||||
|
||||
static void child_handler(int signo)
|
||||
@ -914,9 +903,15 @@ static int service_loop(struct socketlist *socklist)
|
||||
|
||||
for (i = 0; i < socklist->nr; i++) {
|
||||
if (pfd[i].revents & POLLIN) {
|
||||
struct sockaddr_storage ss;
|
||||
unsigned int sslen = sizeof(ss);
|
||||
int incoming = accept(pfd[i].fd, (struct sockaddr *)&ss, &sslen);
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
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) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
@ -927,7 +922,7 @@ static int service_loop(struct socketlist *socklist)
|
||||
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);
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
switch (fork()) {
|
||||
@ -962,6 +1013,7 @@ static void daemonize(void)
|
||||
close(2);
|
||||
sanitize_stdfds();
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
@ -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",
|
||||
listen_port);
|
||||
|
||||
if (pass && gid &&
|
||||
(initgroups(pass->pw_name, gid) || setgid (gid) ||
|
||||
setuid(pass->pw_uid)))
|
||||
die("cannot drop privileges");
|
||||
drop_privileges(cred);
|
||||
|
||||
return service_loop(&socklist);
|
||||
}
|
||||
@ -993,12 +1043,10 @@ int main(int argc, char **argv)
|
||||
{
|
||||
int listen_port = 0;
|
||||
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;
|
||||
int detach = 0;
|
||||
struct passwd *pass = NULL;
|
||||
struct group *group;
|
||||
gid_t gid = 0;
|
||||
struct credentials *cred = NULL;
|
||||
int i;
|
||||
|
||||
git_extract_argv0_path(argv[0]);
|
||||
@ -1019,6 +1067,10 @@ int main(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!strcmp(arg, "--serve")) {
|
||||
serve_mode = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--inetd")) {
|
||||
inetd_mode = 1;
|
||||
log_syslog = 1;
|
||||
@ -1127,10 +1179,10 @@ int main(int argc, char **argv)
|
||||
set_die_routine(daemon_die);
|
||||
} else
|
||||
/* avoid splitting a message in the middle */
|
||||
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||
setvbuf(stderr, NULL, _IOFBF, 4096);
|
||||
|
||||
if (inetd_mode && (group_name || user_name))
|
||||
die("--user and --group are incompatible with --inetd");
|
||||
if (inetd_mode && (detach || group_name || user_name))
|
||||
die("--detach, --user and --group are incompatible with --inetd");
|
||||
|
||||
if (inetd_mode && (listen_port || (listen_addr.nr > 0)))
|
||||
die("--listen= and --port= are incompatible with --inetd");
|
||||
@ -1140,21 +1192,8 @@ int main(int argc, char **argv)
|
||||
if (group_name && !user_name)
|
||||
die("--group supplied without --user");
|
||||
|
||||
if (user_name) {
|
||||
pass = getpwnam(user_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 (user_name)
|
||||
cred = prepare_credentials(user_name, group_name);
|
||||
|
||||
if (strict_paths && (!ok_paths || !*ok_paths))
|
||||
die("option --strict-paths requires a whitelist");
|
||||
@ -1164,19 +1203,13 @@ int main(int argc, char **argv)
|
||||
base_path);
|
||||
|
||||
if (inetd_mode) {
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr *peer = (struct sockaddr *)&ss;
|
||||
socklen_t slen = sizeof(ss);
|
||||
|
||||
if (!freopen("/dev/null", "w", stderr))
|
||||
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) {
|
||||
daemonize();
|
||||
loginfo("Ready to rumble");
|
||||
@ -1187,5 +1220,12 @@ int main(int argc, char **argv)
|
||||
if (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 <regex.h>
|
||||
#include <utime.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/poll.h>
|
||||
#ifndef __MINGW32__
|
||||
#include <sys/wait.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
@ -386,6 +387,14 @@ static inline void *gitmempcpy(void *dest, const void *src, size_t n)
|
||||
}
|
||||
#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);
|
||||
|
||||
typedef void (*try_to_free_t)(size_t);
|
||||
|
Loading…
Reference in New Issue
Block a user