Porting Applications in C

Services for UNIX 3.0 Technical Note

Abstract

This paper is in addition to the information presented in the Interix Software Development Kit User's Guide. After a brief discussion of methods used to make code portable and how they affect the porting process, this paper reviews the differences and similarities between Interix and traditional open systems, and discusses some means of dealing with those differences. It ends with a list of APIs supported in Interix 2.2.

On This Page

Porting Applications in C Porting Applications in C
Examples Examples
Summary of Interfaces Summary of Interfaces
For More Information For More Information

Porting Applications in C

This paper is in addition to the information presented in the Windows Services for Unix 3.0 Software Development Kit User's Guide. After a brief discussion of methods used to make code portable and how they affect the porting process, this note reviews the differences and similarities between Interix and traditional open systems, and discusses some means of dealing with those differences. This document provides a number of examples of porting Unix application and ends with a list of APIs supported in Interix 2.2.

The topics of configuration scripts, porting daemons, and X Window System code deserve separate discussions and will be given their own technical notes.

The usual method for porting an application to Interix is to move the source to an Interix system and then recompile. If a Makefile exists, porting may be as simple as typing make.

Although Interix is a POSIX.1-conforming system, it takes different approaches in some areas than traditional systems, and there are differences outside the areas defined by the standard. Some of these are discussed in the User's Guide.

Code Portability Strategies

There are several basic approaches to porting code. Most applications use more than one of these.

  • Write a custom library of functions for each platform. The application always calls the private version of the function, which in the compilation stage is linked to a platform-specific library. This is a great deal of work, though it may be the appropriate method for a large body of source.

  • Define an extensive set of platform-specific macros that expand to the correct functions and names.

  • Use #ifdef statements to isolate sections of code based on the platform. For example, Interix supports POSIX.1, ANSI/ISO C and many interfaces from both historical BSD and SVR4 systems. Older code written using #ifdefs may make assumptions about the platform that aren't valid. For example, code built around #ifdef BSD will usually try to include <sgtty.h> rather than <termios.h>. By labeling blocks of code with the platform name, you're often trying to hit a moving target; for example, BSD4.4 has some different APIs than BSD4.3, but they're both BSD.

If you're porting an application that provides configurations for different platforms, the closest configuration to Interix is another POSIX system. Depending upon which POSIX features are supported, you may find it useful to try the code in an #ifdef BSDI386. If there's a lot of terminal code and no POSIX support, you may find it easier to start with the SVR4 configuration.

  • Use #ifdef statements where code compilation is dependent upon features. This is the most common approach.

The advantage of this method is that sets of feature test macros can be gathered into a configuration block; new platforms can be defined with a single block of code in one file. Another advantage is to create a record of changes that can be refered to in other projects.

When porting a package for redistribution, remember that Makefiles may also need modifications.

The Interix Environment

Interix is a POSIX.1 system with extensions taken from both BSD and System V. Interix is "more like" a BSD system in some ways, but the POSIX terminal handling is very much like System V. If the application being ported makes extensive use of terminal interfaces or shared memory IPC, you may want to start with the System V version of the code.

When porting a new program, examine the application for features that aren't yet supported in the Interix subsystem. Depending upon the feature, you can use #ifdef statements to isolate them, or you could use a feature-based macro such as HAVE_MEMPCPY for to avoid an unsupported function (in this case mempcpy).

At the end of this paper is a list of the APIs supported by Service for Unix/Interix 3.0. See the reference pages and the Interix SDK User's Guide for more details.

SDK User's Guide

This note extends information found in the Interix SDK User's Guide. Please also refer there. The SDK User's Guide discusses the following:

  • A system overview of Interix

  • Writing POSIX-standard code, including

    • compile-time macros and manifest constants

    • getting system information (<limits.h>, confstr(), fpathconf(), pathconf(), sysconf())

    • POSIX APIs that supplant historical APIs: advisory file locking with fcntl() rather than flock() or lockf(); getcwd() rather than getwd(); mkfifo() rather than mknod(); utime() rather than utimes(); regular expressions with the functions declared in <regex.h>; <stdarg.h> rather than <varargs.h>

    • POSIX terminal I/O with the termios interface

    • POSIX signals, including sigaction()

  • Extensions to POSIX.1 included in Interix:

    • Header files aligned with the Single UNIX Specification

    • Memory-mapped files, System V IPC mechanisms

    • Sockets

    • Pseudoterminals

    • Controlling terminals

    • dynamic linking

  • Interix-specific issues regarding user authentication and absolute pathnames on the Windows NT® operating system.

Unsupported Features

There are several features which Interix does not yet support. They may be supported in future releases. Most of these are mentioned in the SDK User's Guide, but are repeated here.

  • Many ioctl() request are not supported, particularly the disk label and magnetic tape I/O requests.

Sample Configuration Blocks

As an example of a configuration block, here is the one added to apache, the Internet http server:

#elif defined(__INTERIX)
#define     USE_FCNTL_SERIALIZED_ACCEPT
#undef     HAS_GMTOFF
#define     NO_SETSID
#define     JMP_BUF sigjmp_buf
#include <sys/time.h>
#define     getwd(d)      getcwd(d,MAX_STRING_LEN)

Dealing with Missing Header Files

If you can't build your application because Interix is missing header files, do not blindly copy header files from another platform. You need to determine why the header file is being used in the application and whether the same information may be in a different header file on Interix. This is the essence of porting.

If the information is supported on Interix in a different header file, you need to #include that header file. If the information is not supported on Interix, you need to figure out a different way to achieve the same ends. In software that has been ported to many platforms, you can usually achieve the same result by changing configuration options. In custom software, you may need to write a new supporting library function.

Reading the Interix documentation and reference pages will be useful.

Handling Filenames

Earlier versions of the Interix environment did not have a single rooted filesystem. On Windows NT, or Windows2000, multiple filesystems are accessible through drive letters. Access to these are available using the syntax "//L" where L is an uppercase letter. This affected configure scripts, a number of popular software packages, Makefiles, and widgets such as file selection boxes in X applications, none of which make allowances for the special "//" prefix.

With the 3.0 version of Services for Unix, this is no longer an issue, Interix has a single rooted filesystem where "/" is the directory where Services for Unix was installed. This change makes porting much, much easier as we will see in the example section below.

Reserved Filenames (only with c89 and cc)

The compiler interfaces (c89 and cc) pass the list of files to the Microsoft Visual C/C++® compiler. Files to be compiled with c89 and cc must have names that are acceptable to the Microsoft compiler in the Win32® environment. This is not a problem when compiling with gcc; the gcc compiler operates entirely in the Interix environment, where the filenames are not reserved.

The following names are reserved under Win32, regardless of case or file extension.

AUX
LCOMn (where n is a digit)
CON
LPTn (where n is a digit)
NUL
PRN

For example, files named AUX.C, aux.c, aux.h, AUx.h or any other permutation will not compile. This is because the compiler is a Win32 program.

If you have files by these names (aux.c is particularly common), you must rename them.

About Configure Scripts

The ability of a configure script to work out the characteristics of Interix depends almost entirely on how clever the script is and what assumptions it makes. It's not possible to give a recipe for "fixing" configure scripts because each script is different—the heuristics used by configure scripts vary with the version.

Suggestions:

  • On systems such as SVR4 and BSD, the compiler is silent if there is no problem. The Microsoft Visual C/C++ compiler always writes the name of the compiled file to standard output. Because of this, configure scripts may "decide" that APIs aren't present because there was output from the compiler. The version of cc/c89 included in release 2.1 and later catches this output. This is not a problem for gcc.

  • Interix libraries are distributed differently on the system. For example, the ELM configure script searches through libc.a — but many of the interfaces are found in libpsxdll.a. Once the configure script is finished, it has not found many of the APIs that are actually provided. However, searching through libc.so will find these apis because the architecture of libc.so includes functions in libpsxdll.a

Depending on the script, it may be faster to manually change the derived configuration description rather than changing the logic of the configuration script. This is not a portable or reusable solution, but it is sometimes needed. The first apache port for Interix was done this way.

Configure scripts are more thoroughly discussed in the Configure Scripts paper available at https://www.microsoft.com/windows2000/interix.

Interface Conversions

