2000-02-18 03:38:33 +08:00
|
|
|
/* fhandler_termios.cc
|
|
|
|
|
|
|
|
This file is part of Cygwin.
|
|
|
|
|
|
|
|
This software is a copyrighted work licensed under the terms of the
|
|
|
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
|
|
|
details. */
|
|
|
|
|
2000-08-03 00:28:18 +08:00
|
|
|
#include "winsup.h"
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
2000-08-22 11:58:47 +08:00
|
|
|
#include "cygerrno.h"
|
* devices.cc: New file.
* devices.gperf: New file.
* devices.shilka: New file.
* cygwin-gperf: New file.
* cygwin-shilka: New file.
* fhandler_fifo.cc: New file.
* fhandler_nodevice.cc : New file. Reorganize headers so that path.h precedes
fhandler.h throughout. Remove device argument and unit arguments from fhandler
constructors throughout. Remove pc arguments to fhandler functions and use
internal pc element instead, throughout. Use dev element in pc throughout.
Use major/minor elements rather than units and device numbers previously in
fhandler class. Use correct methods for fhandler file names rather than
directly accessing file name variables, throughout.
* Makefile.in (DLL_OFILES): Add devices.o, fhandler_fifo.o
* dcrt0.cc (dll_crt0_1): Call device::init.
* devices.h: Renumber devices based on more Linux-like major/minor numbers.
Add more devices. Declare standard device storage.
(device): Declare struct.
* dir.cc (opendir): Use new 'build_fh_name' to construct a fhandler_* type.
* dtable.cc (dtable::get_debugger_info): Ditto.
(cygwin_attach_handle_to_fd): Ditto.
(dtable::release): Remove special FH_SOCKET case in favor of generic
"need_fixup_before" test.
(dtable::init_std_file_from_handle): Use either build_fh_dev or build_fh_name
to build standard fhandler.
(dtable::build_fh_name): Renamed from dtable::build_fhandler_from_name. Move
out of dtable class. Don't accept a path_conv argument. Just build it here
and pass it to:
(build_fh_pc): Renamed from dtable::build_fhandler. Move out of dtable class.
Use intrinsic device type in path_conv to create new fhandler.
(build_fh_dev): Renamed from dtable::build_fhandler. Move out of dtable class.
Simplify arguments to just take new 'device' type and a name. Just return
pointer to fhandler rather than trying to insert into dtable.
(dtable::dup_worker): Accommodate above build_fh name changes.
(dtable::find_fifo): New (currently broken) function.
(handle_to_fn): Use strechr for efficiency.
* dtable.h: Reflect above build_fh name changes and argument differences.
(fhandler_base *&operator []): Return self rather than copy of self.
* fhandler.cc (fhandler_base::operator =): Use pc element to set normalized
path.
(fhandler_base::set_name): Ditto.
(fhandler_base::raw_read): Use method to access name.
(fhandler_base::write): Correctly use get_output_handle rather than get_handle.
(handler_base::device_access_denied): New function.
(fhandler_base::open): Eliminate pc argument and use pc element of
fhandler_base throughout.
(fhandler_base::fstat): Detect if device is based in filesystem and use
fstat_fs to calculate stat, if so.
(fhandler_base::fhandler_base): Eliminate handling of file names and, instead,
just free appropriate component from pc.
(fhandler_base::opendir): Remove path_conv parameter.
* fhandler.h: Remove all device flags.
(fhandler_base::pc): New element.
(fhandler_base::set_name): Change argument to path_conv.
(fhandler_base::error): New function.
(fhandler_base::exists): New function.
(fhandler_base::pc_binmode): New function.
(fhandler_base::dev): New function.
(fhandler_base::open_fs): New function.
(fhandler_base::fstat_fs): New function.
(fhandler_base::fstat_by_name): New function.
(fhandler_base::fstat_by_handle): New function.
(fhandler_base::isfifo): New function.
(fhandler_base::is_slow): New function.
(fhandler_base::is_auto_device): New function.
(fhandler_base::is_fs_special): New function.
(fhandler_base::device_access_denied): New function.
(fhandler_base::operator DWORD&): New operator.
(fhandler_base::get_name): Return normalized path from pc.
(fhandler_base::get_win32_name): Return windows path from pc.
(fhandler_base::isdevice): Renamed from is_device.
(fhandler_base::get_native_name): Return device format.
(fhandler_fifo): New class.
(fhandler_nodevice): New class.
(select_stuff::device_specific): Remove array.
(select_stuff::device_specific_pipe): New class element.
(select_stuff::device_specific_socket): New class element.
(select_stuff::device_specific_serial): New class element.
(select_stuff::select_stuff): Initialize new elements.
* fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Move to base class
from fhandler_disk_file.
(fhandler_base::fstat_by_name): Ditto.
(fhandler_base::fstat_by_name): Ditto.
(fhandler_disk_file::open): Move most functionality into
fhandler_base::open_fs.
(fhandler_base::open_fs): New function.
(fhandler_disk_file::close): Move most functionality into
fhandler_base::close_fs.
(fhandler_base::close_fs): New function.
* fhandler_mem.cc (fhandler_dev_mem::open): Use device name in debugging
output.
* fhandler_socket.cc (fhandler_socket::set_connect_secret): Copy standard
urandom device into appropriate place.
(fhandler_socket::accept): Reflect change in fdsock return value.
* fhandler_tty.cc: See "throughouts" above.
* net.cc: Accommodate fdsock change throughout.
(fdsock): Return success or failure, accept fd argument and device argument.
* path.cc (symlink_info::major): New element.
(symlink_info::minor): New element.
(symlink_info::parse_device): Declare new function.
(fs_info::update): Accommodate changes in path_conv class.
(path_conv::fillin): Ditto.
(path_conv::return_and_clear_normalized_path): Eliminate.
(path_conv::set_normalized_path): New function.
(path_conv::path_conv): Set info in dev element. Use path_conv methods Check
for FH_FS rather than FH_BAD to indicate when to fill in filesystem stuff.
where appropriate rather than direct access. Use set_normalized_path to set
normalized path.
(windows_device_names): Eliminate.
(get_dev): Ditto.
(get_raw_device_number): Ditto.
(get_device_number): Ditto.
(win32_device_name): Call new device name parser to do most of the heavy
lifting.
(mount_info::conv_to_win32_path): Fill in dev field as appropriate.
(symlink_worker): Handle new device files.
(symlink_info::check): Ditto.
(symlink_info::parse_device): Define new function.
* path.h (executable_states): Move here from fhandler.h.
(fs_info): Rename variables to *_storage and create methods for accessing same.
(path_conv): Add dev element, remove devn and unit and adjust inline methods to
accommodate.
(set_normalized_path): Declare new function.
* pinfo.cc (_pinfo::commune_recv): Add broken support for handling fifos.
(_pinfo::commune_send): Ditto.
* pipe.cc (fhandler_pipe::close): check for existence of handle before closing
it.
(handler_pipe::create): Rename from make_pipe. Change arguments to accept
fhandler_pipe array. Accommodate fifos.
(pipe): Rework to deal with fhandler_pipe::create changes.
(_pipe): Ditto.
* select.cc: Use individual device_specific types throughout rather than
indexing with obsolete device number.
(set_bits): Use is_socket call rather than checking device number.
* shared_info.h (CURR_MOUNT_MAGIC): Update.
(conv_to_win32_path): Reflect addition of device argument.
* syscalls.cc (mknod_worker): New function.
(open): Use build_fh_name to build fhandler.
(chown_worker): Detect if this is an 'auto' device rather than an on-filesystem
device and handle appropriately.
(chmod_device): New function.
(chmod): Detect if this is an 'auto' device rather than an on-filesystem device
and handle appropriately. Use chmod_device to set mode of in-filesystem
devices.
(stat_worker): Eliminate path_conv argument. Call build_fh_name to construct
fhandler. Use fh->error() rather than pc->error to detect errors in fhandler
construction.
(access_worker): New function pulled from access. Accommodate in-filesystem
devices.
(access): Use access_worker.
(fpathconf): Detect if this is an 'auto' device rather than an on-filesystem
device and handle appropriately.
(mknod_worker): New function.
(mknod32): New function.
(chroot): Free normalized path -- assuming it was actually cmalloced.
* tty.cc (create_tty_master): Tweak for new device class.
(tty::common_init): Ditto.
* winsup.h (stat_worker): Remove.
(symlink_worker): Declare.
* exceptions.cc (set_process_mask): Just call sig_dispatch_pending and don't
worry about pending_signals since sig_dispatch_pending should always do the
right thing now.
(sig_handle): Reorganize SIGCONT handling to more closely conform to SUSv3.
* pinfo.h: Move __SIG enum to sigproc.h.
(PICOM_FIFO): New enum element.
(_pinfo): Remove 'thread2signal' stuff throughout class.
(_pinfo::commune_send): Make varargs.
(_pinfo::sigtodo): Eliminate.
(_pinfo::thread2signal): Ditto.
* signal.cc (kill_worker): Eliminate call to setthread2signal.
* sigproc.cc (local_sigtodo): Eliminate.
(getlocal_sigtodo): Ditto.
(sigelem): New class.
(pending_signals): New class.
(sigqueue): New variable, start of sigqueue linked list.
(sigcatch_nonmain): Eliminate.
(sigcatch_main): Eliminate.
(sigcatch_nosync): Eliminate.
(sigcomplete_nonmain): Eliminate.
(pending_signals): Eliminate.
(sig_clear): Call signal thread to clear pending signals, unless already in
signal thread.
(sigpending): Call signal thread to get pending signals.
(sig_dispatch_pending): Eliminate use of pending_signals and just check
sigqueue.
(sigproc_terminate): Eliminate all of the obsolete semaphore stuff. Close
signal pipe handle.
(sig_send): Eliminate all of the obsolete semaphore stuff and use pipe to send
signals.
(getevent): Eliminate.
(pending_signals::add): New function.
(pending_signals::del): New function.
(pending_signals::next): New function.
(wait_sig): Eliminate all of the obsolete semaphore stuff. Use pipe to
communicate and maintain a linked list of signals.
* sigproc.h: Move __SIG defines here. Add __SIGPENDING.
(sig_dispatch_pending): Remove "C" specifier.
(sig_handle): Accept a mask argument.
* thread.cc: Remove signal handling considerations throughout.
2003-09-25 08:37:18 +08:00
|
|
|
#include "path.h"
|
2000-08-22 13:10:20 +08:00
|
|
|
#include "fhandler.h"
|
|
|
|
#include "sigproc.h"
|
|
|
|
#include "pinfo.h"
|
2000-09-08 00:23:51 +08:00
|
|
|
#include "tty.h"
|
2005-06-30 10:52:14 +08:00
|
|
|
#include "cygtls.h"
|
2012-04-18 13:57:38 +08:00
|
|
|
#include "dtable.h"
|
|
|
|
#include "cygheap.h"
|
|
|
|
#include "child_info.h"
|
2011-04-29 16:27:11 +08:00
|
|
|
#include "ntdll.h"
|
2024-11-06 09:19:59 +08:00
|
|
|
#include "tls_pbuf.h"
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2022-01-13 17:16:31 +08:00
|
|
|
/* Wait time for some treminal mutexes. This is set to 0 when the
|
|
|
|
process calls CreateProcess() with DEBUG_PROCESS flag, because
|
|
|
|
the debuggie may be suspended while it grabs the mutex. Without
|
|
|
|
this, GDB may cause deadlock in console or pty I/O. */
|
|
|
|
DWORD NO_COPY mutex_timeout = INFINITE;
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
/* Common functions shared by tty/console */
|
|
|
|
|
|
|
|
void
|
2011-06-04 08:12:29 +08:00
|
|
|
fhandler_termios::tcinit (bool is_pty_master)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
/* Initial termios values */
|
|
|
|
|
2011-06-04 08:12:29 +08:00
|
|
|
if (is_pty_master || !tc ()->initialized ())
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2017-01-31 22:36:24 +08:00
|
|
|
tc ()->ti.c_iflag = BRKINT | ICRNL | IXON | IUTF8;
|
2011-06-04 08:12:29 +08:00
|
|
|
tc ()->ti.c_oflag = OPOST | ONLCR;
|
|
|
|
tc ()->ti.c_cflag = B38400 | CS8 | CREAD;
|
2020-05-17 10:34:44 +08:00
|
|
|
tc ()->ti.c_lflag = ISIG | ICANON | ECHO | IEXTEN
|
|
|
|
| ECHOE | ECHOK | ECHOCTL | ECHOKE;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2011-06-04 08:12:29 +08:00
|
|
|
tc ()->ti.c_cc[VDISCARD] = CFLUSH;
|
2014-11-14 02:37:15 +08:00
|
|
|
tc ()->ti.c_cc[VEOL] = CEOL;
|
2011-06-04 08:12:29 +08:00
|
|
|
tc ()->ti.c_cc[VEOL2] = CEOL2;
|
2014-11-14 02:37:15 +08:00
|
|
|
tc ()->ti.c_cc[VEOF] = CEOF;
|
2011-06-04 08:12:29 +08:00
|
|
|
tc ()->ti.c_cc[VERASE] = CERASE;
|
|
|
|
tc ()->ti.c_cc[VINTR] = CINTR;
|
|
|
|
tc ()->ti.c_cc[VKILL] = CKILL;
|
|
|
|
tc ()->ti.c_cc[VLNEXT] = CLNEXT;
|
2015-03-26 00:21:38 +08:00
|
|
|
tc ()->ti.c_cc[VMIN] = CMIN;
|
2011-06-04 08:12:29 +08:00
|
|
|
tc ()->ti.c_cc[VQUIT] = CQUIT;
|
|
|
|
tc ()->ti.c_cc[VREPRINT] = CRPRNT;
|
|
|
|
tc ()->ti.c_cc[VSTART] = CSTART;
|
|
|
|
tc ()->ti.c_cc[VSTOP] = CSTOP;
|
|
|
|
tc ()->ti.c_cc[VSUSP] = CSUSP;
|
|
|
|
tc ()->ti.c_cc[VSWTC] = CSWTCH;
|
2015-03-26 00:21:38 +08:00
|
|
|
tc ()->ti.c_cc[VTIME] = CTIME;
|
2011-06-04 08:12:29 +08:00
|
|
|
tc ()->ti.c_cc[VWERASE] = CWERASE;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2011-06-04 08:12:29 +08:00
|
|
|
tc ()->ti.c_ispeed = tc ()->ti.c_ospeed = B38400;
|
|
|
|
tc ()->pgid = is_pty_master ? 0 : myself->pgid;
|
|
|
|
tc ()->initialized (true);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fhandler_termios::tcsetpgrp (const pid_t pgid)
|
|
|
|
{
|
2012-01-08 14:24:17 +08:00
|
|
|
termios_printf ("%s, pgid %d, sid %d, tsid %d", tc ()->ttyname (), pgid,
|
2011-06-04 08:12:29 +08:00
|
|
|
myself->sid, tc ()->getsid ());
|
|
|
|
if (myself->sid != tc ()->getsid ())
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
set_errno (EPERM);
|
|
|
|
return -1;
|
|
|
|
}
|
2019-07-24 23:29:53 +08:00
|
|
|
else if (pgid < 0)
|
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
|
|
|
return -1;
|
|
|
|
}
|
2005-06-30 10:52:14 +08:00
|
|
|
int res;
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
res = bg_check (-SIGTTOU);
|
|
|
|
|
|
|
|
switch (res)
|
|
|
|
{
|
|
|
|
case bg_ok:
|
2011-06-04 08:12:29 +08:00
|
|
|
tc ()->setpgid (pgid);
|
2011-12-17 08:03:31 +08:00
|
|
|
if (tc ()->is_console && (strace.active () || !being_debugged ()))
|
2011-10-07 03:47:45 +08:00
|
|
|
tc ()->kill_pgrp (__SIGSETPGRP);
|
2005-06-30 10:52:14 +08:00
|
|
|
res = 0;
|
|
|
|
break;
|
|
|
|
case bg_signalled:
|
|
|
|
if (_my_tls.call_signal_handler ())
|
|
|
|
continue;
|
|
|
|
set_errno (EINTR);
|
2020-08-06 03:58:22 +08:00
|
|
|
fallthrough;
|
2005-06-30 10:52:14 +08:00
|
|
|
default:
|
|
|
|
res = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return res;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fhandler_termios::tcgetpgrp ()
|
|
|
|
{
|
2023-03-05 18:02:13 +08:00
|
|
|
if (CTTY_IS_VALID (myself->ctty) && myself->ctty == tc ()->ntty)
|
2011-06-04 08:12:29 +08:00
|
|
|
return tc ()->pgid;
|
2009-10-07 15:52:30 +08:00
|
|
|
set_errno (ENOTTY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fhandler_pty_master::tcgetpgrp ()
|
|
|
|
{
|
2011-06-04 08:12:29 +08:00
|
|
|
return tc ()->pgid;
|
2011-05-30 14:58:00 +08:00
|
|
|
}
|
|
|
|
|
2013-01-31 13:26:47 +08:00
|
|
|
static inline bool
|
|
|
|
is_flush_sig (int sig)
|
|
|
|
{
|
|
|
|
return sig == SIGINT || sig == SIGQUIT || sig == SIGTSTP;
|
|
|
|
}
|
|
|
|
|
2002-02-23 03:33:41 +08:00
|
|
|
void
|
2022-02-15 22:23:50 +08:00
|
|
|
tty_min::kill_pgrp (int sig, pid_t target_pgid)
|
2002-02-23 03:33:41 +08:00
|
|
|
{
|
2022-02-15 22:23:50 +08:00
|
|
|
target_pgid = target_pgid ?: pgid;
|
2011-12-08 12:09:22 +08:00
|
|
|
bool killself = false;
|
2013-01-31 13:26:47 +08:00
|
|
|
if (is_flush_sig (sig) && cygheap->ctty)
|
|
|
|
cygheap->ctty->sigflush ();
|
2003-09-17 09:15:56 +08:00
|
|
|
winpids pids ((DWORD) PID_MAP_RW);
|
2006-02-07 02:24:11 +08:00
|
|
|
siginfo_t si = {0};
|
2004-01-19 13:46:54 +08:00
|
|
|
si.si_signo = sig;
|
|
|
|
si.si_code = SI_KERNEL;
|
2021-11-02 16:09:40 +08:00
|
|
|
if (sig > 0 && sig < _NSIG)
|
|
|
|
last_sig = sig;
|
2013-01-31 13:26:47 +08:00
|
|
|
|
2002-02-23 03:33:41 +08:00
|
|
|
for (unsigned i = 0; i < pids.npids; i++)
|
|
|
|
{
|
|
|
|
_pinfo *p = pids[i];
|
2022-02-15 22:23:50 +08:00
|
|
|
if (!p || !p->exists () || p->ctty != ntty || p->pgid != target_pgid)
|
2002-02-23 03:33:41 +08:00
|
|
|
continue;
|
2022-02-10 15:53:47 +08:00
|
|
|
if (p->process_state & PID_NOTCYGWIN)
|
2022-02-27 19:40:24 +08:00
|
|
|
continue; /* Do not send signal to non-cygwin process to prevent
|
|
|
|
cmd.exe from crash. */
|
2002-02-23 03:33:41 +08:00
|
|
|
if (p == myself)
|
2013-10-19 04:56:19 +08:00
|
|
|
killself = sig != __SIGSETPGRP && !exit_state;
|
2002-02-23 03:33:41 +08:00
|
|
|
else
|
2005-07-07 04:05:03 +08:00
|
|
|
sig_send (p, si);
|
2002-02-23 03:33:41 +08:00
|
|
|
}
|
|
|
|
if (killself)
|
2004-01-19 13:46:54 +08:00
|
|
|
sig_send (myself, si);
|
2002-02-23 03:33:41 +08:00
|
|
|
}
|
2002-05-28 09:55:40 +08:00
|
|
|
|
2011-06-04 08:12:29 +08:00
|
|
|
int
|
|
|
|
tty_min::is_orphaned_process_group (int pgid)
|
|
|
|
{
|
|
|
|
/* An orphaned process group is a process group in which the parent
|
|
|
|
of every member is either itself a member of the group or is not
|
|
|
|
a member of the group's session. */
|
|
|
|
termios_printf ("checking pgid %d, my sid %d, my parent %d", pgid, myself->sid, myself->ppid);
|
|
|
|
winpids pids ((DWORD) 0);
|
|
|
|
for (unsigned i = 0; i < pids.npids; i++)
|
|
|
|
{
|
|
|
|
_pinfo *p = pids[i];
|
|
|
|
termios_printf ("checking pid %d - has pgid %d\n", p->pid, p->pgid);
|
|
|
|
if (!p || !p->exists () || p->pgid != pgid)
|
2011-06-06 13:02:13 +08:00
|
|
|
continue;
|
2011-06-04 08:12:29 +08:00
|
|
|
pinfo ppid (p->ppid);
|
|
|
|
if (!ppid)
|
|
|
|
continue;
|
|
|
|
termios_printf ("ppid->pgid %d, ppid->sid %d", ppid->pgid, ppid->sid);
|
|
|
|
if (ppid->pgid != pgid && ppid->sid == myself->sid)
|
2011-06-06 13:02:13 +08:00
|
|
|
return 0;
|
2011-06-04 08:12:29 +08:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-07-27 02:03:07 +08:00
|
|
|
/*
|
|
|
|
bg_check: check that this process is either in the foreground process group,
|
|
|
|
or if the terminal operation is allowed for processes which are in a
|
|
|
|
background process group.
|
|
|
|
|
|
|
|
If the operation is not permitted by the terminal configuration for processes
|
|
|
|
which are a member of a background process group, return an error or raise a
|
|
|
|
signal as appropriate.
|
|
|
|
|
|
|
|
This handles the following terminal operations:
|
|
|
|
|
|
|
|
write: sig = SIGTTOU
|
|
|
|
read: sig = SIGTTIN
|
|
|
|
change terminal settings: sig = -SIGTTOU
|
|
|
|
(tcsetattr, tcsetpgrp, etc.)
|
|
|
|
peek (poll, select): sig = SIGTTIN, dontsignal = TRUE
|
|
|
|
*/
|
2001-01-17 22:57:09 +08:00
|
|
|
bg_check_types
|
2016-07-27 02:03:07 +08:00
|
|
|
fhandler_termios::bg_check (int sig, bool dontsignal)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2016-07-27 02:03:07 +08:00
|
|
|
/* Ignore errors:
|
|
|
|
- this process isn't in a process group
|
|
|
|
- tty is invalid
|
|
|
|
|
|
|
|
Everything is ok if:
|
|
|
|
- this process is in the foreground process group, or
|
|
|
|
- this tty is not the controlling tty for this process (???), or
|
|
|
|
- writing, when TOSTOP TTY mode is not set on this tty
|
|
|
|
*/
|
2013-01-31 13:26:47 +08:00
|
|
|
if (!myself->pgid || !tc () || tc ()->getpgid () == myself->pgid ||
|
2011-06-04 08:12:29 +08:00
|
|
|
myself->ctty != tc ()->ntty ||
|
|
|
|
((sig == SIGTTOU) && !(tc ()->ti.c_lflag & TOSTOP)))
|
2001-01-17 22:57:09 +08:00
|
|
|
return bg_ok;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2016-07-27 02:03:07 +08:00
|
|
|
/* sig -SIGTTOU is used to indicate a change to terminal settings, where
|
|
|
|
TOSTOP TTY mode isn't considered when determining if we need to send a
|
|
|
|
signal. */
|
2000-02-18 03:38:33 +08:00
|
|
|
if (sig < 0)
|
|
|
|
sig = -sig;
|
|
|
|
|
2012-01-08 14:24:17 +08:00
|
|
|
termios_printf ("%s, bg I/O pgid %d, tpgid %d, myctty %s", tc ()->ttyname (),
|
|
|
|
myself->pgid, tc ()->getpgid (), myctty ());
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2011-06-04 08:12:29 +08:00
|
|
|
if (tc ()->getsid () == 0)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
/* The pty has been closed by the master. Return an EOF
|
|
|
|
indication. FIXME: There is nothing to stop somebody
|
|
|
|
from reallocating this pty. I think this is the case
|
|
|
|
which is handled by unlockpt on a Unix system. */
|
|
|
|
termios_printf ("closed by master");
|
2001-01-17 22:57:09 +08:00
|
|
|
return bg_eof;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2014-11-29 04:46:13 +08:00
|
|
|
threadlist_t *tl_entry;
|
|
|
|
tl_entry = cygheap->find_tls (_main_tls);
|
2000-02-18 03:38:33 +08:00
|
|
|
int sigs_ignored =
|
2003-11-29 06:13:57 +08:00
|
|
|
((void *) global_sigs[sig].sa_handler == (void *) SIG_IGN) ||
|
2008-02-16 01:53:11 +08:00
|
|
|
(_main_tls->sigmask & SIGTOMASK (sig));
|
2014-11-29 04:46:13 +08:00
|
|
|
cygheap->unlock_tls (tl_entry);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2016-07-27 02:03:07 +08:00
|
|
|
/* If the process is blocking or ignoring SIGTT*, then signals are not sent
|
|
|
|
and background IO is allowed */
|
2011-05-30 14:58:00 +08:00
|
|
|
if (sigs_ignored)
|
|
|
|
return bg_ok; /* Just allow the IO */
|
2016-07-27 02:03:07 +08:00
|
|
|
/* If the process group of the process is orphaned, return EIO */
|
2011-06-04 08:12:29 +08:00
|
|
|
else if (tc ()->is_orphaned_process_group (myself->pgid))
|
2004-01-19 13:46:54 +08:00
|
|
|
{
|
2011-05-30 14:58:00 +08:00
|
|
|
termios_printf ("process group is orphaned");
|
|
|
|
set_errno (EIO); /* This is an IO error */
|
|
|
|
return bg_error;
|
2004-01-19 13:46:54 +08:00
|
|
|
}
|
2016-07-27 02:03:07 +08:00
|
|
|
/* Otherwise, if signalling is desired, the signal is sent to all processes in
|
|
|
|
the process group */
|
|
|
|
else if (!dontsignal)
|
2011-05-30 14:58:00 +08:00
|
|
|
{
|
|
|
|
/* Don't raise a SIGTT* signal if we have already been
|
|
|
|
interrupted by another signal. */
|
2012-07-22 06:58:20 +08:00
|
|
|
if (cygwait ((DWORD) 0) != WAIT_SIGNALED)
|
2011-05-30 14:58:00 +08:00
|
|
|
{
|
|
|
|
siginfo_t si = {0};
|
|
|
|
si.si_signo = sig;
|
|
|
|
si.si_code = SI_KERNEL;
|
|
|
|
kill_pgrp (myself->pgid, si);
|
|
|
|
}
|
|
|
|
return bg_signalled;
|
2011-06-06 13:02:13 +08:00
|
|
|
}
|
2016-07-27 02:03:07 +08:00
|
|
|
return bg_ok;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define set_input_done(x) input_done = input_done || (x)
|
2017-01-31 22:36:24 +08:00
|
|
|
|
|
|
|
int
|
|
|
|
fhandler_termios::eat_readahead (int n)
|
|
|
|
{
|
2020-01-27 20:14:32 +08:00
|
|
|
int oralen = ralen ();
|
2017-01-31 22:36:24 +08:00
|
|
|
if (n < 0)
|
2020-06-30 19:12:50 +08:00
|
|
|
n = ralen () - raixget ();
|
|
|
|
if (n > 0 && ralen () > raixget ())
|
2017-01-31 22:36:24 +08:00
|
|
|
{
|
2020-06-30 19:12:50 +08:00
|
|
|
if ((int) (ralen () -= n) < (int) raixget ())
|
|
|
|
ralen () = raixget ();
|
2017-01-31 22:36:24 +08:00
|
|
|
/* If IUTF8 is set, the terminal is in UTF-8 mode. If so, we erase
|
|
|
|
a complete UTF-8 multibyte sequence on VERASE/VWERASE. Otherwise,
|
|
|
|
if we only erase a single byte, invalid unicode chars are left in
|
|
|
|
the input. */
|
|
|
|
if (tc ()->ti.c_iflag & IUTF8)
|
2020-06-30 19:12:50 +08:00
|
|
|
while (ralen () > raixget () &&
|
2020-01-27 20:14:32 +08:00
|
|
|
((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
|
|
|
|
--ralen ();
|
2017-01-31 22:36:24 +08:00
|
|
|
}
|
2020-06-30 19:12:50 +08:00
|
|
|
oralen = oralen - ralen ();
|
|
|
|
if (raixget () >= ralen ())
|
|
|
|
raixget () = raixput () = ralen () = 0;
|
|
|
|
else if (raixput () > ralen ())
|
|
|
|
raixput () = ralen ();
|
2017-01-31 22:36:24 +08:00
|
|
|
|
|
|
|
return oralen;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2001-05-10 02:53:55 +08:00
|
|
|
inline void
|
|
|
|
fhandler_termios::echo_erase (int force)
|
|
|
|
{
|
2011-06-04 08:12:29 +08:00
|
|
|
if (force || tc ()->ti.c_lflag & ECHO)
|
2001-05-10 02:53:55 +08:00
|
|
|
doecho ("\b \b", 3);
|
|
|
|
}
|
|
|
|
|
2022-02-27 19:40:24 +08:00
|
|
|
/* The basic policy is as follows:
|
|
|
|
- The signal generated by key press will be sent only to cygwin process.
|
|
|
|
- For non-cygwin process, CTRL_C_EVENT will be sent on Ctrl-C. */
|
|
|
|
/* The inferior of GDB is an exception. GDB does not support to hook signal
|
|
|
|
even if the inferior is a cygwin app. As a result, inferior cannot be
|
|
|
|
continued after interruption by Ctrl-C if SIGINT was sent. Therefore,
|
|
|
|
CTRL_C_EVENT rather than SIGINT is sent to the inferior of GDB. */
|
2022-02-15 22:23:50 +08:00
|
|
|
fhandler_termios::process_sig_state
|
|
|
|
fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh)
|
|
|
|
{
|
|
|
|
termios &ti = ttyp->ti;
|
|
|
|
pid_t pgid = ttyp->pgid;
|
|
|
|
|
2022-02-27 19:40:24 +08:00
|
|
|
/* The name *_nat stands for 'native' which means non-cygwin apps. */
|
2022-02-15 22:23:50 +08:00
|
|
|
bool ctrl_c_event_sent = false;
|
|
|
|
bool need_discard_input = false;
|
2022-02-27 19:40:24 +08:00
|
|
|
bool pg_with_nat = false; /* The process group has non-cygwin processes. */
|
|
|
|
bool need_send_sig = false; /* There is process which need the signal. */
|
|
|
|
bool nat_shell = false; /* The shell seems to be a non-cygwin process. */
|
|
|
|
bool cyg_reader = false; /* Cygwin process is reading the tty. */
|
|
|
|
bool with_debugger = false; /* GDB is debugging cygwin app. */
|
|
|
|
bool with_debugger_nat = false; /* GDB is debugging non-cygwin app. */
|
2022-02-15 22:23:50 +08:00
|
|
|
|
|
|
|
winpids pids ((DWORD) 0);
|
|
|
|
for (unsigned i = 0; i < pids.npids; i++)
|
|
|
|
{
|
|
|
|
_pinfo *p = pids[i];
|
2022-02-27 19:40:24 +08:00
|
|
|
/* PID_NOTCYGWIN: check this for non-cygwin process.
|
2022-03-03 10:43:07 +08:00
|
|
|
exec_dwProcessId == dwProcessId:
|
|
|
|
check this for GDB with non-cygwin inferior in pty
|
2022-02-27 19:40:24 +08:00
|
|
|
without pcon enabled. In this case, the inferior is not
|
2022-03-03 10:43:07 +08:00
|
|
|
cygwin process list. This condition is set true as
|
|
|
|
a marker for GDB with non-cygwin inferior in pty code.
|
2022-02-28 06:24:45 +08:00
|
|
|
!PID_CYGPARENT: check this for GDB with cygwin inferior or
|
|
|
|
cygwin apps started from non-cygwin shell. */
|
2022-02-15 22:23:50 +08:00
|
|
|
if (c == '\003' && p && p->ctty == ttyp->ntty && p->pgid == pgid
|
|
|
|
&& ((p->process_state & PID_NOTCYGWIN)
|
2022-04-18 19:07:48 +08:00
|
|
|
|| ((p->exec_dwProcessId == p->dwProcessId)
|
|
|
|
&& ttyp->pty_input_state_eq (tty::to_nat))
|
2022-02-15 22:23:50 +08:00
|
|
|
|| !(p->process_state & PID_CYGPARENT)))
|
|
|
|
{
|
2022-02-27 19:40:24 +08:00
|
|
|
/* Ctrl-C event will be sent only to the processes attaching
|
|
|
|
to the same console. Therefore, attach to the console to
|
|
|
|
which the target process is attaching before sending the
|
|
|
|
CTRL_C_EVENT. After sending the event, reattach to the
|
|
|
|
console to which the process was previously attached. */
|
2022-02-15 22:23:50 +08:00
|
|
|
DWORD resume_pid = 0;
|
2022-03-02 20:35:40 +08:00
|
|
|
if (fh && !fh->is_console ())
|
|
|
|
resume_pid =
|
2022-11-16 00:39:10 +08:00
|
|
|
fhandler_pty_common::attach_console_temporarily (p->dwProcessId);
|
2022-02-25 15:23:58 +08:00
|
|
|
if (fh && p == myself && being_debugged ())
|
2022-02-23 12:24:39 +08:00
|
|
|
{ /* Avoid deadlock in gdb on console. */
|
|
|
|
fh->tcflush(TCIFLUSH);
|
|
|
|
fh->release_input_mutex_if_necessary ();
|
|
|
|
}
|
2022-02-15 22:23:50 +08:00
|
|
|
/* CTRL_C_EVENT does not work for the process started with
|
|
|
|
CREATE_NEW_PROCESS_GROUP flag, so send CTRL_BREAK_EVENT
|
|
|
|
instead. */
|
2022-03-03 10:43:07 +08:00
|
|
|
if (p->process_state & PID_NEW_PG)
|
2022-02-26 03:19:03 +08:00
|
|
|
GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, p->dwProcessId);
|
2022-05-08 21:04:38 +08:00
|
|
|
else if ((!fh || fh->need_send_ctrl_c_event ()
|
|
|
|
|| p->exec_dwProcessId == p->dwProcessId)
|
|
|
|
&& !ctrl_c_event_sent)
|
2022-02-15 22:23:50 +08:00
|
|
|
{
|
|
|
|
GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0);
|
|
|
|
ctrl_c_event_sent = true;
|
|
|
|
}
|
2022-03-02 20:35:40 +08:00
|
|
|
if (fh && !fh->is_console ())
|
2022-02-15 22:23:50 +08:00
|
|
|
{
|
2022-03-01 10:34:16 +08:00
|
|
|
/* If a process on pseudo console is killed by Ctrl-C,
|
|
|
|
this process may take over the ownership of the
|
|
|
|
pseudo console because this process attached to it
|
|
|
|
before sending CTRL_C_EVENT. In this case, closing
|
|
|
|
pseudo console is necessary. */
|
2022-03-01 17:04:35 +08:00
|
|
|
fhandler_pty_slave::release_ownership_of_nat_pipe (ttyp, fh);
|
2022-03-02 20:35:40 +08:00
|
|
|
fhandler_pty_common::resume_from_temporarily_attach (resume_pid);
|
2022-02-15 22:23:50 +08:00
|
|
|
}
|
2022-02-26 03:19:03 +08:00
|
|
|
need_discard_input = true;
|
2022-02-15 22:23:50 +08:00
|
|
|
}
|
|
|
|
if (p && p->ctty == ttyp->ntty && p->pgid == pgid)
|
|
|
|
{
|
|
|
|
if (p->process_state & PID_NOTCYGWIN)
|
2022-02-27 19:40:24 +08:00
|
|
|
pg_with_nat = true; /* The process group has non-cygwin process */
|
2022-02-15 22:23:50 +08:00
|
|
|
if (!(p->process_state & PID_NOTCYGWIN))
|
2022-02-27 19:40:24 +08:00
|
|
|
need_send_sig = true; /* Process which needs signal exists */
|
2022-02-15 22:23:50 +08:00
|
|
|
if (!p->cygstarted)
|
2022-02-27 19:40:24 +08:00
|
|
|
nat_shell = true; /* The shell seems to a non-cygwin shell */
|
2022-02-15 22:23:50 +08:00
|
|
|
if (p->process_state & PID_TTYIN)
|
2022-02-27 19:40:24 +08:00
|
|
|
cyg_reader = true; /* Theh process is reading the tty */
|
2022-02-23 23:57:37 +08:00
|
|
|
if (!p->cygstarted && !(p->process_state & PID_NOTCYGWIN)
|
2022-02-28 06:24:45 +08:00
|
|
|
&& (p->process_state & PID_DEBUGGED))
|
|
|
|
with_debugger = true; /* inferior is cygwin app */
|
2022-02-23 23:57:37 +08:00
|
|
|
if (!(p->process_state & PID_NOTCYGWIN)
|
2022-03-03 10:43:07 +08:00
|
|
|
&& (p->exec_dwProcessId == p->dwProcessId) /* Check marker */
|
2022-04-18 19:07:48 +08:00
|
|
|
&& ttyp->pty_input_state_eq (tty::to_nat)
|
2022-02-28 06:24:45 +08:00
|
|
|
&& p->pid == pgid)
|
|
|
|
with_debugger_nat = true; /* inferior is non-cygwin app */
|
2022-02-15 22:23:50 +08:00
|
|
|
}
|
|
|
|
}
|
2022-02-23 23:57:37 +08:00
|
|
|
if ((with_debugger || with_debugger_nat) && need_discard_input)
|
|
|
|
{
|
|
|
|
if (!(ti.c_lflag & NOFLSH) && fh)
|
|
|
|
{
|
|
|
|
fh->eat_readahead (-1);
|
|
|
|
fh->discard_input ();
|
|
|
|
}
|
|
|
|
ti.c_lflag &= ~FLUSHO;
|
|
|
|
return done_with_debugger;
|
|
|
|
}
|
|
|
|
if (with_debugger_nat)
|
2022-02-27 19:40:24 +08:00
|
|
|
return not_signalled; /* Do not process slgnal keys further.
|
|
|
|
The non-cygwin inferior of GDB cannot receive
|
|
|
|
the signals. */
|
|
|
|
/* Send SIGQUIT to non-cygwin process. Non-cygwin app will not be alerted
|
|
|
|
by kill_pgrp(), however, QUIT key should quit the non-cygwin app
|
|
|
|
if it is started along with cygwin process from cygwin shell. */
|
2022-02-15 22:23:50 +08:00
|
|
|
if ((ti.c_lflag & ISIG) && CCEQ (ti.c_cc[VQUIT], c)
|
|
|
|
&& pg_with_nat && need_send_sig && !nat_shell)
|
|
|
|
{
|
|
|
|
for (unsigned i = 0; i < pids.npids; i++)
|
|
|
|
{
|
|
|
|
_pinfo *p = pids[i];
|
|
|
|
if (p && p->ctty == ttyp->ntty && p->pgid == pgid
|
|
|
|
&& (p->process_state & PID_NOTCYGWIN))
|
|
|
|
sig_send (p, SIGQUIT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((ti.c_lflag & ISIG) && need_send_sig)
|
|
|
|
{
|
|
|
|
int sig;
|
|
|
|
if (CCEQ (ti.c_cc[VINTR], c))
|
|
|
|
sig = SIGINT;
|
|
|
|
else if (CCEQ (ti.c_cc[VQUIT], c))
|
|
|
|
sig = SIGQUIT;
|
2022-02-27 19:40:24 +08:00
|
|
|
else if (pg_with_nat) /* If the process group has a non-cygwin process,
|
|
|
|
it cannot be suspended correctly. Therefore,
|
|
|
|
do not send SIGTSTP. */
|
2022-02-15 22:23:50 +08:00
|
|
|
goto not_a_sig;
|
|
|
|
else if (CCEQ (ti.c_cc[VSUSP], c))
|
|
|
|
sig = SIGTSTP;
|
|
|
|
else
|
|
|
|
goto not_a_sig;
|
|
|
|
|
|
|
|
termios_printf ("got interrupt %d, sending signal %d", c, sig);
|
|
|
|
if (!(ti.c_lflag & NOFLSH) && fh)
|
|
|
|
{
|
|
|
|
fh->eat_readahead (-1);
|
|
|
|
fh->discard_input ();
|
|
|
|
}
|
|
|
|
if (fh)
|
|
|
|
fh->release_input_mutex_if_necessary ();
|
|
|
|
ttyp->kill_pgrp (sig, pgid);
|
|
|
|
if (fh)
|
|
|
|
fh->acquire_input_mutex_if_necessary (mutex_timeout);
|
|
|
|
ti.c_lflag &= ~FLUSHO;
|
|
|
|
return signalled;
|
|
|
|
}
|
|
|
|
not_a_sig:
|
2022-02-25 15:23:58 +08:00
|
|
|
if ((ti.c_lflag & ISIG) && need_discard_input)
|
2022-02-15 22:23:50 +08:00
|
|
|
{
|
|
|
|
if (!(ti.c_lflag & NOFLSH) && fh)
|
|
|
|
{
|
|
|
|
fh->eat_readahead (-1);
|
|
|
|
fh->discard_input ();
|
|
|
|
}
|
|
|
|
ti.c_lflag &= ~FLUSHO;
|
|
|
|
return not_signalled_but_done;
|
|
|
|
}
|
2022-02-23 12:24:39 +08:00
|
|
|
bool to_nat = !cyg_reader && pg_with_nat;
|
|
|
|
return to_nat ? not_signalled_with_nat_reader : not_signalled;
|
2022-02-15 22:23:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2022-02-25 15:23:58 +08:00
|
|
|
fhandler_termios::process_stop_start (char c, tty *ttyp)
|
2022-02-15 22:23:50 +08:00
|
|
|
{
|
|
|
|
termios &ti = ttyp->ti;
|
|
|
|
if (ti.c_iflag & IXON)
|
|
|
|
{
|
|
|
|
if (CCEQ (ti.c_cc[VSTOP], c))
|
|
|
|
{
|
|
|
|
ttyp->output_stopped = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (CCEQ (ti.c_cc[VSTART], c))
|
|
|
|
{
|
|
|
|
restart_output:
|
|
|
|
ttyp->output_stopped = false;
|
|
|
|
return true;
|
|
|
|
}
|
2022-02-25 15:23:58 +08:00
|
|
|
else if ((ti.c_iflag & IXANY) && ttyp->output_stopped)
|
2022-02-15 22:23:50 +08:00
|
|
|
goto restart_output;
|
|
|
|
}
|
|
|
|
if ((ti.c_lflag & ICANON) && (ti.c_lflag & IEXTEN)
|
|
|
|
&& CCEQ (ti.c_cc[VDISCARD], c))
|
|
|
|
{
|
|
|
|
ti.c_lflag ^= FLUSHO;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2002-12-06 00:24:52 +08:00
|
|
|
line_edit_status
|
2014-11-14 02:37:15 +08:00
|
|
|
fhandler_termios::line_edit (const char *rptr, size_t nread, termios& ti,
|
|
|
|
ssize_t *bytes_read)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2002-12-06 00:24:52 +08:00
|
|
|
line_edit_status ret = line_edit_ok;
|
2000-02-18 03:38:33 +08:00
|
|
|
char c;
|
|
|
|
int input_done = 0;
|
2002-12-21 12:38:12 +08:00
|
|
|
bool sawsig = false;
|
2002-12-27 11:50:29 +08:00
|
|
|
int iscanon = ti.c_lflag & ICANON;
|
2021-09-07 18:27:45 +08:00
|
|
|
size_t read_cnt = 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2021-09-07 18:27:45 +08:00
|
|
|
while (read_cnt < nread)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
c = *rptr++;
|
2021-09-07 18:27:45 +08:00
|
|
|
read_cnt++;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2014-11-14 02:37:15 +08:00
|
|
|
paranoid_printf ("char %0o", c);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2002-12-27 11:50:29 +08:00
|
|
|
if (ti.c_iflag & ISTRIP)
|
2000-02-18 03:38:33 +08:00
|
|
|
c &= 0x7f;
|
2022-02-23 12:24:39 +08:00
|
|
|
bool disable_eof_key = false;
|
2022-02-15 22:23:50 +08:00
|
|
|
switch (process_sigs (c, get_ttyp (), this))
|
2022-02-10 15:53:47 +08:00
|
|
|
{
|
2022-02-15 22:23:50 +08:00
|
|
|
case signalled:
|
2002-12-21 12:38:12 +08:00
|
|
|
sawsig = true;
|
2022-02-15 22:23:50 +08:00
|
|
|
fallthrough;
|
|
|
|
case not_signalled_but_done:
|
2022-02-23 23:57:37 +08:00
|
|
|
case done_with_debugger:
|
2022-02-15 22:23:50 +08:00
|
|
|
get_ttyp ()->output_stopped = false;
|
|
|
|
continue;
|
2022-02-23 12:24:39 +08:00
|
|
|
case not_signalled_with_nat_reader:
|
|
|
|
disable_eof_key = true;
|
2022-02-15 22:23:50 +08:00
|
|
|
break;
|
|
|
|
default: /* Not signalled */
|
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2022-02-25 15:23:58 +08:00
|
|
|
if (process_stop_start (c, get_ttyp ()))
|
2022-02-15 22:23:50 +08:00
|
|
|
continue;
|
2012-11-09 01:27:00 +08:00
|
|
|
/* Check for special chars */
|
|
|
|
if (c == '\r')
|
|
|
|
{
|
|
|
|
if (ti.c_iflag & IGNCR)
|
|
|
|
continue;
|
|
|
|
if (ti.c_iflag & ICRNL)
|
|
|
|
{
|
|
|
|
c = '\n';
|
|
|
|
set_input_done (iscanon);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (c == '\n')
|
|
|
|
{
|
|
|
|
if (ti.c_iflag & INLCR)
|
|
|
|
c = '\r';
|
|
|
|
else
|
|
|
|
set_input_done (iscanon);
|
|
|
|
}
|
2013-04-23 17:44:36 +08:00
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
if (!iscanon)
|
|
|
|
/* nothing */;
|
2002-12-27 11:50:29 +08:00
|
|
|
else if (CCEQ (ti.c_cc[VERASE], c))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
if (eat_readahead (1))
|
2001-05-10 02:53:55 +08:00
|
|
|
echo_erase ();
|
2000-02-18 03:38:33 +08:00
|
|
|
continue;
|
|
|
|
}
|
2002-12-27 11:50:29 +08:00
|
|
|
else if (CCEQ (ti.c_cc[VWERASE], c))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
int ch;
|
|
|
|
do
|
|
|
|
if (!eat_readahead (1))
|
|
|
|
break;
|
|
|
|
else
|
2001-05-10 02:53:55 +08:00
|
|
|
echo_erase ();
|
2000-02-18 03:38:33 +08:00
|
|
|
while ((ch = peek_readahead (1)) >= 0 && !isspace (ch));
|
|
|
|
continue;
|
|
|
|
}
|
2002-12-27 11:50:29 +08:00
|
|
|
else if (CCEQ (ti.c_cc[VKILL], c))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
int nchars = eat_readahead (-1);
|
2002-12-27 11:50:29 +08:00
|
|
|
if (ti.c_lflag & ECHO)
|
2001-05-10 02:53:55 +08:00
|
|
|
while (nchars--)
|
|
|
|
echo_erase (1);
|
2000-02-18 03:38:33 +08:00
|
|
|
continue;
|
|
|
|
}
|
2002-12-27 11:50:29 +08:00
|
|
|
else if (CCEQ (ti.c_cc[VREPRINT], c))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2002-12-27 11:50:29 +08:00
|
|
|
if (ti.c_lflag & ECHO)
|
2001-05-10 02:53:55 +08:00
|
|
|
{
|
|
|
|
doecho ("\n\r", 2);
|
2020-01-27 20:14:32 +08:00
|
|
|
doecho (rabuf (), ralen ());
|
2001-05-10 02:53:55 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
continue;
|
|
|
|
}
|
2022-02-15 22:23:50 +08:00
|
|
|
else if (CCEQ (ti.c_cc[VEOF], c) && !disable_eof_key)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
termios_printf ("EOF");
|
2005-07-07 04:05:03 +08:00
|
|
|
accept_input ();
|
2002-12-15 03:40:41 +08:00
|
|
|
ret = line_edit_input_done;
|
2000-02-18 03:38:33 +08:00
|
|
|
continue;
|
|
|
|
}
|
2002-12-27 11:50:29 +08:00
|
|
|
else if (CCEQ (ti.c_cc[VEOL], c) ||
|
|
|
|
CCEQ (ti.c_cc[VEOL2], c) ||
|
2000-02-18 03:38:33 +08:00
|
|
|
c == '\n')
|
|
|
|
{
|
|
|
|
set_input_done (1);
|
|
|
|
termios_printf ("EOL");
|
|
|
|
}
|
|
|
|
|
2002-12-27 11:50:29 +08:00
|
|
|
if (ti.c_iflag & IUCLC && isupper (c))
|
2000-10-19 11:12:44 +08:00
|
|
|
c = cyg_tolower (c);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2002-12-06 00:24:52 +08:00
|
|
|
put_readahead (c);
|
2002-12-28 14:30:47 +08:00
|
|
|
if (ti.c_lflag & ECHO)
|
|
|
|
doecho (&c, 1);
|
2014-11-14 02:37:15 +08:00
|
|
|
/* Write in chunks of 32 bytes to reduce the number of WriteFile calls
|
2020-03-11 20:23:55 +08:00
|
|
|
in non-canonical mode. */
|
2020-01-27 20:14:32 +08:00
|
|
|
if ((!iscanon && ralen () >= 32) || input_done)
|
2002-12-15 03:40:41 +08:00
|
|
|
{
|
2002-12-20 09:38:55 +08:00
|
|
|
int status = accept_input ();
|
2003-01-17 13:33:52 +08:00
|
|
|
if (status != 1)
|
2002-12-17 11:49:34 +08:00
|
|
|
{
|
2002-12-20 09:38:55 +08:00
|
|
|
ret = status ? line_edit_error : line_edit_pipe_full;
|
2002-12-17 11:49:34 +08:00
|
|
|
break;
|
|
|
|
}
|
2002-12-15 03:40:41 +08:00
|
|
|
ret = line_edit_input_done;
|
|
|
|
input_done = 0;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2014-11-14 02:37:15 +08:00
|
|
|
/* If we didn't write all bytes in non-canonical mode, write them now. */
|
2021-09-07 18:27:45 +08:00
|
|
|
if ((input_done || !iscanon) && ralen () > 0 && ret != line_edit_error)
|
2014-11-14 02:37:15 +08:00
|
|
|
{
|
2021-09-07 18:27:45 +08:00
|
|
|
int status;
|
|
|
|
int retry_count = 3;
|
|
|
|
while ((status = accept_input ()) != 1 &&
|
|
|
|
ralen () > 0 && --retry_count > 0)
|
|
|
|
cygwait ((DWORD) 10);
|
2015-02-26 23:58:04 +08:00
|
|
|
if (status != 1)
|
2021-09-07 18:27:45 +08:00
|
|
|
ret = status ? line_edit_error : line_edit_pipe_full;
|
2015-02-26 23:58:04 +08:00
|
|
|
else
|
|
|
|
ret = line_edit_input_done;
|
2014-11-14 02:37:15 +08:00
|
|
|
}
|
|
|
|
|
2014-11-14 18:57:45 +08:00
|
|
|
if (bytes_read)
|
2021-09-07 18:27:45 +08:00
|
|
|
*bytes_read = read_cnt;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2001-03-05 14:28:25 +08:00
|
|
|
if (sawsig)
|
2002-12-06 00:24:52 +08:00
|
|
|
ret = line_edit_signalled;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2002-12-06 00:24:52 +08:00
|
|
|
return ret;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2001-03-13 05:27:42 +08:00
|
|
|
|
2013-04-23 17:44:36 +08:00
|
|
|
off_t
|
|
|
|
fhandler_termios::lseek (off_t, int)
|
2002-03-19 12:39:01 +08:00
|
|
|
{
|
|
|
|
set_errno (ESPIPE);
|
2002-05-28 09:55:40 +08:00
|
|
|
return -1;
|
2002-03-19 12:39:01 +08:00
|
|
|
}
|
2011-04-18 03:56:25 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
fhandler_termios::sigflush ()
|
|
|
|
{
|
2011-04-21 08:53:55 +08:00
|
|
|
/* FIXME: Checking get_ttyp() for NULL is not right since it should not
|
|
|
|
be NULL while this is alive. However, we can conceivably close a
|
|
|
|
ctty while exiting and that will zero this. */
|
2013-01-31 13:26:47 +08:00
|
|
|
if ((!have_execed || have_execed_cygwin) && tc ()
|
|
|
|
&& (tc ()->getpgid () == myself->pgid)
|
|
|
|
&& !(tc ()->ti.c_lflag & NOFLSH))
|
2011-04-18 03:56:25 +08:00
|
|
|
tcflush (TCIFLUSH);
|
|
|
|
}
|
2011-10-12 07:20:38 +08:00
|
|
|
|
2012-02-28 22:03:03 +08:00
|
|
|
pid_t
|
2011-10-12 07:20:38 +08:00
|
|
|
fhandler_termios::tcgetsid ()
|
|
|
|
{
|
2023-03-05 18:02:13 +08:00
|
|
|
if (CTTY_IS_VALID (myself->ctty) && myself->ctty == tc ()->ntty)
|
2011-10-12 07:20:38 +08:00
|
|
|
return tc ()->getsid ();
|
|
|
|
set_errno (ENOTTY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-07-07 05:39:13 +08:00
|
|
|
int
|
|
|
|
fhandler_termios::fstat (struct stat *buf)
|
|
|
|
{
|
|
|
|
fhandler_base::fstat (buf);
|
|
|
|
if (dev_referred_via > 0)
|
|
|
|
buf->st_rdev = dev_referred_via;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-11-19 16:28:15 +08:00
|
|
|
static bool
|
|
|
|
is_console_app (const WCHAR *filename)
|
|
|
|
{
|
|
|
|
HANDLE h;
|
|
|
|
h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
|
|
|
|
NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
char buf[1024];
|
|
|
|
DWORD n;
|
|
|
|
ReadFile (h, buf, sizeof (buf), &n, 0);
|
|
|
|
CloseHandle (h);
|
2023-08-28 16:38:52 +08:00
|
|
|
/* The offset of Subsystem is the same for both IMAGE_NT_HEADERS32 and
|
|
|
|
IMAGE_NT_HEADERS64, so only IMAGE_NT_HEADERS32 is used here. */
|
|
|
|
IMAGE_NT_HEADERS32 *p = (IMAGE_NT_HEADERS32 *) memmem (buf, n, "PE\0\0", 4);
|
|
|
|
if (p && (char *) &p->OptionalHeader.DllCharacteristics <= buf + n)
|
|
|
|
return p->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI;
|
|
|
|
wchar_t *e = wcsrchr (filename, L'.');
|
|
|
|
if (e && (wcscasecmp (e, L".bat") == 0 || wcscasecmp (e, L".cmd") == 0))
|
|
|
|
return true;
|
2022-11-19 16:28:15 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-10-12 07:20:38 +08:00
|
|
|
int
|
2011-10-16 06:37:30 +08:00
|
|
|
fhandler_termios::ioctl (int cmd, void *varg)
|
2011-10-12 07:20:38 +08:00
|
|
|
{
|
|
|
|
if (cmd != TIOCSCTTY)
|
|
|
|
return 1; /* Not handled by this function */
|
|
|
|
|
2013-04-23 17:44:36 +08:00
|
|
|
int arg = (int) (intptr_t) varg;
|
2011-10-16 06:37:30 +08:00
|
|
|
|
2011-10-12 07:20:38 +08:00
|
|
|
if (arg != 0 && arg != 1)
|
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
termios_printf ("myself->ctty %d, myself->sid %d, myself->pid %d, arg %d, tc()->getsid () %d\n",
|
|
|
|
myself->ctty, myself->sid, myself->pid, arg, tc ()->getsid ());
|
2023-03-05 18:02:13 +08:00
|
|
|
if (CTTY_IS_VALID (myself->ctty) || myself->sid != myself->pid
|
|
|
|
|| (!arg && tc ()->getsid () > 0))
|
2011-10-12 07:20:38 +08:00
|
|
|
{
|
|
|
|
set_errno (EPERM);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-12-20 19:26:36 +08:00
|
|
|
if (!myself->set_ctty (this, 0))
|
|
|
|
{
|
|
|
|
set_errno (EPERM);
|
|
|
|
return -1;
|
|
|
|
}
|
2011-10-12 07:20:38 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2022-11-19 16:28:15 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
fhandler_termios::spawn_worker::setup (bool iscygwin, HANDLE h_stdin,
|
|
|
|
const WCHAR *runpath, bool nopcon,
|
|
|
|
bool reset_sendsig,
|
|
|
|
const WCHAR *envblock)
|
|
|
|
{
|
|
|
|
fhandler_pty_slave *ptys_primary = NULL;
|
|
|
|
fhandler_console *cons_native = NULL;
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i ++)
|
|
|
|
{
|
|
|
|
const int chk_order[] = {1, 0, 2};
|
|
|
|
int fd = chk_order[i];
|
|
|
|
fhandler_base *fh = ::cygheap->fdtab[fd];
|
|
|
|
if (fh && fh->get_major () == DEV_PTYS_MAJOR && ptys_primary == NULL)
|
|
|
|
ptys_primary = (fhandler_pty_slave *) fh;
|
|
|
|
else if (fh && fh->get_major () == DEV_CONS_MAJOR
|
|
|
|
&& !iscygwin && cons_native == NULL)
|
|
|
|
cons_native = (fhandler_console *) fh;
|
|
|
|
}
|
|
|
|
if (cons_native)
|
|
|
|
{
|
|
|
|
cons_native->setup_for_non_cygwin_app ();
|
|
|
|
/* Console handles will be already closed by close_all_files()
|
|
|
|
when cleaning up, therefore, duplicate them here. */
|
|
|
|
cons_native->get_duplicated_handle_set (&cons_handle_set);
|
|
|
|
cons_need_cleanup = true;
|
|
|
|
}
|
|
|
|
if (!iscygwin)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
cygheap_fdenum cfd (false);
|
|
|
|
while ((fd = cfd.next ()) >= 0)
|
|
|
|
if (cfd->get_major () == DEV_PTYS_MAJOR)
|
|
|
|
{
|
|
|
|
fhandler_pty_slave *ptys
|
|
|
|
= (fhandler_pty_slave *)(fhandler_base *) cfd;
|
|
|
|
ptys->create_invisible_console ();
|
|
|
|
ptys->setup_locale ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!iscygwin && ptys_primary && is_console_app (runpath))
|
|
|
|
{
|
|
|
|
if (h_stdin == ptys_primary->get_handle_nat ())
|
|
|
|
stdin_is_ptys = true;
|
|
|
|
if (reset_sendsig)
|
|
|
|
myself->sendsig = myself->exec_sendsig;
|
|
|
|
ptys_primary->setup_for_non_cygwin_app (nopcon, envblock, stdin_is_ptys);
|
|
|
|
if (reset_sendsig)
|
|
|
|
myself->sendsig = NULL;
|
|
|
|
ptys_primary->get_duplicated_handle_set (&ptys_handle_set);
|
|
|
|
ptys_ttyp = (tty *) ptys_primary->tc ();
|
|
|
|
ptys_need_cleanup = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fhandler_termios::spawn_worker::cleanup ()
|
|
|
|
{
|
|
|
|
if (ptys_need_cleanup)
|
|
|
|
fhandler_pty_slave::cleanup_for_non_cygwin_app (&ptys_handle_set,
|
|
|
|
ptys_ttyp, stdin_is_ptys);
|
|
|
|
if (cons_need_cleanup)
|
|
|
|
fhandler_console::cleanup_for_non_cygwin_app (&cons_handle_set);
|
|
|
|
close_handle_set ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fhandler_termios::spawn_worker::close_handle_set ()
|
|
|
|
{
|
|
|
|
if (ptys_need_cleanup)
|
|
|
|
fhandler_pty_slave::close_handle_set (&ptys_handle_set);
|
|
|
|
if (cons_need_cleanup)
|
|
|
|
fhandler_console::close_handle_set (&cons_handle_set);
|
|
|
|
}
|
2024-10-31 10:11:33 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
fhandler_termios::atexit_func ()
|
|
|
|
{
|
|
|
|
fhandler_console::pcon_hand_over_proc ();
|
|
|
|
}
|
2024-11-06 09:19:59 +08:00
|
|
|
|
|
|
|
bool
|
|
|
|
fhandler_termios::process_alive (DWORD pid)
|
|
|
|
{
|
|
|
|
/* This function is very similar to _pinfo::alive(), however, this
|
|
|
|
can be used for non-cygwin process which is started from non-cygwin
|
|
|
|
shell. In addition, this checks exit code as well. */
|
|
|
|
if (pid == 0)
|
|
|
|
return false;
|
|
|
|
HANDLE h = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
|
|
|
if (h == NULL)
|
|
|
|
return false;
|
|
|
|
DWORD exit_code;
|
|
|
|
BOOL r = GetExitCodeProcess (h, &exit_code);
|
|
|
|
CloseHandle (h);
|
|
|
|
if (r && exit_code == STILL_ACTIVE)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This functions looks for a process which attached to the same console
|
|
|
|
with current process and is matched to given conditions:
|
|
|
|
match: If true, return given pid if the process pid attaches to the
|
|
|
|
same console, otherwise, return 0. If false, return pid except
|
|
|
|
for given pid.
|
|
|
|
cygwin: return only process's pid which has cygwin pid.
|
|
|
|
stub_only: return only stub process's pid of non-cygwin process. */
|
|
|
|
DWORD
|
|
|
|
fhandler_termios::get_console_process_id (DWORD pid, bool match,
|
|
|
|
bool cygwin, bool stub_only,
|
|
|
|
bool nat)
|
|
|
|
{
|
|
|
|
tmp_pathbuf tp;
|
|
|
|
DWORD *list = (DWORD *) tp.c_get ();
|
|
|
|
const DWORD buf_size = NT_MAX_PATH / sizeof (DWORD);
|
|
|
|
|
|
|
|
DWORD num = GetConsoleProcessList (list, buf_size);
|
|
|
|
if (num == 0 || num > buf_size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
DWORD res_pri = 0, res = 0;
|
|
|
|
/* Last one is the oldest. */
|
|
|
|
/* https://github.com/microsoft/terminal/issues/95 */
|
|
|
|
for (int i = (int) num - 1; i >= 0; i--)
|
|
|
|
if ((match && list[i] == pid) || (!match && list[i] != pid))
|
|
|
|
{
|
|
|
|
if (!process_alive (list[i]))
|
|
|
|
continue;
|
|
|
|
if (!cygwin)
|
|
|
|
{
|
|
|
|
res_pri = list[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pinfo p (cygwin_pid (list[i]));
|
|
|
|
if (nat && !!p && !ISSTATE(p, PID_NOTCYGWIN))
|
|
|
|
continue;
|
|
|
|
if (!!p && p->exec_dwProcessId)
|
|
|
|
{
|
|
|
|
res_pri = stub_only ? p->exec_dwProcessId : list[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!p && !res && stub_only)
|
|
|
|
res = list[i];
|
|
|
|
if (!!p && !res && !stub_only)
|
|
|
|
res = list[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res_pri ?: res;
|
|
|
|
}
|