aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mingw.h3
-rw-r--r--libbb/Config.in9
-rw-r--r--libbb/termios.c218
-rw-r--r--libbb/winansi.c5
-rwxr-xr-xscripts/trylink1
5 files changed, 233 insertions, 3 deletions
diff --git a/include/mingw.h b/include/mingw.h
index b39d94a33..500308947 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -191,6 +191,9 @@ int mingw_getpagesize(void);
191#define getpagesize mingw_getpagesize 191#define getpagesize mingw_getpagesize
192#endif 192#endif
193 193
194int mingw_isatty(int fd);
195#define isatty(fd) mingw_isatty(fd)
196
194/* Use mingw_lstat() instead of lstat()/stat() and 197/* Use mingw_lstat() instead of lstat()/stat() and
195 * mingw_fstat() instead of fstat() on Windows. 198 * mingw_fstat() instead of fstat() on Windows.
196 */ 199 */
diff --git a/libbb/Config.in b/libbb/Config.in
index 112a3d658..a75fb58c0 100644
--- a/libbb/Config.in
+++ b/libbb/Config.in
@@ -26,6 +26,15 @@ config MD5_SIZE_VS_SPEED
26 2 3.0 5088 26 2 3.0 5088
27 3 (smallest) 5.1 4912 27 3 (smallest) 5.1 4912
28 28
29config FEATURE_CYGWIN_TTY
30 bool "Support Cygwin tty"
31 default n
32 depends on MINGW32
33 help
34 Try to sneak in Cygwin shared structure to determine if
35 a file handle is Cygwin tty, useful if you want to use
36 a Cygwin-based terminal emulator.
37
29config FEATURE_EDITING 38config FEATURE_EDITING
30 bool "Command line editing" 39 bool "Command line editing"
31 default n 40 default n
diff --git a/libbb/termios.c b/libbb/termios.c
index f47593a49..5695e9ba2 100644
--- a/libbb/termios.c
+++ b/libbb/termios.c
@@ -4,8 +4,212 @@
4#include "strbuf.h" 4#include "strbuf.h"
5#include "cygwin_termios.h" 5#include "cygwin_termios.h"
6 6
7#if ENABLE_FEATURE_CYGWIN_TTY
8#include <ntdef.h>
9
10/* NtCreateDirectoryObject */
11#define DIRECTORY_QUERY 1
12#define DIRECTORY_TRAVERSE 2
13#define DIRECTORY_CREATE_OBJECT 4
14#define DIRECTORY_CREATE_SUBDIRECTORY 8
15
16#define CYG_SHARED_DIR_ACCESS (DIRECTORY_QUERY \
17 | DIRECTORY_TRAVERSE \
18 | DIRECTORY_CREATE_SUBDIRECTORY \
19 | DIRECTORY_CREATE_OBJECT \
20 | READ_CONTROL)
21
22typedef enum _OBJECT_INFORMATION_CLASS {
23 ObjectNameInformation = 1,
24} OBJECT_INFORMATION_CLASS;
25
26typedef struct _OBJECT_NAME_INFORMATION {
27 UNICODE_STRING Name;
28} OBJECT_NAME_INFORMATION;
29
30VOID NTAPI RtlInitUnicodeString (PUNICODE_STRING, PCWSTR);
31NTSTATUS NTAPI NtOpenSection (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
32NTSTATUS NTAPI NtCreateDirectoryObject (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
33NTSTATUS NTAPI NtQueryObject (HANDLE, OBJECT_INFORMATION_CLASS, VOID *, ULONG, ULONG *);
34
35/* Cygwin's shared_info */
36
37struct winsize {
38 unsigned short ws_row, ws_col;
39 unsigned short ws_xpixel, ws_ypixel;
40};
41
42struct tty_min {
43 pid_t sid; /* Session ID of tty */
44 struct status_flags {
45 unsigned initialized : 1; /* Set if tty is initialized */
46 unsigned rstcons : 1; /* Set if console needs to be set to "non-cooked" */
47 } status;
48
49 pid_t pgid;
50 int output_stopped;
51 int ntty;
52 DWORD last_ctrl_c; /* tick count of last ctrl-c */
53 HWND hwnd; /* Console window handle tty belongs to */
54
55 struct termios ti;
56 struct winsize winsize;
57
58 /* ioctl requests buffer */
59 int cmd;
60 union {
61 struct termios termios;
62 struct winsize winsize;
63 int value;
64 pid_t pid;
65 } arg;
66 /* XXX_retval variables holds master's completion codes. Error are stored as
67 * -ERRNO
68 */
69 int ioctl_retval;
70 int write_error;
71};
72
73struct tty {
74 struct tty_min tty_min;
75 pid_t master_pid; /* PID of tty master process */
76
77 HANDLE from_master, to_master;
78
79 int read_retval;
80 int was_opened; /* True if opened at least once. */
81};
82
83#define NTTYS 128
84struct tty_list {
85 struct tty ttys[NTTYS];
86};
87
88#define CYGWIN_PATH_MAX 4096
89struct shared_info {
90 DWORD version;
91 DWORD cb;
92 unsigned heap_chunk;
93 int heap_slop_inited;
94 unsigned heap_slop;
95 DWORD sys_mount_table_counter;
96 struct tty_list tty;
97 LONG last_used_bindresvport;
98 WCHAR installation_root[CYGWIN_PATH_MAX];
99 DWORD obcaseinsensitive;
100 /* mtinfo mt; */
101};
102
103/* Some magic to recognize shared_info */
104#define CYGWIN_VERSION_SHARED_DATA 5
105#define CYGWIN_VERSION_DLL_IDENTIFIER L"cygwin1"
106#define CYGWIN_VERSION_API_MAJOR 0
107#define CYGWIN_VERSION_API_MINOR 210
108#define SHARED_INFO_CB 39328
109#define CURR_SHARED_MAGIC 0x22f9ff0bU
110
111#define CYGWIN_VERSION_MAGIC(a, b) ((unsigned) ((((unsigned short) a) << 16) | (unsigned short) b))
112#define SHARED_VERSION (unsigned)(CYGWIN_VERSION_API_MAJOR << 8 | CYGWIN_VERSION_API_MINOR)
113#define SHARED_VERSION_MAGIC CYGWIN_VERSION_MAGIC (CURR_SHARED_MAGIC, SHARED_VERSION)
114
115static struct shared_info *get_shared_info()
116{
117 WCHAR buf[32];
118 HANDLE sh;
119 WCHAR base[MAX_PATH];
120 UNICODE_STRING uname;
121 HANDLE dir;
122 NTSTATUS status;
123 OBJECT_ATTRIBUTES attr;
124 static struct shared_info *si = NULL;
125
126 if (si)
127 return si;
128
129 swprintf(base, L"\\BaseNamedObjects\\%sS%d",
130 CYGWIN_VERSION_DLL_IDENTIFIER,
131 CYGWIN_VERSION_SHARED_DATA);
132 RtlInitUnicodeString (&uname, base);
133 InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF, NULL, NULL);
134 status = NtCreateDirectoryObject (&dir, CYG_SHARED_DIR_ACCESS, &attr);
135
136 swprintf(buf, L"%s.%d", L"shared", CYGWIN_VERSION_SHARED_DATA);
137 RtlInitUnicodeString(&uname, buf);
138 InitializeObjectAttributes (&attr, &uname, OBJ_CASE_INSENSITIVE, dir, NULL);
139 status = NtOpenSection (&sh, FILE_MAP_READ | FILE_MAP_WRITE, &attr);
140 si = MapViewOfFileEx(sh, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, NULL);
141 //if (si->version == SHARED_VERSION_MAGIC && si->cb == SHARED_INFO_CB)
142 return si;
143}
144
145static int fd_to_tty(int fd)
146{
147 ULONG len = 0;
148 OBJECT_NAME_INFORMATION dummy_oni, *ntfn;
149 HANDLE h = _get_osfhandle(fd);
150 char buf[PATH_MAX];
151 int tty;
152
153 NtQueryObject (h, ObjectNameInformation, &dummy_oni, sizeof (dummy_oni), &len);
154 ntfn = malloc (len + sizeof (WCHAR));
155 NtQueryObject (h, ObjectNameInformation, ntfn, len, NULL);
156 wcstombs(buf, ntfn->Name.Buffer, 100);
157 tty = -1;
158 swscanf(ntfn->Name.Buffer, L"\\Device\\NamedPipe\\cygwin-tty%d-from-master", &tty);
159 free(ntfn);
160 return tty;
161}
162
163int is_cygwin_tty(int fd)
164{
165 return fd_to_tty(fd) >= 0 && get_shared_info() != NULL;
166}
167
168static int cygwin_tcgetattr(int fd, struct termios *t)
169{
170 int tty = fd_to_tty(fd);
171 struct shared_info *si = get_shared_info();
172 *t = si->tty.ttys[tty].tty_min.ti;
173 return 0;
174}
175
176
177static int cygwin_tcsetattr(int fd, int mode, const struct termios *t)
178{
179 int tty = fd_to_tty(fd);
180 struct shared_info *si;
181
182 if (tty < 0)
183 return -1;
184 si = get_shared_info();
185 si->tty.ttys[tty].tty_min.ti = *t;
186 return 0;
187}
188
189#else
190
191int is_cygwin_tty(int fd)
192{
193 return 0;
194}
195
196#define cygwin_tcgetattr(fd,t) -1
197#define cygwin_tcsetattr(fd,mode,t) -1
198
199#endif
200
201#undef isatty
202int mingw_isatty(int fd)
203{
204 return isatty(fd) || is_cygwin_tty(fd);
205}
206
7int tcgetattr(int fd, struct termios *t) 207int tcgetattr(int fd, struct termios *t)
8{ 208{
209 int ret = cygwin_tcgetattr(fd, t);
210 if (ret >= 0)
211 return ret;
212 /* not cygwin tty, likely windows console */
9 t->c_lflag = ECHO; 213 t->c_lflag = ECHO;
10 return 0; 214 return 0;
11} 215}
@@ -13,7 +217,7 @@ int tcgetattr(int fd, struct termios *t)
13 217
14int tcsetattr(int fd, int mode, const struct termios *t) 218int tcsetattr(int fd, int mode, const struct termios *t)
15{ 219{
16 return 0; 220 return cygwin_tcsetattr(fd, mode, t);
17} 221}
18 222
19static int get_wincon_width_height(const int fd, int *width, int *height) 223static int get_wincon_width_height(const int fd, int *width, int *height)
@@ -36,6 +240,18 @@ static int get_wincon_width_height(const int fd, int *width, int *height)
36 240
37int get_terminal_width_height(const int fd, int *width, int *height) 241int get_terminal_width_height(const int fd, int *width, int *height)
38{ 242{
243#if ENABLE_FEATURE_CYGWIN_TTY
244 int tty = fd_to_tty(fd);
245 struct shared_info *si = get_shared_info();
246
247 if (tty >= 0 && si) {
248 if (width)
249 *width = si->tty.ttys[tty].tty_min.winsize.ws_col;
250 if (height)
251 *height = si->tty.ttys[tty].tty_min.winsize.ws_row;
252 return 0;
253 }
254#endif
39 return get_wincon_width_height(fd, width, height); 255 return get_wincon_width_height(fd, width, height);
40} 256}
41 257
diff --git a/libbb/winansi.c b/libbb/winansi.c
index f3a304436..0e139432d 100644
--- a/libbb/winansi.c
+++ b/libbb/winansi.c
@@ -4,6 +4,7 @@
4 4
5#include <windows.h> 5#include <windows.h>
6#include "libbb.h" 6#include "libbb.h"
7#include "cygwin_termios.h"
7 8
8/* 9/*
9 Functions to be wrapped: 10 Functions to be wrapped:
@@ -278,7 +279,7 @@ int winansi_fputs(const char *str, FILE *stream)
278{ 279{
279 int rv; 280 int rv;
280 281
281 if (!isatty(fileno(stream))) 282 if (!isatty(fileno(stream)) || is_cygwin_tty(fileno(stream)))
282 return fputs(str, stream); 283 return fputs(str, stream);
283 284
284 init(); 285 init();
@@ -301,7 +302,7 @@ static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
301 char *buf = small_buf; 302 char *buf = small_buf;
302 va_list cp; 303 va_list cp;
303 304
304 if (!isatty(fileno(stream))) 305 if (!isatty(fileno(stream)) || is_cygwin_tty(fileno(stream)))
305 goto abort; 306 goto abort;
306 307
307 init(); 308 init();
diff --git a/scripts/trylink b/scripts/trylink
index 63132eda9..6cca80c11 100755
--- a/scripts/trylink
+++ b/scripts/trylink
@@ -11,6 +11,7 @@ try() {
11} 11}
12 12
13try "-lws2_32" "$@" 13try "-lws2_32" "$@"
14try "-lws2_32 -lntdll" "$@"
14try "" "$@" 15try "" "$@"
15try "-lm" "$@" 16try "-lm" "$@"
16try "-lcrypt" "$@" 17try "-lcrypt" "$@"