From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
Almost 9 months have passed since I sent v2, and here's finally v3.
Not so much have happened since v2, the most significant change being
that I've replaced our win32-poll implementation with the one from
gnulib. This gives our the poll-features needed for git-daemon, and
prevents a nasty timing-bug that occured (on Windows) in the previous
series.
Some of the patches have been ejected;
* "daemon: use select() instead of poll()" because our poll now is
sufficient.
* "daemon: use explicit file descriptor" because it wasn't needed
anymore, not even in the previous version.
One patch might be a little bit controversial; "daemon: only use posix
features on posix systems". It replaces "mingw: compile git-daemon", and
changes the logic from opt-out is WIN32 is defined to opt-in if
_POSIX_VERSION defined.
The current version is based on top of junio/next, because the
ab/daemon-multi-select series touches some of the same code.
v2 msgid is [off-list ref] if
you're interrested in comparing.
Erik Faye-Lund (10):
inet_ntop: fix a couple of old-style decls
mingw: use real pid
mingw: support waitpid with pid > 0 and WNOHANG
mingw: add kill emulation
daemon: use run-command api for async serving
daemon: use full buffered mode for stderr
daemon: report connection from root-process
mingw: import poll-emulation from gnulib
mingw: use poll-emulation from gnulib
daemon: only use posix features on posix systems
Martin Storsjö (1):
Improve the mingw getaddrinfo stub to handle more use cases
Mike Pape (3):
mingw: add network-wrappers for daemon
mingw: implement syslog
compat: add inet_pton and inet_ntop prototypes
Makefile | 12 +-
compat/inet_ntop.c | 22 +--
compat/inet_pton.c | 8 +-
compat/mingw.c | 291 +++++++++++++++++++-------
compat/mingw.h | 56 ++++--
compat/win32/poll.c | 596 +++++++++++++++++++++++++++++++++++++++++++++++++++
compat/win32/poll.h | 53 +++++
daemon.c | 199 ++++++++++--------
git-compat-util.h | 10 +
9 files changed, 1045 insertions(+), 202 deletions(-)
create mode 100644 compat/win32/poll.c
create mode 100644 compat/win32/poll.h
--
1.7.3.1.51.ge462f.dirty
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
From: Mike Pape <redacted>
git-daemon requires some socket-functionality that is not yet
supported in the Windows-port. This patch adds said functionality,
and makes sure WSAStartup gets called by socket(), since it is the
first network-call in git-daemon. In addition, a check is added to
prevent WSAStartup (and WSACleanup, though atexit) from being
called more than once, since git-daemon calls both socket() and
gethostbyname().
Signed-off-by: Mike Pape <redacted>
Signed-off-by: Erik Faye-Lund <redacted>
---
compat/mingw.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
compat/mingw.h | 16 ++++++++++++++++
2 files changed, 58 insertions(+), 1 deletions(-)
@@ -1205,6 +1208,44 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)returnconnect(s,sa,sz);}+#undef bind+intmingw_bind(intsockfd,structsockaddr*sa,size_tsz)+{+SOCKETs=(SOCKET)_get_osfhandle(sockfd);+returnbind(s,sa,sz);+}++#undef setsockopt+intmingw_setsockopt(intsockfd,intlvl,intoptname,void*optval,intoptlen)+{+SOCKETs=(SOCKET)_get_osfhandle(sockfd);+returnsetsockopt(s,lvl,optname,(constchar*)optval,optlen);+}++#undef listen+intmingw_listen(intsockfd,intbacklog)+{+SOCKETs=(SOCKET)_get_osfhandle(sockfd);+returnlisten(s,backlog);+}++#undef accept+intmingw_accept(intsockfd1,structsockaddr*sa,socklen_t*sz)+{+intsockfd2;++SOCKETs1=(SOCKET)_get_osfhandle(sockfd1);+SOCKETs2=accept(s1,sa,sz);++/* convert into a file descriptor */+if((sockfd2=_open_osfhandle(s2,O_RDWR|O_BINARY))<0){+closesocket(s2);+returnerror("unable to make a socket file descriptor: %s",+strerror(errno));+}+returnsockfd2;+}+#undef renameintmingw_rename(constchar*pold,constchar*pnew){
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
From: Mike Pape <redacted>
Windows doesn't have inet_pton and inet_ntop, so
add prototypes in git-compat-util.h for them.
At the same time include git-compat-util.h in
the sources for these functions, so they use the
network-wrappers from there on Windows.
Signed-off-by: Mike Pape <redacted>
Signed-off-by: Erik Faye-Lund <redacted>
---
Makefile | 2 ++
compat/inet_ntop.c | 6 +++---
compat/inet_pton.c | 8 +++++---
git-compat-util.h | 8 ++++++++
4 files changed, 18 insertions(+), 6 deletions(-)
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
From: Mike Pape <redacted>
Syslog does not usually exist on Windows, so we implement our own
using Window's ReportEvent mechanism.
Signed-off-by: Mike Pape <redacted>
Signed-off-by: Erik Faye-Lund <redacted>
---
compat/mingw.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++
compat/mingw.h | 15 +++++++++++++
daemon.c | 2 -
git-compat-util.h | 1 +
4 files changed, 76 insertions(+), 2 deletions(-)
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
The Windows port so far used process handles as PID. However,
this does not work consistently with getpid.
Change the code to use the real PID, and use OpenProcess to
get a process-handle. Store the PID and the process handle
in a table protected by a critical section, so we can safely
close the process handle later.
Signed-off-by: Erik Faye-Lund <redacted>
---
compat/mingw.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
compat/mingw.h | 10 ++-----
2 files changed, 72 insertions(+), 8 deletions(-)
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
fork() is only available on POSIX, so to support git-daemon
on Windows we have to use something else.
Instead we invent the flag --serve, which is a stripped down
version of --inetd-mode. We use start_command() to call
git-daemon with this flag appended to serve clients.
Signed-off-by: Erik Faye-Lund <redacted>
---
daemon.c | 86 +++++++++++++++++++++++++++++++-------------------------------
1 files changed, 43 insertions(+), 43 deletions(-)
@@ -695,22 +690,15 @@ 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;-}--add_child(pid,addr,addrlen);-return;-}+cld.argv=(constchar**)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));}staticvoidchild_handler(intsigno)
@@ -991,7 +979,7 @@ int main(int argc, char **argv){intlisten_port=0;structstring_listlisten_addr=STRING_LIST_INIT_NODUP;-intinetd_mode=0;+intserve_mode=0,inetd_mode=0;constchar*pid_file=NULL,*user_name=NULL,*group_name=NULL;intdetach=0;structpasswd*pass=NULL;
@@ -1017,7 +1005,12 @@ int main(int argc, char **argv)continue;}}+if(!strcmp(arg,"--serve")){+serve_mode=1;+continue;+}if(!strcmp(arg,"--inetd")){+serve_mode=1;inetd_mode=1;log_syslog=1;continue;
@@ -1161,12 +1154,12 @@ int main(int argc, char **argv)die("base-path '%s' does not exist or is not a directory",base_path);-if(inetd_mode){+if(serve_mode){structsockaddr_storagess;structsockaddr*peer=(structsockaddr*)&ss;socklen_tslen=sizeof(ss);-if(!freopen("/dev/null","w",stderr))+if(inetd_mode&&!freopen("/dev/null","w",stderr))die_errno("failed to redirect stderr to /dev/null");if(getpeername(0,peer,&slen))
@@ -1185,5 +1178,12 @@ int main(int argc, char **argv)if(pid_file)store_pid(pid_file);+/* 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;+returnserve(&listen_addr,listen_port,pass,gid);}
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
This is a quite limited kill-emulation; it can only handle
SIGTERM on positive pids. However, it's enough for git-daemon.
Signed-off-by: Erik Faye-Lund <redacted>
---
compat/mingw.c | 19 +++++++++++++++++++
compat/mingw.h | 3 +++
2 files changed, 22 insertions(+), 0 deletions(-)
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
Windows doesn't support line buffered mode for file
streams, so let's just use full buffered mode with
a big buffer ("4096 should be enough for everyone")
and add explicit flushing.
Signed-off-by: Erik Faye-Lund <redacted>
---
daemon.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
@@ -1118,7 +1120,7 @@ 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");
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
From: Martin Storsjö <redacted>
Allow the node parameter to be null, which is used for getting
the default bind address.
Also allow the hints parameter to be null, to improve standard
conformance of the stub implementation a little.
Signed-off-by: Martin Storsjo <redacted>
---
compat/mingw.c | 28 +++++++++++++++++++++-------
1 files changed, 21 insertions(+), 7 deletions(-)
@@ -1059,14 +1062,25 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,break;}ai->ai_addrlen=sizeof(structsockaddr_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,+*whichshouldbelookedupusinggetservbyname.Thisis+*currentlynotimplemented*/if(service)sin->sin_port=htons(atoi(service));-sin->sin_addr=*(structin_addr*)h->h_addr;+if(h)+sin->sin_addr=*(structin_addr*)h->h_addr;+elseif(hints&&(hints->ai_flags&AI_PASSIVE))+sin->sin_addr.s_addr=INADDR_ANY;+else+sin->sin_addr.s_addr=INADDR_LOOPBACK;ai->ai_addr=(structsockaddr*)sin;ai->ai_next=0;return0;
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
Report incoming connections from the process that
accept() the connection instead of the handling
process.
This enables "Connection from"-reporting on
Windows, where getpeername(0, ...) consistently
fails.
Signed-off-by: Erik Faye-Lund <redacted>
---
daemon.c | 70 +++++++++++++++++++++++++++++++++++--------------------------
1 files changed, 40 insertions(+), 30 deletions(-)
@@ -692,14 +690,21 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)}}+addrstr=get_addrstr(&port,addr);+strcat(envbuf,addrstr);++cld.env=(constchar**)env;cld.argv=(constchar**)cld_argv;cld.in=incoming;cld.out=dup(incoming);if(start_command(&cld))logerror("unable to fork");-else+else{+loginfo("[%"PRIuMAX"] Connection from %s:%d",+(uintmax_t)cld.pid,addrstr,port);add_child(&cld,addr,addrlen);+}close(incoming);}
@@ -1164,8 +1169,13 @@ int main(int argc, char **argv)if(inetd_mode&&!freopen("/dev/null","w",stderr))die_errno("failed to redirect stderr to /dev/null");-if(getpeername(0,peer,&slen))-peer=NULL;+if(!getpeername(0,peer,&slen)){+intport=-1;+char*addrstr=get_addrstr(&port,peer);+setenv("REMOTE_ADDR",addrstr,1);+loginfo("[%"PRIuMAX"] Connection from %s:%d",+(uintmax_t)getpid(),addrstr,port);+}returnexecute(peer);}
@@ -408,71 +408,6 @@ int pipe(int filedes[2])return0;}-intpoll(structpollfd*ufds,unsignedintnfds,inttimeout)-{-inti,pending;--if(timeout>=0){-if(nfds==0){-Sleep(timeout);-return0;-}-returnerrno=EINVAL,error("poll timeout not supported");-}--/* When there is only one fd to wait for, then we pretend that-*inputisavailableandlettheactualwaithappenwhenthe-*callerinvokesread().-*/-if(nfds==1){-if(!(ufds[0].events&POLLIN))-returnerrno=EINVAL,error("POLLIN not set");-ufds[0].revents=POLLIN;-return0;-}--repeat:-pending=0;-for(i=0;i<nfds;i++){-DWORDavail=0;-HANDLEh=(HANDLE)_get_osfhandle(ufds[i].fd);-if(h==INVALID_HANDLE_VALUE)-return-1;/* errno was set */--if(!(ufds[i].events&POLLIN))-returnerrno=EINVAL,error("POLLIN not set");--/* this emulation works only for pipes */-if(!PeekNamedPipe(h,NULL,0,NULL,&avail,NULL)){-interr=GetLastError();-if(err==ERROR_BROKEN_PIPE){-ufds[i].revents=POLLHUP;-pending++;-}else{-errno=EINVAL;-returnerror("PeekNamedPipe failed,"-" GetLastError: %u",err);-}-}elseif(avail){-ufds[i].revents=POLLIN;-pending++;-}else-ufds[i].revents=0;-}-if(!pending){-/* The only times that we spin here is when the process-*thatisconnectedthroughthepipesiswaitingfor-*itsowninputdatatobecomeavailable.Butsince-*theprocess(pack-objects)isitselfCPUintensive,-*itwillhappilypickupthetimeslicethatweare-*relinquishinghere.-*/-Sleep(0);-gotorepeat;-}-return0;-}-structtm*gmtime_r(consttime_t*timep,structtm*result){/* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
@@ -188,7 +178,6 @@ int pipe(int filedes[2]);unsignedintsleep(unsignedintseconds);intmkstemp(char*template);intgettimeofday(structtimeval*tv,void*tz);-intpoll(structpollfd*ufds,unsignedintnfds,inttimeout);structtm*gmtime_r(consttime_t*timep,structtm*result);structtm*localtime_r(consttime_t*timep,structtm*result);intgetpagesize(void);/* defined in MinGW's libgcc.a */
@@ -0,0 +1,597 @@+/* Emulation for poll(2)+ContributedbyPaoloBonzini.++Copyright2001-2003,2006-2010FreeSoftwareFoundation,Inc.++Thisfileispartofgnulib.++Thisprogramisfreesoftware;youcanredistributeitand/ormodify+itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+theFreeSoftwareFoundation;eitherversion2,or(atyouroption)+anylaterversion.++Thisprogramisdistributedinthehopethatitwillbeuseful,+butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+GNUGeneralPublicLicenseformoredetails.++YoushouldhavereceivedacopyoftheGNUGeneralPublicLicensealong+withthisprogram;ifnot,writetotheFreeSoftwareFoundation,+Inc.,51FranklinStreet,FifthFloor,Boston,MA02110-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<config.h>+#include<alloca.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)++staticBOOL+IsSocketHandle(HANDLEh)+{+WSANETWORKEVENTSev;++if(IsConsoleHandle(h))+returnFALSE;++/* Under Wine, it seems that getsockopt returns 0 for pipes too.+WSAEnumNetworkEventsinsteaddistinguishesthetwocorrectly.*/+ev.lNetworkEvents=0xDEADBEEF;+WSAEnumNetworkEvents((SOCKET)h,NULL,&ev);+returnev.lNetworkEvents!=0xDEADBEEF;+}++/* Declare data structures for ntdll functions. */+typedefstruct_FILE_PIPE_LOCAL_INFORMATION{+ULONGNamedPipeType;+ULONGNamedPipeConfiguration;+ULONGMaximumInstances;+ULONGCurrentInstances;+ULONGInboundQuota;+ULONGReadDataAvailable;+ULONGOutboundQuota;+ULONGWriteQuotaAvailable;+ULONGNamedPipeState;+ULONGNamedPipeEnd;+}FILE_PIPE_LOCAL_INFORMATION,*PFILE_PIPE_LOCAL_INFORMATION;++typedefstruct_IO_STATUS_BLOCK+{+union{+DWORDStatus;+PVOIDPointer;+}u;+ULONG_PTRInformation;+}IO_STATUS_BLOCK,*PIO_STATUS_BLOCK;++typedefenum_FILE_INFORMATION_CLASS{+FilePipeLocalInformation=24+}FILE_INFORMATION_CLASS,*PFILE_INFORMATION_CLASS;++typedefDWORD(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+forthehandle,eliminatethemfrom*P_SOUGHT.*/++staticint+win32_compute_revents(HANDLEh,int*p_sought)+{+inti,ret,happened;+INPUT_RECORD*irbuffer;+DWORDavail,nbuffer;+BOOLbRet;+IO_STATUS_BLOCKiosb;+FILE_PIPE_LOCAL_INFORMATIONfpli;+staticPNtQueryInformationFileNtQueryInformationFile;+staticBOOLonce_only;++switch(GetFileType(h))+{+caseFILE_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);+}+elseif(GetLastError()==ERROR_BROKEN_PIPE)+happened|=POLLHUP;++else+{+/* It was the write-end of the pipe. Check if it is writable.+IfNtQueryInformationFilefails,optimisticallyassumethepipeis+writable.ThiscouldhappenonWin9x,whereNtQueryInformationFile+isnotavailable,orifweinheritapipethatdoesn'tpermit+FILE_READ_ATTRIBUTESaccessonthewriteend(Ithinkthisshould+nothappensinceWinXPSP2;WINEseemsfinetoo).Otherwise,+ensurethatenoughspaceisavailableforatomicwrites.*/+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);+}+returnhappened;++caseFILE_TYPE_CHAR:+ret=WaitForSingleObject(h,0);+if(!IsConsoleHandle(h))+returnret==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)+returnPOLLHUP;+if(!*p_sought)+return0;++irbuffer=(INPUT_RECORD*)alloca(nbuffer*sizeof(INPUT_RECORD));+bRet=PeekConsoleInput(h,irbuffer,nbuffer,&avail);+if(!bRet||avail==0)+returnPOLLHUP;++for(i=0;i<avail;i++)+if(irbuffer[i].EventType==KEY_EVENT)+return*p_sought;+return0;+}+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. */++staticint+win32_compute_revents_socket(SOCKETh,intsought,longlNetworkEvents)+{+inthappened=0;++if((lNetworkEvents&(FD_READ|FD_ACCEPT|FD_CLOSE))==FD_ACCEPT)+happened|=(POLLIN|POLLRDNORM)&sought;++elseif(lNetworkEvents&(FD_READ|FD_ACCEPT|FD_CLOSE))+{+intr,error;++chardata[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. */+elseif(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;++returnhappened;+}++#else /* !MinGW */++/* Convert select(2) returned fd_sets into poll(2) revents values. */+staticint+compute_revents(intfd,intsought,fd_set*rfds,fd_set*wfds,fd_set*efds)+{+inthappened=0;+if(FD_ISSET(fd,rfds))+{+intr;+intsocket_errno;++# if defined __MACH__ && defined __APPLE__+/* There is a bug in Mac OS X that causes it to ignore MSG_PEEK+forsomekindsofdescriptors.Detectifthisdescriptorisa+connectedsocket,aserversocket,orsomethingelseusinga+0-byterecv,anduseioctl(2)todetectPOLLHUP.*/+r=recv(fd,NULL,0,MSG_PEEK);+socket_errno=(r<0)?errno:0;+if(r==0||socket_errno==ENOTSOCK)+ioctl(fd,FIONREAD,&r);+# else+chardata[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'sfine.*/+elseif(r>0||(/* (r == -1) && */socket_errno==ENOTCONN))+happened|=(POLLIN|POLLRDNORM)&sought;++/* Distinguish hung-up sockets from other errors. */+elseif(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;++returnhappened;+}+#endif /* !MinGW */++int+poll(pfd,nfd,timeout)+structpollfd*pfd;+nfds_tnfd;+inttimeout;+{+#ifndef WIN32_NATIVE+fd_setrfds,wfds,efds;+structtimevaltv;+structtimeval*ptv;+intmaxfd,rc;+nfds_ti;++# ifdef _SC_OPEN_MAX+staticintsc_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+simplestcase.*/+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;+}+elseif(timeout>0)+{+ptv=&tv;+ptv->tv_sec=timeout/1000;+ptv->tv_usec=(timeout%1000)*1000;+}+elseif(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+isout-of-banddatareceivedonasocket", hence we push+POLLWRBANDeventsontowfdsinsteadofefds.*/+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)+returnrc;++/* establish results */+rc=0;+for(i=0;i<nfd;i++)+if(pfd[i].fd<0)+pfd[i].revents=0;+else+{+inthappened=compute_revents(pfd[i].fd,pfd[i].events,+&rfds,&wfds,&efds);+if(happened)+{+pfd[i].revents=happened;+rc++;+}+}++returnrc;+#else+staticstructtimevaltv0;+staticHANDLEhEvent;+WSANETWORKEVENTSev;+HANDLEh,handle_array[FD_SETSIZE+2];+DWORDret,wait_timeout,nhandles;+fd_setrfds,wfds,xfds;+BOOLpoll_again;+MSGmsg;+intrc=0;+nfds_ti;++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++)+{+intsought=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))+{+intrequested=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,+screenbufferhandlesarewaitable,andthey'llblockuntil+acharacterisavailable.win32_compute_reventseliminates+bitsforthe"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+noneedtocallselectagain.*/+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 */+BOOLbRet;+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++)+{+inthappened;++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+todistinguishFD_READandFD_ACCEPT;thissavesarecvlater.*/+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. */+intsought=pfd[i].events;+happened=win32_compute_revents(h,&sought);+nhandles++;+}++if((pfd[i].revents|=happened)!=0)+rc++;+}++returnrc;+#endif+}
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
Windows does not supply the POSIX-functions fork(), setuuid(), setgid(),
setsid() and initgroups(). Disable support for --user, --group and
--detach on platforms lacking _POSIX_VERSION.
Signed-off-by: Erik Faye-Lund <redacted>
---
This might be a bit controversial; does anyone know of any systems that
implements fork(), setuuid(), setgid() and setsid() but does not define
_POSIX_VERSION? Perhaps we should have a separate makefile-switch instead?
Makefile | 8 +++-----
daemon.c | 43 +++++++++++++++++++++++++++++++------------
2 files changed, 34 insertions(+), 17 deletions(-)
@@ -401,6 +401,7 @@ EXTRA_PROGRAMS =# ... and all the rest that could be moved out of bindir to gitexecdirPROGRAMS+=$(EXTRA_PROGRAMS)+PROGRAM_OBJS+=daemon.oPROGRAM_OBJS+=fast-import.oPROGRAM_OBJS+=imap-send.oPROGRAM_OBJS+=shell.o
@@ -974,10 +983,12 @@ static int serve(struct string_list *listen_addr, int listen_port, struct passwddie("unable to allocate any listen sockets on port %u",listen_port);+#ifdef _POSIX_VERSIONif(pass&&gid&&(initgroups(pass->pw_name,gid)||setgid(gid)||setuid(pass->pw_uid)))die("cannot drop privileges");+#endifreturnservice_loop(&socklist);}
@@ -987,11 +998,11 @@ int main(int argc, char **argv)intlisten_port=0;structstring_listlisten_addr=STRING_LIST_INIT_NODUP;intserve_mode=0,inetd_mode=0;-constchar*pid_file=NULL,*user_name=NULL,*group_name=NULL;+constchar*pid_file=NULL;+#ifdef _POSIX_VERSIONintdetach=0;-structpasswd*pass=NULL;-structgroup*group;-gid_tgid=0;+constchar*user_name=NULL,*group_name=NULL;+#endifinti;git_extract_argv0_path(argv[0]);
@@ -1080,6 +1091,7 @@ int main(int argc, char **argv)pid_file=arg+11;continue;}+#ifdef _POSIX_VERSIONif(!strcmp(arg,"--detach")){detach=1;log_syslog=1;
@@ -1093,6 +1105,7 @@ int main(int argc, char **argv)group_name=arg+8;continue;}+#endifif(!prefixcmp(arg,"--enable=")){enable_service(arg+9,1);continue;
@@ -1127,14 +1140,17 @@ int main(int argc, char **argv)/* avoid splitting a message in the middle */setvbuf(stderr,NULL,_IOFBF,4096);+#ifdef _POSIX_VERSIONif(inetd_mode&&(group_name||user_name))die("--user and --group are incompatible with --inetd");+#endifif(inetd_mode&&(listen_port||(listen_addr.nr>0)))die("--listen= and --port= are incompatible with --inetd");elseif(listen_port==0)listen_port=DEFAULT_GIT_PORT;+#ifdef _POSIX_VERSIONif(group_name&&!user_name)die("--group supplied without --user");
@@ -1146,13 +1162,14 @@ int main(int argc, char **argv)if(!group_name)gid=pass->pw_gid;else{-group=getgrnam(group_name);+structgroup*group=getgrnam(group_name);if(!group)die("group not found - %s",group_name);gid=group->gr_gid;}}+#endifif(strict_paths&&(!ok_paths||!*ok_paths))die("option --strict-paths requires a whitelist");
@@ -1180,11 +1197,13 @@ int main(int argc, char **argv)returnexecute(peer);}+#ifdef _POSIX_VERSIONif(detach){daemonize();loginfo("Ready to rumble");}else+#endifsanitize_stdfds();if(pid_file)
@@ -1197,5 +1216,5 @@ int main(int argc, char **argv)cld_argv[argc]="--serve";cld_argv[argc+1]=NULL;-returnserve(&listen_addr,listen_port,pass,gid);+returnserve(&listen_addr,listen_port);}
On Sun, Oct 10, 2010 at 13:20, Erik Faye-Lund [off-list ref] wrote:
lib/poll.c and lib/poll.in.h imported from 0a05120 in
git://git.savannah.gnu.org/gnulib.git
Having fought with importing things from gnulib myself using their
tools it would be useful to note in the commit message *how* you
imported this. Did you use the gnulib command with some archane
options so it wouldn't touch the build system while it was at it, or
did you just copy the relevant files manually?
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 4:15 PM, Ævar Arnfjörð Bjarmason
[off-list ref] wrote:
On Sun, Oct 10, 2010 at 13:20, Erik Faye-Lund [off-list ref] wrote:
quoted
lib/poll.c and lib/poll.in.h imported from 0a05120 in
git://git.savannah.gnu.org/gnulib.git
Having fought with importing things from gnulib myself using their
tools it would be useful to note in the commit message *how* you
imported this. Did you use the gnulib command with some archane
options so it wouldn't touch the build system while it was at it, or
did you just copy the relevant files manually?
Sorry if that was unclear - I just copied the files (verbatim).
Patching to make it compile for us comes in the next patch.
I didn't even know that there was a gnulib tool to extract code, but a
quick google-search shows that there is. I'll look into using the tool
instead for the next round.
From: Johannes Sixt <hidden> Date: 2016-06-15 22:49:45
On Sonntag, 10. Oktober 2010, Erik Faye-Lund wrote:
Report incoming connections from the process that
accept() the connection instead of the handling
process.
This enables "Connection from"-reporting on
Windows, where getpeername(0, ...) consistently
fails.
Is this from the process that you invoke with --serve? then this failure could
be due to Winsockets not being initilized. Did you check that?
-- Hannes
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 8:58 PM, Johannes Sixt [off-list ref] wrote:
On Sonntag, 10. Oktober 2010, Erik Faye-Lund wrote:
quoted
Report incoming connections from the process that
accept() the connection instead of the handling
process.
This enables "Connection from"-reporting on
Windows, where getpeername(0, ...) consistently
fails.
Is this from the process that you invoke with --serve? then this failure could
be due to Winsockets not being initilized. Did you check that?
I've tried that, and unfortunately it lack of socket initialization
does not seem to be the reason :(
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 4:28 PM, Erik Faye-Lund [off-list ref] wrote:
On Sun, Oct 10, 2010 at 4:15 PM, Ævar Arnfjörð Bjarmason
[off-list ref] wrote:
quoted
On Sun, Oct 10, 2010 at 13:20, Erik Faye-Lund [off-list ref] wrote:
quoted
lib/poll.c and lib/poll.in.h imported from 0a05120 in
git://git.savannah.gnu.org/gnulib.git
Having fought with importing things from gnulib myself using their
tools it would be useful to note in the commit message *how* you
imported this. Did you use the gnulib command with some archane
options so it wouldn't touch the build system while it was at it, or
did you just copy the relevant files manually?
Sorry if that was unclear - I just copied the files (verbatim).
Patching to make it compile for us comes in the next patch.
I didn't even know that there was a gnulib tool to extract code, but a
quick google-search shows that there is. I'll look into using the tool
instead for the next round.
I've had a quick look at it, and it really doesn't seem like
gnulib-tool is suited for us here. It seems to be intended on pure
autoconf-projects, and starts including all kinds of things that we
don't need. We only care about poll-emulation on Windows, and we don't
need autoconf to tell us if it should be used or not.
So I'm not in favor of using gnulib-tool, and going with the current
method of verbatim copy with a separate fix-up commit. But perhaps I
should clarify the commit message so other people can easily upgrade
the emulation later...
On Sun, Oct 10, 2010 at 13:20, Erik Faye-Lund [off-list ref] wrote:
Windows does not supply the POSIX-functions fork(), setuuid(), setgid(),
setsid() and initgroups(). Disable support for --user, --group and
--detach on platforms lacking _POSIX_VERSION.
FWIW I checked if Perl's fork() emulation with threads on Windows
could emulate this, but no:
perl -E '
if (my $pid = fork()) {
say "$$: child running as $pid"
} else {
sleep 1;
say "$$: running in the background"
}'
On Unix that would detach the process from the terminal, but on
Windows with threads the original process only returns after the child
has finished.
I didn't expect it to act differently, but I thought I'd note it here
in case anyone had it in mind to implement --detach on Windows.
This might be a bit controversial; does anyone know of any systems that
implements fork(), setuuid(), setgid() and setsid() but does not define
_POSIX_VERSION? Perhaps we should have a separate makefile-switch instead?
Even if it's defined it's more self-documenting to have our own
HAVE_POSIX_GOODIES (or something like that) instead.
From: Eric Sunshine <hidden> Date: 2016-06-15 22:49:45
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted hunk
From: Mike Pape<redacted>
git-daemon requires some socket-functionality that is not yet
supported in the Windows-port. This patch adds said functionality,
and makes sure WSAStartup gets called by socket(), since it is the
first network-call in git-daemon. In addition, a check is added to
prevent WSAStartup (and WSACleanup, though atexit) from being
called more than once, since git-daemon calls both socket() and
gethostbyname().
Signed-off-by: Mike Pape<redacted>
Signed-off-by: Erik Faye-Lund<redacted>
---
diff --git a/compat/mingw.c b/compat/mingw.cindex 6590f33..563ef1f 100644--- a/compat/mingw.c+++ b/compat/mingw.c
+#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) {
+ closesocket(s2);
+ return error("unable to make a socket file descriptor: %s",
+ strerror(errno));
Is 'errno' from _open_osfhandle() still valid when handed to strerror()
or has it been clobbered by closesocket()?
Corollary: Does _open_osfhandle() indeed set 'errno', or is it more
appropriate to call WSAGetLastError()? (The documentation I read for
_open_osfhandle() did not say anything about how to determine the reason
for failure.)
-- ES
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 9:31 PM, Erik Faye-Lund [off-list ref] wrote:
On Sun, Oct 10, 2010 at 8:58 PM, Johannes Sixt [off-list ref] wrote:
quoted
On Sonntag, 10. Oktober 2010, Erik Faye-Lund wrote:
quoted
Report incoming connections from the process that
accept() the connection instead of the handling
process.
This enables "Connection from"-reporting on
Windows, where getpeername(0, ...) consistently
fails.
Is this from the process that you invoke with --serve? then this failure could
be due to Winsockets not being initilized. Did you check that?
I've tried that, and unfortunately it lack of socket initialization
does not seem to be the reason :(
But looking at it a bit more, I can do the following code-reduction on
top, changing this to a +10 lines to a -2 lines patch ;)
@@ -518,7 +518,7 @@ static void parse_host_arg(char *extra_args, int buflen)}-staticintexecute(structsockaddr*addr)+staticintexecute(){staticcharline[1000];intpktlen,len,i;
@@ -1179,22 +1179,10 @@ int main(int argc, char **argv)base_path);if(serve_mode){-structsockaddr_storagess;-structsockaddr*peer=(structsockaddr*)&ss;-socklen_tslen=sizeof(ss);-if(inetd_mode&&!freopen("/dev/null","w",stderr))die_errno("failed to redirect stderr to /dev/null");-if(!getpeername(0,peer,&slen)){-intport=-1;-char*addrstr=get_addrstr(&port,peer);-setenv("REMOTE_ADDR",addrstr,1);-loginfo("[%"PRIuMAX"] Connection from %s:%d",-(uintmax_t)getpid(),addrstr,port);-}--returnexecute(peer);+returnexecute();}#ifdef _POSIX_VERSION
From: Eric Sunshine <hidden> Date: 2016-06-15 22:49:45
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
From: Mike Pape<redacted>
Syslog does not usually exist on Windows, so we implement our own
using Window's ReportEvent mechanism.
Signed-off-by: Mike Pape<redacted>
Signed-off-by: Erik Faye-Lund<redacted>
---
+void syslog(int priority, const char *fmt, const char *arg)
+{
+ WORD logtype;
+
+ if (!ms_eventlog)
+ return;
+
+ if (strcmp(fmt, "%s")) {
+ warning("format string of syslog() not implemented");
+ return;
+ }
It is not exactly clear what the intention is here. Is this trying to
say that no formatting directives are allowed in 'fmt' or what? The
simple case it is actually checking (where 'fmt' is solely '%s') could
easily be handled manually, as could more complex formats.
+ /*
+ * ReportEvent() doesn't handle strings containing %n, where n is
+ * an integer. Such events must be reformatted by the caller.
+ */
+ ReportEventA(ms_eventlog,
+ logtype,
+ 0,
+ 0,
+ NULL,
+ 1,
+ 0,
+ (const char **)&arg,
+ NULL);
The comment about '%n' seems to be warning about a potential problem but
does not actually protect against it. Should this issue be handled?
-- ES
On Sun, Oct 10, 2010 at 19:34, Erik Faye-Lund [off-list ref] wrote:
On Sun, Oct 10, 2010 at 4:28 PM, Erik Faye-Lund [off-list ref] wrote:
quoted
On Sun, Oct 10, 2010 at 4:15 PM, Ævar Arnfjörð Bjarmason
[off-list ref] wrote:
quoted
On Sun, Oct 10, 2010 at 13:20, Erik Faye-Lund [off-list ref] wrote:
quoted
lib/poll.c and lib/poll.in.h imported from 0a05120 in
git://git.savannah.gnu.org/gnulib.git
Having fought with importing things from gnulib myself using their
tools it would be useful to note in the commit message *how* you
imported this. Did you use the gnulib command with some archane
options so it wouldn't touch the build system while it was at it, or
did you just copy the relevant files manually?
Sorry if that was unclear - I just copied the files (verbatim).
Patching to make it compile for us comes in the next patch.
I didn't even know that there was a gnulib tool to extract code, but a
quick google-search shows that there is. I'll look into using the tool
instead for the next round.
I've had a quick look at it, and it really doesn't seem like
gnulib-tool is suited for us here. It seems to be intended on pure
autoconf-projects, and starts including all kinds of things that we
don't need. We only care about poll-emulation on Windows, and we don't
need autoconf to tell us if it should be used or not.
The only reason I asked was that I tried to use gnulib-tool at one
point and reached the same conclusion. But in my case I wanted it to
resolve dependencies (i.e. bring in multiple projects), so not using
it was its own pain.
I just thought I'd ask in case you'd spent more time on getting it to
work.
So I'm not in favor of using gnulib-tool, and going with the current
method of verbatim copy with a separate fix-up commit. But perhaps I
should clarify the commit message so other people can easily upgrade
the emulation later...
By all means don't use gnulib, but noting how to upgrade things when
we add anything external in compat/ is a good idea.
From: Eric Sunshine <hidden> Date: 2016-06-15 22:49:45
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
The Windows port so far used process handles as PID. However,
this does not work consistently with getpid.
Perhaps this could be elaborated a bit to explain the interaction with
getpid() and how it is causing problems for daemon mode. For the casual
reader, it is not immediately obvious what is failing or why this patch
is needed.
-- ES
From: Eric Sunshine <hidden> Date: 2016-06-15 22:49:45
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted hunk
fork() is only available on POSIX, so to support git-daemon
on Windows we have to use something else.
Instead we invent the flag --serve, which is a stripped down
version of --inetd-mode. We use start_command() to call
git-daemon with this flag appended to serve clients.
Signed-off-by: Erik Faye-Lund<redacted>
---
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 9:40 PM, Eric Sunshine [off-list ref] wrote:
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
From: Mike Pape<redacted>
git-daemon requires some socket-functionality that is not yet
supported in the Windows-port. This patch adds said functionality,
and makes sure WSAStartup gets called by socket(), since it is the
first network-call in git-daemon. In addition, a check is added to
prevent WSAStartup (and WSACleanup, though atexit) from being
called more than once, since git-daemon calls both socket() and
gethostbyname().
Signed-off-by: Mike Pape<redacted>
Signed-off-by: Erik Faye-Lund<redacted>
---
diff --git a/compat/mingw.c b/compat/mingw.cindex 6590f33..563ef1f 100644--- a/compat/mingw.c+++ b/compat/mingw.c
+#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) {
+ closesocket(s2);
+ return error("unable to make a socket file descriptor:
%s",
+ strerror(errno));
Is 'errno' from _open_osfhandle() still valid when handed to strerror() or
has it been clobbered by closesocket()?
Corollary: Does _open_osfhandle() indeed set 'errno', or is it more
appropriate to call WSAGetLastError()? (The documentation I read for
_open_osfhandle() did not say anything about how to determine the reason for
failure.)
_open_osfhandle seems to set both errno and the winsock-error.
closesocket() sets the winsock-error but not the CRT. I've just tested
with a very simple application:
---8<---
#include <winsock2.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
const char *win32_strerror(DWORD dw)
{
static char tmp[4096];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
tmp, sizeof(tmp), NULL);
return tmp;
}
int main()
{
WSADATA wsa = {0};
WSAStartup(MAKEWORD(2, 0), &wsa);
printf("errno: '%s'\nWSAGetLastError: '%s'\n",
strerror(errno), win32_strerror(WSAGetLastError()));
errno = 0;
_open_osfhandle(-1, O_RDWR | O_BINARY);
printf("errno: '%s'\nWSAGetLastError: '%s'\n",
strerror(errno), win32_strerror(WSAGetLastError()));
errno = 0;
closesocket(-1);
printf("errno: '%s'\nWSAGetLastError: '%s'\n",
strerror(errno), win32_strerror(WSAGetLastError()));
return 0;
}
---8<---
The output is:
---8<---
errno: 'Result too large'
WSAGetLastError: 'The operation completed successfully.
'
errno: 'Bad file descriptor'
WSAGetLastError: 'The handle is invalid.
'
errno: 'No error'
WSAGetLastError: 'An operation was attempted on something that is not a socket.
'
---8<---
So, it seems that WSAGetLastError() gets clobbered by closesocket(),
but not errno.
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 9:50 PM, Eric Sunshine [off-list ref] wrote:
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
From: Mike Pape<redacted>
Syslog does not usually exist on Windows, so we implement our own
using Window's ReportEvent mechanism.
Signed-off-by: Mike Pape<redacted>
Signed-off-by: Erik Faye-Lund<redacted>
---
+void syslog(int priority, const char *fmt, const char *arg)
+{
+ WORD logtype;
+
+ if (!ms_eventlog)
+ return;
+
+ if (strcmp(fmt, "%s")) {
+ warning("format string of syslog() not implemented");
+ return;
+ }
It is not exactly clear what the intention is here. Is this trying to say
that no formatting directives are allowed in 'fmt' or what? The simple case
it is actually checking (where 'fmt' is solely '%s') could easily be handled
manually, as could more complex formats.
This is the result of the feed-back in v1, where we tried to implement
all format strings. But that turned out to be very complex (due to the
lack of a portable va_copy()) and since we control all call-sites for
syslog and already only use "%s" as the format, it should be OK.
Perhaps that should be mentioned in the commit message...
quoted
+ /*
+ * ReportEvent() doesn't handle strings containing %n, where n is
+ * an integer. Such events must be reformatted by the caller.
+ */
+ ReportEventA(ms_eventlog,
+ logtype,
+ 0,
+ 0,
+ NULL,
+ 1,
+ 0,
+ (const char **)&arg,
+ NULL);
The comment about '%n' seems to be warning about a potential problem but
does not actually protect against it. Should this issue be handled?
This is again an issue that was discussed in the first round.
ReportEvent() CANNOT report a string containing "%n" (where n is an
integer). And while we could probably try to work around it by
inserting a space or something, and I don't think we ever were able to
find a case where we could report a string containing "%n" in the
first place...
Are you suggesting that we report an error when we can't report the
string correctly? We could do that, but I'm not sure how the end-user
would benefit from that. ReportEvent is used to report errors (unless
the --verbose flag has been specified), and reporting that we can't
present an error message strike me as a bit confusing... Even the
corrupted error message is probably better :P
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 9:56 PM, Eric Sunshine [off-list ref] wrote:
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
fork() is only available on POSIX, so to support git-daemon
on Windows we have to use something else.
Instead we invent the flag --serve, which is a stripped down
version of --inetd-mode. We use start_command() to call
git-daemon with this flag appended to serve clients.
Signed-off-by: Erik Faye-Lund<redacted>
---
From: Johannes Sixt <hidden> Date: 2016-06-15 22:49:45
On Sonntag, 10. Oktober 2010, Erik Faye-Lund wrote:
On Sun, Oct 10, 2010 at 9:50 PM, Eric Sunshine [off-list ref]
wrote:
quoted
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
+ /*
+ * ReportEvent() doesn't handle strings containing %n, where n
is + * an integer. Such events must be reformatted by the caller.
+ */
The comment about '%n' seems to be warning about a potential problem but
does not actually protect against it. Should this issue be handled?
This is again an issue that was discussed in the first round.
ReportEvent() CANNOT report a string containing "%n" (where n is an
integer). And while we could probably try to work around it by
inserting a space or something, and I don't think we ever were able to
find a case where we could report a string containing "%n" in the
first place...
I recall that it was mentioned that this could happen for IPv6 addresses?
-- Hannes
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 9:53 PM, Eric Sunshine [off-list ref] wrote:
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
The Windows port so far used process handles as PID. However,
this does not work consistently with getpid.
Perhaps this could be elaborated a bit to explain the interaction with
getpid() and how it is causing problems for daemon mode. For the casual
reader, it is not immediately obvious what is failing or why this patch is
needed.
Good point. How about something like this?
"The Windows port so far used process handles as PID. However, this is
not consistent with what getpid returns.
PIDs are system-global identifiers, but process handles are local to a
process. Using PIDs instead of process handles allows for instance a
user to kill a hung process with the Task Manager, something that
would have been impossible with process handles."
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 10:51 PM, Johannes Sixt [off-list ref] wrote:
On Sonntag, 10. Oktober 2010, Erik Faye-Lund wrote:
quoted
On Sun, Oct 10, 2010 at 9:50 PM, Eric Sunshine [off-list ref]
wrote:
quoted
quoted
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
+ /*
+ * ReportEvent() doesn't handle strings containing %n, where n
is + * an integer. Such events must be reformatted by the caller.
+ */
The comment about '%n' seems to be warning about a potential problem but
does not actually protect against it. Should this issue be handled?
This is again an issue that was discussed in the first round.
ReportEvent() CANNOT report a string containing "%n" (where n is an
integer). And while we could probably try to work around it by
inserting a space or something, and I don't think we ever were able to
find a case where we could report a string containing "%n" in the
first place...
I recall that it was mentioned that this could happen for IPv6 addresses?
Ah, that's right. Microsoft even mentions it in MSDN: "Note that the
string that you log cannot contain %n, where n is an integer value
(for example, %1) because the event viewer treats it as an insertion
string. Because an IPv6 address can contain this character sequence,
you cannot log an event message that contains an IPv6 address".
What should we do about it? Error out?
Strangely enough, reporting strings with "%1" works fine when I test
it now. Perhaps this is dependent on the windows-version?
Yep, it is. On Vista 64 it seems to work, but on WinXP it does not.
The string gets expanded into itself 100 times, and then there's
apparently a recursion test.
Also, it is only %1 that does not report correctly on WinXP, probably
because of a check against the wNumStrings-parameter. Even strings
like %11 does not expand.
FormatMessage has the FORMAT_MESSAGE_IGNORE_INSERTS-flag to avoid this
kind of expansion, but unfortunately I can't find similar
functionality for ReportEvent :(
From: Eric Sunshine <hidden> Date: 2016-06-15 22:49:45
On 10/10/2010 4:20 PM, Erik Faye-Lund wrote:
On Sun, Oct 10, 2010 at 9:40 PM, Eric Sunshine[off-list ref] wrote:
quoted
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
From: Mike Pape<redacted>
git-daemon requires some socket-functionality that is not yet
supported in the Windows-port. This patch adds said functionality,
and makes sure WSAStartup gets called by socket(), since it is the
first network-call in git-daemon. In addition, a check is added to
prevent WSAStartup (and WSACleanup, though atexit) from being
called more than once, since git-daemon calls both socket() and
gethostbyname().
Signed-off-by: Mike Pape<redacted>
Signed-off-by: Erik Faye-Lund<redacted>
---
diff --git a/compat/mingw.c b/compat/mingw.cindex 6590f33..563ef1f 100644--- a/compat/mingw.c+++ b/compat/mingw.c
+#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) {
+ closesocket(s2);
+ return error("unable to make a socket file descriptor:
%s",
+ strerror(errno));
Is 'errno' from _open_osfhandle() still valid when handed to strerror() or
has it been clobbered by closesocket()?
Corollary: Does _open_osfhandle() indeed set 'errno', or is it more
appropriate to call WSAGetLastError()? (The documentation I read for
_open_osfhandle() did not say anything about how to determine the reason for
failure.)
_open_osfhandle seems to set both errno and the winsock-error.
closesocket() sets the winsock-error but not the CRT. I've just tested
with a very simple application:
So, it seems that WSAGetLastError() gets clobbered by closesocket(),
but not errno.
Thank you for checking. Even if it is not strictly needed in this case,
for the sake of clarity (and to avoid having this question repeated in
the future), it might be worthwhile to save 'errno' or the result of
WSAGetLastError() in a temporary before invoking closesocket(), and then
pass the temporary to strerror().
-- ES
From: Eric Sunshine <hidden> Date: 2016-06-15 22:49:45
On 10/10/2010 4:37 PM, Erik Faye-Lund wrote:
On Sun, Oct 10, 2010 at 9:50 PM, Eric Sunshine[off-list ref] wrote:
quoted
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
From: Mike Pape<redacted>
Syslog does not usually exist on Windows, so we implement our own
using Window's ReportEvent mechanism.
Signed-off-by: Mike Pape<redacted>
Signed-off-by: Erik Faye-Lund<redacted>
---
+void syslog(int priority, const char *fmt, const char *arg)
+{
+ WORD logtype;
+
+ if (!ms_eventlog)
+ return;
+
+ if (strcmp(fmt, "%s")) {
+ warning("format string of syslog() not implemented");
+ return;
+ }
It is not exactly clear what the intention is here. Is this trying to say
that no formatting directives are allowed in 'fmt' or what? The simple case
it is actually checking (where 'fmt' is solely '%s') could easily be handled
manually, as could more complex formats.
This is the result of the feed-back in v1, where we tried to implement
all format strings.
In retrospect, when thinking more carefully about the conditional
expression, I suppose the code is self-documenting, though perhaps a
comment in code or in commit message would help.
But that turned out to be very complex (due to the
lack of a portable va_copy()) and since we control all call-sites for
syslog and already only use "%s" as the format, it should be OK.
Do you mean vsnprintf() rather than va_copy()?
quoted
quoted
+ /*
+ * ReportEvent() doesn't handle strings containing %n, where n is
+ * an integer. Such events must be reformatted by the caller.
+ */
+ ReportEventA(ms_eventlog,
+ logtype,
+ 0,
+ 0,
+ NULL,
+ 1,
+ 0,
+ (const char **)&arg,
+ NULL);
The comment about '%n' seems to be warning about a potential problem but
does not actually protect against it. Should this issue be handled?
This is again an issue that was discussed in the first round.
ReportEvent() CANNOT report a string containing "%n" (where n is an
integer). And while we could probably try to work around it by
inserting a space or something, and I don't think we ever were able to
find a case where we could report a string containing "%n" in the
first place...
Are you suggesting that we report an error when we can't report the
string correctly? We could do that, but I'm not sure how the end-user
would benefit from that. ReportEvent is used to report errors (unless
the --verbose flag has been specified), and reporting that we can't
present an error message strike me as a bit confusing... Even the
corrupted error message is probably better :P
I am not suggesting reporting an error. As a first-time reader of the
code, I was trying to understand the presence of the comment which did
not really seem to relate to the code. Perhaps adding a "FIXME" to the
comment saying that the condition should perhaps be handled in the
future would help to explain the comments presence.
(On the other hand, for the '%s' check above, the code does report a
warning and then exits, so it is not inconceivable that a '%n' could
also emit a warning.)
-- ES
From: Eric Sunshine <hidden> Date: 2016-06-15 22:49:45
On 10/10/2010 4:52 PM, Erik Faye-Lund wrote:
On Sun, Oct 10, 2010 at 9:53 PM, Eric Sunshine[off-list ref] wrote:
quoted
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
The Windows port so far used process handles as PID. However,
this does not work consistently with getpid.
Perhaps this could be elaborated a bit to explain the interaction with
getpid() and how it is causing problems for daemon mode. For the casual
reader, it is not immediately obvious what is failing or why this patch is
needed.
Good point. How about something like this?
Thanks. This sort of explanation could indeed be helpful as part of the
commit message.
"The Windows port so far used process handles as PID. However, this is
not consistent with what getpid returns.
PIDs are system-global identifiers, but process handles are local to a
process. Using PIDs instead of process handles allows for instance a
user to kill a hung process with the Task Manager, something that
would have been impossible with process handles."
Minor nit: Add commas around 'for instance': "...handles allows, for
instance, a user..."
These also could be combined into a single paragraph.
-- ES
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Sun, Oct 10, 2010 at 11:28 PM, Eric Sunshine [off-list ref] wrote:
On 10/10/2010 4:37 PM, Erik Faye-Lund wrote:
quoted
On Sun, Oct 10, 2010 at 9:50 PM, Eric Sunshine[off-list ref]
wrote:
quoted
On 10/10/2010 9:20 AM, Erik Faye-Lund wrote:
quoted
From: Mike Pape<redacted>
Syslog does not usually exist on Windows, so we implement our own
using Window's ReportEvent mechanism.
Signed-off-by: Mike Pape<redacted>
Signed-off-by: Erik Faye-Lund<redacted>
---
+void syslog(int priority, const char *fmt, const char *arg)
+{
+ WORD logtype;
+
+ if (!ms_eventlog)
+ return;
+
+ if (strcmp(fmt, "%s")) {
+ warning("format string of syslog() not implemented");
+ return;
+ }
It is not exactly clear what the intention is here. Is this trying to say
that no formatting directives are allowed in 'fmt' or what? The simple
case
it is actually checking (where 'fmt' is solely '%s') could easily be
handled
manually, as could more complex formats.
This is the result of the feed-back in v1, where we tried to implement
all format strings.
In retrospect, when thinking more carefully about the conditional
expression, I suppose the code is self-documenting, though perhaps a comment
in code or in commit message would help.
quoted
But that turned out to be very complex (due to the
lack of a portable va_copy()) and since we control all call-sites for
syslog and already only use "%s" as the format, it should be OK.
Do you mean vsnprintf() rather than va_copy()?
OK, I had to read some old discussions to figure out what the issue was :)
The problem was lack of portable va_copy, because I tried to add a
non-variadic version of strbuf_addf(), namely strbuf_vaddf() to do the
work.
I guess it could be implemented pretty easily with vsnprintf(),
though. I was afraid of doing that originally because I know there's
portability issues with the return value of snprintf. Luckily it seems
that we have a fix for that in compat/sprintf.c, and we rely on the
return value being correct in strbuf_addf() so it would probably be
safe.
Something like this (on top)
---8<---
@@ -186,7 +186,7 @@ int setitimer(int type, struct itimerval *in,
struct itimerval *out);
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
int link(const char *oldpath, const char *newpath);
void openlog(const char *ident, int logopt, int facility);
-void syslog(int priority, const char *fmt, const char *arg);
+void syslog(int priority, const char *fmt, ...);
/*
* replacements of existing functions
---8<---
quoted
Are you suggesting that we report an error when we can't report the
string correctly? We could do that, but I'm not sure how the end-user
would benefit from that. ReportEvent is used to report errors (unless
the --verbose flag has been specified), and reporting that we can't
present an error message strike me as a bit confusing... Even the
corrupted error message is probably better :P
I am not suggesting reporting an error. As a first-time reader of the code,
I was trying to understand the presence of the comment which did not really
seem to relate to the code. Perhaps adding a "FIXME" to the comment saying
that the condition should perhaps be handled in the future would help to
explain the comments presence.
A FIXME would certainly a good idea, if I don't just end up supporting
varargs here.
(On the other hand, for the '%s' check above, the code does report a warning
and then exits, so it is not inconceivable that a '%n' could also emit a
warning.)
I guess I could add something like this:
if (strstr(arg, "%1"))
warning("arg contains %1, message might be corrupted");
I don't want to return in that case, because I think some output is
better than no output, and it seems to work on Vista. In fact, working
on Vista is kind of demotivating me to add such a warning in the first
place...
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Mon, Oct 11, 2010 at 12:16 AM, Erik Faye-Lund [off-list ref] wrote:
On Sun, Oct 10, 2010 at 11:28 PM, Eric Sunshine [off-list ref] wrote:
quoted
On 10/10/2010 4:37 PM, Erik Faye-Lund wrote:
quoted
Are you suggesting that we report an error when we can't report the
string correctly? We could do that, but I'm not sure how the end-user
would benefit from that. ReportEvent is used to report errors (unless
the --verbose flag has been specified), and reporting that we can't
present an error message strike me as a bit confusing... Even the
corrupted error message is probably better :P
I am not suggesting reporting an error. As a first-time reader of the code,
I was trying to understand the presence of the comment which did not really
seem to relate to the code. Perhaps adding a "FIXME" to the comment saying
that the condition should perhaps be handled in the future would help to
explain the comments presence.
A FIXME would certainly a good idea, if I don't just end up supporting
varargs here.
Uhm, excuse me for confusing the different comments :P
Yes, a FIXME should definitely be added. And I definitely need to seep now! ;)
From: Eric Sunshine <hidden> Date: 2016-06-15 22:49:45
On 10/10/2010 6:16 PM, Erik Faye-Lund wrote:
quoted hunk
On Sun, Oct 10, 2010 at 11:28 PM, Eric Sunshine[off-list ref] wrote:
quoted
On 10/10/2010 4:37 PM, Erik Faye-Lund wrote:
quoted
This is the result of the feed-back in v1, where we tried to implement
all format strings. But that turned out to be very complex (due to the
lack of a portable va_copy()) and since we control all call-sites for
syslog and already only use "%s" as the format, it should be OK.
Do you mean vsnprintf() rather than va_copy()?
The problem was lack of portable va_copy, because I tried to add a
non-variadic version of strbuf_addf(), namely strbuf_vaddf() to do the
work.
I guess it could be implemented pretty easily with vsnprintf(),
though. I was afraid of doing that originally because I know there's
portability issues with the return value of snprintf. Luckily it seems
that we have a fix for that in compat/sprintf.c, and we rely on the
return value being correct in strbuf_addf() so it would probably be
safe.
Something like this (on top)
@@ -1435,17 +1435,24 @@ void openlog(const char *ident, int logopt,
int facility)
warning("RegisterEventSource() failed: %lu", GetLastError());
}
-void syslog(int priority, const char *fmt, const char *arg)
+void syslog(int priority, const char *fmt, ...)
{
WORD logtype;
+ char *str;
+ int str_len;
+ va_list ap;
if (!ms_eventlog)
return;
- if (strcmp(fmt, "%s")) {
- warning("format string of syslog() not implemented");
- return;
- }
+ va_start(ap, fmt);
+ str_len = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
vsnprintf() can return -1 on error (even the compat/snprintf.c version
can do so), so perhaps check for this condition before the subsequent
malloc(str_len+1)?
Other than the note about -1 return value, this revision looks fine.
quoted
(On the other hand, for the '%s' check above, the code does report a warning
and then exits, so it is not inconceivable that a '%n' could also emit a
warning.)
I guess I could add something like this:
if (strstr(arg, "%1"))
warning("arg contains %1, message might be corrupted");
I don't want to return in that case, because I think some output is
better than no output, and it seems to work on Vista.
Rather than emitting a warning, it might be reasonable to perform a
simple transformation on the string if it contains a %1 (or %n
generally) in order to avoid ReportEvent()'s shortcoming. Even something
as simple as inserting a space between '%' and '1' might be sufficiently
defensive.
-- ES
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Mon, Oct 11, 2010 at 1:20 AM, Eric Sunshine [off-list ref] wrote:
On 10/10/2010 6:16 PM, Erik Faye-Lund wrote:
quoted
On Sun, Oct 10, 2010 at 11:28 PM, Eric Sunshine[off-list ref]
wrote:
quoted
(On the other hand, for the '%s' check above, the code does report a
warning
and then exits, so it is not inconceivable that a '%n' could also emit a
warning.)
I guess I could add something like this:
if (strstr(arg, "%1"))
warning("arg contains %1, message might be corrupted");
I don't want to return in that case, because I think some output is
better than no output, and it seems to work on Vista.
Rather than emitting a warning, it might be reasonable to perform a simple
transformation on the string if it contains a %1 (or %n generally) in order
to avoid ReportEvent()'s shortcoming. Even something as simple as inserting
a space between '%' and '1' might be sufficiently defensive.
Yes, but I'm tempted to defer fixing this until we see that it's a
problem in reality. The logic to somehow escape such sequences looks a
bit nasty in my head. But perhaps strbuf_expand() is the right hammer
for this use...
Then the logical next question becomes what we should expand it to.
Does "%1" -> "% 1" make sense for IPv6 addresses?
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:49:45
On Mon, Oct 11, 2010 at 5:28 PM, Erik Faye-Lund [off-list ref] wrote:
On Mon, Oct 11, 2010 at 1:20 AM, Eric Sunshine [off-list ref] wrote:
quoted
On 10/10/2010 6:16 PM, Erik Faye-Lund wrote:
quoted
On Sun, Oct 10, 2010 at 11:28 PM, Eric Sunshine[off-list ref]
wrote:
quoted
(On the other hand, for the '%s' check above, the code does report a
warning
and then exits, so it is not inconceivable that a '%n' could also emit a
warning.)
I guess I could add something like this:
if (strstr(arg, "%1"))
warning("arg contains %1, message might be corrupted");
I don't want to return in that case, because I think some output is
better than no output, and it seems to work on Vista.
Rather than emitting a warning, it might be reasonable to perform a simple
transformation on the string if it contains a %1 (or %n generally) in order
to avoid ReportEvent()'s shortcoming. Even something as simple as inserting
a space between '%' and '1' might be sufficiently defensive.
Yes, but I'm tempted to defer fixing this until we see that it's a
problem in reality. The logic to somehow escape such sequences looks a
bit nasty in my head. But perhaps strbuf_expand() is the right hammer
for this use...
Then the logical next question becomes what we should expand it to.
Does "%1" -> "% 1" make sense for IPv6 addresses?
Something along these lines? (on top of the previous patch, uhm, with
some local modifications. Sorry, I'm not at home and do not have the
original version at hand. I'm sure you get the picture, though...)
I also added a +1 that was missing and caused the string to be capped.