This section describes some of the conversions which may be required in porting code. Most of these are required to run on any POSIX.1 system. The references listed in the Interix SDK User's Guide are a good source of information on these conversions.

ioctl() Calls

The ioctl() interface has many uses. The POSIX.1 committee did not standardize the ioctl() interface because the last argument ca not be type-checked (its type depends upon the request). Instead, the committee broke out certain pieces of functionality and assigned them to other interfaces.

The Interix API set contains only a few ioctl() operations, including window re-sizing.

The ioctl() interface historically was used to handle disk labels, file I/O, magnetic tape I/O, socket I/O, and terminal I/O. The disk label and magnetic tape I/O requests are not supported in the Interix environment.

File Control

The only ioctl() requests defined for file control are FIONREAD, to get the number of bytes available to read, and FIONBIO, to set and unset non-blocking I/O.

On Interix, the FIONREAD request is equivalent to the fcntl() F_GETNREAD request.

The FIOCLEX and FIONCLEX requests (usually found in <filio.h>) are not provided. They can be replaced with the fcntl() FD_CLOEXEC request.

For example:

#ifndef __INTERIX
(void) ioctl(fd, FIOCLEX, NULL)
#else
(void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFD) |
     FD_CLOEXEC));
#endif

Sockets

The only ioctl() request defined for sockets is SIOCATMARK. Other socket control requests are handled through fcntl() or through functions such as setsockopt().

Terminal Control

In POSIX.1, many of the terminal control calls that used to be handled with ioctl() requests were given separate interfaces (as listed on page 27 of the Interix SDK User's Guide).

For example, the ioctl() requests TIOCGATC, TIOCGATC, TIOCGLTC, and TCGETA all translate to the tcgetattr() call, filling in the termios structure. The requests TIOCSATC, TIOCSATC, TIOCSLTC, and TCSETA translate to the tcsetattr() call.

Allocating a Controlling Terminal

On SVR4, the controlling terminal is allocated when the session leader opens the first terminal device that is not already associated with a session and the open() call does not specify O_NOCTTY. On BSD systems 4.3+, processes allocate the controlling terminal with an ioctl() call, using the request TIOCSCTTY. Interix follows the SVR4 practice.

setpgrp()

Both BSD and System V have a setpgrp() interface, but they have different semantics and behaviors. The System V call changes the caller's process group ID to its own process ID. The BSD call detaches a process from its process group but doesn't change the controlling terminal.

The System V call takes no arguments. It is properly replaced by the POSIX setsid() call. When a process calls setsid() successfully, it creates a new session, which in turn contains a new process group, which contains one process — the calling process. The calling process is now the session and process group leader. The process also disposes of its controlling terminal. (In fact, the setsid() call is used to dispose of a controlling terminal.)

The BSD call takes two arguments, a process ID and a process group ID. It is replaced by the POSIX setpgid() call, which has identical semantics.

Debugging the Ported Code

There are a couple of differences in behavior between Interix and traditional systems such as Solaris that might show up when debugging your ported code.

Segmentation Faults

Some users porting code notice that their application memory faults more often than it did on the original platform. Experience has shown that this usually exposes a defect in the code, not in the Interix subsystem. (A subsystem segmentation fault is a different issue.)

A common cause is trying to de-reference an uninitialized pointer. An uninitialized pointer contains some random bit pattern. An attempt to read or write at the memory address indicated by that bit pattern will succeed or fail, depending on whether the user is allowed access to that address. If it fails, it fails with a segmentation fault. Even if it succeeds, it may cause problems for other applications which are using that chunk of memory.

On Windows NT, Windows 2000 and Windows XP, most of the four-gigabyte address space is off-limits to the user program. Any attempt to read or write in that space causes an application segmentation fault.

For example, this code is incorrect and will behave unexpectedly on a traditional system. It will segmentation-fault on an Interix system:

#include <stdio.h>
struct foo
{
        int one;
        int two;
};
main()
{
     int i1, i2, i3, i4;
        struct foo *t1;
        t1->one = 7;
        printf ("%d\n", t1->one);
}

There are two problems here: first, foo is defined but no actual structure is declared; second, the variable t1 is not initialized. The attempt to de-reference t1, assigning the member one to the value 7, actually points to some random memory location offset to give the access to the structure member. The following two fixes correct the problem:

#include <stdio.h>
struct foo
{
        int one;
} bar;
main()
{
     int i1, i2, i3, i4;
        struct foo *t1;
        t1=&bar;
        t1->one = 7;
        printf ("%d\n", t1->one);
}

A structure (bar) is now declared, and t1 is initialized to its address.

Porting code is often an exercise in discovering assumptions.

This should include some hint as to addresses of shared objects though they should be qualified with "these addresses may change at any time." For example, as of this writing:

The addresses of the other .so's are:

libdb.so

= 0x77c00000

# to 77c30000

libm.so

= 0x77c30000

# to 77c80000

librpc.so

= 0x77c80000

# to 77cb0000

libform.so

= 0x77cb0000

# to 77d00000

libcurses

= 0x77d00000

# to 77d80000

libc.so

= 0x77d80000

# to 77ea0000

SDK User's Guide (and probably plain User's Guide) should mention core files.

SDK User's Guide should mention problems with literal strings in read-only data

By default, gcc generates code for literal strings inline (such as in foo("hithere")) in read-only data. MSVC does not. (They're writeable.)

Such a situation occurred in ps where it was writing into such a string (the old "temporary '\0'" trick), and of course it fell over when compiled with gcc. The command line option -fwritable-strings will convince gcc otherwise. The primary reason for this note, however, is to get it fresh in peoples mind that as we use gcc more if nothing else, to create PIC libc.a) we'll have to be careful about that. (An easy way out of this is to declare the string as a static char[] initialized to that value.)

The GDB Debugger

The GDB debugger is available as part of the Interix Software Development Kit. It is possible

Examples

Introduction

In this section outlines a number of porting examples to show some of the issues that can arise in porting Unix applications to Interix.

zlib-1.1.4

zlib 1.1.4 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files https://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). These documents are also available in other formats from

ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html

unarchive the package

$ gunzip < zlib-1.1.4.tgz | tar xf -
$ ls
ChangeLog       amiga           infblock.c      infutil.c       zconf.h
FAQ             compress.c      infblock.h      infutil.h       zlib.3
INDEX           configure       infcodes.c      maketree.c      zlib.h
Make_vms.com    contrib         infcodes.h      minigzip.c      zlib.html
Makefile        crc32.c         inffast.c       msdos           zutil.c
Makefile.in     deflate.c       inffast.h       nt              zutil.h
Makefile.riscos deflate.h       inffixed.h      os2
README          descrip.mms     inflate.c       trees.c
adler32.c       example.c       inftrees.c      trees.h
algorithm.txt   gzio.c          inftrees.h      uncompr.c

This archive has a configure script, but it is not the usual GNU configure script, so we need to execute this as follows:

$ ./configure --prefix=/usr/local
Checking for gcc...
Building static library libz.a version 1.1.4 with gcc.
Checking for unistd.h... Yes.
Checking for errno.h...  Yes.
Checking for mmap support... Yes.
$

Now we can try a make

$ make
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c example.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c adler32.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c compress.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c crc32.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c gzio.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c uncompr.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c deflate.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c trees.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c zutil.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c inflate.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c infblock.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c inftrees.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c infcodes.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c infutil.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c inffast.c
ar rc libz.a adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o
trees.o  zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o
inffast.o
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -o example example.o -L. -lz
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -c minigzip.c
gcc -O3 -DHAVE_UNISTD_H -DUSE_MMAP -o minigzip minigzip.o -L. -l
$

just to be sure, we will "make test"

$ make test
hello world
uncompress(): hello, hello!
gzread(): hello, hello!
gzgets() after gzseek: hello!
inflate(): hello, hello!
large_inflate(): OK
after inflateSync(): hello, hello!
inflate with dictionary: hello, hello!
_** zlib test OK **_
$

everything looks ok, now we'll make install

$ make install
cp zlib.h zconf.h /usr/local/include
chmod 644 /usr/local/include/zlib.h /usr/local/include/zconf.h
cp libz.a /usr/local/lib
cd /usr/local/lib; chmod 755 libz.a
$

all done, ready for use!

gdbm 1.8.0

