]>
Commit | Line | Data |
---|---|---|
9015e0fb | 1 | /* dtable.cc: file descriptor support. |
1fd5e000 | 2 | |
1fd5e000 CF |
3 | This file is part of Cygwin. |
4 | ||
5 | This software is a copyrighted work licensed under the terms of the | |
6 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
7 | details. */ | |
8 | ||
9 | #define __INSIDE_CYGWIN_NET__ | |
10 | ||
4c8d72de | 11 | #include "winsup.h" |
1fd5e000 CF |
12 | #include <stdlib.h> |
13 | #include <stdio.h> | |
1fd5e000 | 14 | #include <unistd.h> |
1ffe3e67 | 15 | #include <wchar.h> |
1fd5e000 | 16 | |
a1299ba5 | 17 | #define USE_SYS_TYPES_FD_SET |
d0b178fe | 18 | #include <winsock.h> |
e2ebe117 | 19 | #include "pinfo.h" |
9e2baf8d | 20 | #include "cygerrno.h" |
95a8465b | 21 | #include "perprocess.h" |
bccd5e0d | 22 | #include "path.h" |
7ac61736 | 23 | #include "fhandler.h" |
b4fa8164 | 24 | #include "select.h" |
bccd5e0d | 25 | #include "dtable.h" |
0381fec6 | 26 | #include "cygheap.h" |
ab5d348d | 27 | #include "tls_pbuf.h" |
2402700d | 28 | #include "ntdll.h" |
f09acf77 | 29 | #include "shared_info.h" |
1fd5e000 | 30 | |
61522196 CV |
31 | static const DWORD std_consts[] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, |
32 | STD_ERROR_HANDLE}; | |
164a681c | 33 | |
88f0dc31 | 34 | static bool handle_to_fn (HANDLE, char *); |
1ffe3e67 CF |
35 | |
36 | #define WCLEN(x) ((sizeof (x) / sizeof (WCHAR)) - 1) | |
c8a66289 CF |
37 | static const char unknown_file[] = "some disk file"; |
38 | static const WCHAR DEV_NULL[] = L"\\Device\\Null"; | |
019fc8d8 | 39 | static const WCHAR DEV_SOCKET[] = L"\\Device\\Afd"; |
1ffe3e67 | 40 | |
c8a66289 CF |
41 | static const WCHAR DEVICE_PREFIX[] = L"\\device\\"; |
42 | static const size_t DEVICE_PREFIX_LEN WCLEN (DEVICE_PREFIX); | |
1ffe3e67 CF |
43 | |
44 | static const WCHAR DEV_NAMED_PIPE[] = L"\\Device\\NamedPipe\\"; | |
45 | static const size_t DEV_NAMED_PIPE_LEN = WCLEN (DEV_NAMED_PIPE); | |
dd76747b | 46 | |
1ffe3e67 CF |
47 | static const WCHAR DEV_REMOTE[] = L"\\Device\\LanmanRedirector\\"; |
48 | static const size_t DEV_REMOTE_LEN = WCLEN (DEV_REMOTE); | |
49 | ||
50 | static const WCHAR DEV_REMOTE1[] = L"\\Device\\WinDfs\\Root\\"; | |
51 | static const size_t DEV_REMOTE1_LEN = WCLEN (DEV_REMOTE1); | |
634a4140 | 52 | |
1fd5e000 CF |
53 | /* Set aside space for the table of fds */ |
54 | void | |
2d1d1eb1 | 55 | dtable_init () |
1fd5e000 | 56 | { |
0381fec6 | 57 | if (!cygheap->fdtab.size) |
09244c00 | 58 | cygheap->fdtab.extend (NOFILE_INCR, 0); |
1fd5e000 CF |
59 | } |
60 | ||
30c5411d | 61 | void |
1fd5e000 CF |
62 | set_std_handle (int fd) |
63 | { | |
30fa1549 | 64 | fhandler_base *fh = cygheap->fdtab[fd]; |
1fd5e000 | 65 | if (fd == 0) |
30fa1549 | 66 | SetStdHandle (std_consts[fd], fh ? fh->get_handle () : NULL); |
164a681c | 67 | else if (fd <= 2) |
30fa1549 | 68 | SetStdHandle (std_consts[fd], fh ? fh->get_output_handle () : NULL); |
1fd5e000 CF |
69 | } |
70 | ||
71 | int | |
09244c00 | 72 | dtable::extend (size_t howmuch, size_t min) |
1fd5e000 | 73 | { |
eeaa47ef | 74 | size_t new_size = size + howmuch; |
1fd5e000 CF |
75 | fhandler_base **newfds; |
76 | ||
5b8358e6 | 77 | if (new_size <= OPEN_MAX) |
09244c00 | 78 | /* ok */; |
5b8358e6 KB |
79 | else if (size < OPEN_MAX && min < OPEN_MAX) |
80 | new_size = OPEN_MAX; | |
09244c00 | 81 | else |
4d782b42 CF |
82 | { |
83 | set_errno (EMFILE); | |
84 | return 0; | |
85 | } | |
86 | ||
c729f227 | 87 | /* Try to allocate more space for fd table. We can't call realloc () |
1fd5e000 CF |
88 | here to preserve old table if memory allocation fails */ |
89 | ||
b0e82b74 | 90 | if (!(newfds = (fhandler_base **) ccalloc (HEAP_ARGV, new_size, sizeof newfds[0]))) |
1fd5e000 CF |
91 | { |
92 | debug_printf ("calloc failed"); | |
4d782b42 | 93 | set_errno (ENOMEM); |
1fd5e000 CF |
94 | return 0; |
95 | } | |
96 | if (fds) | |
97 | { | |
4d782b42 | 98 | memcpy (newfds, fds, size * sizeof (fds[0])); |
3301015b | 99 | cfree (fds); |
1fd5e000 CF |
100 | } |
101 | ||
102 | size = new_size; | |
103 | fds = newfds; | |
61522196 | 104 | debug_printf ("size %ld, fds %p", size, fds); |
1fd5e000 CF |
105 | return 1; |
106 | } | |
107 | ||
083abe54 CF |
108 | void |
109 | dtable::get_debugger_info () | |
110 | { | |
3c4f2024 CF |
111 | extern bool jit_debug; |
112 | if (!jit_debug && being_debugged ()) | |
083abe54 | 113 | { |
23771fa1 | 114 | char std[3][sizeof ("/dev/ptyNNNN")]; |
083abe54 | 115 | std[0][0] = std[1][0] = std [2][0] = '\0'; |
61522196 CV |
116 | char buf[sizeof ("cYgstd %x") + 64]; |
117 | sprintf (buf, "cYgstd %p %zx %x", &std, sizeof (std[0]), 3); | |
083abe54 CF |
118 | OutputDebugString (buf); |
119 | for (int i = 0; i < 3; i++) | |
120 | if (std[i][0]) | |
121 | { | |
083abe54 | 122 | HANDLE h = GetStdHandle (std_consts[i]); |
7ac61736 | 123 | fhandler_base *fh = build_fh_name (std[i]); |
083abe54 CF |
124 | if (!fh) |
125 | continue; | |
7ac61736 | 126 | fds[i] = fh; |
061095b5 CV |
127 | if (!fh->open ((i ? (i == 2 ? O_RDWR : O_WRONLY) : O_RDONLY) |
128 | | O_BINARY, 0777)) | |
083abe54 CF |
129 | release (i); |
130 | else | |
8f19b4b6 CV |
131 | { |
132 | CloseHandle (h); | |
133 | /* Copy to Windows' idea of a standard handle, otherwise | |
134 | we have invalid standard handles when calling Windows | |
135 | functions (small_printf and strace might suffer, too). */ | |
136 | SetStdHandle (std_consts[i], i ? fh->get_output_handle () | |
137 | : fh->get_handle ()); | |
138 | } | |
083abe54 CF |
139 | } |
140 | } | |
141 | } | |
142 | ||
1fd5e000 | 143 | /* Initialize the file descriptor/handle mapping table. |
10dedaaa CF |
144 | This function should only be called when a cygwin function is invoked |
145 | by a non-cygwin function, i.e., it should only happen very rarely. */ | |
1fd5e000 CF |
146 | |
147 | void | |
083abe54 | 148 | dtable::stdio_init () |
1fd5e000 | 149 | { |
8cb359d9 | 150 | if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT)) |
3eb92a58 | 151 | { |
44d2fc0a | 152 | tty_min *t = cygwin_shared->tty.get_cttyp (); |
a345dc55 | 153 | if (t && t->is_console) |
f09acf77 | 154 | init_console_handler (true); |
3eb92a58 CF |
155 | return; |
156 | } | |
1fd5e000 | 157 | |
083abe54 CF |
158 | HANDLE in = GetStdHandle (STD_INPUT_HANDLE); |
159 | HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); | |
160 | HANDLE err = GetStdHandle (STD_ERROR_HANDLE); | |
1fd5e000 | 161 | |
54030e21 | 162 | init_std_file_from_handle (0, in); |
083abe54 CF |
163 | |
164 | /* STD_ERROR_HANDLE has been observed to be the same as | |
165 | STD_OUTPUT_HANDLE. We need separate handles (e.g. using pipes | |
166 | to pass data from child to parent). */ | |
edf5a5bd CV |
167 | /* CV 2008-10-17: Under debugger control, std fd's have been potentially |
168 | initialized in dtable::get_debugger_info (). In this case | |
169 | init_std_file_from_handle is a no-op, so, even if out == err we don't | |
170 | want to duplicate the handle since it will be unused. */ | |
8f19b4b6 | 171 | if (out == err && (!being_debugged () || not_open (2))) |
083abe54 CF |
172 | { |
173 | /* Since this code is not invoked for forked tasks, we don't have | |
174 | to worry about the close-on-exec flag here. */ | |
7bdbf062 CV |
175 | if (!DuplicateHandle (GetCurrentProcess (), out, |
176 | GetCurrentProcess (), &err, | |
177 | 0, TRUE, DUPLICATE_SAME_ACCESS)) | |
1fd5e000 | 178 | { |
083abe54 CF |
179 | /* If that fails, do this as a fall back. */ |
180 | err = out; | |
7bdbf062 | 181 | system_printf ("couldn't make stderr distinct from stdout, %E"); |
1fd5e000 | 182 | } |
1fd5e000 | 183 | } |
083abe54 | 184 | |
54030e21 CF |
185 | init_std_file_from_handle (1, out); |
186 | init_std_file_from_handle (2, err); | |
1fd5e000 CF |
187 | } |
188 | ||
8e10c431 CF |
189 | const int dtable::initial_archetype_size; |
190 | ||
191 | fhandler_base * | |
192 | dtable::find_archetype (device& dev) | |
193 | { | |
194 | for (unsigned i = 0; i < farchetype; i++) | |
61522196 | 195 | if (archetypes[i]->get_device () == (dev_t) dev) |
8e10c431 CF |
196 | return archetypes[i]; |
197 | return NULL; | |
198 | } | |
199 | ||
200 | fhandler_base ** | |
201 | dtable::add_archetype () | |
202 | { | |
203 | if (farchetype++ >= narchetypes) | |
634a4140 | 204 | archetypes = (fhandler_base **) crealloc_abort (archetypes, (narchetypes += initial_archetype_size) * sizeof archetypes[0]); |
8e10c431 CF |
205 | return archetypes + farchetype - 1; |
206 | } | |
207 | ||
208 | void | |
209 | dtable::delete_archetype (fhandler_base *fh) | |
210 | { | |
8ed5c9b6 | 211 | for (unsigned i = 0; i < farchetype; i++) |
8e10c431 CF |
212 | if (fh == archetypes[i]) |
213 | { | |
6ae28c22 CF |
214 | debug_printf ("deleting element %d for %s(%d/%d)", i, fh->get_name (), |
215 | fh->dev ().get_major (), fh->dev ().get_minor ()); | |
8e10c431 CF |
216 | if (i < --farchetype) |
217 | archetypes[i] = archetypes[farchetype]; | |
218 | break; | |
219 | } | |
220 | ||
221 | delete fh; | |
222 | } | |
223 | ||
1fd5e000 | 224 | int |
499494d2 | 225 | dtable::find_unused_handle (size_t start) |
1fd5e000 | 226 | { |
09244c00 | 227 | /* When extending, try to allocate a NOFILE_INCR chunk |
9915ebec CF |
228 | following the empty fd. */ |
229 | size_t extendby = NOFILE_INCR + ((start >= size) ? 1 + start - size : 0); | |
f456b9f6 | 230 | |
499494d2 | 231 | /* This do loop should only ever execute twice. */ |
f456b9f6 | 232 | int res = -1; |
1fd5e000 CF |
233 | do |
234 | { | |
e773b7cf | 235 | for (size_t i = start; i < size; i++) |
91892f50 | 236 | if (fds[i] == NULL) |
f456b9f6 CF |
237 | { |
238 | res = (int) i; | |
9262c055 | 239 | goto out; |
f456b9f6 | 240 | } |
1fd5e000 | 241 | } |
09244c00 | 242 | while (extend (extendby, start)); |
9262c055 | 243 | out: |
f456b9f6 | 244 | return res; |
1fd5e000 CF |
245 | } |
246 | ||
0646a508 | 247 | void |
9015e0fb | 248 | dtable::release (int fd) |
1fd5e000 | 249 | { |
0646a508 CF |
250 | if (fds[fd]->need_fixup_before ()) |
251 | dec_need_fixup_before (); | |
3143cb7c | 252 | fds[fd]->dec_refcnt (); |
0646a508 | 253 | fds[fd] = NULL; |
30fa1549 CF |
254 | if (fd <= 2) |
255 | set_std_handle (fd); | |
1fd5e000 CF |
256 | } |
257 | ||
45586380 | 258 | extern "C" int |
ebd645e7 CF |
259 | cygwin_attach_handle_to_fd (char *name, int fd, HANDLE handle, mode_t bin, |
260 | DWORD myaccess) | |
261 | { | |
f456b9f6 | 262 | cygheap->fdtab.lock (); |
ebd645e7 CF |
263 | if (fd == -1) |
264 | fd = cygheap->fdtab.find_unused_handle (); | |
7ac61736 | 265 | fhandler_base *fh = build_fh_name (name); |
e5b7e4d1 | 266 | if (!fh) |
f456b9f6 CF |
267 | fd = -1; |
268 | else | |
269 | { | |
270 | cygheap->fdtab[fd] = fh; | |
271 | cygheap->fdtab[fd]->inc_refcnt (); | |
272 | fh->init (handle, myaccess, bin ?: fh->pc_binmode ()); | |
273 | } | |
274 | cygheap->fdtab.unlock (); | |
ebd645e7 CF |
275 | return fd; |
276 | } | |
277 | ||
1fd5e000 | 278 | void |
54030e21 | 279 | dtable::init_std_file_from_handle (int fd, HANDLE handle) |
1fd5e000 | 280 | { |
5e7c84e5 | 281 | tmp_pathbuf tp; |
ebd645e7 | 282 | CONSOLE_SCREEN_BUFFER_INFO buf; |
ebd645e7 | 283 | DCB dcb; |
abb58a6d | 284 | unsigned bin = O_BINARY; |
b2867a68 | 285 | device dev; |
ebd645e7 CF |
286 | |
287 | first_fd_for_open = 0; | |
1ac6d1a1 | 288 | |
083abe54 CF |
289 | if (!not_open (fd)) |
290 | return; | |
291 | ||
cef69559 | 292 | SetLastError (0); |
1ffe3e67 | 293 | DWORD access = 0; |
cef69559 | 294 | DWORD ft = GetFileType (handle); |
5e7c84e5 | 295 | char *name = tp.c_get (); |
1ffe3e67 | 296 | name[0] = '\0'; |
88f0dc31 CF |
297 | if (ft == FILE_TYPE_UNKNOWN && GetLastError () == ERROR_INVALID_HANDLE) |
298 | /* can't figure out what this is */; | |
299 | else if (ft == FILE_TYPE_PIPE) | |
1fd5e000 | 300 | { |
019fc8d8 CV |
301 | int rcv = 0, len = sizeof (int); |
302 | ||
88f0dc31 | 303 | if (handle_to_fn (handle, name)) |
02a33ea7 | 304 | dev.parse (name); |
019fc8d8 | 305 | else if (strcmp (name, ":sock:") == 0 |
02dbd9ae | 306 | /* NtQueryObject returns an error when called on an LSP socket |
859d215b CV |
307 | handle. fhandler_socket::set_socket_handle tries to fetch |
308 | the underlying base socket, but this might fail. */ | |
019fc8d8 CV |
309 | || (strcmp (name, unknown_file) == 0 |
310 | && !::getsockopt ((SOCKET) handle, SOL_SOCKET, SO_RCVBUF, | |
311 | (char *) &rcv, &len))) | |
312 | { | |
313 | /* socket */ | |
03f380c2 | 314 | dev = *af_inet_dev; |
019fc8d8 CV |
315 | name[0] = '\0'; |
316 | } | |
1ffe3e67 CF |
317 | else if (fd == 0) |
318 | dev = *piper_dev; | |
4ab6034f | 319 | else |
1ffe3e67 | 320 | dev = *pipew_dev; |
4ab6034f | 321 | } |
92ddb742 | 322 | else if (GetConsoleScreenBufferInfo (handle, &buf) |
b86f999a | 323 | || GetNumberOfConsoleInputEvents (handle, (DWORD *) &buf)) |
1ffe3e67 | 324 | { |
92ddb742 | 325 | /* Console I/O */ |
13a84ac7 | 326 | if (CTTY_IS_VALID (myself->ctty)) |
44d2fc0a | 327 | dev.parse (myself->ctty); |
1ffe3e67 | 328 | else |
6ae28c22 CF |
329 | { |
330 | dev.parse (FH_CONSOLE); | |
331 | CloseHandle (handle); | |
332 | handle = INVALID_HANDLE_VALUE; | |
333 | } | |
1ffe3e67 | 334 | } |
1ffe3e67 | 335 | else if (GetCommState (handle, &dcb)) |
92ddb742 CF |
336 | /* FIXME: Not right - assumes ttyS0 */ |
337 | dev.parse (DEV_SERIAL_MAJOR, 0); | |
1ffe3e67 CF |
338 | else |
339 | /* Try to figure it out from context - probably a disk file */ | |
340 | handle_to_fn (handle, name); | |
cef69559 | 341 | |
1ffe3e67 | 342 | if (!name[0] && !dev) |
cef69559 CF |
343 | fds[fd] = NULL; |
344 | else | |
4ab6034f | 345 | { |
7ac61736 CF |
346 | fhandler_base *fh; |
347 | ||
348 | if (dev) | |
1ffe3e67 | 349 | fh = build_fh_dev (dev); |
7ac61736 CF |
350 | else |
351 | fh = build_fh_name (name); | |
352 | ||
e5b7e4d1 CF |
353 | if (!fh) |
354 | return; | |
355 | ||
1ffe3e67 | 356 | if (name[0]) |
abb58a6d | 357 | { |
634a4140 CF |
358 | bin = fh->pc_binmode (); |
359 | if (!bin) | |
360 | { | |
361 | bin = fh->get_default_fmode (O_RDWR); | |
362 | if (!bin && dev) | |
363 | bin = O_BINARY; | |
364 | } | |
abb58a6d | 365 | } |
9655ff26 | 366 | |
02a33ea7 CV |
367 | IO_STATUS_BLOCK io; |
368 | FILE_ACCESS_INFORMATION fai; | |
6ae28c22 | 369 | int openflags = O_BINARY; |
02a33ea7 | 370 | |
1091d440 | 371 | /* Console windows are no kernel objects up to Windows 7/2008R2, so the |
d2ef2331 | 372 | access mask returned by NtQueryInformationFile is meaningless. CMD |
1091d440 CV |
373 | always hands down stdin handles as R/O handles, but our tty slave |
374 | sides are R/W. */ | |
06f46dc3 | 375 | if (fh->is_tty ()) |
6ae28c22 CF |
376 | { |
377 | openflags |= O_RDWR; | |
378 | access |= GENERIC_READ | GENERIC_WRITE; | |
379 | } | |
380 | else if (!iscons_dev (dev) | |
381 | && NT_SUCCESS (NtQueryInformationFile (handle, &io, &fai, | |
382 | sizeof fai, | |
383 | FileAccessInformation))) | |
02a33ea7 | 384 | { |
02a33ea7 | 385 | if (fai.AccessFlags & FILE_WRITE_DATA) |
6ae28c22 CF |
386 | { |
387 | openflags |= O_WRONLY; | |
388 | access |= GENERIC_WRITE; | |
389 | } | |
390 | if (fai.AccessFlags & FILE_READ_DATA) | |
391 | { | |
392 | openflags |= openflags & O_WRONLY ? O_RDWR : O_RDONLY; | |
393 | access |= GENERIC_READ; | |
394 | } | |
02a33ea7 | 395 | } |
4248960e | 396 | else if (fd == 0) |
6ae28c22 CF |
397 | { |
398 | openflags |= O_RDONLY; | |
399 | access |= GENERIC_READ; | |
400 | } | |
70300fdb | 401 | else |
6ae28c22 CF |
402 | { |
403 | openflags |= O_WRONLY; | |
404 | access |= GENERIC_WRITE; /* Should be rdwr for stderr but not sure that's | |
405 | possible for some versions of handles */ | |
406 | } | |
407 | if (!fh->init (handle, access, bin)) | |
3c4f2024 | 408 | api_fatal ("couldn't initialize fd %d for %s", fd, fh->get_name ()); |
99be2383 KB |
409 | if (fh->ispipe ()) |
410 | { | |
411 | fhandler_pipe *fhp = (fhandler_pipe *) fh; | |
412 | fhp->set_pipe_buf_size (); | |
90788821 TY |
413 | /* Set read pipe always to nonblocking */ |
414 | fhp->set_pipe_non_blocking (fhp->get_device () == FH_PIPER ? | |
415 | true : fhp->is_nonblocking ()); | |
99be2383 | 416 | } |
1ae0a7c5 | 417 | |
be08c5c4 KB |
418 | if (!fh->open_setup (openflags)) |
419 | api_fatal ("open_setup failed, %E"); | |
6ae28c22 | 420 | fh->usecount = 0; |
1ae0a7c5 | 421 | cygheap->fdtab[fd] = fh; |
3143cb7c | 422 | cygheap->fdtab[fd]->inc_refcnt (); |
1ae0a7c5 | 423 | set_std_handle (fd); |
cef69559 | 424 | paranoid_printf ("fd %d, handle %p", fd, handle); |
2cab4d0b | 425 | fh->post_open_setup (fd); |
1fd5e000 | 426 | } |
1fd5e000 CF |
427 | } |
428 | ||
3d938be6 CV |
429 | #define cnew(name, ...) \ |
430 | ({ \ | |
431 | void* ptr = (void*) ccalloc (HEAP_FHANDLER, 1, sizeof (name)); \ | |
c38da4ee | 432 | ptr ? new (ptr) name (__VA_ARGS__) : NULL; \ |
3d938be6 | 433 | }) |
1ffe3e67 | 434 | |
23771fa1 CF |
435 | #define cnew_no_ctor(name, ...) \ |
436 | ({ \ | |
437 | void* ptr = (void*) ccalloc (HEAP_FHANDLER, 1, sizeof (name)); \ | |
438 | ptr ? new (ptr) name (ptr) : NULL; \ | |
439 | }) | |
440 | ||
4ee93264 CV |
441 | fhandler_base * |
442 | build_fh_name (const char *name, unsigned opt, suffix_info *si) | |
1fd5e000 | 443 | { |
4ee93264 | 444 | path_conv pc (name, opt | PC_NULLEMPTY | PC_POSIX, si); |
4ab6034f CF |
445 | if (pc.error) |
446 | { | |
3d938be6 CV |
447 | fhandler_base *fh = cnew (fhandler_nodevice); |
448 | if (fh) | |
6a7bea70 CF |
449 | fh->set_error (pc.error); |
450 | set_errno (fh ? pc.error : EMFILE); | |
e00700cd | 451 | return fh; |
1fd5e000 CF |
452 | } |
453 | ||
7ac61736 | 454 | return build_fh_pc (pc); |
1fd5e000 CF |
455 | } |
456 | ||
457 | fhandler_base * | |
7ac61736 | 458 | build_fh_dev (const device& dev, const char *unix_name) |
ff938546 | 459 | { |
7ac61736 | 460 | path_conv pc (dev); |
7ac61736 | 461 | if (unix_name) |
d2bd82aa | 462 | pc.set_posix (unix_name); |
7ac61736 | 463 | else |
b2867a68 | 464 | pc.set_posix (dev.name ()); |
7ac61736 | 465 | return build_fh_pc (pc); |
ff938546 CF |
466 | } |
467 | ||
6a7bea70 | 468 | #define fh_unset ((fhandler_base *) 1) |
6ae28c22 CF |
469 | static device last_tty_dev; |
470 | #define fh_last_tty_dev ((fhandler_termios *) cygheap->fdtab.find_archetype (last_tty_dev)) | |
23771fa1 | 471 | |
92ddb742 | 472 | static fhandler_base * |
23771fa1 | 473 | fh_alloc (path_conv& pc) |
1fd5e000 | 474 | { |
6a7bea70 | 475 | fhandler_base *fh = fh_unset; |
23771fa1 | 476 | fhandler_base *fhraw = NULL; |
1fd5e000 | 477 | |
23771fa1 | 478 | switch (pc.dev.get_major ()) |
7b02cb30 | 479 | { |
38d732a1 | 480 | case DEV_PTYS_MAJOR: |
23771fa1 CF |
481 | fh = cnew (fhandler_pty_slave, pc.dev.get_minor ()); |
482 | break; | |
38d732a1 | 483 | case DEV_PTYM_MAJOR: |
23771fa1 | 484 | fh = cnew (fhandler_pty_master, pc.dev.get_minor ()); |
7b02cb30 | 485 | break; |
7b02cb30 CF |
486 | case DEV_FLOPPY_MAJOR: |
487 | case DEV_CDROM_MAJOR: | |
488 | case DEV_SD_MAJOR: | |
b2867a68 CV |
489 | case DEV_SD1_MAJOR ... DEV_SD7_MAJOR: |
490 | case DEV_SD_HIGHPART_START ... DEV_SD_HIGHPART_END: | |
3d938be6 | 491 | fh = cnew (fhandler_dev_floppy); |
7b02cb30 CF |
492 | break; |
493 | case DEV_TAPE_MAJOR: | |
3d938be6 | 494 | fh = cnew (fhandler_dev_tape); |
7b02cb30 CF |
495 | break; |
496 | case DEV_SERIAL_MAJOR: | |
3d938be6 | 497 | fh = cnew (fhandler_serial); |
7b02cb30 | 498 | break; |
44d2fc0a | 499 | case DEV_CONS_MAJOR: |
23771fa1 | 500 | fh = cnew (fhandler_console, pc.dev); |
44d2fc0a | 501 | break; |
7b02cb30 | 502 | default: |
61522196 | 503 | switch ((dev_t) pc.dev) |
7b02cb30 CF |
504 | { |
505 | case FH_CONSOLE: | |
506 | case FH_CONIN: | |
507 | case FH_CONOUT: | |
23771fa1 | 508 | fh = cnew (fhandler_console, pc.dev); |
7b02cb30 | 509 | break; |
23771fa1 CF |
510 | case FH_PTMX: |
511 | if (pc.isopen ()) | |
b03601a6 | 512 | fh = cnew (fhandler_pty_master, -1, (dev_t) pc.dev); |
23771fa1 | 513 | else |
1b23b30b | 514 | fhraw = cnew_no_ctor (fhandler_pty_master, -1); |
7b02cb30 CF |
515 | break; |
516 | case FH_WINDOWS: | |
3d938be6 | 517 | fh = cnew (fhandler_windows); |
7b02cb30 CF |
518 | break; |
519 | case FH_FIFO: | |
3d938be6 | 520 | fh = cnew (fhandler_fifo); |
7b02cb30 CF |
521 | break; |
522 | case FH_PIPE: | |
523 | case FH_PIPER: | |
524 | case FH_PIPEW: | |
3d938be6 | 525 | fh = cnew (fhandler_pipe); |
7b02cb30 | 526 | break; |
03f380c2 | 527 | case FH_INET: |
859d215b CV |
528 | fh = cnew (fhandler_socket_inet); |
529 | break; | |
03f380c2 | 530 | case FH_LOCAL: |
859d215b | 531 | fh = cnew (fhandler_socket_local); |
7b02cb30 | 532 | break; |
6c55be9d | 533 | #ifdef __WITH_AF_UNIX |
7f7532fa CV |
534 | case FH_UNIX: |
535 | fh = cnew (fhandler_socket_unix); | |
536 | break; | |
6c55be9d | 537 | #endif /* __WITH_AF_UNIX */ |
7b02cb30 | 538 | case FH_FS: |
3d938be6 | 539 | fh = cnew (fhandler_disk_file); |
7b02cb30 CF |
540 | break; |
541 | case FH_NULL: | |
3d938be6 | 542 | fh = cnew (fhandler_dev_null); |
7b02cb30 CF |
543 | break; |
544 | case FH_ZERO: | |
545 | case FH_FULL: | |
3d938be6 | 546 | fh = cnew (fhandler_dev_zero); |
7b02cb30 CF |
547 | break; |
548 | case FH_RANDOM: | |
549 | case FH_URANDOM: | |
3d938be6 | 550 | fh = cnew (fhandler_dev_random); |
7b02cb30 | 551 | break; |
7b02cb30 | 552 | case FH_CLIPBOARD: |
3d938be6 | 553 | fh = cnew (fhandler_dev_clipboard); |
7b02cb30 | 554 | break; |
2a4af366 TY |
555 | case FH_OSS_MIXER: |
556 | fh = cnew (fhandler_dev_mixer); | |
557 | break; | |
7b02cb30 | 558 | case FH_OSS_DSP: |
3d938be6 | 559 | fh = cnew (fhandler_dev_dsp); |
7b02cb30 CF |
560 | break; |
561 | case FH_PROC: | |
3d938be6 | 562 | fh = cnew (fhandler_proc); |
7b02cb30 CF |
563 | break; |
564 | case FH_REGISTRY: | |
3d938be6 | 565 | fh = cnew (fhandler_registry); |
7b02cb30 CF |
566 | break; |
567 | case FH_PROCESS: | |
3d938be6 | 568 | fh = cnew (fhandler_process); |
7b02cb30 | 569 | break; |
7aca27b4 CV |
570 | case FH_PROCESSFD: |
571 | fh = cnew (fhandler_process_fd); | |
572 | break; | |
96d7dee2 | 573 | case FH_PROCNET: |
3d938be6 | 574 | fh = cnew (fhandler_procnet); |
96d7dee2 | 575 | break; |
43f65cdd | 576 | case FH_PROCSYS: |
3d938be6 | 577 | fh = cnew (fhandler_procsys); |
43f65cdd | 578 | break; |
d68288f6 | 579 | case FH_PROCSYSVIPC: |
3d938be6 | 580 | fh = cnew (fhandler_procsysvipc); |
d68288f6 | 581 | break; |
7b02cb30 | 582 | case FH_NETDRIVE: |
3d938be6 | 583 | fh = cnew (fhandler_netdrive); |
7b02cb30 | 584 | break; |
1f312200 CV |
585 | case FH_DEV: |
586 | fh = cnew (fhandler_dev); | |
587 | break; | |
c8cf1933 CF |
588 | case FH_DEV_DISK: |
589 | fh = cnew (fhandler_dev_disk); | |
590 | break; | |
4ec08891 JS |
591 | case FH_DEV_FD: |
592 | fh = cnew (fhandler_dev_fd); | |
593 | break; | |
f7c8c454 CV |
594 | case FH_CYGDRIVE: |
595 | fh = cnew (fhandler_cygdrive); | |
596 | break; | |
9d13a299 CV |
597 | case FH_SIGNALFD: |
598 | fh = cnew (fhandler_signalfd); | |
599 | break; | |
068182e2 CV |
600 | case FH_TIMERFD: |
601 | fh = cnew (fhandler_timerfd); | |
602 | break; | |
4fc922b2 CV |
603 | case FH_MQUEUE: |
604 | fh = cnew (fhandler_mqueue); | |
605 | break; | |
7b02cb30 | 606 | case FH_TTY: |
23771fa1 | 607 | if (!pc.isopen ()) |
38d732a1 | 608 | { |
3edb55af TY |
609 | if (CTTY_IS_VALID (myself->ctty)) |
610 | { | |
611 | if (iscons_dev (myself->ctty)) | |
612 | fhraw = cnew_no_ctor (fhandler_console, -1); | |
613 | else | |
614 | fhraw = cnew_no_ctor (fhandler_pty_slave, -1); | |
615 | } | |
6ae28c22 CF |
616 | debug_printf ("not called from open for /dev/tty"); |
617 | } | |
13a84ac7 | 618 | else if (!CTTY_IS_VALID (myself->ctty) && last_tty_dev |
6ae28c22 CF |
619 | && !myself->set_ctty (fh_last_tty_dev, 0)) |
620 | debug_printf ("no /dev/tty assigned"); | |
13a84ac7 | 621 | else if (CTTY_IS_VALID (myself->ctty)) |
6ae28c22 CF |
622 | { |
623 | debug_printf ("determining /dev/tty assignment for ctty %p", myself->ctty); | |
38d732a1 CF |
624 | if (iscons_dev (myself->ctty)) |
625 | fh = cnew (fhandler_console, pc.dev); | |
626 | else | |
b03601a6 TY |
627 | fh = cnew (fhandler_pty_slave, |
628 | minor (myself->ctty), (dev_t) pc.dev); | |
6ae28c22 CF |
629 | if (fh->dev () != FH_NADA) |
630 | fh->set_name ("/dev/tty"); | |
38d732a1 | 631 | } |
23771fa1 | 632 | break; |
0e1ba888 | 633 | } |
7b02cb30 | 634 | } |
7ac61736 | 635 | |
23771fa1 CF |
636 | /* If `fhraw' is set that means that this fhandler is just a dummy |
637 | set up for stat(). Mock it up for use by stat without actually | |
638 | trying to do any real initialization. */ | |
639 | if (fhraw) | |
640 | { | |
641 | fh = fhraw; | |
642 | fh->set_name (pc); | |
643 | if (fh->use_archetype ()) | |
644 | fh->archetype = fh; | |
645 | } | |
2e82c935 | 646 | if (fh == fh_unset) |
3d938be6 | 647 | fh = cnew (fhandler_nodevice); |
23771fa1 CF |
648 | else if (fh->dev () == FH_ERROR) |
649 | { | |
8b4bd082 | 650 | if (!pc.isopen () && pc.dev.isfs ()) |
080f275b | 651 | fh->dev () = pc.dev; /* Special case: This file actually exists on |
8b4bd082 CF |
652 | disk and we're not trying to open it so just |
653 | return the info from pc. */ | |
080f275b CF |
654 | else |
655 | { | |
656 | delete fh; | |
657 | fh = NULL; | |
658 | } | |
23771fa1 | 659 | } |
92ddb742 CF |
660 | return fh; |
661 | } | |
662 | ||
663 | fhandler_base * | |
6ae28c22 | 664 | build_fh_pc (path_conv& pc) |
92ddb742 | 665 | { |
23771fa1 | 666 | fhandler_base *fh = fh_alloc (pc); |
2e82c935 | 667 | |
1c1b04b8 | 668 | if (!fh) |
9e1fd6bc | 669 | { |
23771fa1 | 670 | set_errno (ENXIO); |
9e1fd6bc CV |
671 | goto out; |
672 | } | |
7ac61736 | 673 | |
92ddb742 | 674 | if (!fh->use_archetype ()) |
6ae28c22 | 675 | fh->set_name (pc); |
92ddb742 | 676 | else if ((fh->archetype = cygheap->fdtab.find_archetype (fh->dev ()))) |
6ae28c22 CF |
677 | { |
678 | debug_printf ("found an archetype for %s(%d/%d) io_handle %p", fh->get_name (), fh->dev ().get_major (), fh->dev ().get_minor (), | |
a9c661a9 | 679 | fh->archetype->get_handle ()); |
6ae28c22 | 680 | if (!fh->get_name ()) |
b2867a68 | 681 | fh->set_name (fh->archetype->dev ().name ()); |
6ae28c22 CF |
682 | } |
683 | else if (cygwin_finished_initializing && !pc.isopen ()) | |
684 | fh->set_name (pc); | |
92ddb742 CF |
685 | else |
686 | { | |
6ae28c22 | 687 | if (!fh->get_name ()) |
b2867a68 | 688 | fh->set_name (fh->dev ().native ()); |
23771fa1 CF |
689 | fh->archetype = fh->clone (); |
690 | debug_printf ("created an archetype (%p) for %s(%d/%d)", fh->archetype, fh->get_name (), fh->dev ().get_major (), fh->dev ().get_minor ()); | |
92ddb742 CF |
691 | fh->archetype->archetype = NULL; |
692 | *cygheap->fdtab.add_archetype () = fh->archetype; | |
693 | } | |
694 | ||
6ae28c22 CF |
695 | |
696 | /* Keep track of the last tty-like thing opened. We could potentially want | |
697 | to open it if /dev/tty is referenced. */ | |
13a84ac7 | 698 | if (CTTY_IS_VALID (myself->ctty) || !fh->is_tty () || !pc.isctty_capable ()) |
6ae28c22 CF |
699 | last_tty_dev = FH_NADA; |
700 | else | |
701 | last_tty_dev = fh->dev (); | |
23771fa1 | 702 | |
c3a9063f | 703 | out: |
61522196 | 704 | debug_printf ("fh %p, dev %08x", fh, fh ? (dev_t) fh->dev () : 0); |
7ac61736 | 705 | return fh; |
1fd5e000 CF |
706 | } |
707 | ||
708 | fhandler_base * | |
e70fdfb9 | 709 | dtable::dup_worker (fhandler_base *oldfh, int flags) |
1fd5e000 | 710 | { |
23771fa1 | 711 | fhandler_base *newfh = oldfh->clone (); |
6a7bea70 | 712 | if (!newfh) |
b6624e23 | 713 | debug_printf ("clone failed"); |
6a7bea70 | 714 | else |
1fd5e000 | 715 | { |
92ddb742 | 716 | if (!oldfh->archetype) |
a9c661a9 | 717 | newfh->set_handle (NULL); |
23771fa1 | 718 | |
5f0913df | 719 | newfh->pc.close_conv_handle (); |
23771fa1 | 720 | if (oldfh->dup (newfh, flags)) |
6a7bea70 | 721 | { |
1c1b04b8 CV |
722 | delete newfh; |
723 | newfh = NULL; | |
6a7bea70 CF |
724 | debug_printf ("oldfh->dup failed"); |
725 | } | |
726 | else | |
727 | { | |
8fa8b3a3 CF |
728 | /* Don't increment refcnt here since we don't know if this is a |
729 | allocated fd. So we leave this chore to the caller. */ | |
730 | ||
92ddb742 CF |
731 | newfh->usecount = 0; |
732 | newfh->archetype_usecount (1); | |
8fa8b3a3 | 733 | |
e70fdfb9 | 734 | /* The O_CLOEXEC flag enforces close-on-exec behaviour. */ |
92ddb742 | 735 | newfh->set_close_on_exec (!!(flags & O_CLOEXEC)); |
4eb5175d | 736 | debug_printf ("duped '%s' old %p, new %p", oldfh->get_name (), |
a9c661a9 | 737 | oldfh->get_handle (), newfh->get_handle ()); |
6a7bea70 | 738 | } |
1fd5e000 | 739 | } |
1fd5e000 CF |
740 | return newfh; |
741 | } | |
742 | ||
743 | int | |
e70fdfb9 | 744 | dtable::dup3 (int oldfd, int newfd, int flags) |
1fd5e000 CF |
745 | { |
746 | int res = -1; | |
747 | fhandler_base *newfh = NULL; // = NULL to avoid an incorrect warning | |
748 | ||
61522196 | 749 | debug_printf ("dup3 (%d, %d, %y)", oldfd, newfd, flags); |
2d1d1eb1 | 750 | lock (); |
3143cb7c | 751 | bool do_unlock = true; |
b9c61a8d CF |
752 | bool unlock_on_return; |
753 | if (!(flags & O_EXCL)) | |
754 | unlock_on_return = true; /* Relinquish lock on return */ | |
755 | else | |
756 | { | |
757 | flags &= ~O_EXCL; | |
758 | unlock_on_return = false; /* Return with lock set on success */ | |
759 | } | |
1fd5e000 CF |
760 | |
761 | if (not_open (oldfd)) | |
762 | { | |
5a449743 | 763 | syscall_printf ("fd %d not open", oldfd); |
1fd5e000 CF |
764 | set_errno (EBADF); |
765 | goto done; | |
766 | } | |
5b8358e6 | 767 | if (newfd >= OPEN_MAX || newfd < 0) |
4c78be52 CF |
768 | { |
769 | syscall_printf ("new fd out of bounds: %d", newfd); | |
770 | set_errno (EBADF); | |
771 | goto done; | |
772 | } | |
e70fdfb9 | 773 | if ((flags & ~O_CLOEXEC) != 0) |
1fd5e000 | 774 | { |
61522196 | 775 | syscall_printf ("invalid flags value %y", flags); |
e70fdfb9 CV |
776 | set_errno (EINVAL); |
777 | return -1; | |
1fd5e000 CF |
778 | } |
779 | ||
e70fdfb9 | 780 | if ((newfh = dup_worker (fds[oldfd], flags)) == NULL) |
1fd5e000 CF |
781 | { |
782 | res = -1; | |
783 | goto done; | |
784 | } | |
785 | ||
a9934559 | 786 | debug_printf ("newfh->io_handle %p, oldfh->io_handle %p, new win32_name %p, old win32_name %p", |
a9c661a9 | 787 | newfh->get_handle (), fds[oldfd]->get_handle (), newfh->get_win32_name (), fds[oldfd]->get_win32_name ()); |
b0e82b74 | 788 | |
4c78be52 | 789 | if (!not_open (newfd)) |
5ec14fe4 | 790 | close (newfd); |
3a4ce731 | 791 | else if ((size_t) newfd >= size |
8fa8b3a3 CF |
792 | && find_unused_handle (newfd) < 0) |
793 | /* couldn't extend fdtab */ | |
5a449743 | 794 | { |
4c78be52 CF |
795 | newfh->close (); |
796 | res = -1; | |
5a449743 CF |
797 | goto done; |
798 | } | |
b0e82b74 | 799 | |
1fd5e000 | 800 | fds[newfd] = newfh; |
dd4f0b23 | 801 | |
1fd5e000 CF |
802 | if ((res = newfd) <= 2) |
803 | set_std_handle (res); | |
b9c61a8d | 804 | do_unlock = unlock_on_return; |
1fd5e000 | 805 | |
1fd5e000 | 806 | done: |
3143cb7c CF |
807 | if (do_unlock) |
808 | unlock (); | |
61522196 | 809 | syscall_printf ("%R = dup3(%d, %d, %y)", res, oldfd, newfd, flags); |
1fd5e000 CF |
810 | |
811 | return res; | |
812 | } | |
813 | ||
b4fa8164 CF |
814 | bool |
815 | dtable::select_read (int fd, select_stuff *ss) | |
1fd5e000 | 816 | { |
b0e82b74 | 817 | if (not_open (fd)) |
1fd5e000 CF |
818 | { |
819 | set_errno (EBADF); | |
b4fa8164 | 820 | return false; |
1fd5e000 | 821 | } |
b0e82b74 | 822 | fhandler_base *fh = fds[fd]; |
b4fa8164 | 823 | select_record *s = fh->select_read (ss); |
1fd5e000 | 824 | s->fd = fd; |
c7ef20e7 CF |
825 | if (!s->fh) |
826 | s->fh = fh; | |
169c465a | 827 | s->thread_errno = 0; |
1fd5e000 | 828 | debug_printf ("%s fd %d", fh->get_name (), fd); |
b4fa8164 | 829 | return true; |
1fd5e000 CF |
830 | } |
831 | ||
b4fa8164 CF |
832 | bool |
833 | dtable::select_write (int fd, select_stuff *ss) | |
1fd5e000 | 834 | { |
b0e82b74 | 835 | if (not_open (fd)) |
1fd5e000 CF |
836 | { |
837 | set_errno (EBADF); | |
838 | return NULL; | |
839 | } | |
b0e82b74 | 840 | fhandler_base *fh = fds[fd]; |
b4fa8164 | 841 | select_record *s = fh->select_write (ss); |
1fd5e000 CF |
842 | s->fd = fd; |
843 | s->fh = fh; | |
169c465a | 844 | s->thread_errno = 0; |
106e3acf | 845 | debug_printf ("%s fd %d", fh->get_name (), fd); |
b4fa8164 | 846 | return true; |
1fd5e000 CF |
847 | } |
848 | ||
b4fa8164 CF |
849 | bool |
850 | dtable::select_except (int fd, select_stuff *ss) | |
1fd5e000 | 851 | { |
b0e82b74 | 852 | if (not_open (fd)) |
1fd5e000 CF |
853 | { |
854 | set_errno (EBADF); | |
855 | return NULL; | |
856 | } | |
b0e82b74 | 857 | fhandler_base *fh = fds[fd]; |
b4fa8164 | 858 | select_record *s = fh->select_except (ss); |
1fd5e000 CF |
859 | s->fd = fd; |
860 | s->fh = fh; | |
169c465a | 861 | s->thread_errno = 0; |
1fd5e000 | 862 | debug_printf ("%s fd %d", fh->get_name (), fd); |
b4fa8164 | 863 | return true; |
1fd5e000 CF |
864 | } |
865 | ||
c16548b2 CF |
866 | void |
867 | dtable::move_fd (int from, int to) | |
868 | { | |
869 | // close (to); /* It is assumed that this is close-on-exec */ | |
870 | fds[to] = fds[from]; | |
871 | fds[from] = NULL; | |
872 | } | |
873 | ||
fef1edbc CF |
874 | void |
875 | dtable::set_file_pointers_for_exec () | |
876 | { | |
cce64750 CV |
877 | /* This is not POSIX-compliant so the function is only called for |
878 | non-Cygwin processes. */ | |
0be0b8f0 CV |
879 | LARGE_INTEGER eof = { QuadPart: 0 }; |
880 | ||
2d1d1eb1 | 881 | lock (); |
fef1edbc CF |
882 | fhandler_base *fh; |
883 | for (size_t i = 0; i < size; i++) | |
884 | if ((fh = fds[i]) != NULL && fh->get_flags () & O_APPEND) | |
0be0b8f0 | 885 | SetFilePointerEx (fh->get_handle (), eof, NULL, FILE_END); |
2d1d1eb1 | 886 | unlock (); |
fef1edbc CF |
887 | } |
888 | ||
881beea8 CF |
889 | void |
890 | dtable::fixup_close (size_t i, fhandler_base *fh) | |
891 | { | |
892 | if (fh->archetype) | |
893 | { | |
894 | debug_printf ("closing fd %d since it is an archetype", i); | |
895 | fh->close_with_arch (); | |
896 | } | |
897 | release (i); | |
898 | } | |
899 | ||
b0e82b74 | 900 | void |
52806019 | 901 | dtable::fixup_after_exec () |
1fd5e000 | 902 | { |
b0e82b74 | 903 | first_fd_for_open = 0; |
2e78b61d | 904 | fhandler_base *fh; |
b0e82b74 | 905 | for (size_t i = 0; i < size; i++) |
2e78b61d | 906 | if ((fh = fds[i]) != NULL) |
4f7ac76a | 907 | { |
2e78b61d | 908 | fh->clear_readahead (); |
59297e04 | 909 | fh->fixup_after_exec (); |
881beea8 CF |
910 | /* Close the handle if it's close-on-exec or if an error was detected |
911 | (typically with opening a console in a gui app) by fixup_after_exec. | |
912 | */ | |
a9c661a9 | 913 | if (fh->close_on_exec () || (!fh->nohandle () && !fh->get_handle ())) |
881beea8 | 914 | fixup_close (i, fh); |
421ba492 CF |
915 | else if (fh->get_popen_pid ()) |
916 | close (i); | |
59297e04 | 917 | else if (i == 0) |
a9c661a9 | 918 | SetStdHandle (std_consts[i], fh->get_handle ()); |
59297e04 CF |
919 | else if (i <= 2) |
920 | SetStdHandle (std_consts[i], fh->get_output_handle ()); | |
4f7ac76a | 921 | } |
523985b3 TY |
922 | if (cygheap->ctty) |
923 | cygheap->ctty->fixup_after_exec (); | |
1fd5e000 CF |
924 | } |
925 | ||
926 | void | |
9015e0fb | 927 | dtable::fixup_after_fork (HANDLE parent) |
1fd5e000 | 928 | { |
b0e82b74 | 929 | fhandler_base *fh; |
1fd5e000 | 930 | for (size_t i = 0; i < size; i++) |
b0e82b74 | 931 | if ((fh = fds[i]) != NULL) |
1fd5e000 | 932 | { |
56551a9b | 933 | if (fh->close_on_exec () || fh->need_fork_fixup ()) |
1fd5e000 | 934 | { |
c729f227 | 935 | debug_printf ("fd %d (%s)", i, fh->get_name ()); |
1fd5e000 | 936 | fh->fixup_after_fork (parent); |
a9c661a9 | 937 | if (!fh->nohandle () && !fh->get_handle ()) |
881beea8 CF |
938 | { |
939 | /* This should actually never happen but it's here to make sure | |
940 | we don't crash due to access of an unopened file handle. */ | |
941 | fixup_close (i, fh); | |
942 | continue; | |
943 | } | |
1fd5e000 | 944 | } |
f3acbe3e | 945 | if (i == 0) |
a9c661a9 | 946 | SetStdHandle (std_consts[i], fh->get_handle ()); |
f3acbe3e CF |
947 | else if (i <= 2) |
948 | SetStdHandle (std_consts[i], fh->get_output_handle ()); | |
1fd5e000 | 949 | } |
523985b3 TY |
950 | |
951 | if (cygheap->ctty) | |
952 | cygheap->ctty->fixup_after_fork (parent); | |
1fd5e000 CF |
953 | } |
954 | ||
88f0dc31 CF |
955 | static void |
956 | decode_tty (char *buf, WCHAR *w32) | |
1ffe3e67 CF |
957 | { |
958 | int ttyn = wcstol (w32, NULL, 10); | |
92601445 | 959 | __ptsname (buf, ttyn); |
1ffe3e67 CF |
960 | } |
961 | ||
88f0dc31 CF |
962 | /* Try to derive posix filename from given handle. Return true if |
963 | the handle is associated with a cygwin tty. */ | |
964 | static bool | |
2402700d CF |
965 | handle_to_fn (HANDLE h, char *posix_fn) |
966 | { | |
ab5d348d | 967 | tmp_pathbuf tp; |
1ffe3e67 | 968 | ULONG len = 0; |
1ffe3e67 | 969 | WCHAR *maxmatchdos = NULL; |
5e7c84e5 | 970 | PWCHAR device = tp.w_get (); |
1ffe3e67 | 971 | int maxmatchlen = 0; |
019fc8d8 CV |
972 | OBJECT_NAME_INFORMATION *ntfn = (OBJECT_NAME_INFORMATION *) tp.w_get (); |
973 | ||
974 | NTSTATUS status = NtQueryObject (h, ObjectNameInformation, ntfn, 65536, &len); | |
975 | if (!NT_SUCCESS (status)) | |
61522196 | 976 | debug_printf ("NtQueryObject failed, %y", status); |
019fc8d8 CV |
977 | // NT seems to do this on an unopened file |
978 | else if (!ntfn->Name.Buffer) | |
979 | debug_printf ("nt->Name.Buffer == NULL"); | |
7b9e380f | 980 | else |
1ffe3e67 | 981 | { |
019fc8d8 CV |
982 | WCHAR *w32 = ntfn->Name.Buffer; |
983 | size_t w32len = ntfn->Name.Length / sizeof (WCHAR); | |
984 | w32[w32len] = L'\0'; | |
2bb6b3e5 | 985 | |
019fc8d8 CV |
986 | if (wcscasecmp (w32, DEV_NULL) == 0) |
987 | { | |
988 | strcpy (posix_fn, "/dev/null"); | |
989 | return false; | |
990 | } | |
2bb6b3e5 | 991 | |
019fc8d8 CV |
992 | if (wcscasecmp (w32, DEV_SOCKET) == 0) |
993 | { | |
994 | strcpy (posix_fn, ":sock:"); | |
995 | return false; | |
996 | } | |
2402700d | 997 | |
019fc8d8 CV |
998 | if (wcsncasecmp (w32, DEV_NAMED_PIPE, DEV_NAMED_PIPE_LEN) == 0) |
999 | { | |
1000 | w32 += DEV_NAMED_PIPE_LEN; | |
1001 | if (wcsncmp (w32, L"cygwin-", WCLEN (L"cygwin-")) != 0) | |
1002 | return false; | |
1003 | w32 += WCLEN (L"cygwin-"); | |
526b0fbc | 1004 | /* Check for installation key and trailing dash. */ |
8895d962 CV |
1005 | w32len = cygheap->installation_key.Length / sizeof (WCHAR); |
1006 | if (w32len | |
1007 | && wcsncmp (w32, cygheap->installation_key.Buffer, w32len) != 0) | |
526b0fbc CV |
1008 | return false; |
1009 | w32 += w32len; | |
1010 | if (*w32 != L'-') | |
1011 | return false; | |
1012 | ++w32; | |
2ae8e0e4 | 1013 | bool istty = wcsncmp (w32, L"pty", WCLEN (L"pty")) == 0; |
019fc8d8 | 1014 | if (istty) |
2ae8e0e4 | 1015 | decode_tty (posix_fn, w32 + WCLEN (L"pty")); |
019fc8d8 CV |
1016 | else if (wcsncmp (w32, L"pipe", WCLEN (L"pipe")) == 0) |
1017 | strcpy (posix_fn, "/dev/pipe"); | |
1018 | return istty; | |
1019 | } | |
5bf785a0 | 1020 | |
019fc8d8 CV |
1021 | WCHAR fnbuf[64 * 1024]; |
1022 | if (wcsncasecmp (w32, DEVICE_PREFIX, DEVICE_PREFIX_LEN) != 0 | |
9c36b394 | 1023 | || !QueryDosDeviceW (NULL, fnbuf, sizeof (fnbuf) / sizeof (WCHAR))) |
019fc8d8 CV |
1024 | { |
1025 | sys_wcstombs (posix_fn, NT_MAX_PATH, w32, w32len); | |
1026 | return false; | |
1027 | } | |
2402700d | 1028 | |
019fc8d8 CV |
1029 | for (WCHAR *s = fnbuf; *s; s = wcschr (s, '\0') + 1) |
1030 | { | |
5e7c84e5 | 1031 | if (!QueryDosDeviceW (s, device, NT_MAX_PATH)) |
019fc8d8 CV |
1032 | continue; |
1033 | if (wcschr (s, ':') == NULL) | |
1034 | continue; | |
1035 | WCHAR *q = wcsrchr (device, ';'); | |
1036 | if (q) | |
7b9e380f | 1037 | { |
019fc8d8 CV |
1038 | WCHAR *r = wcschr (q, '\\'); |
1039 | if (r) | |
1040 | wcscpy (q, r + 1); | |
7b9e380f | 1041 | } |
019fc8d8 CV |
1042 | int devlen = wcslen (device); |
1043 | if (device[devlen - 1] == L'\\') | |
1044 | device[--devlen] = L'\0'; | |
1045 | if (devlen < maxmatchlen) | |
1046 | continue; | |
1047 | if (wcsncmp (device, w32, devlen) != 0|| | |
1048 | (w32[devlen] != L'\0' && w32[devlen] != L'\\')) | |
1049 | continue; | |
1050 | maxmatchlen = devlen; | |
1051 | maxmatchdos = s; | |
1052 | debug_printf ("current match '%W' = '%W'\n", s, device); | |
1053 | } | |
1ffe3e67 | 1054 | |
019fc8d8 CV |
1055 | if (maxmatchlen) |
1056 | { | |
1057 | WCHAR *p = wcschr (w32 + DEVICE_PREFIX_LEN, L'\\'); | |
1058 | size_t n = wcslen (maxmatchdos); | |
1059 | WCHAR ch; | |
1060 | if (!p) | |
1061 | ch = L'\0'; | |
1062 | else | |
7b9e380f | 1063 | { |
019fc8d8 CV |
1064 | if (maxmatchdos[n - 1] == L'\\') |
1065 | n--; | |
1066 | w32 += maxmatchlen - n; | |
1067 | ch = L'\\'; | |
7b9e380f | 1068 | } |
019fc8d8 CV |
1069 | memcpy (w32, maxmatchdos, n * sizeof (WCHAR)); |
1070 | w32[n] = ch; | |
1071 | } | |
1072 | else if (wcsncmp (w32, DEV_REMOTE, DEV_REMOTE_LEN) == 0) | |
1073 | { | |
1074 | w32 += DEV_REMOTE_LEN - 2; | |
1075 | *w32 = L'\\'; | |
1076 | debug_printf ("remote drive"); | |
1077 | } | |
1078 | else if (wcsncmp (w32, DEV_REMOTE1, DEV_REMOTE1_LEN) == 0) | |
1079 | { | |
1080 | w32 += DEV_REMOTE1_LEN - 2; | |
1081 | *w32 = L'\\'; | |
1082 | debug_printf ("remote drive"); | |
1083 | } | |
1ffe3e67 | 1084 | |
019fc8d8 CV |
1085 | cygwin_conv_path (CCP_WIN_W_TO_POSIX | CCP_ABSOLUTE, w32, posix_fn, |
1086 | NT_MAX_PATH); | |
37be5a67 | 1087 | |
019fc8d8 CV |
1088 | debug_printf ("derived path '%W', posix '%s'", w32, posix_fn); |
1089 | return false; | |
634a4140 | 1090 | } |
2402700d | 1091 | |
1ffe3e67 | 1092 | strcpy (posix_fn, unknown_file); |
88f0dc31 | 1093 | return false; |
2402700d | 1094 | } |
b14f53a8 CV |
1095 | |
1096 | void | |
1097 | dtable::fixup_before_fork (DWORD target_proc_id) | |
1098 | { | |
1099 | lock (); | |
1100 | fhandler_base *fh; | |
1101 | for (size_t i = 0; i < size; i++) | |
1102 | if ((fh = fds[i]) != NULL) | |
1103 | { | |
b86f999a CF |
1104 | debug_printf ("fd %d (%s)", i, fh->get_name ()); |
1105 | fh->fixup_before_fork_exec (target_proc_id); | |
b14f53a8 CV |
1106 | } |
1107 | unlock (); | |
b86f999a CF |
1108 | } |
1109 | ||
b14f53a8 CV |
1110 | void |
1111 | dtable::fixup_before_exec (DWORD target_proc_id) | |
1112 | { | |
1113 | lock (); | |
1114 | fhandler_base *fh; | |
1115 | for (size_t i = 0; i < size; i++) | |
1116 | if ((fh = fds[i]) != NULL && !fh->close_on_exec ()) | |
1117 | { | |
b86f999a CF |
1118 | debug_printf ("fd %d (%s)", i, fh->get_name ()); |
1119 | fh->fixup_before_fork_exec (target_proc_id); | |
b14f53a8 CV |
1120 | } |
1121 | unlock (); | |
b86f999a | 1122 | } |