Interix Running Win32-based Programs

Services for UNIX 3.0 Technical Note

Abstract

This paper discusses running Win32®-based programs from Interix shell scripts. Almost all of the comments also apply to running Win32-based programs directly from the Interix command line.

On This Page

Running Win32 Programs Running Win32 Programs
Related Links Related Links

Running Win32 Programs

The Interix subsystem replaces the original Microsoft® POSIX subsystem. Interix provides a complete, native UNIX environment than can run concurrently with the Windows subsystem. It comes with a complete collection of UNIX utilities including the ksh and tcsh shells. From these shells you can invoke not only the Interix utilities but also the Win32®-based CUI (command-line) and Win32-based GUI programs.

This paper discusses running Win32 programs from UNIX shell scripts. Almost all of the comments also apply to running Win32-based programs directly from the command line.

The Interix environment that is part of Services for UNIX 3.0 ships with a command called runwin32 which makes finding and running Win32 binaries substantially easier. Interix also comes with a collection of shell scripts located in /usr/contrib/win32/bin that are named after many of the cmd.exe built-in commands and many of the Windows utilities normally found in the main Windows directories like c:/windows/system32.. You can easily use these scripts as examples when writing wrappers for other Win32-based programs.

Besides these special shell scripts, the Interix ksh has also been enhanced with a new case insensitive command searching mechanism that makes it easier to invoke Win32 programs directly without having to use the indirection of the scripts in /usr/contrib/win32/bin.

Once a Win32-based application is started, it interacts directly with the Windows subsystem and there is generally no further connection with the Interix subsystem.

Interactions

Normally when invoking Win32-based programs from the Interix command line, keep in mind the following:

  • You must specify the Win32-based program either with a complete pathname or by adding the location of the Win32-based programs to your PATH. The pathname or filename you type will be treated in a case-sensitive manner so you will have to know the correct case for each path component and the filename. This is a challenge since there is very little consistency in how pre-installed Windows programs are named.

  • The portion of the command line that specifies the program to execute must be in the Interix format, since it is parsed by the Interix subsystem. The rest of the command line that will be passed as arguments to the Win32-based program must be in the form that the program expects (e.g. in Windows pathname format)

  • If the Win32-based program makes use of environment variables, they must be in a form the Win32-based program can use.

  • If other Interix programs use those environment variables, they must be converted back to a form that the Interix programs can use.

  • Running a Win32-based program involves the interaction of the two different permissions models. Interix uses the UNIX permission bits and Windows uses Access Control Lists (ACLs).

  • The return value or exit status of a Win32-based program may not have any significance.

  • You cannot generally run a Win32 interpreter program directly using a #! line in a shell script, you must use #!/bin/sh or #!/bin/ksh instead. The ActiveState Perl is an exception. It would be possible to have #!/Perl/bin/Perl.exe as the first line of a shell script. However, you should note that this will work only from the Interix environment; cmd.exe does not support this construct.

  • The Win32-based program may expect text files to be in the Win32 format (end-of-line marked by CR-LF) instead of the POSIX format (end-of-line marked by LF).

  • When creating pipelines with Win32 commands, you may need to use the cat32.exe program.

Adding Win32-based Programs to Your PATH

From the Interix shells you can run Windows programs such as ATTRIB.EXE, CACLS.EXE and REGEDT32.EXE. You can also redirect the input and output of these programs.

The simplest way to add the Win32 commands to your environment is to add the appropriate directories to your PATH. For example:

$ PATH="$PATH:/dev/fs/C/WINNT/system32"

Note that the pathname is added in the Interix filename format, not the Win32 format. Also note that the case of the directory must exactly match that of the file system.

When you run a Win32-based program, the Interix subsystem converts your PATH variable back to the Win32 format so the Win32-based program has the current PATH. This is the only environment variable that is converted for you; you must handle all others yourself. If your Win32-based programs will need to search the PATH, you should add any additional necessary directories.

When you need to run commands found in PATH, you must specify the entire filename including its suffix (file extension) as well as the correct upper or lower case characters. You might have to type:

