#2618 windows: exec doesn't find symlink without full path

obsolete: 8.4.1
Mo DeJong
Patrick Samson

OS: Windows/Cygwin

$ tclsh
% exec gzip --version
gzip 1.3.5

% exec gunzip --version
couldn't execute "gunzip": no such file or directory

% exec /usr/bin/gunzip --version
couldn't execute "D:\cygwin\bin\gunzip": invalid argument

% exec /usr/bin/gunzip.exe --version
gzip 1.3.5

$ ls -l /usr/bin/gunzip
lrwxrwxrwx 1 Samson Users 19 Nov 27 15:20
/usr/bin/gunzip -> gzip.exe

So, gunzip is a link. Fine, why not.
But why exec is not able to consider links
when searching for the target in its known

Does it work on a pure Unix box?

Please amend the doc to state that.
(I didn't see anything in 8.4.5)


  • Vince Darley
    Vince Darley

    • assigned_to: vincentdarley --> mdejong
  • Vince Darley
    Vince Darley

    Logged In: YES

    I have no knowledge of cygwin, so re-assigning.

  • Logged In: YES

    symlinks from bash aren't file system entities with cygwin.

    To see, open gunzip.exe into notepad and you get:

    that text file doesn't have a valid PE header, therefore it
    connot be run as an executable because it isn't one.

    If it was up to me, I'd mark this bug report invalid and close it.

  • Logged In: YES

    To put it another way, there aren't any Win32 functions to
    decode a cygwin symlink text file.

  • Patrick Samson
    Patrick Samson

    Logged In: YES

    Thanks for pointing how cygwin symlink are made.
    I understand that they are not real exe.

    But I would not consider this report invalid and
    closed, unless you can explain why:
    exec /usr/bin/gunzip.exe
    works but
    exec /usr/bin/gunzip
    exec gunzip
    do not.

  • Don Porter
    Don Porter

    Logged In: YES

    Has the submitter tried:

    eval exec [auto_execok gunzip]


    That's the more reliable, recommended

  • Jeffrey Hobbs
    Jeffrey Hobbs

    Logged In: YES

    auto_execok is the way to go:

    (Tcl) 49 % auto_execok gunzip

    In any case, the reason that only the full path works is
    because that is the only valid exe from Windows point of
    view. Cygwin does lots of bizarre pseudo-Windows stuff that
    just isn't valid from the real Windows point of view.

  • Jeffrey Hobbs
    Jeffrey Hobbs

    • status: open --> closed-invalid
  • Don Porter
    Don Porter

    Logged In: YES

    then just watch out for
    Bug 954263. It's fixed now,
    but will cause trouble if
    you're using Tcl 8.5a1

  • Patrick Samson
    Patrick Samson

    Logged In: YES

    OK for auto_execok if it helps to find the path to the
    executable to gunzip. But I still find a little strange that
    %exec gzip works without any help.
    Both files are located at the same place:
    The only difference is that the latter doesn't have a real
    executable struture, but [auto_execok gunzip] neither.

    Now, another point of frustration:
    % exec [auto_execok gunzip] x.gz
    gzip: x.gz already has .gz suffix -- unchanged

    gzip.exe is executed as expected but it checks if it
    has been so with the application name 'gun*' to
    know if decompression must be exerciced.

    If you look at tcl8.4.1\win\tclWinPipe.c:
    if ((*tclWinProcs->createProcessProc)(NULL,
    (TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE,
    (DWORD) createFlags, NULL, NULL, &startInfo, &procInfo)
    == 0) {

    The first argument is lpApplicationName. If it contains
    'gunzip' then gzip.exe knows it must decompress.
    With NULL, the application name is taken from the
    second argument, which contains 'gzip', so compression
    is selected.

    Any chances to have the application name included
    in the process creation call?

  • Logged In: YES

    But if you look earlier in TclpCreateProcess, you'll see that
    ApplicationType() reads the PE header of gunzip.exe and find
    that it is invalid as an executable.

  • Logged In: NO

    Even the command shell doesn't know what to do with it:

    Microsoft Windows 2000 [Version 5.00.2195]
    (C) Copyright 1985-2000 Microsoft Corp.



  • Patrick Samson
    Patrick Samson

    Logged In: YES

    My mistake. Remember that I run a Cygwin version, not a
    Windows version. I shouldn't have mention tclWinPipe.c,
    but tclUnixPipe.c. In TclpCreateProcess, the call is to
    execvp(newArgv[0], newArgv);
    execvp is in winsup\cygwin\exec.cc. I didn't find anything
    obvious in a few minutes, for this comment.

    Comparison should be done with a bash shell, not a cmd.exe:
    $ gunzip --version
    gunzip 1.3.5

  • Logged In: NO

    Then you should send a bug report to the cygwin folks as
    execvp() is not in the Tcl code.

  • Patrick Samson
    Patrick Samson

    Logged In: YES

    Well, I had to browse deeper in code, and strace.exe the runs
    to know more.
    First let's correct some of my wrong previous assertions:
    - Forget tclUnixPipe.c and execvp(). For the cygwin package
    tclWinPipe.c is used.
    - Forget what I wrote about lpApplicationName. Even directly
    from bash, a CreateProcess() is called with
    lpApplicationName = "C:\cygwin\bin\gzip.exe"
    lpCommandLine="C:\cygwin\bin\gzip.exe /tmp/some.gz"

    Now, what I think is the explanation:
    bash uses spawn.cc. CreateProcess() is called in spawn_guts()
    of this source, with extra information in
    lpStartupInfo.lpReserved2 (which should be NULL for a
    MSC Runtime exe).
    This info will provide the argv for the child process, but
    with the replacement of argv[0]:
    newargv.replace0_maybe (prog_arg);
    That's how gzip.exe gets its arg[0] as "/bin/gunzip.exe".

    Note: the cygwin starter also supports lpReserved2 as NULL,
    but then all this wizardry for arg[0] is missing.

    I guess there is no way for TCL to satisfy these cygwin
    internals, so I'm on my own to replace every "gunzip" with
    "gzip -d" in the tcl-based open source products I use.
    And for any !<symlink> form of exe as well.

    Thanks anyway to all for your comments and assistance.