This library will be used by PERL in a later example. GNU dbm is a set of database routines that use extendible hashing and works similar to the standard UNIX dbm routines.

$ gunzip < gdbm-

bzip2 1.0.1

"bzip2" compresses files using the Burrows-Wheeler block-sorting text compression algorithm, and Huffman coding. Compression is generally considerably better than that achieved by more conventional LZ77/LZ78-based compressors, and approaches the performance of the PPM family of statistical compressors. It provides a library, two headers and a set of binaries. The library is used in other packages.

As usual, we will unarchive the package:

$ gunzip < bzip2-1.0.1.tgz | tar xf -

 

 

$ cd bzip2-1.0.1

 

 

$ ls

 

 

CHANGES

bzlib_private.h

manual_4.html

LICENSE

compress.c

manual_toc.html

Makefile

crctable.c

randtable.c

Makefile-libbz2_so

decompress.c

sample1.bz2

README

dlltest.c

sample1.ref

README.COMPILATION.PROBLEMS

dlltest.dsp

sample2.bz2

Y2K_INFO

huffman.c

sample2.ref

blocksort.c

libbz2.def

sample3.bz2

bzip2.1

libbz2.dsp

sample3.ref

bzip2.1.preformatted

makefile.msc

spewG.c

bzip2.c

manual.ps

unzcrash.c

bzip2.txt

manual.texi

words0

bzip2recover.c

manual_1.html

words1

bzlib.c

manual_2.html

words2

bzlib.h

manual_3.html

words3

 

 

 

As we can see, there is no "configure" script, however there is a Makefile, so we will just attempt a make.

$ make
If compilation produces errors, or a large number of warnings,please read
README.COMPILATION.PROBLEMS -- you might be able to adjust the flags in
this Makefile to improve matters.
gcc -Wall -Winline -O2 -fomit-frame-pointer -fno-strength-reduce …
Doing 6 tests (3 compress, 3 uncompress) ...
If there's a problem, things might stop at this point.
./bzip2 -1  < sample1.ref > sample1.rb2
./bzip2 -2  < sample2.ref > sample2.rb2
…
cmp sample2.tst sample2.ref
cmp sample3.tst sample3.ref
If you got this far and the "cmp"s didn't complain, it looks
like you're in business.
To install in /usr/bin, /usr/lib, /usr/man and /usr/include, type
   make install
To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type
   make install PREFIX=/xxx/yyy
If you are (justifiably) paranoid and want to see what 'make install'
is going to do, you can first do
   make -n install                      or
   make -n install PREFIX=/xxx/yyy      respectively.
The -n instructs make to show the commands it would execute, but
not actually execute them.
Instructions for use are in the preformatted manual page, in the file
bzip2.txt.  For more detailed documentation, read the full manual.
It is available in Postscript form (manual.ps) and HTML form
(manual_toc.html).
You can also do "bzip2 --help" to see some helpful information.
"bzip2 -L" displays the software license.
$

That seemed to compile ok, and as we can see by the output, it works correctly too. So we will follow the installation instructions and run "make install". Since we've decided to install everything in /usr/local, we'll set the PREFIX to that.

$ make install PREFIX=/usr/local
if ( test ! -d /usr/local/bin ) ; then mkdir /usr/local/bin ; fi
if ( test ! -d /usr/local/lib ) ; then mkdir /usr/local/lib ; fi
if ( test ! -d /usr/local/man ) ; then mkdir /usr/local/man ; fi
if ( test ! -d /usr/local/man/man1 ) ; then mkdir /usr/local/man/man1 ;
fi
if ( test ! -d /usr/local/include ) ; then mkdir /usr/local/include ; fi
cp -f bzip2 /usr/local/bin/bzip2
cp -f bzip2 /usr/local/bin/bunzip2
cp -f bzip2 /usr/local/bin/bzcat
cp -f bzip2recover /usr/local/bin/bzip2recover
chmod a+x /usr/local/bin/bzip2
chmod a+x /usr/local/bin/bunzip2
chmod a+x /usr/local/bin/bzcat
chmod a+x /usr/local/bin/bzip2recover
cp -f bzip2.1 /usr/local/man/man1
chmod a+r /usr/local/man/man1/bzip2.1
cp -f bzlib.h /usr/local/include
chmod a+r /usr/local/include/bzlib.h
cp -f libbz2.a /usr/local/lib
chmod a+r /usr/local/lib/libbz2.a
$

This package is complete and installed!

gettext 0.10.40

The gettext package is interesting for authors or maintainers of other packages or programs which they want to see internationalized. As one step the handling of messages in different languages should be implemented. For this task GNU gettext provides the needed tools and library functions.

This package configuration is driven by the configure script, like many GNU packages, running configure with the proper arguments ensures a successful configuration.

$ CFLAGS="-D_ALL_SOURCE" ./configure \
--prefix=/usr/local \
--host=intel-pclocal-interix
checking for a BSD compatible install... /bin/install -c
checking whether build environment is sane... yes
checking whether make sets ${MAKE}... yes
checking for working aclocal... missing
checking for working autoconf... missing
checking for working automake... missing
…
updating cache ./config.cache
creating ./config.status
creating Makefile
creating lib/Makefile
creating intl/Makefile
creating src/Makefile
creating po/Makefile.in
creating doc/Makefile
creating man/Makefile
creating tests/Makefile
creating m4/Makefile
creating misc/Makefile
creating misc/gettextize
creating config.h
creating po/POTFILES
creating po/Makefile
$

This looks promising so far, let's attempt a make.

$ make
make  all-recursive
Making all in doc
cd .  && env LANG= LANGUAGE= /bin/sh /dev/fs/C/src/gettext-0.11.1/missing
--run makeinfo    `echo gettext.texi | sed 's,.*/,,'`
Making all in intl
/bin/sh ../libtool --mode=compile gcc -c -
DLOCALEDIR=\"/usr/local/share/locale\"
 -DLOCALE_ALIAS_PATH=\"/usr/local/share/locale\"  -
DLIBDIR=\"/usr/local/lib\" -DIN_LIBINTL -DHAVE_CONFIG_H -I.. -I. -
I../intl -D_ALL_SOURCE -I/usr/local/include -g -D_ALL_SOURCE -
I/usr/local/include  intl-compat.c
gcc -c -DLOCALEDIR=\"/usr/local/share/locale\" -
DLOCALE_ALIAS_PATH=\"/usr/local/share/locale\" -
DLIBDIR=\"/usr/local/lib\" -DIN_LIBINTL -DHAVE_CONFIG_H -I.. -I. -
I../intl -D_ALL_SOURCE -I/usr/local/include -g -D_ALL_SOURCE -
I/usr/local/include intl-compat.c -o intl-compat.o
echo timestamp > intl-compat.lo
…
gcc -g -D_ALL_SOURCE -I/usr/local/include -o tstngettext tstngettext.o
setlocale.o  -L/usr/local/lib ../lib/.libs/libgettextlib.a
/dev/fs/C/src/gettext-0.11.1/intl/.libs/libintl.a ../intl/.libs/libintl.a
-lc
gcc -DLOCALEDIR=\"\" -DHAVE_CONFIG_H -I. -I. -I.. -I.. -I../lib -I../lib
-I../intl   -D_ALL_SOURCE -I/usr/local/include  -g -D_ALL_SOURCE -
I/usr/local/include -c plural-1-prg.c
/bin/sh ../libtool --mode=link gcc  -g -D_ALL_SOURCE -I/usr/local/include
-L/usr/local/lib -o cake  plural-1-prg.o setlocale.o
../lib/libgettextlib.la ../intl/libintl.la
gcc -g -D_ALL_SOURCE -I/usr/local/include -o cake plural-1-prg.o
setlocale.o  -L/usr/local/lib ../lib/.libs/libgettextlib.a
/dev/fs/C/src/gettext-0.11.1/intl/.libs/libintl.a ../intl/.libs/libintl.a
-lc
$

This looks like a successful build, let's attempt a "make check" to see if we have a good build.