$ CACLS.EXE

Typing the entire filename in the correct case can be a nuisance. To shorten frequently-used commands, you can use aliases, links, or a shell script, depending upon your needs and your system administration environment.

Using Aliases

Aliases have the advantage of easy customization; anyone can set up aliases, even without Administrator privileges. If there are only one or two Win32 commands you expect to use, you won't need to change your PATH.

For example, when using the ksh:

$ alias attrib="/C/WINNT/system32/ATTRIB.EXE"
$ alias cacls="/C/WINNT/system32/CACLS.EXE"

allows you to execute the ATTRIB.EXE program by just typing the word attrib, and run the CACLS.EXE program when you type the command cacls.

Because you can start CMD.EXE (the Windows "DOS" command processor) from the Interix environment, you can use an alias to run CMD.EXE built-in commands. Again assuming your PATH has been set up to include the correct directories, here's how you could set up your Interix environment to give you the dir command for directory listings:

$ alias dir='CMD.EXE /c "dir /on"'
$ dir
Volume in drive C has no label.
Volume Serial Number is 14CC-6DB9
Directory of C:\USERS\jimtru
08/12/96  12:12p        <DIR>          .
08/12/96  12:12p        <DIR>          ..
08/10/96  05:46p                   170 .profile
07/10/96  05:41p                   110 able
    ....
08/02/96  05:20p        <DIR>          test
07/10/96  01:33p                 6,656 REPORT.DOC
       48 File(s)        625,581 bytes
                     358,595,584 bytes free

Using Links

Links have the advantage of being more like a traditional environment where there is a physical file on the filesystem instead of a substitution that occurs only in the shell. Creating a file hard link is simple:

$ cd /dev/fs/C/WINNT/system32
$ ln PING.EXE ping

Assuming your PATH includes /dev/fs/C/WINNT/system32, you can now run the program PING.EXE by typing the command ping. Remember that this is just an example; Interix also supplies its own ping command in /bin/ping.

You can only use a hard link on files located on NTFS file systems. Hard links do not work on FAT filesystems. You may also find that you need Administrator privileges to add the link.

It is also possible to use symbolic links. Symbolic links work with either FAT, FAT32 or NTFS file systems, so as an alternate example you could use:

$ ln –s PING.EXE ping

Experienced users know that links can easily get out of hand and lead to an administrative nightmare.

Using Shell Scripts

Shell scripts may be the best way to invoke any Win32 command-line utility. With a shell script, you have control over the environment variables, you can name the script as you please without any manipulation of the file system, and it can be placed in a publicly-accessible directory such as /usr/local/bin.

As an example the Interix utility /bin/lp is a shell script that calls the Windows print.exe command.

Pathnames

Win32-based programs expect pathnames to be in the Win32 format, such as C:\WINNT\system32, while Interix programs expect them in the Interix format, such as /dev/fs/C/WINNT/system32.

The /bin/unixpath2win utility converts an Interix pathname to a Win32 pathname. The /bin/winpath2unix utility converts a Win32 pathname to an Interix pathname. These are new utilities with Services for UNIX 3.0 that replace the earlier posixpath2nt and ntpath2posix utilities from Interix 2.2. The old utilities are still available for backward compatibility, but are not as functional as the new utilities. The major feature of the new utilities is the support for UNC pathnames. The UNC namespace is now supported by the Interix subsystem via the syntax /net/machineName/shareName.

For example, if you need to convert the path \\inxsrv\public to Interix format:

