Identify console executable and standard one

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Identify console executable and standard one

Vincent.Blondeau
 

Hi,

 

I would like to know from inside the image whether the ST image is a console executable, e.g. PharoConsole.exe vs Pharo.exe (Related to this pull request: https://github.com/pharo-project/pharo/pull/694).

The solution is to add a primitive inside the VM but I have no idea where I should look for…

Could someone give me some pointers?

 

Thanks in advance!

 

Cheers,

Vincent Blondeau
Software Engineer, Software and Controls | Global Product Group
Desk +1 510.572.7499


Lam Research Corporation
4650 Cushing Pkwy, Fremont, CA 94538 USA | www.lamresearch.com

Connect with Lam Research: Facebook | Twitter | LinkedIn

 

Reply | Threaded
Open this post in threaded view
|

Re: Identify console executable and standard one

Eliot Miranda-2
 
Hi Vincent,

On Sat, Apr 14, 2018 at 2:05 PM, <[hidden email]> wrote:
 

Hi,

 

I would like to know from inside the image whether the ST image is a console executable, e.g. PharoConsole.exe vs Pharo.exe (Related to this pull request: https://github.com/pharo-project/pharo/pull/694).

The solution is to add a primitive inside the VM but I have no idea where I should look for…

Could someone give me some pointers?


A quick hack would be to use system attribute 0, the name of the executable:

Smalltalk getSystemAttribute: 0 '/Users/eliot/oscogvm/build.macos64x64/squeak.cog.spur/Squeak.app/Contents/MacOS/Squeak'

and match for Console.exe.  A more thorough approach on unix is to test stdin to see if it is attached to a tty.  Try this at a unix/macos terminal:

$ tty
/dev/ttys006
$ tty </dev/null
not a tty
$ man 3 ttyname
$ man 2 ioctl

I'm not sure how to do this on Windows.  I wrote this in platforms/win32/vm/sqWin32Main.c::WinMain

#if 0 /* This way used to work.  Does no longer. */
  DWORD mode;

  fIsConsole = GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
#elif 0 /* This does /not/ work with STD_INPUT_HANDLE or STD_OUTPUT_HANDLE */
  CONSOLE_SCREEN_BUFFER_INFO csbi;

  if ((fIsConsole = GetConsoleScreenBufferInfo
                        (GetStdHandle(STD_INPUT_HANDLE), &csbi)))
        fIsConsole = csbi.dwCursorPosition.X || csbi.dwCursorPosition.Y;
#else /* This /does/ work; see */
  HWND consoleWnd = GetConsoleWindow();
  DWORD dwProcessId;
  GetWindowThreadProcessId(consoleWnd, &dwProcessId);
  fIsConsole = GetCurrentProcessId() != dwProcessId;
#endif

but it seems like a hack to me.  I'd love to know what the approved future proof way is.

 

Thanks in advance!

 

Cheers,

Vincent Blondeau
Software Engineer, Software and Controls | Global Product Group
Desk +1 510.572.7499


Lam Research Corporation
4650 Cushing Pkwy, Fremont, CA 94538 USA | www.lamresearch.com

Connect with Lam Research: Facebook | Twitter | LinkedIn

 





--
_,,,^..^,,,_
best, Eliot
Reply | Threaded
Open this post in threaded view
|

Re: Identify console executable and standard one

alistairgrant
 
Hi Vincent,

On 15 April 2018 at 00:23, Eliot Miranda <[hidden email]> wrote:

>
> Hi Vincent,
>
> On Sat, Apr 14, 2018 at 2:05 PM, <[hidden email]> wrote:
>>
>>
>>
>> Hi,
>>
>>
>>
>> I would like to know from inside the image whether the ST image is a console executable, e.g. PharoConsole.exe vs Pharo.exe (Related to this pull request: https://github.com/pharo-project/pharo/pull/694).
>>
>> The solution is to add a primitive inside the VM but I have no idea where I should look for…
>>
>> Could someone give me some pointers?
>
>
> A quick hack would be to use system attribute 0, the name of the executable:
>
> Smalltalk getSystemAttribute: 0 '/Users/eliot/oscogvm/build.macos64x64/squeak.cog.spur/Squeak.app/Contents/MacOS/Squeak'
>
> and match for Console.exe.  A more thorough approach on unix is to test stdin to see if it is attached to a tty.  Try this at a unix/macos terminal:
>
> $ tty
> /dev/ttys006
> $ tty </dev/null
> not a tty
> $ man 3 ttyname
> $ man 2 ioctl
>
> I'm not sure how to do this on Windows.  I wrote this in platforms/win32/vm/sqWin32Main.c::WinMain
>
> #if 0 /* This way used to work.  Does no longer. */
>   DWORD mode;
>
>   fIsConsole = GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
> #elif 0 /* This does /not/ work with STD_INPUT_HANDLE or STD_OUTPUT_HANDLE */
>   CONSOLE_SCREEN_BUFFER_INFO csbi;
>
>   if ((fIsConsole = GetConsoleScreenBufferInfo
>                         (GetStdHandle(STD_INPUT_HANDLE), &csbi)))
>         fIsConsole = csbi.dwCursorPosition.X || csbi.dwCursorPosition.Y;
> #else /* This /does/ work; see */
>     /* https://stackoverflow.com/questions/9009333/how-to-check-if-the-program-is-run-from-a-console */
>   HWND consoleWnd = GetConsoleWindow();
>   DWORD dwProcessId;
>   GetWindowThreadProcessId(consoleWnd, &dwProcessId);
>   fIsConsole = GetCurrentProcessId() != dwProcessId;
> #endif
>
> but it seems like a hack to me.  I'd love to know what the approved future proof way is.

If you want to test it, the results of similar code is currently
available from within the image:

SQFile.isStdioStream for stdin notionally provides the information.

On Unix it is set in sqFileStdioHandlesInto() in sqFilePluginBasicPrims.c:

files[0].sessionID = thisSession;
files[0].file = stdin;
files[0].writable = false;
files[0].lastOp = READ_OP;
files[0].isStdioStream = isatty(fileno(stdin));
files[0].lastChar = EOF;


On Windows in sqFileStdioHandlesInto() in sqWin32FilePrims.c:

files[0].sessionID = thisSession;
files[0].file = GetStdHandle(STD_INPUT_HANDLE);
files[0].writable = false;
files[0].lastOp = 0; /* unused on win32 */
files[0].isStdioStream = GetConsoleMode(files[0].file, &mode) != 0;
AddHandleToTable(win32Files, files[0].file);


And SQFile is the byte array handle used in the file streams.

I've been thinking that it would be nice to be able to access the
structure from within the image, but haven't yet come up with a way to
automatically map the fields (Monty did some work which might help,
but I haven't looked at it yet).

Cheers,
Alistair
Reply | Threaded
Open this post in threaded view
|

Re: Identify console executable and standard one

Eliot Miranda-2
 
Hi Alistair,

On Apr 15, 2018, at 12:17 AM, Alistair Grant <[hidden email]> wrote:


Hi Vincent,

On 15 April 2018 at 00:23, Eliot Miranda <[hidden email]> wrote:

Hi Vincent,

On Sat, Apr 14, 2018 at 2:05 PM, <[hidden email]> wrote:



Hi,



I would like to know from inside the image whether the ST image is a console executable, e.g. PharoConsole.exe vs Pharo.exe (Related to this pull request: https://github.com/pharo-project/pharo/pull/694).

The solution is to add a primitive inside the VM but I have no idea where I should look for…

Could someone give me some pointers?


A quick hack would be to use system attribute 0, the name of the executable:

Smalltalk getSystemAttribute: 0 '/Users/eliot/oscogvm/build.macos64x64/squeak.cog.spur/Squeak.app/Contents/MacOS/Squeak'

and match for Console.exe.  A more thorough approach on unix is to test stdin to see if it is attached to a tty.  Try this at a unix/macos terminal:

$ tty
/dev/ttys006
$ tty </dev/null
not a tty
$ man 3 ttyname
$ man 2 ioctl

I'm not sure how to do this on Windows.  I wrote this in platforms/win32/vm/sqWin32Main.c::WinMain

#if 0 /* This way used to work.  Does no longer. */
 DWORD mode;

 fIsConsole = GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
#elif 0 /* This does /not/ work with STD_INPUT_HANDLE or STD_OUTPUT_HANDLE */
 CONSOLE_SCREEN_BUFFER_INFO csbi;

 if ((fIsConsole = GetConsoleScreenBufferInfo
                       (GetStdHandle(STD_INPUT_HANDLE), &csbi)))
       fIsConsole = csbi.dwCursorPosition.X || csbi.dwCursorPosition.Y;
#else /* This /does/ work; see */
   /* https://stackoverflow.com/questions/9009333/how-to-check-if-the-program-is-run-from-a-console */
 HWND consoleWnd = GetConsoleWindow();
 DWORD dwProcessId;
 GetWindowThreadProcessId(consoleWnd, &dwProcessId);
 fIsConsole = GetCurrentProcessId() != dwProcessId;
#endif

but it seems like a hack to me.  I'd love to know what the approved future proof way is.

If you want to test it, the results of similar code is currently
available from within the image:

SQFile.isStdioStream for stdin notionally provides the information.

On Unix it is set in sqFileStdioHandlesInto() in sqFilePluginBasicPrims.c:

files[0].sessionID = thisSession;
files[0].file = stdin;
files[0].writable = false;
files[0].lastOp = READ_OP;
files[0].isStdioStream = isatty(fileno(stdin));
files[0].lastChar = EOF;


On Windows in sqFileStdioHandlesInto() in sqWin32FilePrims.c:

files[0].sessionID = thisSession;
files[0].file = GetStdHandle(STD_INPUT_HANDLE);
files[0].writable = false;
files[0].lastOp = 0; /* unused on win32 */
files[0].isStdioStream = GetConsoleMode(files[0].file, &mode) != 0;
AddHandleToTable(win32Files, files[0].file);

This could be causing problems, because AFAIA GetConsoleMode(files[0].file, &mode) is no longer reliable.  Can you test?

- test a non-console vm launched from a console window and from the desktop; isStdioStream should be false
- test a console vm launched from a console; isStdioStream should be true
- test a console vm launched from the desktop; isStdioStream should be false

Right?

And SQFile is the byte array handle used in the file streams.

I've been thinking that it would be nice to be able to access the
structure from within the image, but haven't yet come up with a way to
automatically map the fields (Monty did some work which might help,
but I haven't looked at it yet).

We could simply add a primitive primitiveDescriptorIsATTY or some such.

Cheers,
Alistair
Reply | Threaded
Open this post in threaded view
|

Re: Identify console executable and standard one

K K Subbu
 
On Sunday 15 April 2018 11:42 PM, Eliot Miranda wrote:

>>
>> On Windows in sqFileStdioHandlesInto() in sqWin32FilePrims.c:
>>
>> files[0].sessionID = thisSession;
>> files[0].file = GetStdHandle(STD_INPUT_HANDLE);
>> files[0].writable = false;
>> files[0].lastOp = 0; /* unused on win32 */
>> files[0].isStdioStream = GetConsoleMode(files[0].file, &mode) != 0;
>> AddHandleToTable(win32Files, files[0].file);
>
> This could be causing problems, because AFAIA
> GetConsoleMode(files[0].file, &mode) is no longer reliable.  Can you test?

I believe _isatty(fd) from io.h is the syscall on Windows:

  https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/isatty

HTH .. Subbu
Reply | Threaded
Open this post in threaded view
|

Re: Identify console executable and standard one

alistairgrant
 
Hi Eliot & Subbu,

On 16 April 2018 at 05:50, K K Subbu <[hidden email]> wrote:

>
> On Sunday 15 April 2018 11:42 PM, Eliot Miranda wrote:
>>>
>>>
>>> On Windows in sqFileStdioHandlesInto() in sqWin32FilePrims.c:
>>>
>>> files[0].sessionID = thisSession;
>>> files[0].file = GetStdHandle(STD_INPUT_HANDLE);
>>> files[0].writable = false;
>>> files[0].lastOp = 0; /* unused on win32 */
>>> files[0].isStdioStream = GetConsoleMode(files[0].file, &mode) != 0;
>>> AddHandleToTable(win32Files, files[0].file);
>>
>>
>> This could be causing problems, because AFAIA
>> GetConsoleMode(files[0].file, &mode) is no longer reliable.  Can you test?
>
>
> I believe _isatty(fd) from io.h is the syscall on Windows:
>
>  https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/isatty
>
> HTH .. Subbu

Right, _isatty sounds like the more sensible call.  Just looking at
the docs, the return value of GetConsoleMode() is simply whether it
succeeded or not.

However, in some quick tests it appears that both _isatty() and
GetConsoleMode() return the correct value when called from a cmd.exe
terminal window (I guess GetConsoleMode() fails if there isn't a
terminal).  They both fail when called from a cygwin shell (mintty).
It looks like vim (yes, the text editor) has some MIT licensed code
that does the check correctly from within mintty.

I think my time will be very limited over the next few days, but I'll
try and narrow this down eventually.


Cheers,
Alistair
Reply | Threaded
Open this post in threaded view
|

Re: Identify console executable and standard one

Ben Coman
 


On 16 April 2018 at 21:17, Alistair Grant <[hidden email]> wrote:
 
Hi Eliot & Subbu,

On 16 April 2018 at 05:50, K K Subbu <[hidden email]> wrote:
>
> On Sunday 15 April 2018 11:42 PM, Eliot Miranda wrote:
>>>
>>>
>>> On Windows in sqFileStdioHandlesInto() in sqWin32FilePrims.c:
>>>
>>> files[0].sessionID = thisSession;
>>> files[0].file = GetStdHandle(STD_INPUT_HANDLE);
>>> files[0].writable = false;
>>> files[0].lastOp = 0; /* unused on win32 */
>>> files[0].isStdioStream = GetConsoleMode(files[0].file, &mode) != 0;
>>> AddHandleToTable(win32Files, files[0].file);
>>
>>
>> This could be causing problems, because AFAIA
>> GetConsoleMode(files[0].file, &mode) is no longer reliable.  Can you test?
>
>
> I believe _isatty(fd) from io.h is the syscall on Windows:
>
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/isatty
>
> HTH .. Subbu

Right, _isatty sounds like the more sensible call.  Just looking at
the docs, the return value of GetConsoleMode() is simply whether it
succeeded or not.

However, in some quick tests it appears that both _isatty() and
GetConsoleMode() return the correct value when called from a cmd.exe
terminal window (I guess GetConsoleMode() fails if there isn't a
terminal).  They both fail when called from a cygwin shell (mintty).
It looks like vim (yes, the text editor) has some MIT licensed code
that does the check correctly from within mintty.


I've was reading around this topic to see if I could find anything useful.
I haven't really got my head around it yet to tell what is directly related,
but here is the most interesting links I found...

How can I tell whether my console program was launched from Explorer or from a command prompt?
https://blogs.msdn.microsoft.com/oldnewthing/20160125-00/?p=92922

What Is conhost.exe and Why Is It Running?
https://www.howtogeek.com/howto/4996/what-is-conhost.exe-and-why-is-it-running/


Both isatty() and GetConsoleScreenBufferInfo() fail with mintty 2.1.5 in MSYS2 [okay with Cygwin]

MSVC's native _isatty() thinks Cygwin Bash is a pipe, not an interactive shell, because it just uses GetFileType() deep under the hood.
https://stackoverflow.com/questions/45223868/how-do-i-play-nice-with-cygwin

ReadConsole and WriteConsole can only be used with console handles; 
ReadConsole and WriteConsole fail if used with a standard handle that has been redirected and is no longer a console handle.
ReadFile and WriteFile can be used with other handles (such as files or pipes). 

 "GetConsoleMode error: 6" when running under Unix emulation environments such as cygwin and msys.  
What this means is that GetConsoleMode is being called on an invalid file handle (STD_INPUT_HANDLE). 

Windows: Improve terminal detection mechanism

Cunningly conquering communicated console caveats. Comprende, mon Capitán?

What does CreateFile(“CONIN$” ..) do?

The CreateFile function enables a process to get a handle to its console's input buffer and active screen buffer, even if STDIN and STDOUT have been redirected. To open a handle to a console's input buffer, specify the CONIN$ value in a call to CreateFile



cheers -ben
Reply | Threaded
Open this post in threaded view
|

Re: Identify console executable and standard one

alistairgrant
 
Hi Ben,

Thanks very much for the links.


On 27 April 2018 at 12:39, Ben Coman <[hidden email]> wrote:

>
>
>
> On 16 April 2018 at 21:17, Alistair Grant <[hidden email]> wrote:
>>
>>
>> Hi Eliot & Subbu,
>>
>> On 16 April 2018 at 05:50, K K Subbu <[hidden email]> wrote:
>> >
>> > On Sunday 15 April 2018 11:42 PM, Eliot Miranda wrote:
>> >>>
>> >>>
>> >>> On Windows in sqFileStdioHandlesInto() in sqWin32FilePrims.c:
>> >>>
>> >>> files[0].sessionID = thisSession;
>> >>> files[0].file = GetStdHandle(STD_INPUT_HANDLE);
>> >>> files[0].writable = false;
>> >>> files[0].lastOp = 0; /* unused on win32 */
>> >>> files[0].isStdioStream = GetConsoleMode(files[0].file, &mode) != 0;
>> >>> AddHandleToTable(win32Files, files[0].file);
>> >>
>> >>
>> >> This could be causing problems, because AFAIA
>> >> GetConsoleMode(files[0].file, &mode) is no longer reliable.  Can you test?
>> >
>> >
>> > I believe _isatty(fd) from io.h is the syscall on Windows:
>> >
>> >  https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/isatty
>> >
>> > HTH .. Subbu
>>
>> Right, _isatty sounds like the more sensible call.  Just looking at
>> the docs, the return value of GetConsoleMode() is simply whether it
>> succeeded or not.
>>
>> However, in some quick tests it appears that both _isatty() and
>> GetConsoleMode() return the correct value when called from a cmd.exe
>> terminal window (I guess GetConsoleMode() fails if there isn't a
>> terminal).  They both fail when called from a cygwin shell (mintty).
>> It looks like vim (yes, the text editor) has some MIT licensed code
>> that does the check correctly from within mintty.
>
>
>
> I've was reading around this topic to see if I could find anything useful.
> I haven't really got my head around it yet to tell what is directly related,
> but here is the most interesting links I found...
>
> How can I tell whether my console program was launched from Explorer or from a command prompt?
> https://blogs.msdn.microsoft.com/oldnewthing/20160125-00/?p=92922
>
> What Is conhost.exe and Why Is It Running?
> https://www.howtogeek.com/howto/4996/what-is-conhost.exe-and-why-is-it-running/
>
> GetConsoleMode fails when input piped
> http://comp.os.ms-windows.programmer.win32.narkive.com/xiPamaWm/getconsolemode-fails-when-input-piped
>
> Both isatty() and GetConsoleScreenBufferInfo() fail with mintty 2.1.5 in MSYS2 [okay with Cygwin]
> https://github.com/mintty/mintty/issues/482

This is the one that says that Windows Consoles and MinTTY terminals
are basically incompatible.



> MSVC's native _isatty() thinks Cygwin Bash is a pipe, not an interactive shell, because it just uses GetFileType() deep under the hood.

This is how Vincent's code checks to see if we're running in a MinTTY
terminal.  It looks for a pipe with a particular name.



> https://stackoverflow.com/questions/45223868/how-do-i-play-nice-with-cygwin
>
> ReadConsole and WriteConsole can only be used with console handles;
> ReadConsole and WriteConsole fail if used with a standard handle that has been redirected and is no longer a console handle.
> ReadFile and WriteFile can be used with other handles (such as files or pipes).
> https://docs.microsoft.com/en-us/windows/console/high-level-console-input-and-output-functions
>
>  "GetConsoleMode error: 6" when running under Unix emulation environments such as cygwin and msys.
> What this means is that GetConsoleMode is being called on an invalid file handle (STD_INPUT_HANDLE).
> https://lists.osuosl.org/pipermail/darcs-users/2004-June/002104.html
>
> Windows: Improve terminal detection mechanism
> https://phabricator.haskell.org/D2809
> https://github.com/git/git/blob/0767172b9068b225c06fd7ce66422e5936ec60a2/compat/winansi.c#L534-L571
> https://fossies.org/linux/vim/src/iscygpty.c
> https://hackage.haskell.org/package/base-4.6.0.0/src/cbits/consUtils.c
>
> Cunningly conquering communicated console caveats. Comprende, mon Capitán?
> http://archives.miloush.net/michkap/archive/2010/05/07/10008232.html
>
> What does CreateFile(“CONIN$” ..) do?
> https://stackoverflow.com/questions/377152/what-does-createfileconin-do?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
>
> The CreateFile function enables a process to get a handle to its console's input buffer and active screen buffer, even if STDIN and STDOUT have been redirected. To open a handle to a console's input buffer, specify the CONIN$ value in a call to CreateFile
> https://docs.microsoft.com/en-us/windows/console/console-handles
>
> Where do writes to stdout go when launched from a cygwin shell, no redirection
> https://stackoverflow.com/questions/4028353/where-do-writes-to-stdout-go-when-launched-from-a-cygwin-shell-no-redirection
>
>
> How to create a Windows program that works both as a GUI and console application
> https://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/


It will take me a while to read through the rest. :-)

Thanks again,
Alistair