$ make check
Making check in doc
…
make  check-TESTS
PASS: test-names.sh
==================
All 1 tests passed
==================
Making check in src
Making check in po
Making check in man
Making check in m4
Making check in projects
Making check in misc
WARNING: Warnings can be ignored. :-)
if test no != no; then  EMACS=no /bin/sh ./elisp-comp po-mode.el;  else :
; fi
Making check in tests
make  check-TESTS
PASS: gettext-1
…
PASS: msgcat-1
msgcat: Cannot convert from "ISO-8859-1" to "UTF-8". msgcat relies on
iconv(). This version was built without iconv().
FAIL: msgcat-2
msgcat: Cannot convert from "ISO-8859-1" to "UTF-8". msgcat relies on
iconv(). This version was built without iconv().
FAIL: msgcat-3
msgcat: Cannot convert from "ISO-8859-1" to "UTF-8". msgcat relies on
iconv(). This version was built without iconv().
FAIL: msgcat-4
PASS: msgcat-5
…
PASS: msgcomm-3
msgcomm: Cannot convert from "ASCII" to "ISO-8859-1". msgcomm relies on
iconv(). This version was built without iconv().
FAIL: msgcomm-4
msgcomm: Cannot convert from "ASCII" to "ISO-8859-1". msgcomm relies on
iconv(). This version was built without iconv().
FAIL: msgcomm-5
msgcomm: Cannot convert from "ASCII" to "ISO-8859-1". msgcomm relies on
iconv(). This version was built without iconv().
FAIL: msgcomm-6
msgcomm: Cannot convert from "ASCII" to "ISO-8859-1". msgcomm relies on
iconv().
 This version was built without iconv().
FAIL: msgcomm-7
PASS: msgcomm-8
…
PASS: msgcomm-15
msgcomm: Cannot convert from "ISO-8859-1" to "UTF-8". msgcomm relies on
iconv(). This version was built without iconv().
FAIL: msgcomm-16
PASS: msgcomm-17
…
PASS: msgcomm-23
msgconv: Cannot convert from "BIG5" to "UTF-8". msgconv relies on
iconv(). This version was built without iconv().
FAIL: msgconv-1
msgconv: Cannot convert from "UTF-8" to "BIG5". msgconv relies on
iconv(). This version was built without iconv().
FAIL: msgconv-2
PASS: msgconv-3
…
PASS: plural-2
Couldn't set locale.
SKIP: lang-c
Couldn't set locale.
SKIP: lang-c++
…
SKIP: lang-pascal
PASS: lang-ycp
msgfmt: Cannot convert from "ISO-8859-1" to "UTF-8". msgfmt relies on
iconv(). This version was built without iconv().
FAIL: lang-tcl
PASS: lang-po
…
PASS: rpath-2bbd
======================
11 of 159 tests failed
======================
*** Error code 1
Stop.
*** Error code 1
Stop.
*** Error code 1
Stop.
$

This looks less promising, and we need to investigate the failures. In this case, most of the failures are a result of Interix not providing the iconv API. The other issues are due to the fact that Interix currently only supports the C and POSIX locales (check the setlocale manpage), the lang-c, lang-c++ and lang-pascal attempt to set the locale to fr_FR which is not possible with Interix. This is found by examining the lang-* files for the tests that were SKIPPED. It is likely that future releases of Interix will support multiple locales. However, more than 90% of this package is operational. It may be that some issues may arise as we continue to use this package, but we can measure this as a qualified success.

xpm 3.4k

XPM (X PixMap) is a format for storing/retrieving X pixmaps to/from files. If we look at the file listing, we will notice that there is no configure script at all. This is a package built for the X-Windows system and it uses a different process for building. With X-Windows applications, the Imakefile is the "configure" counterpart. A different tool is used to construct the Makefiles, xmkmf (create a Makefile from an Imakefile). That tool is also part of the Interix utility set, so we should be able to use this to build this package.

$ ls -CF
CHANGES         FILES           README.AMIGA    cxpm/           namecvt*
COPYRIGHT       Imakefile       README.MSW      doc/            sxpm/
FAQ.html        Makefile.noX    README.html     lib/

There is a README.html, we can read this file to help us understand what the package does and whether there are any instructions on compiling the package. The instructions in the README.html state that we should use "xmkmf -a" to start if the platform supports it, we will try!

$ xmkmf -a
imake -DUseInstalled -I/usr/X11R5/lib/X11/config
make Makefiles
making Makefiles in ./lib...
rm -f lib/Makefile.bak
cd lib; imake -DUseInstalled -I/usr/X11R5/lib/X11/config  -DTOPDIR=../. -
DCURDIR=./lib;  make  UPPREFIX=../ NEWTOP=../ MAKEFILE_SUBDIR=lib
NEW_CURRENT_DIR=./lib
 Makefiles
making Makefiles in ./sxpm...
rm -f sxpm/Makefile.bak
cd sxpm; imake -DUseInstalled -I/usr/X11R5/lib/X11/config  -DTOPDIR=../.
-DCURDIR=./sxpm;  make  UPPREFIX=../ NEWTOP=../ MAKEFILE_SUBDIR=sxpm
NEW_CURRENT_DIR=./
sxpm Makefiles
making Makefiles in ./cxpm...
rm -f cxpm/Makefile.bak
cd cxpm; imake -DUseInstalled -I/usr/X11R5/lib/X11/config  -DTOPDIR=../.
-DCURDIR=./cxpm;  make  UPPREFIX=../ NEWTOP=../ MAKEFILE_SUBDIR=cxpm
NEW_CURRENT_DIR=./
cxpm Makefiles
make includes
including in ./lib...
including in ./sxpm...
including in ./cxpm...
make depend
depending in ./lib...
makedepend  -s "# DO NOT DELETE" -- -I.  -I/usr/X11R5/include  -Dopennt
-- data.c create.c misc.c rgb.c scan.c parse.c hashtab.c
CrBufFrI.c CrDatFrP.c CrPFrBuf.c RdFToI.c WrFFrI.c      CrBufFrP.c
CrIFrBuf.c CrPFrDat.c RdFToP
.c WrFFrP.c      CrDatFrI.c CrIFrDat.c RdFToDat.c WrFFrDat.c     Attrib.c
CrIFrP.c CrPFrI.c Image.c Info.c RdFToBuf.c WrFFrBuf.c
depending in ./sxpm...
makedepend  -s "# DO NOT DELETE" -- -I.././X11 -I..  -I/usr/X11R5/include
-Dopennt     -- sxpm.c
depending in ./cxpm...
makedepend  -s "# DO NOT DELETE" -- -I.././X11 -I..  -I/usr/X11R5/include
-Dopennt     -- cxpm.c

As we can see, the Interix xmkmf utility does support the "-a" flag, so we should now just be able to build the package with "make"

$ make
making all in ./lib...
rm -f data.o
…
making all in ./sxpm...
…
making all in ./cxpm...
…
gcc -fstrength-reduce -fpcc-struct-return -O -O  -static -L/usr/X11R5/lib
-o cxpm cxpm.o
$

Everything built ok, so now, we can install by "make install"

$ make install
installing in ./lib...
install -c -m 0644 libXpm.a /usr/X11R5/lib
+ install -c -m 0444 xpm.h /usr/X11R5/include/X11
install in ./lib done
installing in ./sxpm...
install -c   sxpm /usr/X11R5/bin
install in ./sxpm done
installing in ./cxpm...
install -c   cxpm /usr/X11R5/bin
install in ./cxpm done
$

Another package built and installed!

groff 1.17.2

Many UNIX packages deliver documentation in nroff format. GNU groff is an Open Source replacement for the AT&T nroff package. As usual, we unarchive the package, and run the configure command. If you are building many of the GNU packages, you may want to create a shell script that provides the parameters to the configuration file. This can be very useful for consistency and avoid typing mistakes. The following is an example:

$ cat /usr/local/bin/runconfig
set -x
CPPFLAGS="-D_ALL_SOURCE -I/usr/local/include" \
CXXFLAGS="-D_ALL_SOURCE -I/usr/local/include" \
CFLAGS="-D_ALL_SOURCE -I/usr/local/include" \
LDFLAGS="-L/usr/local/lib" \
./configure --prefix=/usr/local \
--host=intel-pclocal-interix $*

This script sets the compilation flags for C, C++ and CPP, it also includes the /usr/local directory for both include and library files, so the libraries we built above, will be found. Using this script to run the groff configure script we get a good configure and we should be able to make without difficulties.