$ winpath2unix ‘\\inxsrv\publics’/net/inxsrv/publics
$ winpath2unix ‘C:\WINDOWS\system32`
/dev/fs/C/WINDOWS/system32

and back

$ unixpath2win /net/inxsrv/publics\\inxsrv\publics
$ unixpath2win /dev/fs/C/WINDOWS/system32
C:\WINDOWS\system32

Environment Variables

Environment variables are used for storing global information required by several utilities or applications. Often this information is a pathname or a set of command options. For example, HOME contains the pathname of the user's home directory. When an Interix process is started from the Windows subsystem (as most login shells are), it inherits the environment variables as defined in the Windows environment. For further details see "Inherited Environment Variables" below.

Changing the value of an environment variable in the current Interix process does not change the environment variable in the parent process (be it a Windows or an Interix parent process). The environment in the Interix process ends when the Interix process ends. However, a child process does inherit all the environment variables from its parent. So when the parent and child processes are programs based on different subsystems then conflicts can arise. For example, the PATH environment variable is expected to contain Interix format pathnames when used by an Interix process but when a Windows program is spawned, the Windows program expects PATH to contain pathnames in the Windows format.

The normal practice is to convert the environment variable before calling a Win32-based program, and then convert it back to the Interix format after the Win32-based program exits. If the environment variable contains a pathname, you can use the unixpath2win and winpath2unix utilities. Note that this conversion process is not necessary for the PATH environment variable since the Interix subsystem does this automatically.

Here's how the /bin/cc shell script gets the TMP environment variable:

TMP=${TMP:-$(getconf CS_TMPDIR)}     # get a default export TMP=$(unixpath2win $TMP)

The first line gets the current value of TMP; if it has no value, the value of getconf CS_TMPDIR is assigned. The second line converts the value to Interix format and exports the value into the environment.

Because no other Interix utilities are called in the cc script, the environment variable is not converted back to the Interix format. If you need to convert the variable back, use this line:

export TMP=$(winpath2unix $TMP) 

If your shell script contains options to set some of the environment variables, you may want to explicitly unset those environment variables before running the program. This prevents unexpected interactions between variables set by the user and those set by the shell script. The cc shell script unsets these variables:

unset LIB
unset INCLUDE
unset MSC_CMD_FLAGS
unset MSC_IDE_FLAGS

The cc script also supports a –L option which specifies directories that should be given to the linker to find specific library archives. Since the linker is a Windows program these directories need to be in Windows pathname format. The unixpath2win utility is to perform this conversion. For example, the code in /bin/cc looks like:

L)
     dir=$(unixpath2win $OPTARG)
     if [ "$LIB" = "" ]; then
          LIB="$dir";
     else
          LIB="$LIB;$dir";
     fi
    ;;

First dir is assigned the value that was specified with the –L option and this value is converted to the Win32 format. Next, if the environment variable LIB has no current value then it is given the value of dir. If the variable LIB does have a current value then the value of dir is appended to the value in LIB.

PATH_WINDOWS

The Interix ksh has been enhanced to support Windows style path searching. A special environment variable called PATH_WINDOWS has been created. The use of PATH_WINDOWS environment variable eliminates the need to worry about the case of the command file and it eliminates the need to type the command file’s explicit suffix. Much like the behavior one would expect when using the Windows cmd.exe command line shell. This environment variable contains a list of directories where Windows style path searching should be performed. First the search is performed in a case-insensitive manner and second, the search looks for files that have one of several specified suffixes, such as .exe or .bat.

The Interix ksh default login profile file (/etc/profile) sets the PATH_WINDOWS environment variable to a default set of directories and suffixes, namely .com, .exe, .ksh, .bat, and .cmd.

In the Interix ksh , if you type

$ echo $PATH_WINDOWS

you will see the default value of PATH_WINDOWS set to the following (or something similar):

/dev/fs/C/WINDOWS/system32/.com,.exe,.ksh,.bat,.cmd,:\
/dev/fs/C/SFU/common/.com,.exe,.ksh,.bat,.cmd,

Please note that the path name is in Interix format, not Windows format.

You can also specify your own suffix matching order. The value of PATH_WINDOWS is a colon-separated list of directory names with the following format:

pathname[/suffix-list][:pathname[/suffix-list]]

The suffix-list is a comma-separated list of suffixes. Each suffix can contain up to four characters (one character being the dot (.)) and the suffix list can contain up to six separate suffixes. Note that in the example above the suffix list ends in a comma. This means that the last suffix in the list is the empty string (i.e. no suffix). This allows filenames without any suffix to be found. This is useful if you have a directory that contains a mixture of both Windows commands and Interix commands.

If no suffix list is specified with the pathname, then the ksh automatically uses a default set of suffixes.

$ PATH_WINDOWS=/dev/fs/C/WINDOWS/system32
$ echo $PATH_WINDOWS
/dev/fs/C/WINDOWS/system32/.com,.exe,.ksh,.bat,.cmd,

The suffix list is also search order specific. The search for suffixes will occur in the order specified. Using the example above, if a directory contains both foobar.exe and foobar.bat, the foobar.exe file will be matched.

Inherited Environment Variables

The environment of your Interix shell session is created from both the Interix subsystem and the shell’s startup files. When an Interix command is invoked from Windows, the Interix subsystem converts the inherited Win32 environment in the following ways:

  • All environment variable names are converted to uppercase: Path becomes PATH.

  • Each pathname in the value of the PATH environment variable are converted from the Win32 format to the Interix format.

  • If a HOME environment variable exists and then its value is converted from Windows format to Interix format.

    If the HOME environment variable does not exist then a new HOME environment variable is built from the HOMEDRIVE and HOMEPATH variables. This too is converted to Interix format.

The global ksh login shell startup file /etc/profile also adjusts the environment:

  • The existing value in PATH is stored in PATH_ORIG and a new PATH is constructed using values necessary to get a proper Interix working environment.

  • TMPDIR is an environment variable defined by the POSIX/UNIX standards. It must be set to an appropriate value. It is set to the first of $INTERIX_TMPDIR, $TMPDIR, or /tmp whichever one contains an existing directory pathname.

    TMP and TEMP are not converted, since they are not historical UNIX variable names and these are heavily used by Win32-based programs.

  • TERM, TERMCAP, EDITOR, VISUAL, and FCEDIT are set.

  • SHELL is unset.

Your system local startup file (/etc/profile.lcl) and your personal startup files (such as $HOME/.profile) may also alter environment variables.

When you invoke a Win32 program from Interix, the Interix subsystem automatically converts your PATH variable back to the Win32 format so the Win32-based program has the current PATH. This is the only environment variable that is converted for you; you must handle all others yourself.

Suppose you're running vim.exe, the Win32 port of vim. It can take a long time to start because it looks for startup files in the directory specified in HOME. Since HOME contains a path in the wrong format for a Win32-based program, you must wait for the program to time out its search. Rather than wait or use the option to prevent searching for startup files, you could set up an alias that starts the vim.exe program like this:

HOME=$(unixpath2win $HOME) vim.exe

Actually, rather than invoke unixpath2win each time you start vim.exe, you'd probably want to assign the converted value to another variable, either in your $HOME/.profile or your environment ($HOME/.environ) file:

NTHOME=$(unixpath2win $HOME)
alias vim="HOME=$NTHOME vim.exe"

File Permissions

Once you start using both Win32 and Interix utilities on the same files, you may see odd interactions between the Windows security model and the Interix file permissions model.

Miscellaneous

This section outlines some other parts of writing shell scripts that call Win32-based programs, including the exit status of a Win32-based program, the use of interpreter lines in shell scripts, and redirection of standard input and output.

Exit Status

In the Interix environment, the exit status of a program is tightly defined: 0 for success, and a value between 1 and 127 for failure. The high byte of the integer value is reserved for signal information.

In the Win32-based environment, a program can return any 32-bit value. Unless you know that the program returns a POSIX-style exit status, the shell is likely to misinterpret any captured exit status.

Redirecting Standard Input, Output, and Error

Win32-based programs can accept input redirected from standard in (as in < file ); you can also redirect their standard output (with > file ) and their standard error.

Win32-based programs can also be used in command pipelines. However, Win32-based programs are not required to be well-behaved in terms of the three standard file streams. In order to provide more robust behavior when piping to and from Win32-based programs, Interix includes a Win32 utility, cat32.exe, which is simply a "better behaved" filter. If you experience problems with a particular Win32-based program in a pipeline, try inserting cat32 into the pipeline. For example:

$ net.exe users | cat32 | more 

Useful Utilities

Three utilities provided with Interix make it easier to handle the interactions of the two environments:

runwin32

Runs a Win32-based program, converting any arguments containing pathnames to win32 format.

wvisible

Returns true if the current window station is visible, false if it is not.

runwin32

The runwin32 program is a shell script to run Win32 commands. The synopsis is:

runwin32 command arguments

The command is either a cmd.exe built-in command or a file with one of the standard Windows suffixes (like .EXE) that cmd.exe knows how to search for and execute. Because cmd.exe searches for command using the PATH environment variable, PATH is prefixed with the standard Windows system directories (e.g. $SYSTEMROOT and $SYSTEMROOT/system32)

Using runwin32 simplifies the task of locating standard commands such as net.exe or cacls.exe. Instead of setting up an alias for net.exe and then invoking net, or altering your PATH, you can simply call runwin32:

runwin32 net args 

wvisible

The wvisible program checks to see if there is a visible Windows–based workstation. There are no visible window stations if you are logged in over a telnet connection or through some pseudo-tty connections. If there is no visible window station, some Win32-based programs won't run.

The term "window station" is peculiar to Windows NT/Windows 2000/Windows XP. Every Win32 process is associated with a window station object. If the window station is visible, then Win32 windows will be displayed on the machine's video display, and the user can interact with these windows using the keyboard and mouse. If the window station is not visible, then Win32 windows are invisible and non-interactive.

From a telnet session, any Win32 windows you create will not be visible to someone using the mouse and video display. This is a security feature; it is intended to prevent Trojan horses.

Normally, you use wvisible as a test early in a shell script. For example, most of the scripts in /usr/contrib/win32/bin do something like this:

case "$(file $PROG)" in
 *Windows-GUI*)
        wvisible || errmsg "${PROG}"
        ${PROG} $* & ;;
 *Windows-CUI*|*NT-native*)
        ${PROG} $* ;;
  *)
        doscmd ${cmd} $* ;;
esac

If the command program ($PROG) is a Windows GUI program, the script checks to see if the window is visible. If not, it calls the errmsg function.

Example: The lp Script

The /bin/lp script was one of the earliest scripts written to incorporate Win32 utilities. It demonstrates much of what you need to know.

The lp utility makes use of the environment variables LPDEST and PRINTER; this version also lets the user define the location of the Win32 print.exe file in the environment variable LP_PRINT.

The first line defines the script as being executed by the Korn shell:

#!/bin/ksh

A number of variables are initialized, If LPDEST contains a value then the variable PRINTQ is set to be the value of LPDEST. If LPDEST isn't set, PRINTQ is set to the value of PRINTER.

Once the print queue has been defined, it will later be transformed into

QNAME="/D:$(print -r "$PRINTQ" | tr '/' '\\\\')"

This code builds the pathname for the print.exe file, because the user may not have included the Win32 directories in the PATH. The pathname is stored in printcmd. Before actually searching for the print.exe file, the script checks for the value of the LP_PRINT environment variable. Then it checks for the existence of PRINT.EXE and print.exe both in the PATH (using whence) and in the directory stored in ROOT.

printcmd=""
if [ "$LP_PRINT" != "" ]; then
    printcmd=$(whence $LP_PRINT)
    if [ $? -ne 0 ]; then
    print -r "$CMD: LP_PRINT environment variable doesn't name an
executable file" 1>&2
    exit 127
    fi
else
    docmd=${WINDIR}/system32/print.exe
    printcmd=$(ntpath2posix -c ${docmd})
    if [ "$printcmd" = "" ]; then
    print -r "$CMD: cannot find command '${docmd}'." 1>&2
    print -r "$CMD: Set LP_PRINT environment variable to an alternate
print command." 1>&2
    exit 127
    fi
fi

For each copy of each file, the script goes through this sequence: The file is copied to a temporary file in TMP. That temporary filename must be converted to the Win32 format so it can be passed as an argument to the print command. After printing, the temporary file is then removed.