]>
Commit | Line | Data |
---|---|---|
9015e0fb | 1 | /* dtable.cc: file descriptor support. |
1fd5e000 | 2 | |
731028b3 | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, |
a7d2cc16 | 4 | 2005, 2006, 2007, 2008 Red Hat, Inc. |
1fd5e000 CF |
5 | |
6 | This file is part of Cygwin. | |
7 | ||
8 | This software is a copyrighted work licensed under the terms of the | |
9 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
10 | details. */ | |
11 | ||
12 | #define __INSIDE_CYGWIN_NET__ | |
13 | ||
4c8d72de | 14 | #include "winsup.h" |
1fd5e000 CF |
15 | #include <sys/socket.h> |
16 | #include <stdlib.h> | |
17 | #include <stdio.h> | |
1fd5e000 | 18 | #include <unistd.h> |
1ffe3e67 | 19 | #include <wchar.h> |
1fd5e000 | 20 | |
a1299ba5 | 21 | #define USE_SYS_TYPES_FD_SET |
d0b178fe | 22 | #include <winsock.h> |
e2ebe117 | 23 | #include "pinfo.h" |
9e2baf8d | 24 | #include "cygerrno.h" |
95a8465b | 25 | #include "perprocess.h" |
bccd5e0d | 26 | #include "path.h" |
7ac61736 | 27 | #include "fhandler.h" |
bccd5e0d | 28 | #include "dtable.h" |
0381fec6 | 29 | #include "cygheap.h" |
ab5d348d | 30 | #include "tls_pbuf.h" |
2402700d | 31 | #include "ntdll.h" |
f09acf77 | 32 | #include "shared_info.h" |
1fd5e000 | 33 | |
57c89867 | 34 | static const NO_COPY DWORD std_consts[] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, |
083abe54 | 35 | STD_ERROR_HANDLE}; |
164a681c | 36 | |
88f0dc31 | 37 | static bool handle_to_fn (HANDLE, char *); |
1ffe3e67 CF |
38 | |
39 | #define WCLEN(x) ((sizeof (x) / sizeof (WCHAR)) - 1) | |
40 | char unknown_file[] = "some disk file"; | |
41 | const WCHAR DEV_NULL[] = L"\\Device\\Null"; | |
42 | ||
43 | const WCHAR DEVICE_PREFIX[] = L"\\device\\"; | |
44 | const size_t DEVICE_PREFIX_LEN WCLEN (DEVICE_PREFIX); | |
45 | ||
46 | static const WCHAR DEV_NAMED_PIPE[] = L"\\Device\\NamedPipe\\"; | |
47 | static const size_t DEV_NAMED_PIPE_LEN = WCLEN (DEV_NAMED_PIPE); | |
dd76747b | 48 | |
1ffe3e67 CF |
49 | static const WCHAR DEV_REMOTE[] = L"\\Device\\LanmanRedirector\\"; |
50 | static const size_t DEV_REMOTE_LEN = WCLEN (DEV_REMOTE); | |
51 | ||
52 | static const WCHAR DEV_REMOTE1[] = L"\\Device\\WinDfs\\Root\\"; | |
53 | static const size_t DEV_REMOTE1_LEN = WCLEN (DEV_REMOTE1); | |
634a4140 | 54 | |
1fd5e000 CF |
55 | /* Set aside space for the table of fds */ |
56 | void | |
2d1d1eb1 | 57 | dtable_init () |
1fd5e000 | 58 | { |
0381fec6 | 59 | if (!cygheap->fdtab.size) |
c729f227 | 60 | cygheap->fdtab.extend (NOFILE_INCR); |
1fd5e000 CF |
61 | } |
62 | ||
63 | void __stdcall | |
64 | set_std_handle (int fd) | |
65 | { | |
66 | if (fd == 0) | |
0381fec6 | 67 | SetStdHandle (std_consts[fd], cygheap->fdtab[fd]->get_handle ()); |
164a681c | 68 | else if (fd <= 2) |
0381fec6 | 69 | SetStdHandle (std_consts[fd], cygheap->fdtab[fd]->get_output_handle ()); |
1fd5e000 CF |
70 | } |
71 | ||
72 | int | |
9015e0fb | 73 | dtable::extend (int howmuch) |
1fd5e000 CF |
74 | { |
75 | int new_size = size + howmuch; | |
76 | fhandler_base **newfds; | |
77 | ||
78 | if (howmuch <= 0) | |
79 | return 0; | |
80 | ||
4d782b42 CF |
81 | if (new_size > (100 * NOFILE_INCR)) |
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; | |
41f42725 | 104 | debug_printf ("size %d, fds %p", size, fds); |
1fd5e000 CF |
105 | return 1; |
106 | } | |
107 | ||
083abe54 CF |
108 | void |
109 | dtable::get_debugger_info () | |
110 | { | |
918a268c | 111 | if (being_debugged ()) |
083abe54 CF |
112 | { |
113 | char std[3][sizeof ("/dev/ttyNNNN")]; | |
114 | std[0][0] = std[1][0] = std [2][0] = '\0'; | |
115 | char buf[sizeof ("cYgstd %x") + 32]; | |
116 | sprintf (buf, "cYgstd %x %x %x", (unsigned) &std, sizeof (std[0]), 3); | |
117 | OutputDebugString (buf); | |
118 | for (int i = 0; i < 3; i++) | |
119 | if (std[i][0]) | |
120 | { | |
083abe54 | 121 | HANDLE h = GetStdHandle (std_consts[i]); |
7ac61736 | 122 | fhandler_base *fh = build_fh_name (std[i]); |
083abe54 CF |
123 | if (!fh) |
124 | continue; | |
7ac61736 | 125 | fds[i] = fh; |
061095b5 CV |
126 | if (!fh->open ((i ? (i == 2 ? O_RDWR : O_WRONLY) : O_RDONLY) |
127 | | O_BINARY, 0777)) | |
083abe54 CF |
128 | release (i); |
129 | else | |
130 | CloseHandle (h); | |
131 | } | |
132 | } | |
133 | } | |
134 | ||
1fd5e000 | 135 | /* Initialize the file descriptor/handle mapping table. |
10dedaaa CF |
136 | This function should only be called when a cygwin function is invoked |
137 | by a non-cygwin function, i.e., it should only happen very rarely. */ | |
1fd5e000 CF |
138 | |
139 | void | |
083abe54 | 140 | dtable::stdio_init () |
1fd5e000 | 141 | { |
b98ebf54 | 142 | extern void set_console_ctty (); |
1fd5e000 CF |
143 | /* Set these before trying to output anything from strace. |
144 | Also, always set them even if we're to pick up our parent's fds | |
145 | in case they're missed. */ | |
146 | ||
8cb359d9 | 147 | if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT)) |
3eb92a58 | 148 | { |
f09acf77 CF |
149 | tty_min *t = cygwin_shared->tty.get_tty (myself->ctty); |
150 | if (t && t->getpgid () == myself->pid && t->gethwnd ()) | |
151 | init_console_handler (true); | |
3eb92a58 CF |
152 | return; |
153 | } | |
1fd5e000 | 154 | |
083abe54 CF |
155 | HANDLE in = GetStdHandle (STD_INPUT_HANDLE); |
156 | HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); | |
157 | HANDLE err = GetStdHandle (STD_ERROR_HANDLE); | |
1fd5e000 | 158 | |
54030e21 | 159 | init_std_file_from_handle (0, in); |
083abe54 CF |
160 | |
161 | /* STD_ERROR_HANDLE has been observed to be the same as | |
162 | STD_OUTPUT_HANDLE. We need separate handles (e.g. using pipes | |
163 | to pass data from child to parent). */ | |
164 | if (out == err) | |
165 | { | |
166 | /* Since this code is not invoked for forked tasks, we don't have | |
167 | to worry about the close-on-exec flag here. */ | |
b040009e CF |
168 | if (!DuplicateHandle (hMainProc, out, hMainProc, &err, 0, true, |
169 | DUPLICATE_SAME_ACCESS)) | |
1fd5e000 | 170 | { |
083abe54 CF |
171 | /* If that fails, do this as a fall back. */ |
172 | err = out; | |
173 | system_printf ("couldn't make stderr distinct from stdout"); | |
1fd5e000 | 174 | } |
1fd5e000 | 175 | } |
083abe54 | 176 | |
54030e21 CF |
177 | init_std_file_from_handle (1, out); |
178 | init_std_file_from_handle (2, err); | |
65438ec6 | 179 | |
083abe54 CF |
180 | /* Assign the console as the controlling tty for this process if we actually |
181 | have a console and no other controlling tty has been assigned. */ | |
65438ec6 | 182 | if (!fhandler_console::need_invisible () && myself->ctty < 0) |
083abe54 | 183 | set_console_ctty (); |
1fd5e000 CF |
184 | } |
185 | ||
8e10c431 CF |
186 | const int dtable::initial_archetype_size; |
187 | ||
188 | fhandler_base * | |
189 | dtable::find_archetype (device& dev) | |
190 | { | |
191 | for (unsigned i = 0; i < farchetype; i++) | |
192 | if (archetypes[i]->get_device () == (unsigned) dev) | |
193 | return archetypes[i]; | |
194 | return NULL; | |
195 | } | |
196 | ||
197 | fhandler_base ** | |
198 | dtable::add_archetype () | |
199 | { | |
200 | if (farchetype++ >= narchetypes) | |
634a4140 | 201 | archetypes = (fhandler_base **) crealloc_abort (archetypes, (narchetypes += initial_archetype_size) * sizeof archetypes[0]); |
8e10c431 CF |
202 | return archetypes + farchetype - 1; |
203 | } | |
204 | ||
205 | void | |
206 | dtable::delete_archetype (fhandler_base *fh) | |
207 | { | |
8ed5c9b6 | 208 | for (unsigned i = 0; i < farchetype; i++) |
8e10c431 CF |
209 | if (fh == archetypes[i]) |
210 | { | |
8ed5c9b6 | 211 | debug_printf ("deleting element %d for %s", i, fh->get_name ()); |
8e10c431 CF |
212 | if (i < --farchetype) |
213 | archetypes[i] = archetypes[farchetype]; | |
214 | break; | |
215 | } | |
216 | ||
217 | delete fh; | |
218 | } | |
219 | ||
1fd5e000 | 220 | int |
9015e0fb | 221 | dtable::find_unused_handle (int start) |
1fd5e000 | 222 | { |
1fd5e000 CF |
223 | do |
224 | { | |
e773b7cf | 225 | for (size_t i = start; i < size; i++) |
91892f50 CF |
226 | /* See if open -- no need for overhead of not_open */ |
227 | if (fds[i] == NULL) | |
1fd5e000 CF |
228 | return i; |
229 | } | |
230 | while (extend (NOFILE_INCR)); | |
231 | return -1; | |
232 | } | |
233 | ||
234 | void | |
9015e0fb | 235 | dtable::release (int fd) |
1fd5e000 CF |
236 | { |
237 | if (!not_open (fd)) | |
238 | { | |
7ac61736 CF |
239 | if (fds[fd]->need_fixup_before ()) |
240 | dec_need_fixup_before (); | |
9279515a | 241 | fhandler_base *arch = fds[fd]->archetype; |
166b2571 | 242 | delete fds[fd]; |
9279515a CF |
243 | if (arch && !arch->usecount) |
244 | cygheap->fdtab.delete_archetype (arch); | |
1fd5e000 CF |
245 | fds[fd] = NULL; |
246 | } | |
247 | } | |
248 | ||
45586380 | 249 | extern "C" int |
ebd645e7 CF |
250 | cygwin_attach_handle_to_fd (char *name, int fd, HANDLE handle, mode_t bin, |
251 | DWORD myaccess) | |
252 | { | |
253 | if (fd == -1) | |
254 | fd = cygheap->fdtab.find_unused_handle (); | |
7ac61736 CF |
255 | fhandler_base *fh = build_fh_name (name); |
256 | cygheap->fdtab[fd] = fh; | |
257 | fh->init (handle, myaccess, bin ?: fh->pc_binmode ()); | |
ebd645e7 CF |
258 | return fd; |
259 | } | |
260 | ||
1fd5e000 | 261 | void |
54030e21 | 262 | dtable::init_std_file_from_handle (int fd, HANDLE handle) |
1fd5e000 | 263 | { |
ebd645e7 CF |
264 | CONSOLE_SCREEN_BUFFER_INFO buf; |
265 | struct sockaddr sa; | |
266 | int sal = sizeof (sa); | |
267 | DCB dcb; | |
abb58a6d | 268 | unsigned bin = O_BINARY; |
7ac61736 | 269 | device dev; |
ab5d348d | 270 | tmp_pathbuf tp; |
ebd645e7 | 271 | |
7ac61736 | 272 | dev.devn = 0; /* FIXME: device */ |
ebd645e7 | 273 | first_fd_for_open = 0; |
1ac6d1a1 | 274 | |
083abe54 CF |
275 | if (!not_open (fd)) |
276 | return; | |
277 | ||
cef69559 | 278 | SetLastError (0); |
1ffe3e67 | 279 | DWORD access = 0; |
cef69559 | 280 | DWORD ft = GetFileType (handle); |
1ffe3e67 CF |
281 | char name[NT_MAX_PATH]; |
282 | name[0] = '\0'; | |
88f0dc31 CF |
283 | if (ft == FILE_TYPE_UNKNOWN && GetLastError () == ERROR_INVALID_HANDLE) |
284 | /* can't figure out what this is */; | |
285 | else if (ft == FILE_TYPE_PIPE) | |
1fd5e000 | 286 | { |
88f0dc31 | 287 | if (handle_to_fn (handle, name)) |
1ffe3e67 CF |
288 | /* ok */; |
289 | else if (fd == 0) | |
290 | dev = *piper_dev; | |
4ab6034f | 291 | else |
1ffe3e67 | 292 | dev = *pipew_dev; |
88f0dc31 CF |
293 | if (name[0]) |
294 | access = FILE_CREATE_PIPE_INSTANCE; | |
4ab6034f | 295 | } |
1ffe3e67 CF |
296 | else if (GetConsoleScreenBufferInfo (handle, &buf)) |
297 | { | |
298 | /* Console output */ | |
299 | if (ISSTATE (myself, PID_USETTY)) | |
300 | dev.parse (FH_TTY); | |
301 | else | |
302 | dev = *console_dev; | |
303 | } | |
304 | else if (GetNumberOfConsoleInputEvents (handle, (DWORD *) &buf)) | |
305 | { | |
306 | /* Console input */ | |
307 | if (ISSTATE (myself, PID_USETTY)) | |
308 | dev.parse (FH_TTY); | |
309 | else | |
310 | dev = *console_dev; | |
311 | } | |
312 | else if (wsock_started && getpeername ((SOCKET) handle, &sa, &sal) == 0) | |
313 | /* socket */ | |
314 | dev = *tcp_dev; | |
315 | else if (GetCommState (handle, &dcb)) | |
316 | /* serial */ | |
317 | dev.parse (DEV_TTYS_MAJOR, 0); | |
318 | else | |
319 | /* Try to figure it out from context - probably a disk file */ | |
320 | handle_to_fn (handle, name); | |
cef69559 | 321 | |
1ffe3e67 | 322 | if (!name[0] && !dev) |
cef69559 CF |
323 | fds[fd] = NULL; |
324 | else | |
4ab6034f | 325 | { |
7ac61736 CF |
326 | fhandler_base *fh; |
327 | ||
328 | if (dev) | |
1ffe3e67 | 329 | fh = build_fh_dev (dev); |
7ac61736 CF |
330 | else |
331 | fh = build_fh_name (name); | |
332 | ||
333 | if (fh) | |
334 | cygheap->fdtab[fd] = fh; | |
335 | ||
1ffe3e67 | 336 | if (name[0]) |
abb58a6d | 337 | { |
634a4140 CF |
338 | bin = fh->pc_binmode (); |
339 | if (!bin) | |
340 | { | |
341 | bin = fh->get_default_fmode (O_RDWR); | |
342 | if (!bin && dev) | |
343 | bin = O_BINARY; | |
344 | } | |
abb58a6d | 345 | } |
9655ff26 | 346 | |
4248960e | 347 | if (dev == FH_TTY || dev == FH_CONSOLE) |
88f0dc31 | 348 | access |= GENERIC_READ | GENERIC_WRITE; |
4248960e | 349 | else if (fd == 0) |
88f0dc31 | 350 | access |= GENERIC_READ; |
70300fdb | 351 | else |
88f0dc31 | 352 | access |= GENERIC_WRITE; /* Should be rdwr for stderr but not sure that's |
634a4140 CF |
353 | possible for some versions of handles */ |
354 | fh->init (handle, access, bin); | |
cef69559 CF |
355 | set_std_handle (fd); |
356 | paranoid_printf ("fd %d, handle %p", fd, handle); | |
1fd5e000 | 357 | } |
1fd5e000 CF |
358 | } |
359 | ||
dcb091ca | 360 | #define cnew(name) new ((void *) ccalloc (HEAP_FHANDLER, 1, sizeof (name))) name |
1ffe3e67 CF |
361 | |
362 | static fhandler_base * | |
363 | build_fh_name_worker (path_conv& pc, HANDLE h, unsigned opt, suffix_info *si) | |
1fd5e000 | 364 | { |
4ab6034f CF |
365 | if (pc.error) |
366 | { | |
e00700cd | 367 | fhandler_base *fh = cnew (fhandler_nodevice) (); |
6a7bea70 CF |
368 | if (fh) |
369 | fh->set_error (pc.error); | |
370 | set_errno (fh ? pc.error : EMFILE); | |
e00700cd | 371 | return fh; |
1fd5e000 CF |
372 | } |
373 | ||
7ac61736 CF |
374 | if (!pc.exists () && h) |
375 | pc.fillin (h); | |
2402700d | 376 | |
7ac61736 | 377 | return build_fh_pc (pc); |
1fd5e000 | 378 | } |
1ffe3e67 CF |
379 | fhandler_base * |
380 | build_fh_name (const char *name, HANDLE h, unsigned opt, suffix_info *si) | |
381 | { | |
382 | path_conv pc (name, opt | PC_NULLEMPTY | PC_POSIX, si); | |
383 | return build_fh_name_worker (pc, h, opt, si); | |
384 | } | |
385 | ||
88f0dc31 | 386 | #if 0 /* Not needed yet */ |
1ffe3e67 CF |
387 | #define cnew(name) new ((void *) ccalloc (HEAP_FHANDLER, 1, sizeof (name))) name |
388 | fhandler_base * | |
389 | build_fh_name (const UNICODE_STRING *name, HANDLE h, unsigned opt, suffix_info *si) | |
390 | { | |
391 | path_conv pc (name, opt | PC_NULLEMPTY | PC_POSIX, si); | |
392 | return build_fh_name_worker (pc, h, opt, si); | |
393 | } | |
88f0dc31 | 394 | #endif |
1fd5e000 CF |
395 | |
396 | fhandler_base * | |
7ac61736 | 397 | build_fh_dev (const device& dev, const char *unix_name) |
ff938546 | 398 | { |
7ac61736 | 399 | path_conv pc (dev); |
7ac61736 | 400 | if (unix_name) |
861ef997 | 401 | pc.set_normalized_path (unix_name, false); |
7ac61736 | 402 | else |
861ef997 | 403 | pc.set_normalized_path (dev.name, false); |
7ac61736 | 404 | return build_fh_pc (pc); |
ff938546 CF |
405 | } |
406 | ||
6a7bea70 | 407 | #define fh_unset ((fhandler_base *) 1) |
ff938546 | 408 | fhandler_base * |
7ac61736 | 409 | build_fh_pc (path_conv& pc) |
1fd5e000 | 410 | { |
6a7bea70 | 411 | fhandler_base *fh = fh_unset; |
1fd5e000 | 412 | |
7b02cb30 CF |
413 | switch (pc.dev.major) |
414 | { | |
415 | case DEV_TTYS_MAJOR: | |
416 | fh = cnew (fhandler_tty_slave) (); | |
417 | break; | |
418 | case DEV_TTYM_MAJOR: | |
419 | fh = cnew (fhandler_tty_master) (); | |
420 | break; | |
421 | case DEV_CYGDRIVE_MAJOR: | |
422 | fh = cnew (fhandler_cygdrive) (); | |
423 | break; | |
424 | case DEV_FLOPPY_MAJOR: | |
425 | case DEV_CDROM_MAJOR: | |
426 | case DEV_SD_MAJOR: | |
cc9dbc90 | 427 | case DEV_SD1_MAJOR: |
9e3f289f CV |
428 | case DEV_SD2_MAJOR: |
429 | case DEV_SD3_MAJOR: | |
430 | case DEV_SD4_MAJOR: | |
431 | case DEV_SD5_MAJOR: | |
432 | case DEV_SD6_MAJOR: | |
433 | case DEV_SD7_MAJOR: | |
7b02cb30 CF |
434 | fh = cnew (fhandler_dev_floppy) (); |
435 | break; | |
436 | case DEV_TAPE_MAJOR: | |
437 | fh = cnew (fhandler_dev_tape) (); | |
438 | break; | |
439 | case DEV_SERIAL_MAJOR: | |
440 | fh = cnew (fhandler_serial) (); | |
441 | break; | |
442 | default: | |
443 | switch (pc.dev) | |
444 | { | |
445 | case FH_CONSOLE: | |
446 | case FH_CONIN: | |
447 | case FH_CONOUT: | |
448 | fh = cnew (fhandler_console) (); | |
449 | break; | |
450 | case FH_PTYM: | |
451 | fh = cnew (fhandler_pty_master) (); | |
452 | break; | |
453 | case FH_WINDOWS: | |
454 | fh = cnew (fhandler_windows) (); | |
455 | break; | |
456 | case FH_FIFO: | |
457 | fh = cnew (fhandler_fifo) (); | |
458 | break; | |
459 | case FH_PIPE: | |
460 | case FH_PIPER: | |
461 | case FH_PIPEW: | |
462 | fh = cnew (fhandler_pipe) (); | |
463 | break; | |
464 | case FH_TCP: | |
465 | case FH_UDP: | |
466 | case FH_ICMP: | |
467 | case FH_UNIX: | |
468 | case FH_STREAM: | |
469 | case FH_DGRAM: | |
470 | fh = cnew (fhandler_socket) (); | |
471 | break; | |
472 | case FH_FS: | |
473 | fh = cnew (fhandler_disk_file) (); | |
474 | break; | |
475 | case FH_NULL: | |
476 | fh = cnew (fhandler_dev_null) (); | |
477 | break; | |
478 | case FH_ZERO: | |
479 | case FH_FULL: | |
480 | fh = cnew (fhandler_dev_zero) (); | |
481 | break; | |
482 | case FH_RANDOM: | |
483 | case FH_URANDOM: | |
484 | fh = cnew (fhandler_dev_random) (); | |
485 | break; | |
486 | case FH_MEM: | |
487 | case FH_PORT: | |
488 | fh = cnew (fhandler_dev_mem) (); | |
489 | break; | |
490 | case FH_CLIPBOARD: | |
491 | fh = cnew (fhandler_dev_clipboard) (); | |
492 | break; | |
493 | case FH_OSS_DSP: | |
494 | fh = cnew (fhandler_dev_dsp) (); | |
495 | break; | |
496 | case FH_PROC: | |
497 | fh = cnew (fhandler_proc) (); | |
498 | break; | |
499 | case FH_REGISTRY: | |
500 | fh = cnew (fhandler_registry) (); | |
501 | break; | |
502 | case FH_PROCESS: | |
503 | fh = cnew (fhandler_process) (); | |
504 | break; | |
96d7dee2 CV |
505 | case FH_PROCNET: |
506 | fh = cnew (fhandler_procnet) (); | |
507 | break; | |
7b02cb30 CF |
508 | case FH_NETDRIVE: |
509 | fh = cnew (fhandler_netdrive) (); | |
510 | break; | |
511 | case FH_TTY: | |
0e1ba888 | 512 | { |
7b02cb30 CF |
513 | if (myself->ctty == TTY_CONSOLE) |
514 | fh = cnew (fhandler_console) (); | |
515 | else if (myself->ctty >= 0) | |
516 | fh = cnew (fhandler_tty_slave) (); | |
0e1ba888 | 517 | break; |
7b02cb30 CF |
518 | } |
519 | case FH_KMSG: | |
520 | fh = cnew (fhandler_mailslot) (); | |
521 | break; | |
0e1ba888 | 522 | } |
7b02cb30 | 523 | } |
7ac61736 | 524 | |
2e82c935 CF |
525 | if (fh == fh_unset) |
526 | fh = cnew (fhandler_nodevice) (); | |
527 | ||
528 | if (fh) | |
529 | fh->set_name (pc); | |
6a7bea70 | 530 | else |
2e82c935 | 531 | set_errno (EMFILE); |
7ac61736 CF |
532 | |
533 | debug_printf ("fh %p", fh); | |
534 | return fh; | |
1fd5e000 CF |
535 | } |
536 | ||
537 | fhandler_base * | |
9015e0fb | 538 | dtable::dup_worker (fhandler_base *oldfh) |
1fd5e000 | 539 | { |
7ac61736 | 540 | fhandler_base *newfh = build_fh_pc (oldfh->pc); |
6a7bea70 CF |
541 | if (!newfh) |
542 | debug_printf ("build_fh_pc failed"); | |
543 | else | |
1fd5e000 | 544 | { |
6a7bea70 CF |
545 | *newfh = *oldfh; |
546 | newfh->set_io_handle (NULL); | |
dcb091ca | 547 | if (oldfh->dup (newfh)) |
6a7bea70 CF |
548 | { |
549 | cfree (newfh); | |
550 | debug_printf ("oldfh->dup failed"); | |
551 | } | |
552 | else | |
553 | { | |
554 | newfh->close_on_exec (false); | |
555 | debug_printf ("duped '%s' old %p, new %p", oldfh->get_name (), oldfh->get_io_handle (), newfh->get_io_handle ()); | |
556 | } | |
1fd5e000 | 557 | } |
1fd5e000 CF |
558 | return newfh; |
559 | } | |
560 | ||
561 | int | |
9015e0fb | 562 | dtable::dup2 (int oldfd, int newfd) |
1fd5e000 CF |
563 | { |
564 | int res = -1; | |
565 | fhandler_base *newfh = NULL; // = NULL to avoid an incorrect warning | |
566 | ||
567 | MALLOC_CHECK; | |
568 | debug_printf ("dup2 (%d, %d)", oldfd, newfd); | |
2d1d1eb1 | 569 | lock (); |
1fd5e000 CF |
570 | |
571 | if (not_open (oldfd)) | |
572 | { | |
5a449743 | 573 | syscall_printf ("fd %d not open", oldfd); |
1fd5e000 CF |
574 | set_errno (EBADF); |
575 | goto done; | |
576 | } | |
577 | ||
4c78be52 CF |
578 | if (newfd < 0) |
579 | { | |
580 | syscall_printf ("new fd out of bounds: %d", newfd); | |
581 | set_errno (EBADF); | |
582 | goto done; | |
583 | } | |
584 | ||
1fd5e000 CF |
585 | if (newfd == oldfd) |
586 | { | |
587 | res = 0; | |
588 | goto done; | |
589 | } | |
590 | ||
591 | if ((newfh = dup_worker (fds[oldfd])) == NULL) | |
592 | { | |
593 | res = -1; | |
594 | goto done; | |
595 | } | |
596 | ||
4c78be52 CF |
597 | debug_printf ("newfh->io_handle %p, oldfh->io_handle %p", |
598 | newfh->get_io_handle (), fds[oldfd]->get_io_handle ()); | |
b0e82b74 | 599 | |
4c78be52 | 600 | if (!not_open (newfd)) |
5ec14fe4 | 601 | close (newfd); |
4c78be52 CF |
602 | else if ((size_t) newfd < size) |
603 | /* nothing to do */; | |
604 | else if (find_unused_handle (newfd) < 0) | |
5a449743 | 605 | { |
4c78be52 CF |
606 | newfh->close (); |
607 | res = -1; | |
5a449743 CF |
608 | goto done; |
609 | } | |
b0e82b74 | 610 | |
1fd5e000 | 611 | fds[newfd] = newfh; |
dd4f0b23 | 612 | |
1fd5e000 CF |
613 | if ((res = newfd) <= 2) |
614 | set_std_handle (res); | |
615 | ||
1fd5e000 | 616 | done: |
4c78be52 | 617 | MALLOC_CHECK; |
2d1d1eb1 | 618 | unlock (); |
1fd5e000 CF |
619 | syscall_printf ("%d = dup2 (%d, %d)", res, oldfd, newfd); |
620 | ||
621 | return res; | |
622 | } | |
623 | ||
624 | select_record * | |
9015e0fb | 625 | dtable::select_read (int fd, select_record *s) |
1fd5e000 | 626 | { |
b0e82b74 | 627 | if (not_open (fd)) |
1fd5e000 CF |
628 | { |
629 | set_errno (EBADF); | |
630 | return NULL; | |
631 | } | |
b0e82b74 | 632 | fhandler_base *fh = fds[fd]; |
1fd5e000 CF |
633 | s = fh->select_read (s); |
634 | s->fd = fd; | |
635 | s->fh = fh; | |
169c465a | 636 | s->thread_errno = 0; |
1fd5e000 CF |
637 | debug_printf ("%s fd %d", fh->get_name (), fd); |
638 | return s; | |
639 | } | |
640 | ||
641 | select_record * | |
9015e0fb | 642 | dtable::select_write (int fd, select_record *s) |
1fd5e000 | 643 | { |
b0e82b74 | 644 | if (not_open (fd)) |
1fd5e000 CF |
645 | { |
646 | set_errno (EBADF); | |
647 | return NULL; | |
648 | } | |
b0e82b74 | 649 | fhandler_base *fh = fds[fd]; |
1fd5e000 CF |
650 | s = fh->select_write (s); |
651 | s->fd = fd; | |
652 | s->fh = fh; | |
169c465a | 653 | s->thread_errno = 0; |
1fd5e000 CF |
654 | debug_printf ("%s fd %d", fh->get_name (), fd); |
655 | return s; | |
656 | } | |
657 | ||
658 | select_record * | |
9015e0fb | 659 | dtable::select_except (int fd, select_record *s) |
1fd5e000 | 660 | { |
b0e82b74 | 661 | if (not_open (fd)) |
1fd5e000 CF |
662 | { |
663 | set_errno (EBADF); | |
664 | return NULL; | |
665 | } | |
b0e82b74 | 666 | fhandler_base *fh = fds[fd]; |
1fd5e000 CF |
667 | s = fh->select_except (s); |
668 | s->fd = fd; | |
669 | s->fh = fh; | |
169c465a | 670 | s->thread_errno = 0; |
1fd5e000 CF |
671 | debug_printf ("%s fd %d", fh->get_name (), fd); |
672 | return s; | |
673 | } | |
674 | ||
b0e82b74 CF |
675 | /* Function to walk the fd table after an exec and perform |
676 | per-fhandler type fixups. */ | |
dd4f0b23 CV |
677 | void |
678 | dtable::fixup_before_fork (DWORD target_proc_id) | |
679 | { | |
2d1d1eb1 | 680 | lock (); |
dd4f0b23 CV |
681 | fhandler_base *fh; |
682 | for (size_t i = 0; i < size; i++) | |
683 | if ((fh = fds[i]) != NULL) | |
684 | { | |
c729f227 | 685 | debug_printf ("fd %d (%s)", i, fh->get_name ()); |
dd4f0b23 CV |
686 | fh->fixup_before_fork_exec (target_proc_id); |
687 | } | |
2d1d1eb1 | 688 | unlock (); |
dd4f0b23 CV |
689 | } |
690 | ||
c16548b2 CF |
691 | void |
692 | dtable::move_fd (int from, int to) | |
693 | { | |
694 | // close (to); /* It is assumed that this is close-on-exec */ | |
695 | fds[to] = fds[from]; | |
696 | fds[from] = NULL; | |
697 | } | |
698 | ||
dd4f0b23 CV |
699 | void |
700 | dtable::fixup_before_exec (DWORD target_proc_id) | |
701 | { | |
2d1d1eb1 | 702 | lock (); |
dd4f0b23 CV |
703 | fhandler_base *fh; |
704 | for (size_t i = 0; i < size; i++) | |
56551a9b | 705 | if ((fh = fds[i]) != NULL && !fh->close_on_exec ()) |
dd4f0b23 | 706 | { |
c729f227 | 707 | debug_printf ("fd %d (%s)", i, fh->get_name ()); |
dd4f0b23 CV |
708 | fh->fixup_before_fork_exec (target_proc_id); |
709 | } | |
2d1d1eb1 | 710 | unlock (); |
dd4f0b23 CV |
711 | } |
712 | ||
fef1edbc CF |
713 | void |
714 | dtable::set_file_pointers_for_exec () | |
715 | { | |
cce64750 CV |
716 | /* This is not POSIX-compliant so the function is only called for |
717 | non-Cygwin processes. */ | |
ad4e943f | 718 | LONG off_high = 0; |
2d1d1eb1 | 719 | lock (); |
fef1edbc CF |
720 | fhandler_base *fh; |
721 | for (size_t i = 0; i < size; i++) | |
722 | if ((fh = fds[i]) != NULL && fh->get_flags () & O_APPEND) | |
ad4e943f | 723 | SetFilePointer (fh->get_handle (), 0, &off_high, FILE_END); |
2d1d1eb1 | 724 | unlock (); |
fef1edbc CF |
725 | } |
726 | ||
b0e82b74 | 727 | void |
52806019 | 728 | dtable::fixup_after_exec () |
1fd5e000 | 729 | { |
b0e82b74 | 730 | first_fd_for_open = 0; |
2e78b61d | 731 | fhandler_base *fh; |
b0e82b74 | 732 | for (size_t i = 0; i < size; i++) |
2e78b61d | 733 | if ((fh = fds[i]) != NULL) |
4f7ac76a | 734 | { |
2e78b61d | 735 | fh->clear_readahead (); |
59297e04 | 736 | fh->fixup_after_exec (); |
56551a9b | 737 | if (fh->close_on_exec ()) |
8ed5c9b6 CF |
738 | { |
739 | if (fh->archetype) | |
578e142a CF |
740 | { |
741 | debug_printf ("closing fd %d since it is an archetype", i); | |
742 | fh->close (); | |
743 | } | |
8ed5c9b6 CF |
744 | release (i); |
745 | } | |
59297e04 CF |
746 | else if (i == 0) |
747 | SetStdHandle (std_consts[i], fh->get_io_handle ()); | |
748 | else if (i <= 2) | |
749 | SetStdHandle (std_consts[i], fh->get_output_handle ()); | |
4f7ac76a | 750 | } |
1fd5e000 CF |
751 | } |
752 | ||
753 | void | |
9015e0fb | 754 | dtable::fixup_after_fork (HANDLE parent) |
1fd5e000 | 755 | { |
b0e82b74 | 756 | fhandler_base *fh; |
1fd5e000 | 757 | for (size_t i = 0; i < size; i++) |
b0e82b74 | 758 | if ((fh = fds[i]) != NULL) |
1fd5e000 | 759 | { |
56551a9b | 760 | if (fh->close_on_exec () || fh->need_fork_fixup ()) |
1fd5e000 | 761 | { |
c729f227 | 762 | debug_printf ("fd %d (%s)", i, fh->get_name ()); |
1fd5e000 CF |
763 | fh->fixup_after_fork (parent); |
764 | } | |
f3acbe3e CF |
765 | if (i == 0) |
766 | SetStdHandle (std_consts[i], fh->get_io_handle ()); | |
767 | else if (i <= 2) | |
768 | SetStdHandle (std_consts[i], fh->get_output_handle ()); | |
1fd5e000 | 769 | } |
1fd5e000 CF |
770 | } |
771 | ||
f7239090 | 772 | #ifdef NEWVFORK |
1fd5e000 | 773 | int |
9015e0fb | 774 | dtable::vfork_child_dup () |
1fd5e000 CF |
775 | { |
776 | fhandler_base **newtable; | |
2d1d1eb1 | 777 | lock (); |
c729f227 | 778 | newtable = (fhandler_base **) ccalloc (HEAP_ARGV, size, sizeof (fds[0])); |
1fd5e000 CF |
779 | int res = 1; |
780 | ||
928eca7a | 781 | /* Remove impersonation */ |
70249d56 | 782 | cygheap->user.deimpersonate (); |
9279515a | 783 | if (cygheap->ctty) |
e9737793 CF |
784 | { |
785 | cygheap->ctty->usecount++; | |
59297e04 | 786 | cygheap->console_count++; |
e9737793 CF |
787 | report_tty_counts (cygheap->ctty, "vfork dup", "incremented ", ""); |
788 | } | |
928eca7a | 789 | |
1fd5e000 CF |
790 | for (size_t i = 0; i < size; i++) |
791 | if (not_open (i)) | |
792 | continue; | |
a7670c1e | 793 | else if ((newtable[i] = dup_worker (fds[i])) != NULL) |
56551a9b | 794 | newtable[i]->set_close_on_exec (fds[i]->close_on_exec ()); |
a7670c1e | 795 | else |
1fd5e000 CF |
796 | { |
797 | res = 0; | |
1fd5e000 CF |
798 | goto out; |
799 | } | |
b0e82b74 | 800 | |
1fd5e000 CF |
801 | fds_on_hold = fds; |
802 | fds = newtable; | |
c729f227 | 803 | |
1fd5e000 | 804 | out: |
380aaf2d | 805 | /* Restore impersonation */ |
70249d56 | 806 | cygheap->user.reimpersonate (); |
380aaf2d | 807 | |
2d1d1eb1 | 808 | unlock (); |
1fd5e000 CF |
809 | return 1; |
810 | } | |
811 | ||
812 | void | |
9015e0fb | 813 | dtable::vfork_parent_restore () |
1fd5e000 | 814 | { |
2d1d1eb1 | 815 | lock (); |
1fd5e000 | 816 | |
001197ae | 817 | fhandler_tty_slave *ctty_on_hold = cygheap->ctty_on_hold; |
f9fb1149 | 818 | close_all_files (); |
1fd5e000 CF |
819 | fhandler_base **deleteme = fds; |
820 | fds = fds_on_hold; | |
821 | fds_on_hold = NULL; | |
b0e82b74 | 822 | cfree (deleteme); |
2d1d1eb1 | 823 | unlock (); |
e80cbe3e | 824 | |
42f5993f CF |
825 | if (cygheap->ctty != ctty_on_hold) |
826 | { | |
827 | cygheap->ctty = ctty_on_hold; // revert | |
828 | cygheap->ctty->close (); // Undo previous bump of this archetype | |
829 | } | |
e80cbe3e | 830 | cygheap->ctty_on_hold = NULL; |
0381fec6 CF |
831 | } |
832 | ||
833 | void | |
834 | dtable::vfork_child_fixup () | |
835 | { | |
836 | if (!fds_on_hold) | |
837 | return; | |
a7670c1e | 838 | debug_printf ("here"); |
0381fec6 CF |
839 | fhandler_base **saveme = fds; |
840 | fds = fds_on_hold; | |
841 | ||
842 | fhandler_base *fh; | |
9279515a CF |
843 | for (int i = 0; i < (int) size; i++) |
844 | if ((fh = fds[i]) != NULL) | |
0381fec6 | 845 | { |
0381fec6 | 846 | fh->clear_readahead (); |
56551a9b | 847 | if (!fh->archetype && fh->close_on_exec ()) |
cdcfe4e8 CF |
848 | release (i); |
849 | else | |
850 | { | |
851 | fh->close (); | |
9279515a | 852 | release (i); |
cdcfe4e8 | 853 | } |
0381fec6 CF |
854 | } |
855 | ||
856 | fds = saveme; | |
857 | cfree (fds_on_hold); | |
858 | fds_on_hold = NULL; | |
859 | ||
e80cbe3e CF |
860 | if (cygheap->ctty_on_hold) |
861 | { | |
862 | cygheap->ctty_on_hold->close (); | |
863 | cygheap->ctty_on_hold = NULL; | |
864 | } | |
1fd5e000 | 865 | } |
f7239090 | 866 | #endif /*NEWVFORK*/ |
2402700d | 867 | |
88f0dc31 CF |
868 | static void |
869 | decode_tty (char *buf, WCHAR *w32) | |
1ffe3e67 CF |
870 | { |
871 | int ttyn = wcstol (w32, NULL, 10); | |
872 | __small_sprintf (buf, "/dev/tty%d", ttyn); | |
873 | } | |
874 | ||
88f0dc31 CF |
875 | /* Try to derive posix filename from given handle. Return true if |
876 | the handle is associated with a cygwin tty. */ | |
877 | static bool | |
2402700d CF |
878 | handle_to_fn (HANDLE h, char *posix_fn) |
879 | { | |
ab5d348d | 880 | tmp_pathbuf tp; |
1ffe3e67 CF |
881 | ULONG len = 0; |
882 | OBJECT_NAME_INFORMATION dummy_oni; | |
883 | WCHAR *maxmatchdos = NULL; | |
884 | int maxmatchlen = 0; | |
2402700d | 885 | |
1ffe3e67 CF |
886 | NtQueryObject (h, ObjectNameInformation, &dummy_oni, sizeof (dummy_oni), &len); |
887 | if (!len) | |
888 | { | |
889 | debug_printf ("NtQueryObject failed 1"); | |
890 | goto unknown; | |
891 | } | |
2402700d | 892 | |
1ffe3e67 | 893 | OBJECT_NAME_INFORMATION *ntfn = (OBJECT_NAME_INFORMATION *) alloca (len + sizeof (WCHAR)); |
ab5d348d | 894 | NTSTATUS res = NtQueryObject (h, ObjectNameInformation, ntfn, len, NULL); |
cef69559 | 895 | |
ee4388c4 | 896 | if (!NT_SUCCESS (res)) |
2402700d | 897 | { |
1ffe3e67 CF |
898 | debug_printf ("NtQueryObject failed 2"); |
899 | goto unknown; | |
2402700d | 900 | } |
2bb6b3e5 CF |
901 | |
902 | // NT seems to do this on an unopened file | |
903 | if (!ntfn->Name.Buffer) | |
904 | { | |
905 | debug_printf ("nt->Name.Buffer == NULL"); | |
1ffe3e67 | 906 | goto unknown; |
2bb6b3e5 CF |
907 | } |
908 | ||
1ffe3e67 CF |
909 | WCHAR *w32 = ntfn->Name.Buffer; |
910 | size_t w32len = ntfn->Name.Length / sizeof (WCHAR); | |
911 | w32[w32len] = L'\0'; | |
2402700d | 912 | |
1ffe3e67 CF |
913 | if (wcscasecmp (w32, DEV_NULL) == 0) |
914 | { | |
915 | strcpy (posix_fn, "/dev/null"); | |
88f0dc31 | 916 | return false; |
1ffe3e67 | 917 | } |
5bf785a0 | 918 | |
1ffe3e67 CF |
919 | if (wcsncasecmp (w32, DEV_NAMED_PIPE, DEV_NAMED_PIPE_LEN) == 0) |
920 | { | |
921 | w32 += DEV_NAMED_PIPE_LEN; | |
88f0dc31 CF |
922 | if (wcsncmp (w32, L"cygwin-", WCLEN (L"cygwin-")) != 0) |
923 | return false; | |
924 | w32 += WCLEN (L"cygwin-"); | |
925 | bool istty = wcsncmp (w32, L"tty", WCLEN (L"tty")) == 0; | |
926 | if (istty) | |
927 | decode_tty (posix_fn, w32 + WCLEN (L"tty")); | |
928 | else if (wcsncmp (w32, L"pipe", WCLEN (L"pipe")) == 0) | |
929 | strcpy (posix_fn, "/dev/pipe"); | |
930 | return istty; | |
1ffe3e67 | 931 | } |
2402700d | 932 | |
1ffe3e67 CF |
933 | |
934 | WCHAR fnbuf[64 * 1024]; | |
935 | if (wcsncasecmp (w32, DEVICE_PREFIX, DEVICE_PREFIX_LEN) != 0 | |
936 | || !QueryDosDeviceW (NULL, fnbuf, sizeof (fnbuf))) | |
937 | { | |
938 | sys_wcstombs (posix_fn, NT_MAX_PATH, w32, w32len); | |
88f0dc31 | 939 | return false; |
1ffe3e67 CF |
940 | } |
941 | ||
942 | for (WCHAR *s = fnbuf; *s; s = wcschr (s, '\0') + 1) | |
2402700d | 943 | { |
1ffe3e67 CF |
944 | WCHAR device[NT_MAX_PATH]; |
945 | if (!QueryDosDeviceW (s, device, sizeof (device))) | |
2402700d | 946 | continue; |
1ffe3e67 | 947 | if (wcschr (s, ':') == NULL) |
2402700d | 948 | continue; |
1ffe3e67 | 949 | WCHAR *q = wcsrchr (device, ';'); |
37be5a67 CF |
950 | if (q) |
951 | { | |
1ffe3e67 | 952 | WCHAR *r = wcschr (q, '\\'); |
37be5a67 | 953 | if (r) |
1ffe3e67 | 954 | wcscpy (q, r + 1); |
37be5a67 | 955 | } |
1ffe3e67 CF |
956 | int devlen = wcslen (device); |
957 | if (device[devlen - 1] == L'\\') | |
958 | device[--devlen] = L'\0'; | |
37be5a67 CF |
959 | if (devlen < maxmatchlen) |
960 | continue; | |
1ffe3e67 CF |
961 | if (wcsncmp (device, w32, devlen) != 0|| |
962 | (w32[devlen] != L'\0' && w32[devlen] != L'\\')) | |
2402700d | 963 | continue; |
37be5a67 CF |
964 | maxmatchlen = devlen; |
965 | maxmatchdos = s; | |
1ffe3e67 | 966 | debug_printf ("current match '%W' = '%W'\n", s, device); |
37be5a67 CF |
967 | } |
968 | ||
37be5a67 CF |
969 | if (maxmatchlen) |
970 | { | |
1ffe3e67 CF |
971 | WCHAR *p = wcschr (w32 + DEVICE_PREFIX_LEN, L'\\'); |
972 | size_t n = wcslen (maxmatchdos); | |
973 | WCHAR ch; | |
974 | if (!p) | |
975 | ch = L'\0'; | |
976 | else | |
977 | { | |
978 | if (maxmatchdos[n - 1] == L'\\') | |
979 | n--; | |
980 | w32 += maxmatchlen - n; | |
981 | ch = L'\\'; | |
982 | } | |
983 | memcpy (w32, maxmatchdos, n * sizeof (WCHAR)); | |
984 | w32[n] = ch; | |
634a4140 | 985 | } |
1ffe3e67 | 986 | else if (wcsncmp (w32, DEV_REMOTE, DEV_REMOTE_LEN) == 0) |
ce006ffa | 987 | { |
1ffe3e67 CF |
988 | w32 += DEV_REMOTE_LEN - 2; |
989 | *w32 = L'\\'; | |
ce006ffa | 990 | debug_printf ("remote drive"); |
634a4140 | 991 | } |
1ffe3e67 | 992 | else if (wcsncmp (w32, DEV_REMOTE1, DEV_REMOTE1_LEN) == 0) |
634a4140 | 993 | { |
1ffe3e67 CF |
994 | w32 += DEV_REMOTE1_LEN - 2; |
995 | *w32 = L'\\'; | |
634a4140 | 996 | debug_printf ("remote drive"); |
ce006ffa CF |
997 | } |
998 | ||
1ffe3e67 CF |
999 | cygwin_conv_path (CCP_WIN_W_TO_POSIX | CCP_ABSOLUTE, w32, posix_fn, |
1000 | NT_MAX_PATH); | |
1001 | ||
1002 | debug_printf ("derived path '%W', posix '%s'", w32, posix_fn); | |
88f0dc31 | 1003 | return false; |
2402700d | 1004 | |
1ffe3e67 CF |
1005 | unknown: |
1006 | strcpy (posix_fn, unknown_file); | |
88f0dc31 | 1007 | return false; |
2402700d | 1008 | } |