$ runconfig
+ ./configure --prefix=/usr/local --host=intel-pclocal-interix
+ CPPFLAGS=-D_ALL_SOURCE -I/usr/local/include CXXFLAGS=-g -D_ALL_SOURCE -
I/usr/l
ocal/include CFLAGS=-g -D_ALL_SOURCE -I/usr/local/include LDFLAGS=-
L/usr/local/lib
configure: WARNING: If you wanted to set the --build type, don't use –
host.
    If a cross compiler is detected then cross compile mode will be used.
checking for intel-pclocal-interix-gcc... no
checking for gcc... gcc
checking for C compiler default output... a.out
checking whether the C compiler works... yes
…
checking for prefix of system macro packages...
checking which system macro packages should be made available...
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/xditview/Imakefile
$

This looks fine, so let's attempt a make

$ make
g++ -I. -I/dev/fs/C/src/groff-1.17.2/src/libs/libgroff  -
I/dev/fs/C/src/groff-1.17.2/src/include -I/dev/fs/C/src/groff-
1.17.2/src/include -DHAVE_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DIRENT_H=1
-DHAVE_LIMITS_H=1 -DHAVE_SYS_DIR_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1
-DHAVE_MATH_H=1 -DRET_TYPE_SRAND_IS_VOID=1 -DHAVE_CC_OSFCN_H=1 -
DHAVE_CC_LIMITS_H=1 -DRETSIGTYPE=void -DHAVE_STRUCT_EXCEPTION=1 -DHAVE
_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_FMOD=1 -
DHAVE_STRTOL=1 -DHAVE_GETCWD=1 -DHAVE_STRERROR=1 -DHAVE_PUTENV=1 -
DHAVE_RENAME=1 -DHAVE_STRCASECMP=1 -DHAVE_STRNCASECMP=1 -DHAVE_STRSEP=1 -
DHAVE_STRDUP=1 -DHAVE_MKSTEMP=1 -DHAVE_MKSTEMP_PROTO=1 -g -D_ALL_SOURCE -
I/usr/local/include  -c assert.cc
g++ -I. -I/dev/fs/C/src/groff-1.17.2/src/libs/libgroff  -
I/dev/fs/C/src/groff-1.17.2/src/include -I/dev/fs/C/src/groff-
1.17.2/src/include -DHAVE_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DIRENT_H=1
-DHAVE_LIMITS_H=1 -DHAVE_SYS_DIR_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1
-DHAVE_MATH_H=1 -DRET_TYPE_SRAND_IS_VOID=1 -DHAVE_CC_OSFCN_H=1 -
DHAVE_CC_LIMITS_H=1 -DRETSIGTYPE=void -DHAVE_STRUCT_EXCEPTION=1 -
DHAVE_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_FMOD=1 -
DHAVE_STRTOL=1 -DHAVE_GETCWD=1 -DHAVE_STRERROR=1 -DHAVE_PUTENV=1 -
DHAVE_RENAME=1 -DHAVE_STRCASECMP=1 -DHAVE_STRNCASECMP=1 -DHAVE_STRSEP=1 -
DHAVE_STRDUP=1 -DHAVE_MKSTEMP=1 -DHAVE_MKSTEMP_PROTO=1 -g -D_ALL_SOURCE -
I/usr/local/include  -c change_lf.cc
…
Making pfbtops.n from pfbtops.man
rm -f DESC
cat /dev/fs/C/src/groff-1.17.2/font/devps/DESC.in >DESC
echo broken 7 >>DESC
if test "letter" = A4; then  echo "paperlength 841890" >>DESC;  else
echo "paperlength 792000" >>DESC;  fi
test -z 'lp' || echo print 'lp' >>DESC
rm -f prologue
sed -f /dev/fs/C/src/groff-1.17.2/font/devps/psstrip.sed prologue.ps
>prologue
rm -f symbolsl.pfa
sed -f /dev/fs/C/src/groff-1.17.2/font/devps/psstrip.sed symbolsl.ps
>symbolsl.pfa
rm -f zapfdr.pfa
sed -f /dev/fs/C/src/groff-1.17.2/font/devps/psstrip.sed zapfdr.ps
>zapfdr.pfa
cat /dev/fs/C/src/groff-1.17.2/font/devdvi/DESC.in >DESC
test -z 'lp' || echo print 'lp' >>DESC
rm -f DESC
echo "res 600" >DESC
echo "unitwidth `expr 7620000 / 600`" >>DESC
cat /dev/fs/C/src/groff-1.17.2/font/devlj4/DESC.in >>DESC
if test "letter" = A4; then  echo "papersize a4" >>DESC;  else  echo
"papersize
letter" >>DESC;  fi
test -z 'lp' || echo print 'lp' >>DESC
Making R
…
chmod +x nroff
Making nroff.n from nroff.man
rm -f mmroff
sed -e 's;/usr/bin/perl;/bin/perl;' /dev/fs/C/src/groff-
1.17.2/contrib/mm/mmroff.pl >mmroff
chmod +x mmroff
Making groff_mm.n from groff_mm.man
Making groff_mmse.n from groff_mmse.man
Making mmroff.n from mmroff.man
$

It looks like we've got a good build, but there some things that we should take the time to look at. Sometimes, GNU packages create a config.h file that contains different constant definitions. In this case, those constants are defined in the compilation. By reviewing these compile flags we can learn some things about the Interix. For example, the "-DHAVE_*_H" flags indicate that we have a particular header file. "-DHAVE_STRSEP" means that we have the strsep(2) API (separate strings). Sometimes, we may have functionality not found by the configure script. This would be the case for the makedev() function. For example, on Solaris8, this is implemented as a function, but in Interix, it is defined as a macro in /usr/include/sys/makedev.h. A configure script that is testing for makedev, may not include the correct header file and thus not determine that makedev() is available with Interix. In this case, you would need to either alter the CFLAGS (as in this build) or modify the config.h file.

Since we have a good build, let's try a "make check"

$ make check
$

That didn't seem to do anything, however, there is a test-groff file in the directory, by inspection, it looks like it could be used, and there is a description in the INSTALL file that describes how to use it.

$ ./test-groff -man -Tascii src/roff/groff/groff.n | less

Running this command, we get what looks like a man page, so we've probably got a good build. At this point, we should attempt a make install.

$ make install
test -d /usr/local/man || /dev/fs/C/src/groff-1.17.2/mkinstalldirs
/usr/local/man
test -d /usr/local/man/man1 || /dev/fs/C/src/groff-1.17.2/mkinstalldirs
/usr/local/man/man1
test -d /usr/local/man/man5 || /dev/fs/C/src/groff-1.17.2/mkinstalldirs
/usr/local/man/man5
test -d /usr/local/man/man7 || /dev/fs/C/src/groff-1.17.2/mkinstalldirs
/usr/local/man/man7
test -d /usr/local/bin || /dev/fs/C/src/groff-1.17.2/mkinstalldirs
/usr/local/bin
rm -f /usr/local/bin/groff
/bin/install -c groff /usr/local/bin/groff
…
rm -f /usr/local/bin/mmroff
/bin/install -c mmroff /usr/local/bin/mmroff
test -d /usr/local/share/groff/1.17.2/tmac || /dev/fs/C/src/groff-
1.17.2/mkinstalldirs /usr/local/share/groff/1.17.2/tmac
rm -f /usr/local/share/groff/1.17.2/tmac/tmac.m
rm -f /usr/local/share/groff/1.17.2/tmac/m.tmac
/bin/install -c -m 644 /dev/fs/C/src/groff-1.17.2/contrib/mm/m.tmac
/usr/local/share/groff/1.17.2/tmac/m.tmac
test -d /usr/local/share/groff/1.17.2/tmac/mm || /dev/fs/C/src/groff-
1.17.2/mkinstalldirs /usr/local/share/groff/1.17.2/tmac/mm
for f in 0.MT 5.MT 4.MT ms.cov se_ms.cov; do  rm -f
/usr/local/share/groff/1.17.2/tmac/mm/$f;  /bin/install -c -m 644
/dev/fs/C/src/groff-1.17.2/contrib/mm/mm/$
f /usr/local/share/groff/1.17.2/tmac/mm/$f;  done
for f in locale se_locale; do  test -f
/usr/local/share/groff/1.17.2/tmac/mm/$f
|| touch /usr/local/share/groff/1.17.2/tmac/mm/$f;  done

