blob: c5379aa384c7ed63d6d4fff0190fe2910ac9a0fb [file] [log] [blame]
Alexandre Julliard642d3131998-07-12 19:29:36 +00001/*
2 * Client part of the client/server communication
3 *
4 * Copyright (C) 1998 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard642d3131998-07-12 19:29:36 +000019 */
20
François Gouget14259412001-11-06 20:57:11 +000021#include "config.h"
Francois Gouget386cf6e2001-10-14 16:25:47 +000022#include "wine/port.h"
Howard Abrams13277481999-07-10 13:16:29 +000023
Alexandre Julliard642d3131998-07-12 19:29:36 +000024#include <assert.h>
Alexandre Julliard2fe57772000-01-25 01:40:27 +000025#include <ctype.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000026#include <errno.h>
Alexandre Julliard62a8b431999-01-19 17:48:23 +000027#include <fcntl.h>
Patrik Stridvall43255542002-08-09 01:07:29 +000028#ifdef HAVE_PWD_H
29# include <pwd.h>
30#endif
Alexandre Julliard42cc2bd2000-06-07 03:49:41 +000031#include <signal.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000032#include <stdio.h>
33#include <string.h>
Alexandre Julliard829fe321998-07-26 14:27:39 +000034#include <sys/types.h>
Patrik Stridvall96336321999-10-24 22:13:47 +000035#ifdef HAVE_SYS_SOCKET_H
36# include <sys/socket.h>
37#endif
Alexandre Julliardd8041112000-04-14 14:42:41 +000038#ifdef HAVE_SYS_WAIT_H
39#include <sys/wait.h>
40#endif
Alexandre Julliard2fe57772000-01-25 01:40:27 +000041#include <sys/un.h>
Howard Abrams13277481999-07-10 13:16:29 +000042#ifdef HAVE_SYS_MMAN_H
Alexandre Julliard5bc78081999-06-22 17:26:53 +000043#include <sys/mman.h>
Howard Abrams13277481999-07-10 13:16:29 +000044#endif
Alexandre Julliard2fe57772000-01-25 01:40:27 +000045#include <sys/stat.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000046#include <sys/uio.h>
47#include <unistd.h>
Marcus Meissner317af321999-02-17 13:51:06 +000048#include <stdarg.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000049
Alexandre Julliard642d3131998-07-12 19:29:36 +000050#include "thread.h"
Alexandre Julliard4144b5b2002-06-20 23:21:27 +000051#include "wine/library.h"
Alexandre Julliard37e95032001-07-19 00:39:09 +000052#include "wine/server.h"
Alexandre Julliard642d3131998-07-12 19:29:36 +000053#include "winerror.h"
Alexandre Julliard2fe57772000-01-25 01:40:27 +000054#include "options.h"
Alexandre Julliard642d3131998-07-12 19:29:36 +000055
Alexandre Julliard829fe321998-07-26 14:27:39 +000056/* Some versions of glibc don't define this */
57#ifndef SCM_RIGHTS
58#define SCM_RIGHTS 1
59#endif
Alexandre Julliard642d3131998-07-12 19:29:36 +000060
Alexandre Julliard2fe57772000-01-25 01:40:27 +000061#define SOCKETNAME "socket" /* name of the socket file */
Alexandre Julliard4144b5b2002-06-20 23:21:27 +000062#define LOCKNAME "lock" /* name of the lock file */
Alexandre Julliard2fe57772000-01-25 01:40:27 +000063
Dmitry Timoshkovb3eaa8662001-09-11 00:29:24 +000064#ifndef HAVE_MSGHDR_ACCRIGHTS
Alexandre Julliardebe29ef1999-06-26 08:43:26 +000065/* data structure used to pass an fd with sendmsg/recvmsg */
66struct cmsg_fd
67{
68 int len; /* sizeof structure */
69 int level; /* SOL_SOCKET */
70 int type; /* SCM_RIGHTS */
71 int fd; /* fd to pass */
72};
Dmitry Timoshkovb3eaa8662001-09-11 00:29:24 +000073#endif /* HAVE_MSGHDR_ACCRIGHTS */
Alexandre Julliard767e6f61998-08-09 12:47:43 +000074
Alexandre Julliard2fe57772000-01-25 01:40:27 +000075static void *boot_thread_id;
Alexandre Julliardf5242402001-02-28 21:45:23 +000076static sigset_t block_set; /* signals to block during server calls */
77static int fd_socket; /* socket to exchange file descriptors with the server */
Alexandre Julliard2fe57772000-01-25 01:40:27 +000078
Alexandre Julliard4144b5b2002-06-20 23:21:27 +000079#ifdef __GNUC__
80static void fatal_error( const char *err, ... ) __attribute__((noreturn, format(printf,1,2)));
81static void fatal_perror( const char *err, ... ) __attribute__((noreturn, format(printf,1,2)));
82static void server_connect_error( const char *serverdir ) __attribute__((noreturn));
83#endif
84
Alexandre Julliard2fe57772000-01-25 01:40:27 +000085/* die on a fatal error; use only during initialization */
86static void fatal_error( const char *err, ... )
87{
88 va_list args;
89
90 va_start( args, err );
91 fprintf( stderr, "wine: " );
92 vfprintf( stderr, err, args );
93 va_end( args );
94 exit(1);
95}
96
97/* die on a fatal error; use only during initialization */
98static void fatal_perror( const char *err, ... )
99{
100 va_list args;
101
102 va_start( args, err );
103 fprintf( stderr, "wine: " );
104 vfprintf( stderr, err, args );
105 perror( " " );
106 va_end( args );
107 exit(1);
108}
109
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000110/***********************************************************************
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000111 * server_protocol_error
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000112 */
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000113void server_protocol_error( const char *err, ... )
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000114{
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000115 va_list args;
116
117 va_start( args, err );
Alexandre Julliard8859d772001-03-01 22:13:49 +0000118 fprintf( stderr, "wine client error:%p: ", NtCurrentTeb()->tid );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000119 vfprintf( stderr, err, args );
120 va_end( args );
Alexandre Julliard5016e922002-01-07 18:04:07 +0000121 SYSDEPS_AbortThread(1);
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000122}
123
124
Alexandre Julliard642d3131998-07-12 19:29:36 +0000125/***********************************************************************
Alexandre Julliard5f195f82001-02-20 23:45:07 +0000126 * server_protocol_perror
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000127 */
Alexandre Julliard5f195f82001-02-20 23:45:07 +0000128void server_protocol_perror( const char *err )
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000129{
Alexandre Julliard8859d772001-03-01 22:13:49 +0000130 fprintf( stderr, "wine client error:%p: ", NtCurrentTeb()->tid );
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000131 perror( err );
Alexandre Julliard5016e922002-01-07 18:04:07 +0000132 SYSDEPS_AbortThread(1);
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000133}
134
135
136/***********************************************************************
137 * send_request
Alexandre Julliard642d3131998-07-12 19:29:36 +0000138 *
139 * Send a request to the server.
140 */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000141static void send_request( const struct __server_request_info *req )
Alexandre Julliard642d3131998-07-12 19:29:36 +0000142{
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000143 int i, ret;
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000144
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000145 if (!req->u.req.request_header.request_size)
146 {
147 if ((ret = write( NtCurrentTeb()->request_fd, &req->u.req,
148 sizeof(req->u.req) )) == sizeof(req->u.req)) return;
149
150 }
151 else
152 {
153 struct iovec vec[__SERVER_MAX_DATA+1];
154
155 vec[0].iov_base = (void *)&req->u.req;
156 vec[0].iov_len = sizeof(req->u.req);
157 for (i = 0; i < req->data_count; i++)
158 {
159 vec[i+1].iov_base = (void *)req->data[i].ptr;
160 vec[i+1].iov_len = req->data[i].size;
161 }
162 if ((ret = writev( NtCurrentTeb()->request_fd, vec, i+1 )) ==
163 req->u.req.request_header.request_size + sizeof(req->u.req)) return;
164 }
165
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000166 if (ret >= 0) server_protocol_error( "partial write %d\n", ret );
Alexandre Julliard5016e922002-01-07 18:04:07 +0000167 if (errno == EPIPE) SYSDEPS_AbortThread(0);
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000168 server_protocol_perror( "sendmsg" );
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000169}
170
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000171
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000172/***********************************************************************
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000173 * read_reply_data
Alexandre Julliard642d3131998-07-12 19:29:36 +0000174 *
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000175 * Read data from the reply buffer; helper for wait_reply.
Alexandre Julliard642d3131998-07-12 19:29:36 +0000176 */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000177static void read_reply_data( void *buffer, size_t size )
Alexandre Julliard642d3131998-07-12 19:29:36 +0000178{
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000179 int ret;
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000180
181 for (;;)
182 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000183 if ((ret = read( NtCurrentTeb()->reply_fd, buffer, size )) > 0)
184 {
185 if (!(size -= ret)) return;
186 buffer = (char *)buffer + ret;
187 continue;
188 }
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000189 if (!ret) break;
Alexandre Julliard86113532000-08-29 03:54:30 +0000190 if (errno == EINTR) continue;
191 if (errno == EPIPE) break;
Alexandre Julliard5f195f82001-02-20 23:45:07 +0000192 server_protocol_perror("read");
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000193 }
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000194 /* the server closed the connection; time to die... */
Alexandre Julliard5016e922002-01-07 18:04:07 +0000195 SYSDEPS_AbortThread(0);
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000196}
197
198
199/***********************************************************************
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000200 * wait_reply
201 *
202 * Wait for a reply from the server.
203 */
204inline static void wait_reply( struct __server_request_info *req )
205{
206 read_reply_data( &req->u.reply, sizeof(req->u.reply) );
207 if (req->u.reply.reply_header.reply_size)
208 read_reply_data( req->reply_data, req->u.reply.reply_header.reply_size );
209}
210
211
212/***********************************************************************
Patrik Stridvalld0a41772001-02-14 23:11:17 +0000213 * wine_server_call (NTDLL.@)
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000214 *
215 * Perform a server call.
216 */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000217unsigned int wine_server_call( void *req_ptr )
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000218{
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000219 struct __server_request_info * const req = req_ptr;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000220 sigset_t old_set;
221
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000222 memset( (char *)&req->u.req + req->size, 0, sizeof(req->u.req) - req->size );
Alexandre Julliardf5242402001-02-28 21:45:23 +0000223 sigprocmask( SIG_BLOCK, &block_set, &old_set );
Alexandre Julliard67a74992001-02-27 02:09:16 +0000224 send_request( req );
225 wait_reply( req );
Alexandre Julliardf5242402001-02-28 21:45:23 +0000226 sigprocmask( SIG_SETMASK, &old_set, NULL );
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000227 return req->u.reply.reply_header.error;
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000228}
229
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000230
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000231/***********************************************************************
Alexandre Julliardf5242402001-02-28 21:45:23 +0000232 * wine_server_send_fd
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000233 *
Alexandre Julliardf5242402001-02-28 21:45:23 +0000234 * Send a file descriptor to the server.
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000235 */
Alexandre Julliardf5242402001-02-28 21:45:23 +0000236void wine_server_send_fd( int fd )
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000237{
Alexandre Julliardf5242402001-02-28 21:45:23 +0000238#ifndef HAVE_MSGHDR_ACCRIGHTS
239 struct cmsg_fd cmsg;
240#endif
241 struct send_fd data;
242 struct msghdr msghdr;
243 struct iovec vec;
244 int ret;
245
246 vec.iov_base = (void *)&data;
247 vec.iov_len = sizeof(data);
248
249 msghdr.msg_name = NULL;
250 msghdr.msg_namelen = 0;
251 msghdr.msg_iov = &vec;
252 msghdr.msg_iovlen = 1;
253
254#ifdef HAVE_MSGHDR_ACCRIGHTS
255 msghdr.msg_accrights = (void *)&fd;
256 msghdr.msg_accrightslen = sizeof(fd);
257#else /* HAVE_MSGHDR_ACCRIGHTS */
258 cmsg.len = sizeof(cmsg);
259 cmsg.level = SOL_SOCKET;
260 cmsg.type = SCM_RIGHTS;
261 cmsg.fd = fd;
262 msghdr.msg_control = &cmsg;
263 msghdr.msg_controllen = sizeof(cmsg);
264 msghdr.msg_flags = 0;
265#endif /* HAVE_MSGHDR_ACCRIGHTS */
266
267 data.tid = (void *)GetCurrentThreadId();
268 data.fd = fd;
269
270 for (;;)
271 {
272 if ((ret = sendmsg( fd_socket, &msghdr, 0 )) == sizeof(data)) return;
273 if (ret >= 0) server_protocol_error( "partial write %d\n", ret );
274 if (errno == EINTR) continue;
Alexandre Julliard5016e922002-01-07 18:04:07 +0000275 if (errno == EPIPE) SYSDEPS_AbortThread(0);
Alexandre Julliardf5242402001-02-28 21:45:23 +0000276 server_protocol_perror( "sendmsg" );
277 }
Alexandre Julliard6ebbe3c1999-01-01 17:04:00 +0000278}
279
280
281/***********************************************************************
Alexandre Julliard8859d772001-03-01 22:13:49 +0000282 * receive_fd
Alexandre Julliardd549f692000-12-22 02:04:15 +0000283 *
284 * Receive a file descriptor passed from the server.
Alexandre Julliardd549f692000-12-22 02:04:15 +0000285 */
Alexandre Julliard51885742002-05-30 20:12:58 +0000286static int receive_fd( obj_handle_t *handle )
Alexandre Julliardd549f692000-12-22 02:04:15 +0000287{
288 struct iovec vec;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000289 int ret, fd;
Alexandre Julliardd549f692000-12-22 02:04:15 +0000290
291#ifdef HAVE_MSGHDR_ACCRIGHTS
292 struct msghdr msghdr;
293
294 fd = -1;
295 msghdr.msg_accrights = (void *)&fd;
296 msghdr.msg_accrightslen = sizeof(fd);
297#else /* HAVE_MSGHDR_ACCRIGHTS */
298 struct msghdr msghdr;
299 struct cmsg_fd cmsg;
300
301 cmsg.len = sizeof(cmsg);
302 cmsg.level = SOL_SOCKET;
303 cmsg.type = SCM_RIGHTS;
304 cmsg.fd = -1;
305 msghdr.msg_control = &cmsg;
306 msghdr.msg_controllen = sizeof(cmsg);
307 msghdr.msg_flags = 0;
308#endif /* HAVE_MSGHDR_ACCRIGHTS */
309
310 msghdr.msg_name = NULL;
311 msghdr.msg_namelen = 0;
312 msghdr.msg_iov = &vec;
313 msghdr.msg_iovlen = 1;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000314 vec.iov_base = (void *)handle;
315 vec.iov_len = sizeof(*handle);
Alexandre Julliardd549f692000-12-22 02:04:15 +0000316
317 for (;;)
318 {
Alexandre Julliard8859d772001-03-01 22:13:49 +0000319 if ((ret = recvmsg( fd_socket, &msghdr, 0 )) > 0)
Alexandre Julliardd549f692000-12-22 02:04:15 +0000320 {
321#ifndef HAVE_MSGHDR_ACCRIGHTS
322 fd = cmsg.fd;
323#endif
Alexandre Julliard8859d772001-03-01 22:13:49 +0000324 if (fd == -1) server_protocol_error( "no fd received for handle %d\n", *handle );
325 fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
Alexandre Julliardd549f692000-12-22 02:04:15 +0000326 return fd;
327 }
328 if (!ret) break;
329 if (errno == EINTR) continue;
330 if (errno == EPIPE) break;
Alexandre Julliard5f195f82001-02-20 23:45:07 +0000331 server_protocol_perror("recvmsg");
Alexandre Julliardd549f692000-12-22 02:04:15 +0000332 }
333 /* the server closed the connection; time to die... */
Alexandre Julliard5016e922002-01-07 18:04:07 +0000334 SYSDEPS_AbortThread(0);
Alexandre Julliardd549f692000-12-22 02:04:15 +0000335}
336
337
338/***********************************************************************
Alexandre Julliard8d1550d2002-03-23 18:48:12 +0000339 * store_cached_fd
Alexandre Julliard8859d772001-03-01 22:13:49 +0000340 *
Alexandre Julliard8d1550d2002-03-23 18:48:12 +0000341 * Store the cached fd value for a given handle back into the server.
342 * Returns the new fd, which can be different if there was already an
343 * fd in the cache for that handle.
Alexandre Julliard8859d772001-03-01 22:13:49 +0000344 */
Alexandre Julliard51885742002-05-30 20:12:58 +0000345inline static int store_cached_fd( int fd, obj_handle_t handle )
Alexandre Julliard8859d772001-03-01 22:13:49 +0000346{
Alexandre Julliard8859d772001-03-01 22:13:49 +0000347 SERVER_START_REQ( set_handle_info )
348 {
Alexandre Julliard8d1550d2002-03-23 18:48:12 +0000349 req->handle = handle;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000350 req->flags = 0;
351 req->mask = 0;
352 req->fd = fd;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000353 if (!wine_server_call( req ))
Alexandre Julliard8859d772001-03-01 22:13:49 +0000354 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000355 if (reply->cur_fd != fd)
Alexandre Julliard8859d772001-03-01 22:13:49 +0000356 {
357 /* someone was here before us */
358 close( fd );
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000359 fd = reply->cur_fd;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000360 }
361 }
362 else
363 {
364 close( fd );
365 fd = -1;
366 }
367 }
368 SERVER_END_REQ;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000369 return fd;
370}
371
372
373/***********************************************************************
Alexandre Julliardbe367c72002-05-30 20:40:02 +0000374 * wine_server_fd_to_handle (NTDLL.@)
375 *
376 * Allocate a file handle for a Unix fd.
377 */
378int wine_server_fd_to_handle( int fd, unsigned int access, int inherit, obj_handle_t *handle )
379{
380 int ret;
381
382 *handle = 0;
383 wine_server_send_fd( fd );
384
385 SERVER_START_REQ( alloc_file_handle )
386 {
387 req->access = access;
388 req->inherit = inherit;
389 req->fd = fd;
390 if (!(ret = wine_server_call( req ))) *handle = reply->handle;
391 }
392 SERVER_END_REQ;
393 return ret;
394}
395
396
397/***********************************************************************
Alexandre Julliard8d1550d2002-03-23 18:48:12 +0000398 * wine_server_handle_to_fd (NTDLL.@)
399 *
400 * Retrieve the Unix fd corresponding to a file handle.
401 */
Alexandre Julliard51885742002-05-30 20:12:58 +0000402int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd,
Alexandre Julliard8d1550d2002-03-23 18:48:12 +0000403 enum fd_type *type, int *flags )
404{
Alexandre Julliard51885742002-05-30 20:12:58 +0000405 obj_handle_t fd_handle;
Alexandre Julliard8d1550d2002-03-23 18:48:12 +0000406 int ret, fd = -1;
407
408 *unix_fd = -1;
409 for (;;)
410 {
411 SERVER_START_REQ( get_handle_fd )
412 {
413 req->handle = handle;
414 req->access = access;
415 if (!(ret = wine_server_call( req ))) fd = reply->fd;
416 if (type) *type = reply->type;
417 if (flags) *flags = reply->flags;
418 }
419 SERVER_END_REQ;
420 if (ret) return ret;
421
422 if (fd != -1) break;
423
424 /* it wasn't in the cache, get it from the server */
425 fd = receive_fd( &fd_handle );
426 /* and store it back into the cache */
427 fd = store_cached_fd( fd, fd_handle );
428
429 if (fd_handle == handle) break;
430 /* if we received a different handle this means there was
431 * a race with another thread; we restart everything from
432 * scratch in this case.
433 */
434 }
435
436 if ((fd != -1) && ((fd = dup(fd)) == -1)) return STATUS_TOO_MANY_OPENED_FILES;
437 *unix_fd = fd;
438 return STATUS_SUCCESS;
439}
440
441
442/***********************************************************************
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000443 * start_server
444 *
445 * Start a new wine server.
446 */
447static void start_server( const char *oldcwd )
448{
449 static int started; /* we only try once */
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000450 char *path, *p;
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000451 if (!started)
452 {
Alexandre Julliardd8041112000-04-14 14:42:41 +0000453 int status;
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000454 int pid = fork();
455 if (pid == -1) fatal_perror( "fork" );
456 if (!pid)
457 {
Alexandre Julliard50097a02000-09-10 03:24:28 +0000458 /* if server is explicitly specified, use this */
459 if ((p = getenv("WINESERVER")))
460 {
Alexandre Julliard61d26d72001-05-09 19:46:39 +0000461 if (p[0] != '/' && oldcwd[0] == '/') /* make it an absolute path */
462 {
463 if (!(path = malloc( strlen(oldcwd) + strlen(p) + 1 )))
464 fatal_error( "out of memory\n" );
465 sprintf( path, "%s/%s", oldcwd, p );
466 p = path;
467 }
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000468 execl( p, p, NULL );
Alexandre Julliard50097a02000-09-10 03:24:28 +0000469 fatal_perror( "could not exec the server '%s'\n"
470 " specified in the WINESERVER environment variable", p );
471 }
472
Alexandre Julliardeafa3912000-01-25 21:19:58 +0000473 /* first try the installation dir */
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000474 execl( BINDIR "/wineserver", "wineserver", NULL );
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000475
Alexandre Julliardeafa3912000-01-25 21:19:58 +0000476 /* now try the dir we were launched from */
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000477 if (full_argv0)
478 {
479 if (!(path = malloc( strlen(full_argv0) + 20 )))
480 fatal_error( "out of memory\n" );
481 if ((p = strrchr( strcpy( path, full_argv0 ), '/' )))
482 {
483 strcpy( p, "/wineserver" );
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000484 execl( path, path, NULL );
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000485 }
Alexandre Julliard35363162002-05-22 21:32:49 +0000486 free(path);
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000487 }
488
Alexandre Julliard35363162002-05-22 21:32:49 +0000489 /* finally try the path */
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000490 execlp( "wineserver", "wineserver", NULL );
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000491 fatal_error( "could not exec wineserver\n" );
492 }
Alexandre Julliardd8041112000-04-14 14:42:41 +0000493 waitpid( pid, &status, 0 );
494 status = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000495 if (status == 2) return; /* server lock held by someone else, will retry later */
Alexandre Julliardd8041112000-04-14 14:42:41 +0000496 if (status) exit(status); /* server failed */
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000497 started = 1;
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000498 }
499}
500
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000501
502/***********************************************************************
503 * server_connect_error
504 *
505 * Try to display a meaningful explanation of why we couldn't connect
506 * to the server.
507 */
508static void server_connect_error( const char *serverdir )
509{
510 int fd;
511 struct flock fl;
512
513 if ((fd = open( LOCKNAME, O_WRONLY )) == -1)
514 fatal_error( "for some mysterious reason, the wine server never started.\n" );
515
516 fl.l_type = F_WRLCK;
517 fl.l_whence = SEEK_SET;
518 fl.l_start = 0;
519 fl.l_len = 1;
520 if (fcntl( fd, F_GETLK, &fl ) != -1)
521 {
522 if (fl.l_type == F_WRLCK) /* the file is locked */
523 fatal_error( "a wine server seems to be running, but I cannot connect to it.\n"
524 " You probably need to kill that process (it might be pid %d).\n",
525 (int)fl.l_pid );
526 fatal_error( "for some mysterious reason, the wine server failed to run.\n" );
527 }
528 fatal_error( "the file system of '%s' doesn't support locks,\n"
529 " and there is a 'socket' file in that directory that prevents wine from starting.\n"
530 " You should make sure no wine server is running, remove that file and try again.\n",
531 serverdir );
532}
533
534
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000535/***********************************************************************
536 * server_connect
537 *
538 * Attempt to connect to an existing server socket.
539 * We need to be in the server directory already.
540 */
541static int server_connect( const char *oldcwd, const char *serverdir )
542{
543 struct sockaddr_un addr;
544 struct stat st;
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000545 int s, slen, retry;
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000546
Alexandre Julliardd8041112000-04-14 14:42:41 +0000547 /* chdir to the server directory */
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000548 if (chdir( serverdir ) == -1)
549 {
550 if (errno != ENOENT) fatal_perror( "chdir to %s", serverdir );
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000551 start_server( "." );
Alexandre Julliardd8041112000-04-14 14:42:41 +0000552 if (chdir( serverdir ) == -1) fatal_perror( "chdir to %s", serverdir );
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000553 }
Alexandre Julliardd8041112000-04-14 14:42:41 +0000554
555 /* make sure we are at the right place */
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000556 if (stat( ".", &st ) == -1) fatal_perror( "stat %s", serverdir );
557 if (st.st_uid != getuid()) fatal_error( "'%s' is not owned by you\n", serverdir );
558 if (st.st_mode & 077) fatal_error( "'%s' must not be accessible by other users\n", serverdir );
559
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000560 for (retry = 0; retry < 6; retry++)
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000561 {
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000562 /* if not the first try, wait a bit to leave the previous server time to exit */
563 if (retry)
564 {
565 usleep( 100000 * retry * retry );
566 start_server( oldcwd );
567 if (lstat( SOCKETNAME, &st ) == -1) continue; /* still no socket, wait a bit more */
568 }
569 else if (lstat( SOCKETNAME, &st ) == -1) /* check for an already existing socket */
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000570 {
571 if (errno != ENOENT) fatal_perror( "lstat %s/%s", serverdir, SOCKETNAME );
572 start_server( oldcwd );
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000573 if (lstat( SOCKETNAME, &st ) == -1) continue; /* still no socket, wait a bit more */
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000574 }
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000575
Roberto Augusto Pungartnik19f8dda2000-09-22 22:19:58 +0000576 /* make sure the socket is sane (ISFIFO needed for Solaris) */
577 if (!S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode))
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000578 fatal_error( "'%s/%s' is not a socket\n", serverdir, SOCKETNAME );
579 if (st.st_uid != getuid())
580 fatal_error( "'%s/%s' is not owned by you\n", serverdir, SOCKETNAME );
581
582 /* try to connect to it */
583 addr.sun_family = AF_UNIX;
584 strcpy( addr.sun_path, SOCKETNAME );
585 slen = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path) + 1;
Juergen Lock2d33ab92000-02-13 16:03:29 +0000586#ifdef HAVE_SOCKADDR_SUN_LEN
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000587 addr.sun_len = slen;
Juergen Lock2d33ab92000-02-13 16:03:29 +0000588#endif
Alexandre Julliard42cc2bd2000-06-07 03:49:41 +0000589 if ((s = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" );
Alexandre Julliardc10c9ef2000-08-11 21:16:53 +0000590 if (connect( s, (struct sockaddr *)&addr, slen ) != -1)
591 {
592 fcntl( s, F_SETFD, 1 ); /* set close on exec flag */
593 return s;
594 }
595 close( s );
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000596 }
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000597 server_connect_error( serverdir );
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000598}
599
600
601/***********************************************************************
Alexandre Julliardf0167521999-03-21 19:26:25 +0000602 * CLIENT_InitServer
Alexandre Julliard642d3131998-07-12 19:29:36 +0000603 *
Alexandre Julliardf0167521999-03-21 19:26:25 +0000604 * Start the server and create the initial socket pair.
Alexandre Julliard642d3131998-07-12 19:29:36 +0000605 */
Alexandre Julliard8859d772001-03-01 22:13:49 +0000606void CLIENT_InitServer(void)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000607{
Alexandre Julliard8859d772001-03-01 22:13:49 +0000608 int size;
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000609 char *oldcwd;
Alexandre Julliard51885742002-05-30 20:12:58 +0000610 obj_handle_t dummy_handle;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000611
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000612 /* retrieve the current directory */
613 for (size = 512; ; size *= 2)
Alexandre Julliardf0167521999-03-21 19:26:25 +0000614 {
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +0000615 if (!(oldcwd = malloc( size ))) break;
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000616 if (getcwd( oldcwd, size )) break;
617 free( oldcwd );
618 if (errno == ERANGE) continue;
619 oldcwd = NULL;
Ulrich Weigand371fd751999-04-11 17:13:03 +0000620 break;
Alexandre Julliardf0167521999-03-21 19:26:25 +0000621 }
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000622
Alexandre Julliarda3e0cfc2000-07-16 18:21:34 +0000623 /* if argv[0] is a relative path, make it absolute */
624 full_argv0 = argv0;
625 if (oldcwd && argv0[0] != '/' && strchr( argv0, '/' ))
626 {
627 char *new_argv0 = malloc( strlen(oldcwd) + strlen(argv0) + 2 );
628 if (new_argv0)
629 {
630 strcpy( new_argv0, oldcwd );
631 strcat( new_argv0, "/" );
632 strcat( new_argv0, argv0 );
633 full_argv0 = new_argv0;
634 }
635 }
636
Alexandre Julliardd8041112000-04-14 14:42:41 +0000637 /* connect to the server */
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000638 fd_socket = server_connect( oldcwd, wine_get_server_dir() );
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000639
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000640 /* switch back to the starting directory */
641 if (oldcwd)
642 {
643 chdir( oldcwd );
644 free( oldcwd );
645 }
Alexandre Julliardf5242402001-02-28 21:45:23 +0000646
647 /* setup the signal mask */
648 sigemptyset( &block_set );
649 sigaddset( &block_set, SIGALRM );
650 sigaddset( &block_set, SIGIO );
651 sigaddset( &block_set, SIGINT );
652 sigaddset( &block_set, SIGHUP );
653
Alexandre Julliard8859d772001-03-01 22:13:49 +0000654 /* receive the first thread request fd on the main socket */
655 NtCurrentTeb()->request_fd = receive_fd( &dummy_handle );
656
657 CLIENT_InitThread();
658}
659
660
661/***********************************************************************
Alexandre Julliard642d3131998-07-12 19:29:36 +0000662 * CLIENT_InitThread
663 *
664 * Send an init thread request. Return 0 if OK.
665 */
Alexandre Julliard8859d772001-03-01 22:13:49 +0000666void CLIENT_InitThread(void)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000667{
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000668 TEB *teb = NtCurrentTeb();
Alexandre Julliard8859d772001-03-01 22:13:49 +0000669 int version, ret;
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000670 int reply_pipe[2];
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000671
Alexandre Julliard42cc2bd2000-06-07 03:49:41 +0000672 /* ignore SIGPIPE so that we get a EPIPE error instead */
673 signal( SIGPIPE, SIG_IGN );
François Gouget103295c2002-06-13 21:57:38 +0000674 /* automatic child reaping to avoid zombies */
675 signal( SIGCHLD, SIG_IGN );
Alexandre Julliard42cc2bd2000-06-07 03:49:41 +0000676
Alexandre Julliard8859d772001-03-01 22:13:49 +0000677 /* create the server->client communication pipes */
678 if (pipe( reply_pipe ) == -1) server_protocol_perror( "pipe" );
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000679 if (pipe( teb->wait_fd ) == -1) server_protocol_perror( "pipe" );
Alexandre Julliard8859d772001-03-01 22:13:49 +0000680 wine_server_send_fd( reply_pipe[1] );
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000681 wine_server_send_fd( teb->wait_fd[1] );
Alexandre Julliard8859d772001-03-01 22:13:49 +0000682 teb->reply_fd = reply_pipe[0];
Alexandre Julliard714156d2002-08-13 18:24:27 +0000683 close( reply_pipe[1] );
Alexandre Julliardd549f692000-12-22 02:04:15 +0000684
Alexandre Julliard8859d772001-03-01 22:13:49 +0000685 /* set close on exec flag */
686 fcntl( teb->reply_fd, F_SETFD, 1 );
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000687 fcntl( teb->wait_fd[0], F_SETFD, 1 );
688 fcntl( teb->wait_fd[1], F_SETFD, 1 );
Alexandre Julliardd549f692000-12-22 02:04:15 +0000689
Alexandre Julliard8859d772001-03-01 22:13:49 +0000690 SERVER_START_REQ( init_thread )
691 {
692 req->unix_pid = getpid();
693 req->teb = teb;
694 req->entry = teb->entry_point;
695 req->reply_fd = reply_pipe[1];
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000696 req->wait_fd = teb->wait_fd[1];
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000697 ret = wine_server_call( req );
698 teb->pid = reply->pid;
699 teb->tid = reply->tid;
700 version = reply->version;
701 if (reply->boot) boot_thread_id = teb->tid;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000702 else if (boot_thread_id == teb->tid) boot_thread_id = 0;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000703 }
704 SERVER_END_REQ;
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000705
Alexandre Julliard8859d772001-03-01 22:13:49 +0000706 if (ret) server_protocol_error( "init_thread failed with status %x\n", ret );
707 if (version != SERVER_PROTOCOL_VERSION)
Alexandre Julliard5fb54562000-03-08 22:01:02 +0000708 server_protocol_error( "version mismatch %d/%d.\n"
709 "Your %s binary was not upgraded correctly,\n"
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000710 "or you have an older one somewhere in your PATH.\n"
711 "Or maybe the wrong wineserver is still running?\n",
Alexandre Julliard8859d772001-03-01 22:13:49 +0000712 version, SERVER_PROTOCOL_VERSION,
713 (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000714}
715
Alexandre Julliardd549f692000-12-22 02:04:15 +0000716
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000717/***********************************************************************
718 * CLIENT_BootDone
719 *
720 * Signal that we have finished booting, and set debug level.
721 */
Alexandre Julliard8859d772001-03-01 22:13:49 +0000722void CLIENT_BootDone( int debug_level )
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000723{
Alexandre Julliard67a74992001-02-27 02:09:16 +0000724 SERVER_START_REQ( boot_done )
Alexandre Julliard86113532000-08-29 03:54:30 +0000725 {
Alexandre Julliard86113532000-08-29 03:54:30 +0000726 req->debug_level = debug_level;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000727 wine_server_call( req );
Alexandre Julliard86113532000-08-29 03:54:30 +0000728 }
729 SERVER_END_REQ;
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000730}
731
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000732
733/***********************************************************************
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000734 * CLIENT_IsBootThread
Alexandre Julliard338e7571998-12-27 15:28:54 +0000735 *
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000736 * Return TRUE if current thread is the boot thread.
Alexandre Julliard338e7571998-12-27 15:28:54 +0000737 */
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000738int CLIENT_IsBootThread(void)
Alexandre Julliard338e7571998-12-27 15:28:54 +0000739{
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000740 return (GetCurrentThreadId() == (DWORD)boot_thread_id);
Alexandre Julliard338e7571998-12-27 15:28:54 +0000741}