ReactOS 0.4.15-dev-7842-g558ab78
ctty.c
Go to the documentation of this file.
1/*
2 * CTTY.C - ctty (Change TTY) command.
3 *
4 * This command redirects the first three standard handles
5 * stdin, stdout, stderr to another terminal.
6 *
7 *
8 * History:
9 *
10 * 14 Aug 1998 (John P Price)
11 * - Created dummy command.
12 *
13 * 2000/01/14 ska
14 * + Added to change the first three handles to the given device name
15 * + Supports only redirection of stdin and stdout, e.g.:
16 * C:> CTTY COM1 >file
17 * -or-
18 * C:> echo Hallo | CTTY COM1 | echo du
19 * The CTTY command effects the commands on the _next_ line.
20 *
21 * 20 Oct 2016 (Hermes Belusca-Maito)
22 * Port it to NT.
23 */
24
25#include "precomp.h"
26
27#if defined(INCLUDE_CMD_CTTY) && defined(FEATURE_REDIRECTION)
28
29static WORD
31{
32 /* Console reserved "file" names */
33 static const LPCWSTR DosLPTDevice = L"LPT";
34 static const LPCWSTR DosCOMDevice = L"COM";
35 static const LPCWSTR DosPRNDevice = L"PRN";
36 static const LPCWSTR DosAUXDevice = L"AUX";
37 static const LPCWSTR DosCONDevice = L"CON";
38 static const LPCWSTR DosNULDevice = L"NUL";
39
41 ULONG DeviceNameInfo;
42 WORD DeviceType = 0; // 0: Unknown; 1: CON; 2: COM etc...
43
44#ifndef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
45 /* Convert from the current process/thread's codepage to UTF-16 */
46 DWORD len = strlen(pszName) + 1;
47 WCHAR *buffer = cmd_alloc(len * sizeof(WCHAR));
48 if (!buffer)
49 {
50 // SetLastError(ERROR_NOT_ENOUGH_MEMORY);
51 return FALSE;
52 }
53 len = (DWORD)MultiByteToWideChar(CP_THREAD_ACP, // CP_ACP, CP_OEMCP
54 0, pszName, (INT)len, buffer, (INT)len);
56#else
57 DeviceName = pszName;
58#endif
59
60 /*
61 * Check whether we deal with a DOS device, and if so,
62 * strip the path till the file name.
63 * Therefore, things like \\.\CON or C:\some_path\COM1
64 * are transformed into CON or COM1, for example.
65 */
66 DeviceNameInfo = RtlIsDosDeviceName_U(DeviceName);
67 if (DeviceNameInfo != 0)
68 {
69 DeviceName = (LPCWSTR)((ULONG_PTR)DeviceName + ((DeviceNameInfo >> 16) & 0xFFFF));
70
71 if (_wcsnicmp(DeviceName, DosCONDevice, 3) == 0)
72 {
73 DeviceType = 1;
74 }
75 else
76 if ( _wcsnicmp(DeviceName, DosLPTDevice, 3) == 0 ||
77 _wcsnicmp(DeviceName, DosCOMDevice, 3) == 0 ||
78 _wcsnicmp(DeviceName, DosPRNDevice, 3) == 0 ||
79 _wcsnicmp(DeviceName, DosAUXDevice, 3) == 0 ||
80 _wcsnicmp(DeviceName, DosNULDevice, 3) == 0 )
81 {
82 DeviceType = 2;
83 }
84 // else DeviceType = 0;
85 }
86
87#ifndef _UNICODE
89#endif
90
91 return DeviceType;
92}
93
94/*
95 * See also redir.c!PerformRedirection().
96 *
97 * The CTTY command allows only the usage of CON, COM, AUX, LPT, PRN and NUL
98 * DOS devices as valid terminal devices. Everything else is forbidden.
99 *
100 * CTTY does not set ERRORLEVEL on error.
101 */
103{
104 static SECURITY_ATTRIBUTES SecAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
105
108 HANDLE hDevice, hStdHandles[3]; // hStdIn, hStdOut, hStdErr;
109
110 /* The user asked for help */
111 if (_tcsncmp(param, _T("/?"), 2) == 0)
112 {
114 return 0;
115 }
116
117 if (!*param)
118 {
120 return 1;
121 }
122
123 /* Check whether this is a valid terminal device name */
125 if (DeviceType == 1)
126 {
127 /*
128 * Special case for CON device.
129 *
130 * We do not open CON with GENERIC_READ or GENERIC_WRITE as is,
131 * but instead we separately open CONIN$ and CONOUT$ with both
132 * GENERIC_READ | GENERIC_WRITE access.
133 * We do so because otherwise, opening in particular CON with GENERIC_WRITE
134 * only would open CONOUT$ with an handle not passing the IsConsoleHandle()
135 * test, meaning that we could not use the full console functionalities.
136 */
137 BOOL bRetry = FALSE;
138
139RetryOpenConsole:
140 /*
141 * If we previously failed in opening handles to the console,
142 * this means the existing console is almost destroyed.
143 * Close the existing console and allocate and open a new one.
144 */
145 if (bRetry)
146 {
147 FreeConsole();
148 if (!AllocConsole())
149 return 1;
150 }
151
152 /* Attempt to retrieve a handle for standard input */
153 hStdHandles[0] = CreateFile(_T("CONIN$"),
156 &SecAttr,
158 0,
159 NULL);
160 if (hStdHandles[0] == INVALID_HANDLE_VALUE)
161 {
162 // TODO: Error
163 // error_no_rw_device(param);
164
165 if (bRetry)
166 return 1;
167 bRetry = TRUE;
168 goto RetryOpenConsole;
169 }
170
171 /* Attempt to retrieve a handle for standard output.
172 * Note that GENERIC_READ is needed for IsConsoleHandle() to succeed afterwards. */
173 hStdHandles[1] = CreateFile(_T("CONOUT$"),
176 &SecAttr,
178 0,
179 NULL);
180 if (hStdHandles[1] == INVALID_HANDLE_VALUE)
181 {
182 // TODO: Error
183 // error_no_rw_device(param);
184
185 CloseHandle(hStdHandles[0]);
186
187 if (bRetry)
188 return 1;
189 bRetry = TRUE;
190 goto RetryOpenConsole;
191 }
192
193 /* Duplicate a handle for standard error */
195 hStdHandles[1],
197 &hStdHandles[2],
198 0, // GENERIC_WRITE,
199 TRUE,
200 DUPLICATE_SAME_ACCESS /* 0 */);
201 if (!Success)
202 {
203 // TODO: Error
204 // error_no_rw_device(param);
205 CloseHandle(hStdHandles[1]);
206 CloseHandle(hStdHandles[0]);
207 return 1;
208 }
209 }
210 else if (DeviceType == 2)
211 {
212 /*
213 * COM and the other devices can only be opened once.
214 * Since we need different handles, we need to duplicate them.
215 */
216
217 /* Attempt to retrieve a handle to the device for read/write access */
218 hDevice = CreateFile(param,
221 &SecAttr,
223 0, // FILE_FLAG_OVERLAPPED, // 0,
224 NULL);
225 if (hDevice == INVALID_HANDLE_VALUE)
226 {
227 // TODO: Error
228 // error_no_rw_device(param);
229 return 1;
230 }
231
232 /* Duplicate a handle for standard input */
234 hDevice,
236 &hStdHandles[0],
238 TRUE,
239 0);
240 if (!Success)
241 {
242 // TODO: Error
243 // error_no_rw_device(param);
244 CloseHandle(hDevice);
245 return 1;
246 }
247
248 /* Duplicate a handle for standard output */
250 hDevice,
252 &hStdHandles[1],
254 TRUE,
255 0);
256 if (!Success)
257 {
258 // TODO: Error
259 // error_no_rw_device(param);
260 CloseHandle(hStdHandles[0]);
261 CloseHandle(hDevice);
262 return 1;
263 }
264
265 /* Duplicate a handle for standard error */
267 hDevice,
269 &hStdHandles[2],
271 TRUE,
272 0);
273 if (!Success)
274 {
275 // TODO: Error
276 // error_no_rw_device(param);
277 CloseHandle(hStdHandles[1]);
278 CloseHandle(hStdHandles[0]);
279 CloseHandle(hDevice);
280 return 1;
281 }
282
283 /* Now get rid of the main device handle */
284 CloseHandle(hDevice);
285 }
286 else
287 {
288 // FIXME: Localize!
289 ConOutPrintf(L"Invalid device '%s'\n", param);
290 return 1;
291 }
292
293#if 0
294 /* Now change the file descriptors:
295 0 := rdonly
296 1,2 := wronly
297
298 if CTTY is called within a pipe or its I/O is redirected,
299 oldinfd or oldoutfd is not equal to -1. In such case the
300 old*fd is modified in order to effect the file descriptor
301 after the redirections are restored. Otherwise a pipe or
302 redirection would left CTTY in a half-made status.
303 */
304 // int failed;
305 failed = dup2(f, 2); /* no redirection support */
306 if(oldinfd != -1)
307 dos_close(oldinfd);
308 oldinfd = f;
309 if(oldoutfd != -1)
310 dos_close(oldoutfd);
311 if((oldoutfd = dup(f)) == -1)
312 failed = 1;
313
314 if(failed)
315 error_ctty_dup(param);
316
317 return failed;
318#endif
319
320 /* Now set the standard handles */
321
322 hDevice = GetHandle(0);
323 if (hDevice != INVALID_HANDLE_VALUE)
324 CloseHandle(hDevice);
325 SetHandle(0, hStdHandles[0]);
326
327 hDevice = GetHandle(1);
328 if (hDevice != INVALID_HANDLE_VALUE)
329 CloseHandle(hDevice);
330 SetHandle(1, hStdHandles[1]);
331
332 hDevice = GetHandle(2);
333 if (hDevice != INVALID_HANDLE_VALUE)
334 CloseHandle(hDevice);
335 SetHandle(2, hStdHandles[2]);
336
337 return 0;
338}
339
340#endif /* INCLUDE_CMD_CTTY && FEATURE_REDIRECTION */
341
342/* EOF */
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
BOOL WINAPI AllocConsole(VOID)
Definition: console.c:74
BOOL WINAPI FreeConsole(VOID)
Definition: console.c:156
VOID SetHandle(UINT Number, HANDLE Handle)
Definition: redir.c:50
VOID error_req_param_missing(VOID)
Definition: error.c:110
VOID ConOutResPaging(BOOL StartPaging, UINT resID)
Definition: console.c:182
#define ConOutPrintf(szStr,...)
Definition: console.h:41
#define STRING_CTTY_HELP
Definition: resource.h:86
#define cmd_free(ptr)
Definition: cmddbg.h:31
#define cmd_alloc(size)
Definition: cmddbg.h:29
static WORD CheckTerminalDeviceType(IN LPCTSTR pszName)
Definition: ctty.c:30
INT cmd_ctty(LPTSTR param)
Definition: ctty.c:102
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define CloseHandle
Definition: compat.h:739
struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES
#define OPEN_EXISTING
Definition: compat.h:775
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GetCurrentProcess()
Definition: compat.h:759
#define GENERIC_READ
Definition: compat.h:135
#define MultiByteToWideChar
Definition: compat.h:110
#define FILE_SHARE_READ
Definition: compat.h:136
BOOL WINAPI DuplicateHandle(IN HANDLE hSourceProcessHandle, IN HANDLE hSourceHandle, IN HANDLE hTargetProcessHandle, OUT LPHANDLE lpTargetHandle, IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN DWORD dwOptions)
Definition: handle.c:149
@ Success
Definition: eventcreate.c:712
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
GLuint buffer
Definition: glext.h:5915
GLfloat f
Definition: glext.h:7540
GLfloat param
Definition: glext.h:5796
GLenum GLsizei len
Definition: glext.h:6722
#define _tcsncmp
Definition: tchar.h:1428
#define f
Definition: ke_i.h:83
#define dup
Definition: syshdrs.h:51
DeviceType
Definition: mmdrv.h:42
NTSYSAPI ULONG NTAPI RtlIsDosDeviceName_U(_In_ PCWSTR Name)
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define DWORD
Definition: nt_native.h:44
#define GENERIC_WRITE
Definition: nt_native.h:90
#define L(x)
Definition: ntvdm.h:50
#define INT
Definition: polytest.cpp:20
_Check_return_ _CRTIMP int __cdecl dup2(_In_ int _FileHandleSrc, _In_ int _FileHandleDst)
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
#define GetHandle(h)
Definition: treelist.c:116
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define _T(x)
Definition: vfdio.h:22
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3275
#define CreateFile
Definition: winbase.h:3684
#define CP_THREAD_ACP
Definition: winnls.h:233
#define DUPLICATE_SAME_ACCESS
__wchar_t WCHAR
Definition: xmlstorage.h:180
const CHAR * LPCTSTR
Definition: xmlstorage.h:193
CHAR * LPTSTR
Definition: xmlstorage.h:192
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185