Another application compiled, tested and installed in minutes!

perl 5.6.1

Now that we have a number of applications and libraries built, we should look at something more complicated. PERL is a fairly complicated package that runs on a large number of UNIX systems as well as a native Win32 port. However, there are some differences between the UNIX and Windows releases. For example, the Windows release does not support the UNIX model for shared memory and does not provide an "exec" function. PERL also has a different configure script, that is somewhat different than the GNU configure script. This Configure script is interactive, and allows for choices to be made as the configuration progresses. For purposes of this document, I have decided to use the non-interactive mode and describe the flags that are set to provide the best PERL port. In order to configure PERL, we will use the following flags:

$ ./Configure -dOes -Ddosuid=undef -Dprefix=/usr/local \
-Dd_bincompat3=undef -Dcc=gcc -Dcflags="-D_ALL_SOURCE" -Dd_poll=undef \
-Dldflags="--dynamic -Wl,-E" -Dusenm=define -Dld="gcc" \
-Dlddlflags="--shared" -Ddont_use_nlink=define -Dusemymalloc="undef" \
-Dcccdlflags="none" libpth='/usr/local/lib /usr/lib' \
-Dinstallusrbinperl=undef -Dcf_email="support@microsoft.com" \
libs='-ldb -lm -lcrypt -lgdbm -lrpclib -ldl' \
perllibs='-ldb -lm -lcrypt -lgdbm -lrpclib -ldl'
$

Going through the flags one by one:

Oes

 

dosuid

Do not provide a setuid perl

prefix

set the installation directory to /usr/local

d_bincompat3=undef

Don't be binary compatible with earlier releases

cc=gcc

Use the gcc compiler

cflags="-D_ALL_SOURCE"

Add "_ALL_SOURCE" to CFLAGS. This flag is used to get access to more than the standard POSIX APIs.

d_poll=undef

Do not use the poll API. With Interix, this API is only usefull with the /proc filesystem. The reason that this is disabled in PERL is because PERL will try to use this as a general purpose poll API.

ldflags="--dynamic -Wl,-E"

In order to take advantage of dynamic linking, we need to provide the appropriate flags to gcc. The "--dynamic" flag instructs gcc to link against the dynamic libaries provided by Inteirx. the "-Wl, -E" ensures that the linker will add all symbols to the dynamic-symbol table. This will be required for proper operation of the dynamic modules.

ld="gcc"

Use gcc as a linker. For Interix, this is the easiest way to build shared libraries.

usenm=define

Use NM to determine what symbols and routines are available

lddlflags="--shared"

add "--shared" to the command line when building shared libraries

dont_use_nlink=define

PERL will check the nlink member of the stat structure to determine whether the file is a directory. Interix does not use the nlink member to designate a directory.

usemymalloc="undef"

Do not use the PERL malloc

cccdlflags="none"

no additional flags are necessary for dynamic linking

installusrbinperl=undef

do not install /usr/bin/perl

cf_email="myname@somewhere.com"

set the email address of the builder

libpth='/usr/local/lib /usr/lib'

use this as the library path when looking for libraries.

libs='-ldb -lm -lcrypt -lgdbm
-lrpclib -ldl'

Use these libraries when linking PERL

If these flags are used, a build of perl should be successful.

$ ./Configure -dOes -Ddosuid=undef -Dprefix=/usr/local \
-Dd_bincompat3=undef -Dcc=gcc -Dcflags="-D_ALL_SOURCE" -Dd_poll=undef \
-Dldflags="--dynamic -Wl,-E" -Dusenm=define -Dld="gcc" \
-Dlddlflags="--shared" -Ddont_use_nlink=define -Dusemymalloc="undef" \
-Dcccdlflags="none" libpth='/usr/local/lib /usr/lib' \
-Dinstallusrbinperl=undef -Dcf_email="support@microsoft.com" \
libs='-ldb -lm -lcrypt -lgdbm -lrpclib -ldl' \
perllibs='-ldb -lm -lcrypt -lgdbm -lrpclib -ldl'
(I see you are using the Korn shell.  Some ksh's blow up on Configure,
mainly on older exotic systems.  If yours does, try the Bourne shell
instead.)
First let's make sure your kit is complete.  Checking...
Locating common programs...
Checking compatibility between /bin/echo and builtin echo (if any)...
Symbolic links are supported.
…
Finding dependencies for hash.o.
Finding dependencies for str.o.
Finding dependencies for util.o.
Finding dependencies for walk.o.
echo Makefile.SH cflags.SH | tr ' ' '\n' >.shlist
Updating makefile...
Now you must run 'make'.
If you compile perl5 on a different machine or from a different object
directory, copy the Policy.sh file from this object directory to the
new one before you run Configure -- this will help you with most of
the policy defaults.

OK, now let's try to build PERL

$ make
`sh  cflags libperl.a miniperlmain.o`  miniperlmain.c
          CCCMD =  gcc -DPERL_CORE -c -I/usr/local/include -O
`sh  cflags libperl.a perl.o`  perl.c
          CCCMD =  gcc -DPERL_CORE -c -I/usr/local/include -O
