From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: "Ben Key" Newsgroups: gmane.emacs.sources,gmane.emacs.devel Subject: preliminary patch for emacsclient.c Date: Thu, 7 Nov 2002 00:12:37 -0500 Sender: gnu-emacs-sources-admin@gnu.org Message-ID: <002b01c2861c$4a7800e0$6501a8c0@GODDESS> Reply-To: NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_002C_01C285F2.61A37F80" X-Trace: main.gmane.org 1036646395 25723 80.91.224.249 (7 Nov 2002 05:19:55 GMT) X-Complaints-To: usenet@main.gmane.org NNTP-Posting-Date: Thu, 7 Nov 2002 05:19:55 +0000 (UTC) Return-path: Original-Received: from monty-python.gnu.org ([199.232.76.173]) by main.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 189f53-0006fm-00 for ; Thu, 07 Nov 2002 06:19:49 +0100 Original-Received: from localhost ([127.0.0.1] helo=monty-python.gnu.org) by monty-python.gnu.org with esmtp (Exim 4.10) id 189f5i-0005HP-00; Thu, 07 Nov 2002 00:20:31 -0500 Original-Received: from list by monty-python.gnu.org with tmda-scanned (Exim 4.10) id 189eyC-0000ns-00 for gnu-emacs-sources@gnu.org; Thu, 07 Nov 2002 00:12:44 -0500 Original-Received: from mail by monty-python.gnu.org with spam-scanned (Exim 4.10) id 189ey9-0000m0-00 for gnu-emacs-sources@gnu.org; Thu, 07 Nov 2002 00:12:43 -0500 Original-Received: from smtp-server2-bak.tampabay.rr.com ([65.32.1.45] helo=smtp-server2.tampabay.rr.com) by monty-python.gnu.org with esmtp (Exim 4.10) id 189ey8-0000hh-00; Thu, 07 Nov 2002 00:12:40 -0500 Original-Received: from GODDESS (6535194hfc48.tampabay.rr.com [65.35.194.48]) by smtp-server2.tampabay.rr.com (8.12.2/8.12.2) with SMTP id gA75CbS8009239; Thu, 7 Nov 2002 00:12:37 -0500 (EST) Original-To: "Emacs-Devel \(E-mail\)" , "Gnu-Emacs-Sources \(E-mail\)" X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook CWS, Build 9.0.2416 (9.0.2911.0) X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106 Importance: Normal Errors-To: gnu-emacs-sources-admin@gnu.org X-BeenThere: gnu-emacs-sources@gnu.org X-Mailman-Version: 2.0.11 Precedence: bulk List-Help: List-Post: List-Subscribe: , List-Id: GNU Emacs source code postings and patches List-Unsubscribe: , List-Archive: Xref: main.gmane.org gmane.emacs.sources:204 gmane.emacs.devel:9212 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:9212 This is a multi-part message in MIME format. ------=_NextPart_000_002C_01C285F2.61A37F80 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit As requested, here is a patch that incorporates the changes I have made so far to emacsclient.c. These changes have not been fully tested since I have not been able to get server-start to work. ------=_NextPart_000_002C_01C285F2.61A37F80 Content-Type: application/octet-stream; name="21_3-emacsclient.c.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="21_3-emacsclient.c.diff" --- _21.3/lib-src/emacsclient.c 2002-09-30 20:45:30.000000000 -0400=0A= +++ 21.3/lib-src/emacsclient.c 2002-11-06 23:47:58.000000000 -0500=0A= @@ -40,7 +40,18 @@=0A= #else=0A= # include =0A= #endif /* not VMS */=0A= -=0A= +#ifdef WINDOWSNT=0A= +# include =0A= +# include =0A= + extern int _execvp (const char*, char* const*);=0A= +# ifndef HAVE_STRUCT_SOCKADDR_UN=0A= + struct sockaddr_un=0A= + {=0A= + short int sun_family; /* AF_UNIX */=0A= + char sun_path[108]; /* path name (gag) */=0A= + };=0A= +# endif=0A= +#endif=0A= char *getenv (), *getwd ();=0A= char *getcwd ();=0A= =0A= @@ -229,7 +240,6 @@=0A= }=0A= =0A= =0A= -=0C=0A= #if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)=0A= =0A= int=0A= @@ -248,7 +258,904 @@=0A= =0A= #include =0A= #include =0A= +#ifndef WINDOWSNT=0A= #include =0A= +#endif=0A= +#ifdef WINDOWSNT=0A= +/*=0A= + BEGIN: Borrowed from w32.c=0A= +*/=0A= +/* parallel array of private info on file handles */=0A= +filedesc fd_info [ MAXDESC ];=0A= +/* Wrappers for winsock functions to map between our file descriptors=0A= + and winsock's handles; also set h_errno for convenience.=0A= +=0A= + To allow Emacs to run on systems which don't have winsock support=0A= + installed, we dynamically link to winsock on startup if present, and=0A= + otherwise provide the minimum necessary functionality=0A= + (eg. gethostname). */=0A= +=0A= +/* function pointers for relevant socket functions */=0A= +int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA = lpWSAData);=0A= +void (PASCAL *pfn_WSASetLastError) (int iError);=0A= +int (PASCAL *pfn_WSAGetLastError) (void);=0A= +int (PASCAL *pfn_socket) (int af, int type, int protocol);=0A= +int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int = namelen);=0A= +int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int = namelen);=0A= +int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);=0A= +int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);=0A= +int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);=0A= +int (PASCAL *pfn_closesocket) (SOCKET s);=0A= +int (PASCAL *pfn_shutdown) (SOCKET s, int how);=0A= +int (PASCAL *pfn_WSACleanup) (void);=0A= +u_short (PASCAL *pfn_htons) (u_short hostshort);=0A= +u_short (PASCAL *pfn_ntohs) (u_short netshort);=0A= +unsigned long (PASCAL *pfn_inet_addr) (const char * cp);=0A= +int (PASCAL *pfn_gethostname) (char * name, int namelen);=0A= +struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);=0A= +struct servent * (PASCAL *pfn_getservbyname) (const char * name, const = char * proto);=0A= +int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * = namelen);=0A= +int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,=0A= + const char * optval, int optlen);=0A= +int (PASCAL *pfn_listen) (SOCKET s, int backlog);=0A= +int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,=0A= + int * namelen);=0A= +SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * = addrlen);=0A= +int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,=0A= + struct sockaddr * from, int * fromlen);=0A= +int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int = flags,=0A= + const struct sockaddr * to, int tolen);=0A= +=0A= +/* SetHandleInformation is only needed to make sockets non-inheritable. = */=0A= +BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, = DWORD flags);=0A= +#ifndef HANDLE_FLAG_INHERIT=0A= +#define HANDLE_FLAG_INHERIT 1=0A= +#endif=0A= +=0A= +HANDLE winsock_lib;=0A= +static int winsock_inuse;=0A= +BOOL=0A= +term_winsock (void)=0A= +{=0A= + if (winsock_lib !=3D NULL && winsock_inuse =3D=3D 0)=0A= + {=0A= + /* Not sure what would cause WSAENETDOWN, or even if it can happen=0A= + after WSAStartup returns successfully, but it seems reasonable=0A= + to allow unloading winsock anyway in that case. */=0A= + if (pfn_WSACleanup () =3D=3D 0 ||=0A= + pfn_WSAGetLastError () =3D=3D WSAENETDOWN)=0A= + {=0A= + if (FreeLibrary (winsock_lib))=0A= + winsock_lib =3D NULL;=0A= + return TRUE;=0A= + }=0A= + }=0A= + return FALSE;=0A= +}=0A= +=0A= +BOOL=0A= +init_winsock (int load_now)=0A= +{=0A= + WSADATA winsockData;=0A= + if (winsock_lib !=3D NULL)=0A= + return TRUE;=0A= + pfn_SetHandleInformation =3D NULL;=0A= + pfn_SetHandleInformation=0A= + =3D (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),=0A= + "SetHandleInformation");=0A= + winsock_lib =3D LoadLibrary ("wsock32.dll");=0A= + if (winsock_lib !=3D NULL)=0A= + {=0A= + /* dynamically link to socket functions */=0A= +#define LOAD_PROC(fn) \=0A= + if ((pfn_##fn =3D (void *) GetProcAddress (winsock_lib, #fn)) = =3D=3D NULL) \=0A= + goto fail;=0A= + LOAD_PROC( WSAStartup );=0A= + LOAD_PROC( WSASetLastError );=0A= + LOAD_PROC( WSAGetLastError );=0A= + LOAD_PROC( socket );=0A= + LOAD_PROC( bind );=0A= + LOAD_PROC( connect );=0A= + LOAD_PROC( ioctlsocket );=0A= + LOAD_PROC( recv );=0A= + LOAD_PROC( send );=0A= + LOAD_PROC( closesocket );=0A= + LOAD_PROC( shutdown );=0A= + LOAD_PROC( htons );=0A= + LOAD_PROC( ntohs );=0A= + LOAD_PROC( inet_addr );=0A= + LOAD_PROC( gethostname );=0A= + LOAD_PROC( gethostbyname );=0A= + LOAD_PROC( getservbyname );=0A= + LOAD_PROC( getpeername );=0A= + LOAD_PROC( WSACleanup );=0A= + LOAD_PROC( setsockopt );=0A= + LOAD_PROC( listen );=0A= + LOAD_PROC( getsockname );=0A= + LOAD_PROC( accept );=0A= + LOAD_PROC( recvfrom );=0A= + LOAD_PROC( sendto );=0A= +#undef LOAD_PROC=0A= + /* specify version 1.1 of winsock */=0A= + if (pfn_WSAStartup (0x101, &winsockData) =3D=3D 0)=0A= + {=0A= + if (winsockData.wVersion !=3D 0x101)=0A= + goto fail;=0A= + if (!load_now)=0A= + {=0A= + /* Report that winsock exists and is usable, but leave=0A= + socket functions disabled. I am assuming that calling=0A= + WSAStartup does not require any network interaction,=0A= + and in particular does not cause or require a dial-up=0A= + connection to be established. */=0A= + pfn_WSACleanup ();=0A= + FreeLibrary (winsock_lib);=0A= + winsock_lib =3D NULL;=0A= + }=0A= + winsock_inuse =3D 0;=0A= + return TRUE;=0A= + }=0A= + fail:=0A= + FreeLibrary (winsock_lib);=0A= + winsock_lib =3D NULL;=0A= + }=0A= + return FALSE;=0A= +}=0A= +=0A= +int h_errno =3D 0;=0A= +=0A= +/* function to set h_errno for compatability; map winsock error codes to=0A= + normal system codes where they overlap (non-overlapping definitions=0A= + are already in */=0A= +static void set_errno ()=0A= +{=0A= + if (winsock_lib =3D=3D NULL)=0A= + h_errno =3D EINVAL;=0A= + else=0A= + h_errno =3D pfn_WSAGetLastError ();=0A= + switch (h_errno)=0A= + {=0A= + case WSAEACCES: h_errno =3D EACCES; break;=0A= + case WSAEBADF: h_errno =3D EBADF; break;=0A= + case WSAEFAULT: h_errno =3D EFAULT; break;=0A= + case WSAEINTR: h_errno =3D EINTR; break;=0A= + case WSAEINVAL: h_errno =3D EINVAL; break;=0A= + case WSAEMFILE: h_errno =3D EMFILE; break;=0A= + case WSAENAMETOOLONG: h_errno =3D ENAMETOOLONG; break;=0A= + case WSAENOTEMPTY: h_errno =3D ENOTEMPTY; break;=0A= + }=0A= + errno =3D h_errno;=0A= +}=0A= +=0A= +static void check_errno ()=0A= +{=0A= + if (h_errno =3D=3D 0 && winsock_lib !=3D NULL)=0A= + pfn_WSASetLastError (0);=0A= +}=0A= +=0A= +/* Extend strerror to handle the winsock-specific error codes. */=0A= +struct {=0A= + int errnum;=0A= + char * msg;=0A= +} _wsa_errlist[] =3D {=0A= + WSAEINTR , "Interrupted function call",=0A= + WSAEBADF , "Bad file descriptor",=0A= + WSAEACCES , "Permission denied",=0A= + WSAEFAULT , "Bad address",=0A= + WSAEINVAL , "Invalid argument",=0A= + WSAEMFILE , "Too many open files",=0A= + WSAEWOULDBLOCK , "Resource temporarily unavailable",=0A= + WSAEINPROGRESS , "Operation now in progress",=0A= + WSAEALREADY , "Operation already in progress",=0A= + WSAENOTSOCK , "Socket operation on non-socket",=0A= + WSAEDESTADDRREQ , "Destination address required",=0A= + WSAEMSGSIZE , "Message too long",=0A= + WSAEPROTOTYPE , "Protocol wrong type for socket",=0A= + WSAENOPROTOOPT , "Bad protocol option",=0A= + WSAEPROTONOSUPPORT , "Protocol not supported",=0A= + WSAESOCKTNOSUPPORT , "Socket type not supported",=0A= + WSAEOPNOTSUPP , "Operation not supported",=0A= + WSAEPFNOSUPPORT , "Protocol family not supported",=0A= + WSAEAFNOSUPPORT , "Address family not supported by protocol = family",=0A= + WSAEADDRINUSE , "Address already in use",=0A= + WSAEADDRNOTAVAIL , "Cannot assign requested address",=0A= + WSAENETDOWN , "Network is down",=0A= + WSAENETUNREACH , "Network is unreachable",=0A= + WSAENETRESET , "Network dropped connection on reset",=0A= + WSAECONNABORTED , "Software caused connection abort",=0A= + WSAECONNRESET , "Connection reset by peer",=0A= + WSAENOBUFS , "No buffer space available",=0A= + WSAEISCONN , "Socket is already connected",=0A= + WSAENOTCONN , "Socket is not connected",=0A= + WSAESHUTDOWN , "Cannot send after socket shutdown",=0A= + WSAETOOMANYREFS , "Too many references", /* not sure */=0A= + WSAETIMEDOUT , "Connection timed out",=0A= + WSAECONNREFUSED , "Connection refused",=0A= + WSAELOOP , "Network loop", /* not sure */=0A= + WSAENAMETOOLONG , "Name is too long",=0A= + WSAEHOSTDOWN , "Host is down",=0A= + WSAEHOSTUNREACH , "No route to host",=0A= + WSAENOTEMPTY , "Buffer not empty", /* not sure */=0A= + WSAEPROCLIM , "Too many processes",=0A= + WSAEUSERS , "Too many users", /* not sure */=0A= + WSAEDQUOT , "Double quote in host name", /* really = not sure */=0A= + WSAESTALE , "Data is stale", /* not sure */=0A= + WSAEREMOTE , "Remote error", /* not sure */=0A= + WSASYSNOTREADY , "Network subsystem is unavailable",=0A= + WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",=0A= + WSANOTINITIALISED , "Winsock not initialized successfully",=0A= + WSAEDISCON , "Graceful shutdown in progress",=0A= +#ifdef WSAENOMORE=0A= + WSAENOMORE , "No more operations allowed", /* not sure = */=0A= + WSAECANCELLED , "Operation cancelled", /* not sure */=0A= + WSAEINVALIDPROCTABLE , "Invalid procedure table from service = provider",=0A= + WSAEINVALIDPROVIDER , "Invalid service provider version number",=0A= + WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",=0A= + WSASYSCALLFAILURE , "System call failured",=0A= + WSASERVICE_NOT_FOUND , "Service not found", /* not sure */=0A= + WSATYPE_NOT_FOUND , "Class type not found",=0A= + WSA_E_NO_MORE , "No more resources available", /* really = not sure */=0A= + WSA_E_CANCELLED , "Operation already cancelled", /* really = not sure */=0A= + WSAEREFUSED , "Operation refused", /* not sure */=0A= +#endif=0A= + WSAHOST_NOT_FOUND , "Host not found",=0A= + WSATRY_AGAIN , "Authoritative host not found during name = lookup",=0A= + WSANO_RECOVERY , "Non-recoverable error during name lookup",=0A= + WSANO_DATA , "Valid name, no data record of requested = type",=0A= + -1, NULL=0A= +};=0A= +=0A= +char *=0A= +sys_strerror(int error_no)=0A= +{=0A= + int i;=0A= + static char unknown_msg[40];=0A= + if (error_no >=3D 0 && error_no < sys_nerr)=0A= + return sys_errlist[error_no];=0A= + for (i =3D 0; _wsa_errlist[i].errnum >=3D 0; i++)=0A= + if (_wsa_errlist[i].errnum =3D=3D error_no)=0A= + return _wsa_errlist[i].msg;=0A= + sprintf(unknown_msg, "Unidentified error: %d", error_no);=0A= + return unknown_msg;=0A= +}=0A= +=0A= +/* [andrewi 3-May-96] I've had conflicting results using both methods,=0A= + but I believe the method of keeping the socket handle separate (and=0A= + insuring it is not inheritable) is the correct one. */=0A= +=0A= +//#define SOCK_REPLACE_HANDLE=0A= +=0A= +#ifdef SOCK_REPLACE_HANDLE=0A= +#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))=0A= +#else=0A= +#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)=0A= +#endif=0A= +=0A= +int socket_to_fd (SOCKET s);=0A= +=0A= +int=0A= +sys_socket(int af, int type, int protocol)=0A= +{=0A= + SOCKET s;=0A= +=0A= + if (winsock_lib =3D=3D NULL)=0A= + {=0A= + h_errno =3D ENETDOWN;=0A= + return INVALID_SOCKET;=0A= + }=0A= +=0A= + check_errno ();=0A= +=0A= + /* call the real socket function */=0A= + s =3D pfn_socket (af, type, protocol);=0A= +=0A= + if (s !=3D INVALID_SOCKET)=0A= + return socket_to_fd (s);=0A= +=0A= + set_errno ();=0A= + return -1;=0A= +}=0A= +=0A= +/* Convert a SOCKET to a file descriptor. */=0A= +int=0A= +socket_to_fd (SOCKET s)=0A= +{=0A= + int fd;=0A= + child_process * cp;=0A= +=0A= + /* Although under NT 3.5 _open_osfhandle will accept a socket=0A= + handle, if opened with SO_OPENTYPE =3D=3D SO_SYNCHRONOUS_NONALERT,=0A= + that does not work under NT 3.1. However, we can get the same=0A= + effect by using a backdoor function to replace an existing=0A= + descriptor handle with the one we want. */=0A= +=0A= + /* allocate a file descriptor (with appropriate flags) */=0A= + fd =3D _open ("NUL:", _O_RDWR);=0A= + if (fd >=3D 0)=0A= + {=0A= +#ifdef SOCK_REPLACE_HANDLE=0A= + /* now replace handle to NUL with our socket handle */=0A= + CloseHandle ((HANDLE) _get_osfhandle (fd));=0A= + _free_osfhnd (fd);=0A= + _set_osfhnd (fd, s);=0A= + /* setmode (fd, _O_BINARY); */=0A= +#else=0A= + /* Make a non-inheritable copy of the socket handle. Note=0A= + that it is possible that sockets aren't actually kernel=0A= + handles, which appears to be the case on Windows 9x when=0A= + the MS Proxy winsock client is installed. */=0A= + {=0A= + /* Apparently there is a bug in NT 3.51 with some service=0A= + packs, which prevents using DuplicateHandle to make a=0A= + socket handle non-inheritable (causes WSACleanup to=0A= + hang). The work-around is to use SetHandleInformation=0A= + instead if it is available and implemented. */=0A= + if (pfn_SetHandleInformation)=0A= + {=0A= + pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);=0A= + }=0A= + else=0A= + {=0A= + HANDLE parent =3D GetCurrentProcess ();=0A= + HANDLE new_s =3D INVALID_HANDLE_VALUE;=0A= +=0A= + if (DuplicateHandle (=0A= + parent,=0A= + (HANDLE) s,=0A= + parent,=0A= + &new_s,=0A= + 0,=0A= + FALSE,=0A= + DUPLICATE_SAME_ACCESS))=0A= + {=0A= + /* It is possible that DuplicateHandle succeeds even=0A= + though the socket wasn't really a kernel handle,=0A= + because a real handle has the same value. So=0A= + test whether the new handle really is a socket. */=0A= + long nonblocking =3D 0;=0A= + if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) =3D=3D = 0)=0A= + {=0A= + pfn_closesocket (s);=0A= + s =3D (SOCKET) new_s;=0A= + }=0A= + else=0A= + {=0A= + CloseHandle (new_s);=0A= + }=0A= + }=0A= + }=0A= + }=0A= + fd_info[fd].hnd =3D (HANDLE) s;=0A= +#endif=0A= +=0A= + /* set our own internal flags */=0A= + fd_info[fd].flags =3D FILE_SOCKET | FILE_BINARY | FILE_READ | = FILE_WRITE;=0A= +=0A= + cp =3D new_child ();=0A= + if (cp)=0A= + {=0A= + cp->fd =3D fd;=0A= + cp->status =3D STATUS_READ_ACKNOWLEDGED;=0A= +=0A= + /* attach child_process to fd_info */=0A= + if (fd_info[ fd ].cp !=3D NULL)=0A= + {=0A= + DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));=0A= + abort ();=0A= + }=0A= +=0A= + fd_info[ fd ].cp =3D cp;=0A= +=0A= + /* success! */=0A= + winsock_inuse++; /* count open sockets */=0A= + return fd;=0A= + }=0A= +=0A= + /* clean up */=0A= + _close (fd);=0A= + }=0A= + pfn_closesocket (s);=0A= + h_errno =3D EMFILE;=0A= + return -1;=0A= +}=0A= +=0A= +=0A= +int=0A= +sys_bind (int s, const struct sockaddr * addr, int namelen)=0A= +{=0A= + if (winsock_lib =3D=3D NULL)=0A= + {=0A= + h_errno =3D ENOTSOCK;=0A= + return SOCKET_ERROR;=0A= + }=0A= +=0A= + check_errno ();=0A= + if (fd_info[s].flags & FILE_SOCKET)=0A= + {=0A= + int rc =3D pfn_bind (SOCK_HANDLE (s), addr, namelen);=0A= + if (rc =3D=3D SOCKET_ERROR)=0A= + set_errno ();=0A= + return rc;=0A= + }=0A= + h_errno =3D ENOTSOCK;=0A= + return SOCKET_ERROR;=0A= +}=0A= +=0A= +=0A= +int=0A= +sys_connect (int s, const struct sockaddr * name, int namelen)=0A= +{=0A= + if (winsock_lib =3D=3D NULL)=0A= + {=0A= + h_errno =3D ENOTSOCK;=0A= + return SOCKET_ERROR;=0A= + }=0A= +=0A= + check_errno ();=0A= + if (fd_info[s].flags & FILE_SOCKET)=0A= + {=0A= + int rc =3D pfn_connect (SOCK_HANDLE (s), name, namelen);=0A= + if (rc =3D=3D SOCKET_ERROR)=0A= + set_errno ();=0A= + return rc;=0A= + }=0A= + h_errno =3D ENOTSOCK;=0A= + return SOCKET_ERROR;=0A= +}=0A= +=0A= +int=0A= +sys_gethostname (char * name, int namelen)=0A= +{=0A= + if (winsock_lib !=3D NULL)=0A= + return pfn_gethostname (name, namelen);=0A= +=0A= + if (namelen > MAX_COMPUTERNAME_LENGTH)=0A= + return !GetComputerName (name, (DWORD *)&namelen);=0A= +=0A= + h_errno =3D EFAULT;=0A= + return SOCKET_ERROR;=0A= +}=0A= +=0A= +/* Function to do blocking read of one byte, needed to implement=0A= + select. It is only allowed on sockets and pipes. */=0A= +int=0A= +_sys_read_ahead (int fd)=0A= +{=0A= + child_process * cp;=0A= + int rc;=0A= +=0A= + if (fd < 0 || fd >=3D MAXDESC)=0A= + return STATUS_READ_ERROR;=0A= +=0A= + cp =3D fd_info[fd].cp;=0A= +=0A= + if (cp =3D=3D NULL || cp->fd !=3D fd || cp->status !=3D = STATUS_READ_READY)=0A= + return STATUS_READ_ERROR;=0A= +=0A= + if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) =3D=3D 0=0A= + || (fd_info[fd].flags & FILE_READ) =3D=3D 0)=0A= + {=0A= + DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe = or socket!\n", fd));=0A= + abort ();=0A= + }=0A= +=0A= + cp->status =3D STATUS_READ_IN_PROGRESS;=0A= +=0A= + if (fd_info[fd].flags & FILE_PIPE)=0A= + {=0A= + rc =3D _read (fd, &cp->chr, sizeof (char));=0A= +=0A= + /* Give subprocess time to buffer some more output for us before=0A= + reporting that input is available; we need this because Windows 95=0A= + connects DOS programs to pipes by making the pipe appear to be=0A= + the normal console stdout - as a result most DOS programs will=0A= + write to stdout without buffering, ie. one character at a=0A= + time. Even some W32 programs do this - "dir" in a command=0A= + shell on NT is very slow if we don't do this. */=0A= + if (rc > 0)=0A= + {=0A= + int wait =3D 0;=0A= + if (nowait=3D=3D0)=0A= + {=0A= + wait=3D100;=0A= + }=0A= + if (wait > 0)=0A= + Sleep (wait);=0A= + else if (wait < 0)=0A= + while (++wait <=3D 0)=0A= + /* Yield remainder of our time slice, effectively giving a=0A= + temporary priority boost to the child process. */=0A= + Sleep (0);=0A= + }=0A= + }=0A= +#ifdef HAVE_SOCKETS=0A= + else if (fd_info[fd].flags & FILE_SOCKET)=0A= + {=0A= + unsigned long nblock =3D 0;=0A= + /* We always want this to block, so temporarily disable NDELAY. = */=0A= + if (fd_info[fd].flags & FILE_NDELAY)=0A= + pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);=0A= +=0A= + rc =3D pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);=0A= +=0A= + if (fd_info[fd].flags & FILE_NDELAY)=0A= + {=0A= + nblock =3D 1;=0A= + pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);=0A= + }=0A= + }=0A= +#endif=0A= +=0A= + if (rc =3D=3D sizeof (char))=0A= + cp->status =3D STATUS_READ_SUCCEEDED;=0A= + else=0A= + cp->status =3D STATUS_READ_FAILED;=0A= +=0A= + return cp->status;=0A= +}=0A= +=0A= +/*=0A= +BEGIN: Borrowed from w32proc.c=0A= +*/=0A= +=0A= +/* Emulate getpwuid, getpwnam and others. */=0A= +=0A= +#define PASSWD_FIELD_SIZE 256=0A= +=0A= +static char the_passwd_name[PASSWD_FIELD_SIZE];=0A= +static char the_passwd_passwd[PASSWD_FIELD_SIZE];=0A= +static char the_passwd_gecos[PASSWD_FIELD_SIZE];=0A= +static char the_passwd_dir[PASSWD_FIELD_SIZE];=0A= +static char the_passwd_shell[PASSWD_FIELD_SIZE];=0A= +=0A= +static struct passwd the_passwd =3D=0A= +{=0A= + the_passwd_name,=0A= + the_passwd_passwd,=0A= + 0,=0A= + 0,=0A= + 0,=0A= + the_passwd_gecos,=0A= + the_passwd_dir,=0A= + the_passwd_shell,=0A= +};=0A= +=0A= +int=0A= +getuid ()=0A= +{=0A= + return the_passwd.pw_uid;=0A= +}=0A= +=0A= +int=0A= +geteuid ()=0A= +{=0A= + /* I could imagine arguing for checking to see whether the user is=0A= + in the Administrators group and returning a UID of 0 for that=0A= + case, but I don't know how wise that would be in the long run. */=0A= + return getuid ();=0A= +}=0A= +=0A= +int=0A= +getgid ()=0A= +{=0A= + return the_passwd.pw_gid;=0A= +}=0A= +=0A= +int=0A= +getegid ()=0A= +{=0A= + return getgid ();=0A= +}=0A= +=0A= +struct passwd *=0A= +getpwuid (int uid)=0A= +{=0A= + if (uid =3D=3D the_passwd.pw_uid)=0A= + return &the_passwd;=0A= + return NULL;=0A= +}=0A= +=0A= +struct passwd *=0A= +getpwnam (char *name)=0A= +{=0A= + struct passwd *pw;=0A= +=0A= + pw =3D getpwuid (getuid ());=0A= + if (!pw)=0A= + return pw;=0A= +=0A= + if (stricmp (name, pw->pw_name))=0A= + return NULL;=0A= +=0A= + return pw;=0A= +}=0A= +=0A= +void=0A= +init_user_info ()=0A= +{=0A= + /* Find the user's real name by opening the process token and=0A= + looking up the name associated with the user-sid in that token.=0A= +=0A= + Use the relative portion of the identifier authority value from=0A= + the user-sid as the user id value (same for group id using the=0A= + primary group sid from the process token). */=0A= +=0A= + char user_sid[256], name[256], domain[256];=0A= + DWORD length =3D sizeof (name), dlength =3D sizeof = (domain), trash;=0A= + HANDLE token =3D NULL;=0A= + SID_NAME_USE user_type;=0A= +=0A= + if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)=0A= + && GetTokenInformation (token, TokenUser,=0A= + (PVOID) user_sid, sizeof (user_sid), &trash)=0A= + && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,=0A= + domain, &dlength, &user_type))=0A= + {=0A= + strcpy (the_passwd.pw_name, name);=0A= + /* Determine a reasonable uid value. */=0A= + if (stricmp ("administrator", name) =3D=3D 0)=0A= + {=0A= + the_passwd.pw_uid =3D 0;=0A= + the_passwd.pw_gid =3D 0;=0A= + }=0A= + else=0A= + {=0A= + SID_IDENTIFIER_AUTHORITY * pSIA;=0A= +=0A= + pSIA =3D GetSidIdentifierAuthority (*((PSID *) user_sid));=0A= + /* I believe the relative portion is the last 4 bytes (of 6)=0A= + with msb first. */=0A= + the_passwd.pw_uid =3D ((pSIA->Value[2] << 24) +=0A= + (pSIA->Value[3] << 16) +=0A= + (pSIA->Value[4] << 8) +=0A= + (pSIA->Value[5] << 0));=0A= + /* restrict to conventional uid range for normal users */=0A= + the_passwd.pw_uid =3D the_passwd.pw_uid % 60001;=0A= +=0A= + /* Get group id */=0A= + if (GetTokenInformation (token, TokenPrimaryGroup,=0A= + (PVOID) user_sid, sizeof (user_sid), &trash))=0A= + {=0A= + SID_IDENTIFIER_AUTHORITY * pSIA;=0A= +=0A= + pSIA =3D GetSidIdentifierAuthority (*((PSID *) user_sid));=0A= + the_passwd.pw_gid =3D ((pSIA->Value[2] << 24) +=0A= + (pSIA->Value[3] << 16) +=0A= + (pSIA->Value[4] << 8) +=0A= + (pSIA->Value[5] << 0));=0A= + /* I don't know if this is necessary, but for safety... */=0A= + the_passwd.pw_gid =3D the_passwd.pw_gid % 60001;=0A= + }=0A= + else=0A= + the_passwd.pw_gid =3D the_passwd.pw_uid;=0A= + }=0A= + }=0A= + /* If security calls are not supported (presumably because we=0A= + are running under Windows 95), fallback to this. */=0A= + else if (GetUserName (name, &length))=0A= + {=0A= + strcpy (the_passwd.pw_name, name);=0A= + if (stricmp ("administrator", name) =3D=3D 0)=0A= + the_passwd.pw_uid =3D 0;=0A= + else=0A= + the_passwd.pw_uid =3D 123;=0A= + the_passwd.pw_gid =3D the_passwd.pw_uid;=0A= + }=0A= + else=0A= + {=0A= + strcpy (the_passwd.pw_name, "unknown");=0A= + the_passwd.pw_uid =3D 123;=0A= + the_passwd.pw_gid =3D 123;=0A= + }=0A= +=0A= + /* Ensure HOME and SHELL are defined. */=0A= + if (getenv ("HOME") =3D=3D NULL)=0A= + abort ();=0A= + if (getenv ("SHELL") =3D=3D NULL)=0A= + {=0A= + if (getenv ("ComSpec")=3D=3DNULL)=0A= + {=0A= + abort ();=0A= + }=0A= + }=0A= +=0A= + /* Set dir and shell from environment variables. */=0A= + strcpy (the_passwd.pw_dir, getenv ("HOME"));=0A= + if (getenv("SHELL"))=0A= + {=0A= + strcpy (the_passwd.pw_shell, getenv ("SHELL"));=0A= + }=0A= + else=0A= + {=0A= + strcpy (the_passwd.pw_shell, getenv ("ComSpec"));=0A= + }=0A= +=0A= + if (token)=0A= + CloseHandle (token);=0A= +}=0A= +=0A= +/*=0A= +END: Borrowed from w32.c=0A= +*/=0A= +=0A= +/*=0A= +BEGIN: Borrowed from w32proc.c=0A= +*/=0A= +=0A= +=0A= +/* Child process management list. */=0A= +int child_proc_count =3D 0;=0A= +child_process child_procs[ MAX_CHILDREN ];=0A= +child_process *dead_child =3D NULL;=0A= +=0A= +DWORD WINAPI reader_thread (void *arg);=0A= +=0A= +child_process *=0A= +new_child (void)=0A= +{=0A= + child_process *cp;=0A= + DWORD id;=0A= +=0A= + for (cp =3D child_procs+(child_proc_count-1); cp >=3D child_procs; = cp--)=0A= + if (!CHILD_ACTIVE (cp))=0A= + goto Initialise;=0A= + if (child_proc_count =3D=3D MAX_CHILDREN)=0A= + return NULL;=0A= + cp =3D &child_procs[child_proc_count++];=0A= +=0A= + Initialise:=0A= + memset (cp, 0, sizeof(*cp));=0A= + cp->fd =3D -1;=0A= + cp->pid =3D -1;=0A= + cp->procinfo.hProcess =3D NULL;=0A= + cp->status =3D STATUS_READ_ERROR;=0A= +=0A= + /* use manual reset event so that select() will function properly */=0A= + cp->char_avail =3D CreateEvent (NULL, TRUE, FALSE, NULL);=0A= + if (cp->char_avail)=0A= + {=0A= + cp->char_consumed =3D CreateEvent (NULL, FALSE, FALSE, NULL);=0A= + if (cp->char_consumed)=0A= + {=0A= + cp->thrd =3D CreateThread (NULL, 1024, reader_thread, cp, 0, &id);=0A= + if (cp->thrd)=0A= + return cp;=0A= + }=0A= + }=0A= + delete_child (cp);=0A= + return NULL;=0A= +}=0A= +=0A= +void=0A= +delete_child (child_process *cp)=0A= +{=0A= + int i;=0A= +=0A= + /* Should not be deleting a child that is still needed. */=0A= + for (i =3D 0; i < MAXDESC; i++)=0A= + if (fd_info[i].cp =3D=3D cp)=0A= + abort ();=0A= +=0A= + if (!CHILD_ACTIVE (cp))=0A= + return;=0A= +=0A= + /* reap thread if necessary */=0A= + if (cp->thrd)=0A= + {=0A= + DWORD rc;=0A= +=0A= + if (GetExitCodeThread (cp->thrd, &rc) && rc =3D=3D STILL_ACTIVE)=0A= + {=0A= + /* let the thread exit cleanly if possible */=0A= + cp->status =3D STATUS_READ_ERROR;=0A= + SetEvent (cp->char_consumed);=0A= + if (WaitForSingleObject (cp->thrd, 1000) !=3D WAIT_OBJECT_0)=0A= + {=0A= + DebPrint (("delete_child.WaitForSingleObject (thread) failed "=0A= + "with %lu for fd %ld\n", GetLastError (), cp->fd));=0A= + TerminateThread (cp->thrd, 0);=0A= + }=0A= + }=0A= + CloseHandle (cp->thrd);=0A= + cp->thrd =3D NULL;=0A= + }=0A= + if (cp->char_avail)=0A= + {=0A= + CloseHandle (cp->char_avail);=0A= + cp->char_avail =3D NULL;=0A= + }=0A= + if (cp->char_consumed)=0A= + {=0A= + CloseHandle (cp->char_consumed);=0A= + cp->char_consumed =3D NULL;=0A= + }=0A= +=0A= + /* update child_proc_count (highest numbered slot in use plus one) */=0A= + if (cp =3D=3D child_procs + child_proc_count - 1)=0A= + {=0A= + for (i =3D child_proc_count-1; i >=3D 0; i--)=0A= + if (CHILD_ACTIVE (&child_procs[i]))=0A= + {=0A= + child_proc_count =3D i + 1;=0A= + break;=0A= + }=0A= + }=0A= + if (i < 0)=0A= + child_proc_count =3D 0;=0A= +}=0A= +=0A= +=0A= +/* Find a child by pid. */=0A= +static child_process *=0A= +find_child_pid (DWORD pid)=0A= +{=0A= + child_process *cp;=0A= +=0A= + for (cp =3D child_procs+(child_proc_count-1); cp >=3D child_procs; = cp--)=0A= + if (CHILD_ACTIVE (cp) && pid =3D=3D cp->pid)=0A= + return cp;=0A= + return NULL;=0A= +}=0A= +=0A= +/* Thread proc for child process and socket reader threads. Each thread=0A= + is normally blocked until woken by select() to check for input by=0A= + reading one char. When the read completes, char_avail is signalled=0A= + to wake up the select emulator and the thread blocks itself again. */=0A= +DWORD WINAPI=0A= +reader_thread (void *arg)=0A= +{=0A= + child_process *cp;=0A= +=0A= + /* Our identity */=0A= + cp =3D (child_process *)arg;=0A= +=0A= + /* We have to wait for the go-ahead before we can start */=0A= + if (cp =3D=3D NULL=0A= + || WaitForSingleObject (cp->char_consumed, INFINITE) !=3D = WAIT_OBJECT_0)=0A= + return 1;=0A= +=0A= + for (;;)=0A= + {=0A= + int rc;=0A= +=0A= + rc =3D _sys_read_ahead (cp->fd);=0A= +=0A= + /* The name char_avail is a misnomer - it really just means the=0A= + read-ahead has completed, whether successfully or not. */=0A= + if (!SetEvent (cp->char_avail))=0A= + {=0A= + DebPrint (("reader_thread.SetEvent failed with %lu for fd %ld\n",=0A= + GetLastError (), cp->fd));=0A= + return 1;=0A= + }=0A= +=0A= + if (rc =3D=3D STATUS_READ_ERROR)=0A= + return 1;=0A= +=0A= + /* If the read died, the child has died so let the thread die */=0A= + if (rc =3D=3D STATUS_READ_FAILED)=0A= + break;=0A= +=0A= + /* Wait until our input is acknowledged before reading again */=0A= + if (WaitForSingleObject (cp->char_consumed, INFINITE) !=3D = WAIT_OBJECT_0)=0A= + {=0A= + DebPrint (("reader_thread.WaitForSingleObject failed with "=0A= + "%lu for fd %ld\n", GetLastError (), cp->fd));=0A= + break;=0A= + }=0A= + }=0A= + return 0;=0A= +}=0A= +=0A= +/*=0A= +END: Borrowed from w32proc.c=0A= +*/=0A= +=0A= +=0A= +=0A= +=0A= +#endif /* WINDOWSNT */=0A= +=0A= #include =0A= #include =0A= =0A= @@ -288,6 +1195,11 @@=0A= char *cwd, *str;=0A= char string[BUFSIZ];=0A= =0A= +#ifdef WINDOWSNT=0A= + init_winsock (1);=0A= + init_user_info ();=0A= +#endif=0A= +=0A= progname =3D argv[0];=0A= =0A= /* Process options. */=0A= @@ -488,6 +1400,9 @@=0A= printf ("\n");=0A= fflush (stdout);=0A= =0A= +#ifdef WINDOWSNT=0A= + term_winsock ();=0A= +#endif=0A= return 0;=0A= }=0A= =0A= ------=_NextPart_000_002C_01C285F2.61A37F80--