Commit | Line | Data |
---|---|---|
642d3136 | 1 | /* |
52f692fb | 2 | * Wine server communication |
642d3136 AJ |
3 | * |
4 | * Copyright (C) 1998 Alexandre Julliard | |
0799c1a7 AJ |
5 | * |
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 | |
360a3f91 | 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
642d3136 AJ |
19 | */ |
20 | ||
1425941e | 21 | #include "config.h" |
386cf6e3 | 22 | #include "wine/port.h" |
13277480 | 23 | |
642d3136 | 24 | #include <assert.h> |
2fe57779 | 25 | #include <ctype.h> |
215738a1 FG |
26 | #ifdef HAVE_DIRENT_H |
27 | # include <dirent.h> | |
28 | #endif | |
642d3136 | 29 | #include <errno.h> |
62a8b433 | 30 | #include <fcntl.h> |
42cc2bdf | 31 | #include <signal.h> |
04869eb6 | 32 | #include <stdarg.h> |
642d3136 AJ |
33 | #include <stdio.h> |
34 | #include <string.h> | |
829fe323 | 35 | #include <sys/types.h> |
96336324 PS |
36 | #ifdef HAVE_SYS_SOCKET_H |
37 | # include <sys/socket.h> | |
38 | #endif | |
d804111d AJ |
39 | #ifdef HAVE_SYS_WAIT_H |
40 | #include <sys/wait.h> | |
41 | #endif | |
45e56818 | 42 | #ifdef HAVE_SYS_UN_H |
2fe57779 | 43 | #include <sys/un.h> |
45e56818 | 44 | #endif |
13277480 | 45 | #ifdef HAVE_SYS_MMAN_H |
5bc78089 | 46 | #include <sys/mman.h> |
13277480 | 47 | #endif |
821d4c46 FG |
48 | #ifdef HAVE_SYS_STAT_H |
49 | # include <sys/stat.h> | |
50 | #endif | |
45e56818 | 51 | #ifdef HAVE_SYS_UIO_H |
642d3136 | 52 | #include <sys/uio.h> |
45e56818 | 53 | #endif |
5adfec28 AJ |
54 | #ifdef HAVE_SYS_THR_H |
55 | #include <sys/ucontext.h> | |
56 | #include <sys/thr.h> | |
57 | #endif | |
d016f819 PS |
58 | #ifdef HAVE_UNISTD_H |
59 | # include <unistd.h> | |
60 | #endif | |
642d3136 | 61 | |
e37c6e18 | 62 | #include "ntstatus.h" |
1a1583a3 | 63 | #define WIN32_NO_STATUS |
4144b5b8 | 64 | #include "wine/library.h" |
37e9503a | 65 | #include "wine/server.h" |
bb4ddfec | 66 | #include "wine/debug.h" |
3ec73af3 | 67 | #include "ntdll_misc.h" |
642d3136 | 68 | |
bb4ddfec AJ |
69 | WINE_DEFAULT_DEBUG_CHANNEL(server); |
70 | ||
829fe323 AJ |
71 | /* Some versions of glibc don't define this */ |
72 | #ifndef SCM_RIGHTS | |
73 | #define SCM_RIGHTS 1 | |
74 | #endif | |
642d3136 | 75 | |
3269d8c7 AJ |
76 | #ifndef MSG_CMSG_CLOEXEC |
77 | #define MSG_CMSG_CLOEXEC 0 | |
78 | #endif | |
79 | ||
2fe57779 | 80 | #define SOCKETNAME "socket" /* name of the socket file */ |
4144b5b8 | 81 | #define LOCKNAME "lock" /* name of the lock file */ |
2fe57779 | 82 | |
653d2c4a AJ |
83 | #ifdef __i386__ |
84 | static const enum cpu_type client_cpu = CPU_x86; | |
85 | #elif defined(__x86_64__) | |
86 | static const enum cpu_type client_cpu = CPU_x86_64; | |
87 | #elif defined(__ALPHA__) | |
88 | static const enum cpu_type client_cpu = CPU_ALPHA; | |
89 | #elif defined(__powerpc__) | |
90 | static const enum cpu_type client_cpu = CPU_POWERPC; | |
91 | #elif defined(__sparc__) | |
92 | static const enum cpu_type client_cpu = CPU_SPARC; | |
93 | #else | |
94 | #error Unsupported CPU | |
95 | #endif | |
96 | ||
12c90b04 | 97 | unsigned int server_cpus = 0; |
747d58d2 | 98 | int is_wow64 = FALSE; |
7e47d19d | 99 | |
5537dbbf | 100 | #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS |
ebe29ef3 AJ |
101 | /* data structure used to pass an fd with sendmsg/recvmsg */ |
102 | struct cmsg_fd | |
103 | { | |
cdf92942 AJ |
104 | struct |
105 | { | |
106 | size_t len; /* size of structure */ | |
107 | int level; /* SOL_SOCKET */ | |
108 | int type; /* SCM_RIGHTS */ | |
109 | } header; | |
110 | int fd; /* fd to pass */ | |
ebe29ef3 | 111 | }; |
5537dbbf | 112 | #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ |
767e6f6f | 113 | |
aaf477f2 | 114 | timeout_t server_start_time = 0; /* time of server startup */ |
9ad56286 | 115 | |
c388c58b | 116 | sigset_t server_block_set; /* signals to block during server calls */ |
52f692fb | 117 | static int fd_socket = -1; /* socket to exchange file descriptors with the server */ |
2fe57779 | 118 | |
b87bce1b AJ |
119 | static RTL_CRITICAL_SECTION fd_cache_section; |
120 | static RTL_CRITICAL_SECTION_DEBUG critsect_debug = | |
121 | { | |
122 | 0, 0, &fd_cache_section, | |
123 | { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, | |
124 | 0, 0, { (DWORD_PTR)(__FILE__ ": fd_cache_section") } | |
125 | }; | |
126 | static RTL_CRITICAL_SECTION fd_cache_section = { &critsect_debug, -1, 0, 0, 0, 0 }; | |
127 | ||
128 | ||
4144b5b8 AJ |
129 | #ifdef __GNUC__ |
130 | static void fatal_error( const char *err, ... ) __attribute__((noreturn, format(printf,1,2))); | |
131 | static void fatal_perror( const char *err, ... ) __attribute__((noreturn, format(printf,1,2))); | |
132 | static void server_connect_error( const char *serverdir ) __attribute__((noreturn)); | |
133 | #endif | |
134 | ||
2fe57779 AJ |
135 | /* die on a fatal error; use only during initialization */ |
136 | static void fatal_error( const char *err, ... ) | |
137 | { | |
138 | va_list args; | |
139 | ||
140 | va_start( args, err ); | |
141 | fprintf( stderr, "wine: " ); | |
142 | vfprintf( stderr, err, args ); | |
143 | va_end( args ); | |
144 | exit(1); | |
145 | } | |
146 | ||
147 | /* die on a fatal error; use only during initialization */ | |
148 | static void fatal_perror( const char *err, ... ) | |
149 | { | |
150 | va_list args; | |
151 | ||
152 | va_start( args, err ); | |
153 | fprintf( stderr, "wine: " ); | |
154 | vfprintf( stderr, err, args ); | |
155 | perror( " " ); | |
156 | va_end( args ); | |
157 | exit(1); | |
158 | } | |
159 | ||
4dba172e | 160 | |
767e6f6f | 161 | /*********************************************************************** |
ebe29ef3 | 162 | * server_protocol_error |
767e6f6f | 163 | */ |
ebe29ef3 | 164 | void server_protocol_error( const char *err, ... ) |
767e6f6f | 165 | { |
767e6f6f AJ |
166 | va_list args; |
167 | ||
168 | va_start( args, err ); | |
f7b0ba7a | 169 | fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); |
767e6f6f AJ |
170 | vfprintf( stderr, err, args ); |
171 | va_end( args ); | |
cc933f58 | 172 | abort_thread(1); |
767e6f6f AJ |
173 | } |
174 | ||
175 | ||
642d3136 | 176 | /*********************************************************************** |
5f195f8c | 177 | * server_protocol_perror |
5bc78089 | 178 | */ |
5f195f8c | 179 | void server_protocol_perror( const char *err ) |
5bc78089 | 180 | { |
f7b0ba7a | 181 | fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); |
5bc78089 | 182 | perror( err ); |
cc933f58 | 183 | abort_thread(1); |
5bc78089 AJ |
184 | } |
185 | ||
186 | ||
187 | /*********************************************************************** | |
188 | * send_request | |
642d3136 AJ |
189 | * |
190 | * Send a request to the server. | |
191 | */ | |
7378fac5 | 192 | static unsigned int send_request( const struct __server_request_info *req ) |
5bc78089 | 193 | { |
a9b4a471 HL |
194 | unsigned int i; |
195 | int ret; | |
9caa71ee AJ |
196 | |
197 | if (!req->u.req.request_header.request_size) | |
198 | { | |
ab29aa21 | 199 | if ((ret = write( ntdll_get_thread_data()->request_fd, &req->u.req, |
7378fac5 | 200 | sizeof(req->u.req) )) == sizeof(req->u.req)) return STATUS_SUCCESS; |
9caa71ee AJ |
201 | |
202 | } | |
203 | else | |
204 | { | |
205 | struct iovec vec[__SERVER_MAX_DATA+1]; | |
206 | ||
207 | vec[0].iov_base = (void *)&req->u.req; | |
208 | vec[0].iov_len = sizeof(req->u.req); | |
209 | for (i = 0; i < req->data_count; i++) | |
210 | { | |
211 | vec[i+1].iov_base = (void *)req->data[i].ptr; | |
212 | vec[i+1].iov_len = req->data[i].size; | |
213 | } | |
ab29aa21 | 214 | if ((ret = writev( ntdll_get_thread_data()->request_fd, vec, i+1 )) == |
7378fac5 | 215 | req->u.req.request_header.request_size + sizeof(req->u.req)) return STATUS_SUCCESS; |
9caa71ee | 216 | } |
d90e964c | 217 | |
d90e964c | 218 | if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); |
cc933f58 | 219 | if (errno == EPIPE) abort_thread(0); |
7378fac5 | 220 | if (errno == EFAULT) return STATUS_ACCESS_VIOLATION; |
de7fab45 | 221 | server_protocol_perror( "write" ); |
5bc78089 AJ |
222 | } |
223 | ||
9caa71ee | 224 | |
642d3136 | 225 | /*********************************************************************** |
9caa71ee | 226 | * read_reply_data |
642d3136 | 227 | * |
9caa71ee | 228 | * Read data from the reply buffer; helper for wait_reply. |
642d3136 | 229 | */ |
9caa71ee | 230 | static void read_reply_data( void *buffer, size_t size ) |
642d3136 | 231 | { |
ebe29ef3 | 232 | int ret; |
642d3136 | 233 | |
5bc78089 | 234 | for (;;) |
642d3136 | 235 | { |
ab29aa21 | 236 | if ((ret = read( ntdll_get_thread_data()->reply_fd, buffer, size )) > 0) |
9caa71ee AJ |
237 | { |
238 | if (!(size -= ret)) return; | |
239 | buffer = (char *)buffer + ret; | |
240 | continue; | |
241 | } | |
12f29b50 | 242 | if (!ret) break; |
86113530 AJ |
243 | if (errno == EINTR) continue; |
244 | if (errno == EPIPE) break; | |
5f195f8c | 245 | server_protocol_perror("read"); |
642d3136 | 246 | } |
12f29b50 | 247 | /* the server closed the connection; time to die... */ |
cc933f58 | 248 | abort_thread(0); |
642d3136 AJ |
249 | } |
250 | ||
251 | ||
9caa71ee AJ |
252 | /*********************************************************************** |
253 | * wait_reply | |
254 | * | |
255 | * Wait for a reply from the server. | |
256 | */ | |
7378fac5 | 257 | static inline unsigned int wait_reply( struct __server_request_info *req ) |
9caa71ee AJ |
258 | { |
259 | read_reply_data( &req->u.reply, sizeof(req->u.reply) ); | |
260 | if (req->u.reply.reply_header.reply_size) | |
261 | read_reply_data( req->reply_data, req->u.reply.reply_header.reply_size ); | |
7378fac5 | 262 | return req->u.reply.reply_header.error; |
9caa71ee AJ |
263 | } |
264 | ||
265 | ||
642d3136 | 266 | /*********************************************************************** |
d0a41774 | 267 | * wine_server_call (NTDLL.@) |
d549f690 AJ |
268 | * |
269 | * Perform a server call. | |
038d1c4d RS |
270 | * |
271 | * PARAMS | |
272 | * req_ptr [I/O] Function dependent data | |
273 | * | |
274 | * RETURNS | |
275 | * Depends on server function being called, but usually an NTSTATUS code. | |
276 | * | |
277 | * NOTES | |
278 | * Use the SERVER_START_REQ and SERVER_END_REQ to help you fill out the | |
279 | * server request structure for the particular call. E.g: | |
280 | *| SERVER_START_REQ( event_op ) | |
281 | *| { | |
282 | *| req->handle = handle; | |
283 | *| req->op = SET_EVENT; | |
284 | *| ret = wine_server_call( req ); | |
285 | *| } | |
286 | *| SERVER_END_REQ; | |
d549f690 | 287 | */ |
9caa71ee | 288 | unsigned int wine_server_call( void *req_ptr ) |
d549f690 | 289 | { |
9caa71ee | 290 | struct __server_request_info * const req = req_ptr; |
f5242405 | 291 | sigset_t old_set; |
7378fac5 | 292 | unsigned int ret; |
f5242405 | 293 | |
36334a1b | 294 | pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); |
7378fac5 AJ |
295 | ret = send_request( req ); |
296 | if (!ret) ret = wait_reply( req ); | |
36334a1b | 297 | pthread_sigmask( SIG_SETMASK, &old_set, NULL ); |
7378fac5 | 298 | return ret; |
d549f690 AJ |
299 | } |
300 | ||
301 | ||
146fb0de AJ |
302 | /*********************************************************************** |
303 | * server_enter_uninterrupted_section | |
304 | */ | |
305 | void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) | |
306 | { | |
36334a1b | 307 | pthread_sigmask( SIG_BLOCK, &server_block_set, sigset ); |
146fb0de AJ |
308 | RtlEnterCriticalSection( cs ); |
309 | } | |
310 | ||
311 | ||
312 | /*********************************************************************** | |
313 | * server_leave_uninterrupted_section | |
314 | */ | |
315 | void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) | |
316 | { | |
317 | RtlLeaveCriticalSection( cs ); | |
36334a1b | 318 | pthread_sigmask( SIG_SETMASK, sigset, NULL ); |
146fb0de AJ |
319 | } |
320 | ||
321 | ||
d549f690 | 322 | /*********************************************************************** |
038d1c4d | 323 | * wine_server_send_fd (NTDLL.@) |
642d3136 | 324 | * |
f5242405 | 325 | * Send a file descriptor to the server. |
038d1c4d RS |
326 | * |
327 | * PARAMS | |
328 | * fd [I] file descriptor to send | |
329 | * | |
330 | * RETURNS | |
331 | * nothing | |
642d3136 | 332 | */ |
768160e9 | 333 | void CDECL wine_server_send_fd( int fd ) |
d549f690 | 334 | { |
5537dbbf | 335 | #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS |
f5242405 AJ |
336 | struct cmsg_fd cmsg; |
337 | #endif | |
338 | struct send_fd data; | |
339 | struct msghdr msghdr; | |
340 | struct iovec vec; | |
341 | int ret; | |
342 | ||
343 | vec.iov_base = (void *)&data; | |
344 | vec.iov_len = sizeof(data); | |
345 | ||
346 | msghdr.msg_name = NULL; | |
347 | msghdr.msg_namelen = 0; | |
348 | msghdr.msg_iov = &vec; | |
349 | msghdr.msg_iovlen = 1; | |
350 | ||
5537dbbf | 351 | #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS |
f5242405 AJ |
352 | msghdr.msg_accrights = (void *)&fd; |
353 | msghdr.msg_accrightslen = sizeof(fd); | |
5537dbbf | 354 | #else /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ |
cdf92942 AJ |
355 | cmsg.header.len = sizeof(cmsg.header) + sizeof(fd); |
356 | cmsg.header.level = SOL_SOCKET; | |
357 | cmsg.header.type = SCM_RIGHTS; | |
358 | cmsg.fd = fd; | |
f5242405 | 359 | msghdr.msg_control = &cmsg; |
cdf92942 | 360 | msghdr.msg_controllen = sizeof(cmsg.header) + sizeof(fd); |
f5242405 | 361 | msghdr.msg_flags = 0; |
5537dbbf | 362 | #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ |
f5242405 | 363 | |
54f22873 | 364 | data.tid = GetCurrentThreadId(); |
f5242405 AJ |
365 | data.fd = fd; |
366 | ||
367 | for (;;) | |
368 | { | |
369 | if ((ret = sendmsg( fd_socket, &msghdr, 0 )) == sizeof(data)) return; | |
370 | if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); | |
371 | if (errno == EINTR) continue; | |
cc933f58 | 372 | if (errno == EPIPE) abort_thread(0); |
f5242405 AJ |
373 | server_protocol_perror( "sendmsg" ); |
374 | } | |
d549f690 AJ |
375 | } |
376 | ||
377 | ||
378 | /*********************************************************************** | |
8859d772 | 379 | * receive_fd |
d549f690 AJ |
380 | * |
381 | * Receive a file descriptor passed from the server. | |
d549f690 | 382 | */ |
51885749 | 383 | static int receive_fd( obj_handle_t *handle ) |
642d3136 | 384 | { |
5bc78089 | 385 | struct iovec vec; |
8859d772 | 386 | int ret, fd; |
642d3136 | 387 | |
5537dbbf | 388 | #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS |
1bb94039 PS |
389 | struct msghdr msghdr; |
390 | ||
d549f690 AJ |
391 | fd = -1; |
392 | msghdr.msg_accrights = (void *)&fd; | |
393 | msghdr.msg_accrightslen = sizeof(fd); | |
5537dbbf | 394 | #else /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ |
1bb94039 PS |
395 | struct msghdr msghdr; |
396 | struct cmsg_fd cmsg; | |
397 | ||
cdf92942 AJ |
398 | cmsg.header.len = sizeof(cmsg.header) + sizeof(fd); |
399 | cmsg.header.level = SOL_SOCKET; | |
400 | cmsg.header.type = SCM_RIGHTS; | |
401 | cmsg.fd = -1; | |
1bb94039 | 402 | msghdr.msg_control = &cmsg; |
cdf92942 | 403 | msghdr.msg_controllen = sizeof(cmsg.header) + sizeof(fd); |
1bb94039 | 404 | msghdr.msg_flags = 0; |
5537dbbf | 405 | #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ |
1bb94039 PS |
406 | |
407 | msghdr.msg_name = NULL; | |
408 | msghdr.msg_namelen = 0; | |
5bc78089 AJ |
409 | msghdr.msg_iov = &vec; |
410 | msghdr.msg_iovlen = 1; | |
8859d772 AJ |
411 | vec.iov_base = (void *)handle; |
412 | vec.iov_len = sizeof(*handle); | |
1bb94039 | 413 | |
5bc78089 | 414 | for (;;) |
642d3136 | 415 | { |
3269d8c7 | 416 | if ((ret = recvmsg( fd_socket, &msghdr, MSG_CMSG_CLOEXEC )) > 0) |
5bc78089 | 417 | { |
5537dbbf | 418 | #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS |
d549f690 | 419 | fd = cmsg.fd; |
5bc78089 | 420 | #endif |
3269d8c7 | 421 | if (fd != -1) fcntl( fd, F_SETFD, FD_CLOEXEC ); /* in case MSG_CMSG_CLOEXEC is not supported */ |
d549f690 | 422 | return fd; |
5bc78089 | 423 | } |
12f29b50 | 424 | if (!ret) break; |
86113530 AJ |
425 | if (errno == EINTR) continue; |
426 | if (errno == EPIPE) break; | |
5f195f8c | 427 | server_protocol_perror("recvmsg"); |
642d3136 | 428 | } |
12f29b50 | 429 | /* the server closed the connection; time to die... */ |
cc933f58 | 430 | abort_thread(0); |
5bc78089 | 431 | } |
767e6f6f | 432 | |
767e6f6f | 433 | |
027491f6 AJ |
434 | /***********************************************************************/ |
435 | /* fd cache support */ | |
28418cc9 | 436 | |
83ce9587 AJ |
437 | struct fd_cache_entry |
438 | { | |
439 | int fd; | |
d85121f1 AJ |
440 | enum server_fd_type type : 6; |
441 | unsigned int access : 2; | |
442 | unsigned int options : 24; | |
83ce9587 AJ |
443 | }; |
444 | ||
027491f6 AJ |
445 | #define FD_CACHE_BLOCK_SIZE (65536 / sizeof(struct fd_cache_entry)) |
446 | #define FD_CACHE_ENTRIES 128 | |
447 | ||
448 | static struct fd_cache_entry *fd_cache[FD_CACHE_ENTRIES]; | |
449 | static struct fd_cache_entry fd_cache_initial_block[FD_CACHE_BLOCK_SIZE]; | |
450 | ||
d1b3d484 | 451 | static inline unsigned int handle_to_index( HANDLE handle, unsigned int *entry ) |
027491f6 | 452 | { |
d1b3d484 | 453 | unsigned int idx = (wine_server_obj_handle(handle) >> 2) - 1; |
027491f6 AJ |
454 | *entry = idx / FD_CACHE_BLOCK_SIZE; |
455 | return idx % FD_CACHE_BLOCK_SIZE; | |
456 | } | |
457 | ||
28418cc9 AJ |
458 | |
459 | /*********************************************************************** | |
460 | * add_fd_to_cache | |
461 | * | |
462 | * Caller must hold fd_cache_section. | |
463 | */ | |
d1b3d484 | 464 | static int add_fd_to_cache( HANDLE handle, int fd, enum server_fd_type type, |
d85121f1 | 465 | unsigned int access, unsigned int options ) |
28418cc9 | 466 | { |
027491f6 AJ |
467 | unsigned int entry, idx = handle_to_index( handle, &entry ); |
468 | int prev_fd; | |
28418cc9 | 469 | |
027491f6 | 470 | if (entry >= FD_CACHE_ENTRIES) |
28418cc9 | 471 | { |
027491f6 AJ |
472 | FIXME( "too many allocated handles, not caching %p\n", handle ); |
473 | return 0; | |
474 | } | |
28418cc9 | 475 | |
027491f6 AJ |
476 | if (!fd_cache[entry]) /* do we need to allocate a new block of entries? */ |
477 | { | |
478 | if (!entry) fd_cache[0] = fd_cache_initial_block; | |
28418cc9 | 479 | else |
28418cc9 | 480 | { |
027491f6 AJ |
481 | void *ptr = wine_anon_mmap( NULL, FD_CACHE_BLOCK_SIZE * sizeof(struct fd_cache_entry), |
482 | PROT_READ | PROT_WRITE, 0 ); | |
483 | if (ptr == MAP_FAILED) return 0; | |
484 | fd_cache[entry] = ptr; | |
28418cc9 AJ |
485 | } |
486 | } | |
027491f6 AJ |
487 | /* store fd+1 so that 0 can be used as the unset value */ |
488 | prev_fd = interlocked_xchg( &fd_cache[entry][idx].fd, fd + 1 ) - 1; | |
489 | fd_cache[entry][idx].type = type; | |
d85121f1 AJ |
490 | fd_cache[entry][idx].access = access; |
491 | fd_cache[entry][idx].options = options; | |
027491f6 AJ |
492 | if (prev_fd != -1) close( prev_fd ); |
493 | return 1; | |
28418cc9 AJ |
494 | } |
495 | ||
496 | ||
497 | /*********************************************************************** | |
498 | * get_cached_fd | |
499 | * | |
500 | * Caller must hold fd_cache_section. | |
501 | */ | |
d1b3d484 | 502 | static inline int get_cached_fd( HANDLE handle, enum server_fd_type *type, |
d85121f1 | 503 | unsigned int *access, unsigned int *options ) |
28418cc9 | 504 | { |
027491f6 | 505 | unsigned int entry, idx = handle_to_index( handle, &entry ); |
28418cc9 AJ |
506 | int fd = -1; |
507 | ||
027491f6 | 508 | if (entry < FD_CACHE_ENTRIES && fd_cache[entry]) |
83ce9587 | 509 | { |
027491f6 AJ |
510 | fd = fd_cache[entry][idx].fd - 1; |
511 | if (type) *type = fd_cache[entry][idx].type; | |
d85121f1 AJ |
512 | if (access) *access = fd_cache[entry][idx].access; |
513 | if (options) *options = fd_cache[entry][idx].options; | |
83ce9587 | 514 | } |
28418cc9 AJ |
515 | return fd; |
516 | } | |
517 | ||
518 | ||
519 | /*********************************************************************** | |
520 | * server_remove_fd_from_cache | |
521 | */ | |
d1b3d484 | 522 | int server_remove_fd_from_cache( HANDLE handle ) |
28418cc9 | 523 | { |
027491f6 | 524 | unsigned int entry, idx = handle_to_index( handle, &entry ); |
28418cc9 AJ |
525 | int fd = -1; |
526 | ||
027491f6 AJ |
527 | if (entry < FD_CACHE_ENTRIES && fd_cache[entry]) |
528 | fd = interlocked_xchg( &fd_cache[entry][idx].fd, 0 ) - 1; | |
28418cc9 | 529 | |
28418cc9 AJ |
530 | return fd; |
531 | } | |
532 | ||
533 | ||
9ddb9294 AJ |
534 | /*********************************************************************** |
535 | * server_get_unix_fd | |
536 | * | |
537 | * The returned unix_fd should be closed iff needs_close is non-zero. | |
538 | */ | |
d1b3d484 | 539 | int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, |
d85121f1 | 540 | int *needs_close, enum server_fd_type *type, unsigned int *options ) |
9ddb9294 | 541 | { |
735dbc40 | 542 | sigset_t sigset; |
9ddb9294 | 543 | obj_handle_t fd_handle; |
d85121f1 | 544 | int ret = 0, fd; |
335ce754 | 545 | unsigned int access = 0; |
9ddb9294 AJ |
546 | |
547 | *unix_fd = -1; | |
548 | *needs_close = 0; | |
d85121f1 | 549 | wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA; |
9ddb9294 | 550 | |
735dbc40 | 551 | server_enter_uninterrupted_section( &fd_cache_section, &sigset ); |
9ddb9294 | 552 | |
d85121f1 AJ |
553 | fd = get_cached_fd( handle, type, &access, options ); |
554 | if (fd != -1) goto done; | |
9ddb9294 AJ |
555 | |
556 | SERVER_START_REQ( get_handle_fd ) | |
557 | { | |
d1b3d484 | 558 | req->handle = wine_server_obj_handle( handle ); |
9ddb9294 AJ |
559 | if (!(ret = wine_server_call( req ))) |
560 | { | |
83ce9587 | 561 | if (type) *type = reply->type; |
d85121f1 AJ |
562 | if (options) *options = reply->options; |
563 | access = reply->access; | |
564 | if ((fd = receive_fd( &fd_handle )) != -1) | |
83ce9587 | 565 | { |
d1b3d484 | 566 | assert( wine_server_ptr_handle(fd_handle) == handle ); |
d85121f1 AJ |
567 | *needs_close = (reply->removable || |
568 | !add_fd_to_cache( handle, fd, reply->type, | |
569 | reply->access, reply->options )); | |
83ce9587 | 570 | } |
d85121f1 | 571 | else ret = STATUS_TOO_MANY_OPENED_FILES; |
9ddb9294 AJ |
572 | } |
573 | } | |
574 | SERVER_END_REQ; | |
575 | ||
9ddb9294 | 576 | done: |
735dbc40 | 577 | server_leave_uninterrupted_section( &fd_cache_section, &sigset ); |
d85121f1 AJ |
578 | if (!ret && ((access & wanted_access) != wanted_access)) |
579 | { | |
580 | ret = STATUS_ACCESS_DENIED; | |
581 | if (*needs_close) close( fd ); | |
582 | } | |
9ddb9294 AJ |
583 | if (!ret) *unix_fd = fd; |
584 | return ret; | |
585 | } | |
586 | ||
587 | ||
be367c72 AJ |
588 | /*********************************************************************** |
589 | * wine_server_fd_to_handle (NTDLL.@) | |
590 | * | |
038d1c4d RS |
591 | * Allocate a file handle for a Unix file descriptor. |
592 | * | |
593 | * PARAMS | |
594 | * fd [I] Unix file descriptor. | |
595 | * access [I] Win32 access flags. | |
d02c4a1b | 596 | * attributes [I] Object attributes. |
038d1c4d RS |
597 | * handle [O] Address where Wine file handle will be stored. |
598 | * | |
599 | * RETURNS | |
600 | * NTSTATUS code | |
be367c72 | 601 | */ |
768160e9 | 602 | int CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes, HANDLE *handle ) |
be367c72 AJ |
603 | { |
604 | int ret; | |
605 | ||
606 | *handle = 0; | |
607 | wine_server_send_fd( fd ); | |
608 | ||
609 | SERVER_START_REQ( alloc_file_handle ) | |
610 | { | |
27b1aec9 | 611 | req->access = access; |
d02c4a1b | 612 | req->attributes = attributes; |
27b1aec9 | 613 | req->fd = fd; |
d1b3d484 | 614 | if (!(ret = wine_server_call( req ))) *handle = wine_server_ptr_handle( reply->handle ); |
be367c72 AJ |
615 | } |
616 | SERVER_END_REQ; | |
617 | return ret; | |
618 | } | |
619 | ||
620 | ||
8d1550d1 AJ |
621 | /*********************************************************************** |
622 | * wine_server_handle_to_fd (NTDLL.@) | |
623 | * | |
038d1c4d RS |
624 | * Retrieve the file descriptor corresponding to a file handle. |
625 | * | |
626 | * PARAMS | |
627 | * handle [I] Wine file handle. | |
628 | * access [I] Win32 file access rights requested. | |
629 | * unix_fd [O] Address where Unix file descriptor will be stored. | |
d85121f1 | 630 | * options [O] Address where the file open options will be stored. Optional. |
038d1c4d RS |
631 | * |
632 | * RETURNS | |
633 | * NTSTATUS code | |
8d1550d1 | 634 | */ |
768160e9 | 635 | int CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd, |
d85121f1 | 636 | unsigned int *options ) |
8d1550d1 | 637 | { |
d85121f1 | 638 | int needs_close, ret = server_get_unix_fd( handle, access, unix_fd, &needs_close, NULL, options ); |
8d1550d1 | 639 | |
9ddb9294 | 640 | if (!ret && !needs_close) |
28418cc9 | 641 | { |
9ddb9294 | 642 | if ((*unix_fd = dup(*unix_fd)) == -1) ret = FILE_GetNtStatus(); |
28418cc9 | 643 | } |
b87bce1b | 644 | return ret; |
8d1550d1 AJ |
645 | } |
646 | ||
647 | ||
f3f435ff AJ |
648 | /*********************************************************************** |
649 | * wine_server_release_fd (NTDLL.@) | |
650 | * | |
038d1c4d RS |
651 | * Release the Unix file descriptor returned by wine_server_handle_to_fd. |
652 | * | |
653 | * PARAMS | |
654 | * handle [I] Wine file handle. | |
655 | * unix_fd [I] Unix file descriptor to release. | |
656 | * | |
657 | * RETURNS | |
658 | * nothing | |
f3f435ff | 659 | */ |
768160e9 | 660 | void CDECL wine_server_release_fd( HANDLE handle, int unix_fd ) |
f3f435ff AJ |
661 | { |
662 | close( unix_fd ); | |
663 | } | |
664 | ||
665 | ||
6f68b774 AJ |
666 | /*********************************************************************** |
667 | * server_pipe | |
668 | * | |
669 | * Create a pipe for communicating with the server. | |
670 | */ | |
671 | int server_pipe( int fd[2] ) | |
672 | { | |
673 | int ret; | |
674 | #ifdef HAVE_PIPE2 | |
675 | static int have_pipe2 = 1; | |
676 | ||
677 | if (have_pipe2) | |
678 | { | |
679 | if (!(ret = pipe2( fd, O_CLOEXEC ))) return ret; | |
680 | if (errno == ENOSYS || errno == EINVAL) have_pipe2 = 0; /* don't try again */ | |
681 | } | |
682 | #endif | |
683 | if (!(ret = pipe( fd ))) | |
684 | { | |
685 | fcntl( fd[0], F_SETFD, FD_CLOEXEC ); | |
686 | fcntl( fd[1], F_SETFD, FD_CLOEXEC ); | |
687 | } | |
688 | return ret; | |
689 | } | |
690 | ||
691 | ||
2fe57779 AJ |
692 | /*********************************************************************** |
693 | * start_server | |
694 | * | |
695 | * Start a new wine server. | |
696 | */ | |
dcdb0d0b | 697 | static void start_server(void) |
2fe57779 AJ |
698 | { |
699 | static int started; /* we only try once */ | |
bb4ddfec | 700 | char *argv[3]; |
8e73e411 AT |
701 | static char wineserver[] = "server/wineserver"; |
702 | static char debug[] = "-d"; | |
daeccba7 | 703 | |
2fe57779 AJ |
704 | if (!started) |
705 | { | |
d804111d | 706 | int status; |
2fe57779 AJ |
707 | int pid = fork(); |
708 | if (pid == -1) fatal_perror( "fork" ); | |
709 | if (!pid) | |
710 | { | |
8e73e411 AT |
711 | argv[0] = wineserver; |
712 | argv[1] = TRACE_ON(server) ? debug : NULL; | |
bb4ddfec | 713 | argv[2] = NULL; |
9dffd134 | 714 | wine_exec_wine_binary( argv[0], argv, getenv("WINESERVER") ); |
2fe57779 AJ |
715 | fatal_error( "could not exec wineserver\n" ); |
716 | } | |
d804111d AJ |
717 | waitpid( pid, &status, 0 ); |
718 | status = WIFEXITED(status) ? WEXITSTATUS(status) : 1; | |
4144b5b8 | 719 | if (status == 2) return; /* server lock held by someone else, will retry later */ |
d804111d | 720 | if (status) exit(status); /* server failed */ |
4144b5b8 AJ |
721 | started = 1; |
722 | } | |
723 | } | |
724 | ||
725 | ||
870bba3e AJ |
726 | /*********************************************************************** |
727 | * setup_config_dir | |
728 | * | |
729 | * Setup the wine configuration dir. | |
730 | */ | |
731 | static void setup_config_dir(void) | |
732 | { | |
733 | const char *p, *config_dir = wine_get_config_dir(); | |
870bba3e AJ |
734 | |
735 | if (chdir( config_dir ) == -1) | |
736 | { | |
737 | if (errno != ENOENT) fatal_perror( "chdir to %s\n", config_dir ); | |
738 | ||
739 | if ((p = strrchr( config_dir, '/' )) && p != config_dir) | |
740 | { | |
741 | struct stat st; | |
742 | char *tmp_dir; | |
743 | ||
744 | if (!(tmp_dir = malloc( p + 1 - config_dir ))) fatal_error( "out of memory\n" ); | |
745 | memcpy( tmp_dir, config_dir, p - config_dir ); | |
746 | tmp_dir[p - config_dir] = 0; | |
747 | if (!stat( tmp_dir, &st ) && st.st_uid != getuid()) | |
748 | fatal_error( "'%s' is not owned by you, refusing to create a configuration directory there\n", | |
749 | tmp_dir ); | |
750 | free( tmp_dir ); | |
751 | } | |
752 | ||
753 | mkdir( config_dir, 0777 ); | |
754 | if (chdir( config_dir ) == -1) fatal_perror( "chdir to %s\n", config_dir ); | |
e44dd0f8 | 755 | MESSAGE( "wine: created the configuration directory '%s'\n", config_dir ); |
870bba3e AJ |
756 | } |
757 | ||
758 | if (mkdir( "dosdevices", 0777 ) == -1) | |
759 | { | |
760 | if (errno == EEXIST) return; | |
761 | fatal_perror( "cannot create %s/dosdevices\n", config_dir ); | |
762 | } | |
763 | ||
764 | /* create the drive symlinks */ | |
765 | ||
766 | mkdir( "drive_c", 0777 ); | |
767 | symlink( "../drive_c", "dosdevices/c:" ); | |
768 | symlink( "/", "dosdevices/z:" ); | |
870bba3e AJ |
769 | } |
770 | ||
771 | ||
4144b5b8 AJ |
772 | /*********************************************************************** |
773 | * server_connect_error | |
774 | * | |
775 | * Try to display a meaningful explanation of why we couldn't connect | |
776 | * to the server. | |
777 | */ | |
778 | static void server_connect_error( const char *serverdir ) | |
779 | { | |
780 | int fd; | |
781 | struct flock fl; | |
782 | ||
783 | if ((fd = open( LOCKNAME, O_WRONLY )) == -1) | |
784 | fatal_error( "for some mysterious reason, the wine server never started.\n" ); | |
785 | ||
786 | fl.l_type = F_WRLCK; | |
787 | fl.l_whence = SEEK_SET; | |
788 | fl.l_start = 0; | |
789 | fl.l_len = 1; | |
790 | if (fcntl( fd, F_GETLK, &fl ) != -1) | |
791 | { | |
792 | if (fl.l_type == F_WRLCK) /* the file is locked */ | |
793 | fatal_error( "a wine server seems to be running, but I cannot connect to it.\n" | |
794 | " You probably need to kill that process (it might be pid %d).\n", | |
795 | (int)fl.l_pid ); | |
796 | fatal_error( "for some mysterious reason, the wine server failed to run.\n" ); | |
2fe57779 | 797 | } |
4144b5b8 AJ |
798 | fatal_error( "the file system of '%s' doesn't support locks,\n" |
799 | " and there is a 'socket' file in that directory that prevents wine from starting.\n" | |
800 | " You should make sure no wine server is running, remove that file and try again.\n", | |
801 | serverdir ); | |
2fe57779 AJ |
802 | } |
803 | ||
4144b5b8 | 804 | |
2fe57779 AJ |
805 | /*********************************************************************** |
806 | * server_connect | |
807 | * | |
808 | * Attempt to connect to an existing server socket. | |
809 | * We need to be in the server directory already. | |
810 | */ | |
870bba3e | 811 | static int server_connect(void) |
2fe57779 | 812 | { |
870bba3e | 813 | const char *serverdir; |
2fe57779 AJ |
814 | struct sockaddr_un addr; |
815 | struct stat st; | |
dcdb0d0b AJ |
816 | int s, slen, retry, fd_cwd; |
817 | ||
818 | /* retrieve the current directory */ | |
819 | fd_cwd = open( ".", O_RDONLY ); | |
820 | if (fd_cwd != -1) fcntl( fd_cwd, F_SETFD, 1 ); /* set close on exec flag */ | |
2fe57779 | 821 | |
870bba3e AJ |
822 | setup_config_dir(); |
823 | serverdir = wine_get_server_dir(); | |
824 | ||
d804111d | 825 | /* chdir to the server directory */ |
2fe57779 AJ |
826 | if (chdir( serverdir ) == -1) |
827 | { | |
828 | if (errno != ENOENT) fatal_perror( "chdir to %s", serverdir ); | |
dcdb0d0b | 829 | start_server(); |
d804111d | 830 | if (chdir( serverdir ) == -1) fatal_perror( "chdir to %s", serverdir ); |
2fe57779 | 831 | } |
d804111d AJ |
832 | |
833 | /* make sure we are at the right place */ | |
2fe57779 AJ |
834 | if (stat( ".", &st ) == -1) fatal_perror( "stat %s", serverdir ); |
835 | if (st.st_uid != getuid()) fatal_error( "'%s' is not owned by you\n", serverdir ); | |
836 | if (st.st_mode & 077) fatal_error( "'%s' must not be accessible by other users\n", serverdir ); | |
837 | ||
4144b5b8 | 838 | for (retry = 0; retry < 6; retry++) |
2fe57779 | 839 | { |
4144b5b8 AJ |
840 | /* if not the first try, wait a bit to leave the previous server time to exit */ |
841 | if (retry) | |
842 | { | |
843 | usleep( 100000 * retry * retry ); | |
dcdb0d0b | 844 | start_server(); |
4144b5b8 AJ |
845 | if (lstat( SOCKETNAME, &st ) == -1) continue; /* still no socket, wait a bit more */ |
846 | } | |
847 | else if (lstat( SOCKETNAME, &st ) == -1) /* check for an already existing socket */ | |
c10c9ef4 AJ |
848 | { |
849 | if (errno != ENOENT) fatal_perror( "lstat %s/%s", serverdir, SOCKETNAME ); | |
dcdb0d0b | 850 | start_server(); |
4144b5b8 | 851 | if (lstat( SOCKETNAME, &st ) == -1) continue; /* still no socket, wait a bit more */ |
c10c9ef4 | 852 | } |
d804111d | 853 | |
19f8dda0 RAP |
854 | /* make sure the socket is sane (ISFIFO needed for Solaris) */ |
855 | if (!S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) | |
c10c9ef4 AJ |
856 | fatal_error( "'%s/%s' is not a socket\n", serverdir, SOCKETNAME ); |
857 | if (st.st_uid != getuid()) | |
858 | fatal_error( "'%s/%s' is not owned by you\n", serverdir, SOCKETNAME ); | |
2fe57779 | 859 | |
c10c9ef4 AJ |
860 | /* try to connect to it */ |
861 | addr.sun_family = AF_UNIX; | |
862 | strcpy( addr.sun_path, SOCKETNAME ); | |
863 | slen = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path) + 1; | |
5537dbbf | 864 | #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN |
c10c9ef4 | 865 | addr.sun_len = slen; |
2d33ab91 | 866 | #endif |
42cc2bdf | 867 | if ((s = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" ); |
c10c9ef4 AJ |
868 | if (connect( s, (struct sockaddr *)&addr, slen ) != -1) |
869 | { | |
dcdb0d0b AJ |
870 | /* switch back to the starting directory */ |
871 | if (fd_cwd != -1) | |
872 | { | |
873 | fchdir( fd_cwd ); | |
874 | close( fd_cwd ); | |
875 | } | |
c10c9ef4 AJ |
876 | fcntl( s, F_SETFD, 1 ); /* set close on exec flag */ |
877 | return s; | |
878 | } | |
879 | close( s ); | |
2fe57779 | 880 | } |
4144b5b8 | 881 | server_connect_error( serverdir ); |
2fe57779 AJ |
882 | } |
883 | ||
884 | ||
c273498e AJ |
885 | #ifdef __APPLE__ |
886 | #include <mach/mach.h> | |
887 | #include <mach/mach_error.h> | |
888 | #include <servers/bootstrap.h> | |
889 | ||
890 | /* send our task port to the server */ | |
891 | static void send_server_task_port(void) | |
892 | { | |
893 | mach_port_t bootstrap_port, wineserver_port; | |
894 | kern_return_t kret; | |
895 | ||
896 | struct { | |
897 | mach_msg_header_t header; | |
898 | mach_msg_body_t body; | |
899 | mach_msg_port_descriptor_t task_port; | |
900 | } msg; | |
901 | ||
902 | if (task_get_bootstrap_port(mach_task_self(), &bootstrap_port) != KERN_SUCCESS) return; | |
903 | ||
904 | kret = bootstrap_look_up(bootstrap_port, (char*)wine_get_server_dir(), &wineserver_port); | |
905 | if (kret != KERN_SUCCESS) | |
906 | fatal_error( "cannot find the server port: 0x%08x\n", kret ); | |
907 | ||
908 | mach_port_deallocate(mach_task_self(), bootstrap_port); | |
909 | ||
910 | msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX; | |
911 | msg.header.msgh_size = sizeof(msg); | |
912 | msg.header.msgh_remote_port = wineserver_port; | |
913 | msg.header.msgh_local_port = MACH_PORT_NULL; | |
914 | ||
915 | msg.body.msgh_descriptor_count = 1; | |
916 | msg.task_port.name = mach_task_self(); | |
917 | msg.task_port.disposition = MACH_MSG_TYPE_COPY_SEND; | |
918 | msg.task_port.type = MACH_MSG_PORT_DESCRIPTOR; | |
919 | ||
920 | kret = mach_msg_send(&msg.header); | |
921 | if (kret != KERN_SUCCESS) | |
922 | server_protocol_error( "mach_msg_send failed: 0x%08x\n", kret ); | |
923 | ||
924 | mach_port_deallocate(mach_task_self(), wineserver_port); | |
925 | } | |
926 | #endif /* __APPLE__ */ | |
927 | ||
5adfec28 AJ |
928 | |
929 | /*********************************************************************** | |
930 | * get_unix_tid | |
931 | * | |
932 | * Retrieve the Unix tid to use on the server side for the current thread. | |
933 | */ | |
934 | static int get_unix_tid(void) | |
935 | { | |
936 | int ret = -1; | |
937 | #if defined(linux) && defined(__i386__) | |
938 | __asm__("int $0x80" : "=a" (ret) : "0" (224) /* SYS_gettid */); | |
939 | #elif defined(linux) && defined(__x86_64__) | |
940 | __asm__("syscall" : "=a" (ret) : "0" (186) /* SYS_gettid */); | |
941 | #elif defined(__sun) | |
942 | ret = pthread_self(); | |
943 | #elif defined(__APPLE__) | |
944 | ret = mach_thread_self(); | |
945 | #elif defined(__FreeBSD__) | |
946 | long lwpid; | |
947 | thr_self( &lwpid ); | |
948 | ret = lwpid; | |
949 | #endif | |
950 | return ret; | |
951 | } | |
952 | ||
953 | ||
642d3136 | 954 | /*********************************************************************** |
4dba172e | 955 | * server_init_process |
642d3136 | 956 | * |
f016752b | 957 | * Start the server and create the initial socket pair. |
642d3136 | 958 | */ |
4dba172e | 959 | void server_init_process(void) |
642d3136 | 960 | { |
1d2d0d56 | 961 | obj_handle_t version; |
c316f0e4 | 962 | const char *env_socket = getenv( "WINESERVERSOCKET" ); |
04869eb6 | 963 | |
c316f0e4 | 964 | if (env_socket) |
04869eb6 | 965 | { |
c316f0e4 AJ |
966 | fd_socket = atoi( env_socket ); |
967 | if (fcntl( fd_socket, F_SETFD, 1 ) == -1) | |
968 | fatal_perror( "Bad server socket %d", fd_socket ); | |
e0546309 | 969 | unsetenv( "WINESERVERSOCKET" ); |
04869eb6 | 970 | } |
870bba3e | 971 | else fd_socket = server_connect(); |
f5242405 AJ |
972 | |
973 | /* setup the signal mask */ | |
c388c58b AJ |
974 | sigemptyset( &server_block_set ); |
975 | sigaddset( &server_block_set, SIGALRM ); | |
976 | sigaddset( &server_block_set, SIGIO ); | |
977 | sigaddset( &server_block_set, SIGINT ); | |
978 | sigaddset( &server_block_set, SIGHUP ); | |
979 | sigaddset( &server_block_set, SIGUSR1 ); | |
980 | sigaddset( &server_block_set, SIGUSR2 ); | |
981 | sigaddset( &server_block_set, SIGCHLD ); | |
36334a1b | 982 | pthread_sigmask( SIG_BLOCK, &server_block_set, NULL ); |
f5242405 | 983 | |
8859d772 | 984 | /* receive the first thread request fd on the main socket */ |
1d2d0d56 | 985 | ntdll_get_thread_data()->request_fd = receive_fd( &version ); |
c273498e | 986 | |
1d2d0d56 AJ |
987 | if (version != SERVER_PROTOCOL_VERSION) |
988 | server_protocol_error( "version mismatch %d/%d.\n" | |
989 | "Your %s binary was not upgraded correctly,\n" | |
990 | "or you have an older one somewhere in your PATH.\n" | |
991 | "Or maybe the wrong wineserver is still running?\n", | |
992 | version, SERVER_PROTOCOL_VERSION, | |
993 | (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" ); | |
c273498e AJ |
994 | #ifdef __APPLE__ |
995 | send_server_task_port(); | |
996 | #endif | |
642d3136 AJ |
997 | } |
998 | ||
999 | ||
8891d6de AJ |
1000 | /*********************************************************************** |
1001 | * server_init_process_done | |
1002 | */ | |
1003 | NTSTATUS server_init_process_done(void) | |
1004 | { | |
1005 | PEB *peb = NtCurrentTeb()->Peb; | |
1006 | IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress ); | |
1007 | NTSTATUS status; | |
1008 | ||
1009 | /* Install signal handlers; this cannot be done earlier, since we cannot | |
1010 | * send exceptions to the debugger before the create process event that | |
1011 | * is sent by REQ_INIT_PROCESS_DONE. | |
1012 | * We do need the handlers in place by the time the request is over, so | |
1013 | * we set them up here. If we segfault between here and the server call | |
1014 | * something is very wrong... */ | |
531ff0be | 1015 | signal_init_process(); |
8891d6de AJ |
1016 | |
1017 | /* Signal the parent process to continue */ | |
1018 | SERVER_START_REQ( init_process_done ) | |
1019 | { | |
2cf868c0 AJ |
1020 | req->module = wine_server_client_ptr( peb->ImageBaseAddress ); |
1021 | #ifdef __i386__ | |
1022 | req->ldt_copy = wine_server_client_ptr( &wine_ldt_copy ); | |
1023 | #endif | |
c6c335d7 | 1024 | req->entry = wine_server_client_ptr( (char *)peb->ImageBaseAddress + nt->OptionalHeader.AddressOfEntryPoint ); |
2cf868c0 | 1025 | req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI); |
8891d6de AJ |
1026 | status = wine_server_call( req ); |
1027 | } | |
1028 | SERVER_END_REQ; | |
1029 | ||
8891d6de AJ |
1030 | return status; |
1031 | } | |
1032 | ||
1033 | ||
8859d772 | 1034 | /*********************************************************************** |
4dba172e | 1035 | * server_init_thread |
8859d772 AJ |
1036 | * |
1037 | * Send an init thread request. Return 0 if OK. | |
1038 | */ | |
5adfec28 | 1039 | size_t server_init_thread( void *entry_point ) |
8859d772 | 1040 | { |
1d2d0d56 | 1041 | int ret; |
e5dedb19 | 1042 | int reply_pipe[2]; |
22ae4ff6 | 1043 | struct sigaction sig_act; |
11ad6a0a | 1044 | size_t info_size; |
22ae4ff6 AJ |
1045 | |
1046 | sig_act.sa_handler = SIG_IGN; | |
1047 | sig_act.sa_flags = 0; | |
1048 | sigemptyset( &sig_act.sa_mask ); | |
8859d772 | 1049 | |
93416cda | 1050 | /* ignore SIGPIPE so that we get an EPIPE error instead */ |
22ae4ff6 | 1051 | sigaction( SIGPIPE, &sig_act, NULL ); |
103295c7 | 1052 | /* automatic child reaping to avoid zombies */ |
22ae4ff6 AJ |
1053 | #ifdef SA_NOCLDWAIT |
1054 | sig_act.sa_flags |= SA_NOCLDWAIT; | |
1055 | #endif | |
1056 | sigaction( SIGCHLD, &sig_act, NULL ); | |
8859d772 AJ |
1057 | |
1058 | /* create the server->client communication pipes */ | |
6f68b774 AJ |
1059 | if (server_pipe( reply_pipe ) == -1) server_protocol_perror( "pipe" ); |
1060 | if (server_pipe( ntdll_get_thread_data()->wait_fd ) == -1) server_protocol_perror( "pipe" ); | |
8859d772 | 1061 | wine_server_send_fd( reply_pipe[1] ); |
ab29aa21 AJ |
1062 | wine_server_send_fd( ntdll_get_thread_data()->wait_fd[1] ); |
1063 | ntdll_get_thread_data()->reply_fd = reply_pipe[0]; | |
714156d7 | 1064 | close( reply_pipe[1] ); |
8859d772 | 1065 | |
67a74999 | 1066 | SERVER_START_REQ( init_thread ) |
86113530 | 1067 | { |
5adfec28 AJ |
1068 | req->unix_pid = getpid(); |
1069 | req->unix_tid = get_unix_tid(); | |
fa864380 | 1070 | req->teb = wine_server_client_ptr( NtCurrentTeb() ); |
c6c335d7 | 1071 | req->entry = wine_server_client_ptr( entry_point ); |
8859d772 | 1072 | req->reply_fd = reply_pipe[1]; |
ab29aa21 | 1073 | req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; |
0424f381 | 1074 | req->debug_level = (TRACE_ON(server) != 0); |
653d2c4a | 1075 | req->cpu = client_cpu; |
9caa71ee | 1076 | ret = wine_server_call( req ); |
e142779b DT |
1077 | NtCurrentTeb()->ClientId.UniqueProcess = ULongToHandle(reply->pid); |
1078 | NtCurrentTeb()->ClientId.UniqueThread = ULongToHandle(reply->tid); | |
9ad56286 | 1079 | info_size = reply->info_size; |
9ad56286 | 1080 | server_start_time = reply->server_start; |
7e47d19d | 1081 | server_cpus = reply->all_cpus; |
86113530 AJ |
1082 | } |
1083 | SERVER_END_REQ; | |
8859d772 | 1084 | |
747d58d2 AJ |
1085 | #ifndef _WIN64 |
1086 | is_wow64 = (server_cpus & (1 << CPU_x86_64)) != 0; | |
1087 | #endif | |
1088 | ntdll_get_thread_data()->wow64_redir = is_wow64; | |
1089 | ||
279defe6 AJ |
1090 | if (ret) |
1091 | { | |
1092 | if (ret == STATUS_NOT_SUPPORTED) | |
1093 | { | |
1094 | static const char * const cpu_arch[] = { "x86", "x86_64", "Alpha", "PowerPC", "Sparc" }; | |
1095 | server_protocol_error( "the running wineserver doesn't support the %s architecture.\n", | |
1096 | cpu_arch[client_cpu] ); | |
1097 | } | |
1098 | else server_protocol_error( "init_thread failed with status %x\n", ret ); | |
1099 | } | |
11ad6a0a | 1100 | return info_size; |
767e6f6f | 1101 | } |