perl.c: In function `S_open_script':
perl.c:2573: warning: assignment makes pointer from integer without a
cast
`sh  cflags libperl.a gv.o`  gv.c
          CCCMD =  gcc -DPERL_CORE -c -I/usr/local/include -O
`sh  cflags libperl.a toke.o`  toke.c
          CCCMD =  gcc -DPERL_CORE -c -I/usr/local/include -O
…
chmod 644 re.bs
rm -f ../../lib/auto/re/re.so
LD_RUN_PATH="" gcc  --shared -L/usr/local/lib re_exec.o re_comp.o re.o  -
o ../..
/lib/auto/re/re.so
chmod 755 ../../lib/auto/re/re.so
cp re.bs ../../lib/auto/re/re.bs
chmod 644 ../../lib/auto/re/re.bs
        Making Errno (nonxs)
Writing Makefile for Errno
../../miniperl -I../../lib -I../../lib -I../../lib -I../../lib
Errno_pm.PL Errno
.pm
cp Errno.pm ../../lib/Errno.pm
        Everything is up to date. 'make test' to run test suite.
$

This looks very promising, now let's attempt a test

$ make test
        AutoSplitting perl library
./miniperl -Ilib -e 'use AutoSplit;  aut
*/*.pm
        Making DynaLoader (static)
gcc -o perl --dynamic -Wl,-E -L/usr/loca
naLoader.a  libperl.a `cat ext.libs` -ls
        Making utilities
…
        Making attrs (dynamic)
        Making re (dynamic)
        Making Errno (nonxs)
cd t && (rm -f perl; /bin/ln -s ../perl
if (true </dev/tty) >/dev/null 2>&1; the
  cd t && PERL_SKIP_TTY_TEST=1  ./perl T
base/cond............ok
…
io/openpid...........Hangup
$

Oh, oh. This could be a problem. The PERL test is exiting and the test is reporting a Hangup. By inspecting the test, we see that SIGPIPE is being ignored, perhaps we should also ignore SIGHUP.

To attempt a work-around, we add

         $SIG{HUP} = 'IGNORE';

after the

         $SIG{PIPE} = 'IGNORE';

and rerun our make test.

$ make test
        AutoSplitting perl library
…
op/goto_xs...........ok
op/grent.............FAILED at test 1
op/grep..............ok

apache

rpm

ssh

Summary of Interfaces

These are the interfaces documented with Interix 2.2. This list is a guide, not an absolute reference. Some of the APIs are provided for compatibility and may follow either the BSD or System V behavior. See the reference pages for more information.

This list does not include macro definitions. For example, getdtablesize() is available as a macro in <unistd.h>; it is not listed here. (The macro actually calls sysconf(_SC_OPEN_MAX).)

This list also does not include the X11R5 routines or the Motif 1.2.4 routines. The X11R5 libraries come with the Interix SDK.

Because the list spans several pages, the table is organized alphabetically across rows.

System Interfaces, Standard C, Math, DB, RPC, Lex, Yacc and dl Libraries

a64l

floorf

isalnum

realpath

strcoll

clntudp_bufcreate

abort

fmod

isalpha

recv

strcpy

clntudp_create

abs

fnmatch

isascii

recvfrom

strcspn

dbm_clearerr

accept

fopen

isatty

regcomp

strdup

dbm_close

access

fork

isblank

regerror

strerror

dbm_delete

acos

fpathconf

iscntrl

regexec

strftime

dbm_error

acosh

fprintf

isdigit

regfree

strlcat

dbm_fetch

alarm

fpurge

isgraph

remainder

strlcpy

dbm_firstkey

asctime

fputc

isinf

remove

strlen

dbm_nextkey

asin

fputs

isinff

rename

strmode

dbm_open

asinh

fread

islower

renamewtmpx

strncasecmp

dbm_store

assert

free

isnan

rewind

strncat

endrpcent

atan

freopen

isnanf

rewinddir

strncmp

get_myaddress

atan2

frexp

isprint

rexec

strncpy

getrpcbyname

atan2f

fscanf

ispunct

rindex

strpbrk

getrpcbynumber

atanf

fseek

isspace

rint

strptime

getrpcent

atanh

fsetpos

isupper

rmdir

strrchr

getrpcport

atexit

fstat

isxdigit

rresvport

strsep

longjmp

atof

fstatvfs

j0

ruserok

strsignal

pmap_getmaps

atoi

fsync

j1

sbrk

strsigname

pmap_getport

atol

ftell

jn

scalb

strspn

pmap_rmtcall

basename

ftime

jrand48

scalbn

strstr

pmap_set

bcmp

ftok

kill

scalbnf

strtod

pmap_unset

bcopy

ftruncate

killpg

scanf

strtok

registerrpc

bind

fts_children

l64a

seed48

strtol

setjmp

brk

fts_close

labs

seekdir

strtoul

setrpcent

bsearch

fts_open

lchown

select

strunvis

svc_getreq

bzero

fts_read

lcong48

semctl

strvis

svc_getreqset

cabs

fts_set

ldexp

semget

strvisx

svc_register

calloc

ftw

ldiv

semop

strxfrm

svc_run

catclose

fwrite

lfind

send

swab

svc_sendreply

catgets

gamma

lgamma

sendto

symlink

svc_unregister

catopen

gamma_r

lgamma_r

setbuf

sysconf

svcerr_auth

cbrt

gcvt

link

setbuffer

syslog

svcerr_decode

ceil

getbsize

listen

setegid

system

svcerr_noproc

cfgetispeed

getc

localeconv

setenv

tan

svcerr_noprog

cfgetospeed

getchar

localtime

seteuid

tanf

svcerr_progvers

cfsetispeed

getcwd

lockf

setgid

tanh

svcerr_systemerr

cfsetospeed

getdtablesize

log

setgrent

tcdrain

svcerr_weakauth

chdir

getegid

log10

sethostent

tcflow

svcfd_create

chmod

getenv

log1p

setitimer

tcflush

svcraw_create

chown

geteuid

logb

setjmp

tcgetattr

svctcp_create

chroot

getgid

login

setlinebuf

tcgetpgrp

svcudp_bufcreate

clearerr

getgrent

longjmp

setlocale

tcsendbreak

t_accept

clock

getgrgid

lrand48

setlogmask

tcsetattr

t_alloc

close

getgrnam

lsearch

setmode

tcsetpgrp

t_bind

closedir

getgroups

lseek

setnetent

tdelete

t_close

closelog

gethostbyaddr

lstat

setpgid

telldir

t_connect

confstr

gethostbyname

madvise

setpriority

tempnam

t_error

connect

gethostent

malloc

setprotoent

tfind

t_free

copysign

gethostname

mctl

setpwent

time

t_getinfo

copysignf

getitimer

memccpy

setregid

times

t_getprotaddr

cos

getlogin

memchr

setreuid

tmpfile

t_getstate

cosf

getmode

memcmp

setrlimit

tmpnam

t_listen

cosh

getnetbyaddr

memcntl

setservent

toascii

t_look

creat

getnetbyname

memcpy

setsid

truncate

t_open

ctermid

getnetent

memmove

setsockopt

tsearch

t_optmgmt

ctime

getopt

memset

setstate

ttyname

t_rcv

cuserid

getpass

mkdir

settimeofday

ttyslot

t_rcvconnect

daemon

getpeername

mkfifo

setuid

twalk

t_rcvdis

difftime

getpgrp

mknod

setutxent

tzset

t_rcvrel

dirfd

getpid

mkstemp

setvbuf

ualarm

t_rcvudata

dirname

getppid

mktemp

shmat

ulimit

t_rcvuderr

div

getpriority

mktime

shmctl

umask

t_snd

drand48

getprotobyname

mmap

shmdt

uname

t_snddis

drem

getprotobynumber

modf

shmget

ungetc

t_sndrel

dup

getprotoent

mprotect

shutdown

unlink

t_sndudata

dup2

getpwent

mrand48

sigaction

unlockpt

t_strerror

ecvt

getpwnam

msgctl

sigaddset

unsetenv

t_sync

endgrent

getpwuid

msgget

sigblock

unvis

t_unbind

endhostent

getrlimit

msgrcv

sigdelset

usleep

xdr_accepted_reply

endnetent

getrusage

msgsnd

sigemptyset

utime

xdr_array

endprotoent

gets

msync

sigfillset

verr

xdr_authunix_parms

endpwent

getservbyname

munmap

sighold

verrx

xdr_bool

endservent

getservbyport

nextafter

sigignore

vfork

xdr_bytes

endutxent

getservent

nftw

sigismember

vfprintf

xdr_callhdr

erand48

getsockname

nice

siglongjmp

vis

xdr_callmsg

erf

getsockopt

nrand48

signal

vprintf

xdr_char

erfc

gettimeofday

ntohl

significand

vscanf

xdr_double

err

getuid

ntohs

sigpause

vsnprintf

xdr_enum

errx

getutxent

open

sigpending

vsprintf

xdr_float

execl

getutxid

opendir

sigprocmask

vsscanf

xdr_free

execle

getutxline

openlog

sigrelse

vsyslog

xdr_int

execlp

glob

openpty

sigset

vwarn

xdr_long

execv

globfree

pathconf

sigsetjmp

vwarnx

xdr_opaque

execve

gmtime

pause

sigsetmask

wait

xdr_opaque_auth

execvp

grantpt

pclose

sigsuspend

waitpid

xdr_pmap

exp

hcreate

perror

sigvec

warn

xdr_pmaplist

expm1

hcreate_r

pipe

sin

warnx

xdr_pointer

fabs

hdestroy

poll

sinf

write

xdr_reference

fabsf

hdestroy_r

popen

sinh

writev

xdr_rejected_reply

fchdir

hsearch

pow

sleep

y0

xdr_replymsg

fchmod

hsearch_r

printf

snprintf

y1

xdr_short

fchown

htonl

ptsname

socket

yn

xdr_string

fclose

htons

putc

socketpair

z_abs

xdr_u_char

fcntl

hypot

putchar

sprintf

authnone_create

xdr_u_int

fcvt

ilogb

putenv

sqrt

authunix_create

xdr_u_long

fdopen

index

puts

sqrtf

authunix_create_default

xdr_u_short

feof

inet_addr

pututxline

sradixsort

bindresvport

xdr_union

ferror

inet_aton

qsort

srand

callrpc

xdr_vector

fflush

inet_lnaof

radixsort

srand48

clnt_broadcast

xdr_void

ffs

inet_makeaddr

raise

srandom

clnt_create

xdr_wrapstring

fgetc

inet_netof

rand

sscanf

clnt_pcreateerror

xdrmem_create

fgetln

inet_network

random

stat

clnt_perrno

xdrrec_create

fgetpos

inet_ntoa

rcmd

statvfs

clnt_perror

xdrrec_endofrecord

fgets

init

read

strcasecmp

clnt_spcreateerror

xdrrec_eof

fileno

initstate

readdir

strcasestr

clnt_sperrno

xdrrec_skiprecord

finite

ioctl

readlink

strcat

clnt_sperror

xdrstdio_create

finitef

ipcs

readv

strchr

clntraw_create

xprt_register

flock

iruserok

realloc

strcmp

clnttcp_create

xprt_unregister

floor

isalnum

realpath

strcoll

clntudp_bufcreate

dlopen

dlsym

dlerror

dlclose

 

 

 

Curses, Menus, Panels ,Forms and Terminfo APIs

The following APIs make up the ported ncurses libraries:

addch

init_color

mvinsch

ripoffline

ungetch

addchnstr

init_pair

mvinsnstr

savetty

ungetmouse

addchstr

initscr

mvinsstr

scanw

unpost_menu

addnstr

innstr

mvinstr

scr_dump

untouchwin

addstr

insch

mvprintw

scr_init

update_panels

attr_get

insdelln

mvscanw

scr_restore

use_env

attr_off

insertln

mvwaddch

scr_set

vidattr

attr_on

insnstr

mvwaddchnstr

scrl

vidputs

attr_set

insstr

mvwaddchstr

scroll

vline

attroff

instr

mvwaddnstr

scrollok

vw_printw

attron

intrflush

mvwaddstr

set_current_item

vw_scanw

attrset

is_linetouched

mvwchgat

set_curterm

vwprintw

baudrate

is_wintouched

mvwdelch

set_item_init

vwscanw

beep

isendwin

mvwgetch

set_item_opts

waddch

bkgd

item_count

mvwgetstr

set_item_term

waddchnstr

bkgdset

item_description

mvwin

set_item_userptr

waddchstr

border

item_index

mvwinch

set_item_value

waddnstr

bottom_panel

item_init

mvwinchnstr

set_menu_back

waddstr

box

item_name

mvwinchstr

set_menu_fore

wattr_get

can_change_color

item_opts

mvwinnstr

set_menu_format

wattr_off

cbreak

item_opts_off

mvwinsch

set_menu_grey

wattr_on

chgat

item_opts_on

mvwinsnstr

set_menu_init

wattr_set

clear

item_term

mvwinsstr

set_menu_items

wattroff

clearok

item_userptr

mvwinstr

set_menu_mark

wattron

clrtobot

item_value

mvwprintw

set_menu_opts

wattrset

clrtoeol

item_visible

mvwscanw

set_menu_pad

wbkgd

color_content

keyname

napms

set_menu_pattern

wbkgdset

copywin

keypad

new_item

set_menu_sub

wborder

current_item

killchar

new_menu

set_menu_term

wchgat

curs_set

leaveok

new_panel

set_menu_userptr

wclear

def_prog_mode

longname

newpad

set_panel_userptr

wclrtobot

def_shell_mode

menu_back

newterm

set_term

wclrtoeol

del_curterm

menu_driver

newwin

set_top_row

wcursyncup

del_panel

menu_fore

nl

setscrreg

wdelch

delay_output

menu_format

nocbreak

setupterm

wdeleteln

delch

menu_grey

nodelay

show_panel

wechochar

deleteln

menu_init

noecho

slk_clear

werase

delscreen

menu_items

nonl

slk_init

wgetch

delwin

menu_mark

noqiflush

slk_label

wgetstr

derwin

menu_opts

noraw

slk_noutrefresh

whline

doupdate

menu_opts_off

notimeout

slk_refresh

winch

dupwin

menu_opts_on

overlay

slk_restore

winchnstr

echo

menu_pad

overwrite

slk_set

winchstr

echochar

menu_pattern

pair_content

slk_touch

winnstr

endwin

menu_sub

panel_above

standend

winsch

erasechar

menu_term

panel_below

standout

winsdelln

filter

menu_userptr

panel_hidden

start_color

winsertln

flash

menu_win

panel_userptr

subpad

winsnstr

flushinp

meta

panel_window

subwin

winsstr

free_item

mousemask

pechochar

syncok

winstr

free_menu

move

pnoutrefresh

termattrs

wmove

getch

move_panel

pos_menu_cursor

termname

wnoutrefresh

getmouse

mvaddch

post_menu

tgetent

wprintw

getstr

mvaddchnstr

prefresh

tgetflag

wredrawln

getwin

mvaddchstr

printw

tgetnum

wrefresh

halfdelay

mvaddnstr

putp

tgetstr

wresize

has_colors

mvaddstr

putwin

tgoto

wscanw

has_ic

mvchgat

qiflush

tigetflag

wscrl

has_il

mvcur

raw

tigetnum

wsetscrreg

hide_panel

mvdelch

redrawwin

tigetstr

wstandend

hline

mvderwin

refresh

timeout

wstandout

idcok

mvgetch

replace_panel

top_panel

wsyncdown

idlok

mvgetstr

reset_prog_mode

top_row

wsyncup

immedok

mvinch

reset_shell_mode

tparm

wtimeout

inch

mvinchnstr

resetty

tputs

wtouchln

inchnstr

mvinchstr

restartterm

typeahead

wvline

inchstr

mvinnstr

ripoffline

unctrl

 

Interix-Specific APIs

The following APIs are unique to Interix:

_getInstallPath

_getInstallPath_Win

_prefixInstallPath

_prefixInstallPath_Win

authenticateuser

chpass

env_alloc

env_array

env_cron

env_expand_win

env_free

env_get

env_login

env_put

env_putarray

env_set

env_strfree

env_unset

env_winlogin

execl_asuser

execle_asuser

execlp_asuser

execv_asuser

execve_asuser

execvp_asuser

fullqualname

getgrent_nomembers

getgrgid_ex

getgrgid_nomembers

getgrnam_nomembers

getloginenv

getpdomain

getpwuid_ex

getreg_strvalue

getreg_wstrvalue

getsecret

gettzenv

group_from_gid

ntpath2posix

path_casesensitive

path_convert

setsecret

setuser

stripdomainprefix

uidtontsid

unixpath2win

user_from_uid

winpath2unix

The routines _getInstallPath() and _prefixInstallPath() retrieve the Interix install root ($INTERIX_ROOT) and prefix it to a string, respectively. They are discussed in the Interix SDK User's Guide.

The authenticateuser() and exec*_asuser() routines are used to login as another user. They are discussed in the Interix SDK User's Guide. These APIs are now deprecated in favor of the setuser() call; the man page for the setuser() call is included in this note, because it was not included in the 2.2 Service Pack 1 release.

The uidtontsid() routine converts a POSIX-style user ID number into the user's Windows NT security ID.

The remaining routines are convenience routines:

The _ntpath2posix() routine converts a Windows NT-style pathname such as C:\Interix to its Interix equivalent, //C/Interix.

The stripdomainprefix() routine removes the domain prefix from a user name, so that a string such as "ADMIN+jo" becomes "jo".

The gettzenv() routine retrieves the value of the Win32 system's TZ environment variable.

For more information about the routines, see the relevant reference pages using the man command or using the Adobe Acrobat documents.

setuser() Reference

NAME

setuser() — change effective and real uid and gid of process

SYNOPSIS

#include <opennt/security.h>
int setuser(char *username, char *password, int flags)

DESCRIPTION

The setuser() function changes the effective and real uid and gid of the current process to that of the specified username. All of the security attributes and permissions become those of username. However, the process' current working directory does not change.

The setuser() utility takes the following arguments:

username

The name of the user. If the username is not fully qualified with a domain name (that is, "domain+name"), it is not changed. On a system configured for workgroups, specify the domain as NULL: that is, the string "+name".

password

The plaintext password for the specified username.

flags

Control flags. These possible values for flags are defined in <opennt/security.h>:

SU_COMPLETE

Change the real and effective user and group IDs and all security attributes to the default for the specified user.

SU_CHECK

Check that the process will be able to perform a setuser() action using SU_COMPLETE for the specified username and password. This is a quick way to verify a password for a user. This action is equivalent to the older Interix call, authenticateuser().

There can be a performance degradation if a process changes identity to a user who does not have permission to be located in the current working directory. The best solution is, after a call to setuser(), to chdir() to a directory known to be permitted for the new identity.

RETURN VALUE

On success, the setuser() function returns 0. On failure, it returns -1 and sets errno.

ERRORS

The setuser() function can fail for the following reasons:

[EINVAL]

An argument is invalid or is missing.

[ENOMEM]

Not enough memory to complete the request.

[EPERM]

The requesting process does not have permission to change to the new user. One or both of the username or password were incorrectly specified.

NOTES:

This function replaces authenticateuser(). In fact, the version of authenticateuser() in this release is a wrapper around setuser().

SEE ALSO

setuid(), setgid(), exec_asuser(), authenticateuser()

For More Information

For more information about Interix, see the Interix Web site at: https://www.microsoft.com/windows2000/interix.