2004, 2005 by Marc J. Rochkind. All rights reserved. Portions marked "Open Source" may be copied under license.

 

Jtux Java-To-UNIX Package

Page Updated 5-Nov-2005

Contents

Goals and Non-Goals

What's in Jtux

Licensing and Availability (Including Download)

Building and Installing Jtux

Other Similar Work

Design Decisions

Examples

JavaDocs

Goals and Non-Goals

Jtux is a Java interface to most of the POSIX/SUS system calls. The goals of Jtux are to provide:

bulletAn educational tool for learning UNIX programming with Java or Jython, instead of C or C++, which are the usual languages. By "leaning UNIX programming," we mean "learning the standard POSIX/SUS UNIX API."
bulletAccess to UNIX features that are currently unsupported by Java packages.
bulletConsistent error handling. An error from a system call, no matter how it's indicated (-1 return, NULL return, error-code return, etc.) always results in throwing a UErrorException.

Jtux does not:

bulletProvide an object-oriented view of the UNIX API.
bulletFix any of the inconsistencies in UNIX system-call naming or arguments, or clean up most of the redundancies. (It does, however, fix the error-handling inconsistencies.) In fact, nearly every Jtux method has the same name and the same arguments as the corresponding POSIX/SUS call.
bulletProvide portability other than that already provided by POSIX/SUS. Jtux does not work in Java/Jython environments that aren't hosted on a POSIX/SUS system, such as Windows, and there is no interest in making it work on those environments.
bulletWork in applets, because the Java Native Interface (JNI) does not.

If you want an object-oriented approach to UNIX facilities that's more in the spirit of Java, you're better off using other Java packages. For example, java.net.Socket, instead of jtux.UNetwork. However, Jtux is the most complete UNIX package for Java or Jython, by a very wide margin.

What's in Jtux

As of 23-April-2004, Jtux includes the following 186 calls:

abort getppid poll setpgid
accept getrlimit pread setrlimit
access getrusage pselect setsid
alarm getsid pthread_sigmask setsockopt
bind getsockopt putenv setuid
chdir getuid pwrite shm_open
chmod htonl read shm_unlink
chown htons readdir shmat
chroot inet_ntop readlink shmctl
clock inet_pton readv shmdt
close kill recv shmget
closedir lchown recvfrom sigaction
connect link recvmsg sigaddset
creat listen rename sigaltstack
dup lockf rewinddir sigdelset
dup2 lseek rmdir sigemptyset
execvp lstat S_ISBLK sigfillset
_exit mkdir S_ISCHR siginterrupt
exit mkfifo S_ISDIR sigismember
fchdir mknod S_ISFIFO sigpending
fchmod mkstemp S_ISLNK sigprocmask
fchown mmap S_ISREG sigqueue
fcntl mq_close S_ISSOCK sigsuspend
FD_CLR mq_getattr seekdir sigtimedwait
FD_ISSET mq_notify select sigwait
FD_SET mq_open sem_close sigwaitinfo
FD_ZERO mq_open sem_destroy sleep
fdatasync mq_receive sem_getvalue sockatmark
fork mq_send sem_init socket
freeaddrinfo mq_setattr sem_open stat
fstat mq_timedreceive sem_open statvfs
fstatvfs mq_timedsend sem_post symlink
fsync mq_unlink sem_timedwait sync
ftok msgctl sem_trywait system
ftruncate msgget sem_unlink telldir
gai_strerror msgrcv sem_wait times
getaddrinfo msgsnd semctl truncate
getcwd munmap semget umask
getegid nanosleep semop unlink
getenv nice send unsetenv
geteuid ntohl sendmsg usleep
getgid ntohs sendto utime
gethostid open setegid wait
gethostname open setenv waitpid
getnameinfo opendir seteuid write
getpgid pause setgid writev
getpid pipe

Briefly what we have is all POSIX/SUS calls dealing with files, file systems, directories, sockets, pipes, processes, System V messages/semaphores/shared memory, POSIX messages/semaphores/shared memory, signals, environment, and more. I've tried very hard to be complete; for example, there's not only write, but also pwrite and writev; there's not only send, but also, sendmsg and sendto. Every argument of every function and every field of every structure is supported, except where technically impossible, as noted below under "Design Decisions."

See the JavaDoc documentation for more details.

Licensing and Availability

Jtux is distributed as Open Source under the BSD license. Click here to download experimental source code.

Building and Installing Jtux

As of 23-April-2003, Jtux has been tested only with Java 1.4.2 on SunOS x86 5.8 (Solaris 8) and on RedHat Linux 9, although it's intended to run on any reasonably up-to-date UNIX, Linux, FreeBSD, or Darwin system. Meanwhile, if you discover any porting problems, please send mail to Marc.

On 5-Nov-2005, Jtux was for the first time compiled and tested on OS X 10.4 (Tiger) and with a newer version of gcc (4.0.0), which helped find a few errors in the Jtux C source. I've also included specific instructions for OS X, which appear below.

I will prepare a new Jtux archive when I get a chance; meanwhile, you can read the errata here.

All of the Java and C (JNI) code is included, but without any makefiles or other build instructions. Here's what you have to do (on Solaris, Linux, and OS X; other systems are different), assuming that the Jtux source tree is in a subdirectory of the current directory named "jtux":

bulletCompile the C files with a sequence like this, for gcc on Solaris:

INCLUDEPATH=/home/marc/jdk14/j2sdk1.4.2/include
COPTS="-Wimplicit -Wstrict-prototypes -Wall -Wno-unknown-pragmas \
-D_REENTRANT -D_THREAD_SAFE -std=c99"

gcc $COPTS -fPIC -c -DSOLARIS -I. -Ijtux/include -I$INCLUDEPATH \
-I$INCLUDEPATH/solaris jtux/jtux*.c

For Linux, change the words "SOLARIS" and "solaris" to "LINUX" and "linux". If you don't use gcc, you'll have to figure out the options for your compiler.

On my Mac, my commands looked like this:

# Note that OS X 10.4 (Tiger) seems to have a __DARWIN_UNIX03 symbol for SUS3 compatibility.

JTUXSRC=/Users/marc/aup/src/jtux/jtux
INCLUDEPATH=/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Headers
COPTS="-Wimplicit -Wstrict-prototypes -Wall -Wno-unknown-pragmas \
-D_REENTRANT -D_THREAD_SAFE -std=c99"

gcc $COPTS -fPIC -c -DDARWIN -D__DARWIN_UNIX03 -I. -I$JTUXSRC/include -I$INCLUDEPATH \
-I$INCLUDEPATH/solaris $JTUXSRC/jtux*.c

bullet Create a shared library like this:

gcc -o libjtux.so -shared -lrt -lsocket -lnsl *.o

On Linux, leave off the -lsocket argument.

On OS X, it's like this:

gcc -o libjtux.jnilib -dynamiclib -framework JavaVM *.o

bullet Compile the Java files:

cat >jtux.java.list <<'[End of listing]'
jtux/UErrorException.java
jtux/UFile.java
jtux/UClock.java
jtux/UDir.java
jtux/UConstant.java
jtux/UProcess.java
jtux/UUtil.java
jtux/UExitStatus.java
jtux/USysVIPC.java
jtux/UPosixIPC.java
jtux/UNetwork.java
jtuxTest.java
[End of listing]
javac @jtux.java.list

jtuxTest.java contains the main program; the one supplied runs lots of tests. (If you want a copy of the jtuxTest.java, email me.)

bulletRun a Java program (the -Xint flag is important):

JAVA=java
JAVAOPTS='-Xcheck:jni -ea -Xint'
$JAVA $JAVAOPTS '-Djava.library.path=.:/usr/lib' jtuxTest

In case you're wondering why there's no reference to the libjtux.jnilib library, it's loaded dynamically by the file UProcess.java. (This is actually true even if you weren't wondering.)

bulletOr, run a Jython program like this:

jython pgm.jy

However, note that my jython command has been doctored to include the -Xint option on the java command.

Other Similar Work

Jtux is the most ambitious, but by no means the first, attempt to interface Java to POSIX/SUS. Some other packages are listed here. If I've said anything wrong about any of them and you know better, please email me.

java-posix

http://www.honeylocust.com/posix/

This is non-functioning early work on a project that doesn't seem to have been worked on since 1997.

Easy Posix Toolkit for Java

http://www.amug.org/~glguerin/sw/easyposix/overview.html

Interfaces to about 40 POSIX calls; implemented for Mac OS X only.

Posix for Java

http://www.bmsi.com/java/posix/package.html

Seems to be an attempt to build an object-oriented class hierarchy for POSIX. Difficult to say exactly how much of POSIX/SUS it covers, because it doesn't follow the POSIX/SUS API directly.

jnios

http://sourceforge.net/projects/jnios

An interface specifically for Jython, intended to implement the Python modules os and posix.

Posix in Java Package

http://jan.netcomp.monash.edu.au/java/posix/

Seems to implement about 20 POSIX/SUS calls.

Design Decisions

This section discusses some of the design decisions that were made for Jtux.

What to Include

SUS Version 3 includes 1123 system interfaces. The criteria used to winnow them down for Jtux were:

bulletStandard C functions were eliminated.
bulletThreading was eliminated, since Java and Jython already have threading, and POSIX Threads invoked directly would probably not work reliably.
bulletObsolete and defective functions were eliminated, such as signal (use sigaction), gethostbyname (use getaddrinfo), and tmpnam (use mkstemp).
bulletWhere both reentrant and non-reentrant APIs exist, generally the non-reentrant API was used (e.g., readdir) with the reentrant semantics (since an object is returned, not a pointer to static storage, as in C).
bulletAccounting, logging, tracing, scheduling, and spawning functions were eliminated.
bulletSTREAMs functions were eliminated.

Also, some work (20 - 30 functions) was postponed until later:

bulletTerminal I/O, including pseudo terminals.
bulletInterval timers (other than alarm).
bulletReal-time clocks.

When a function was included, an attempt, usually successful, was made to implement 100% of its functionality.

Primitive Types

Java has only eight primitive types, whereas C has an unlimited number via the typedef facility. For a type like, say, pid_t in C, one can go two ways:

bulletUse a Java primitive type, such as int.
bulletDefine a Java class named pid_t.

Jtux uses the former approach so that calling methods and dealing with fields in structures can be as much like C as possible. During start up, Jtux checks that each of the primitive types it uses as a typedef-type replacement is wide enough for the job.

Pointers

In most cases where the C API uses a pointer, the Java interface uses a reference, but there are a few places where literally a pointer must be used, such as shmat (which attaches a shared-memory segment). There's not a whole lot one can do with such a pointer in a Java program, but that's not Jtux's problem. So, it simply stores the C pointer in a long.

Jtux supplies two non-standard functions, jaddr_to_seg and jaddr_from_seg to copy data between pointers represented as longs and Java byte arrays.

Structures

Any C structure named "struct X" becomes a Java class s_X. Each field has the same name as in the C structure. The type of a field is either one of the Java primitive types (see "Primitive Types," above) or the name of a Jtux class. In a few cases POSIX/SUS uses a typedef (e.g., siginfo_t), so the word "struct" doesn't appear, and for these the Jtux class is just the same as the typedef name, without the "s_" in front..

Sometimes in C a field is a pointer to a structure and sometimes it's the structure itself. In Java, of course, it is always a reference to an object. Thus, in the structure addrinfo, the field ai_next, which is of type "struct addrinfo *" in C, becomes type s_addrinfo in Java.

Unions

Instead of unions, which Java doesn't have, Jtux uses a base class with subclasses for each member of the union. These are used differently from the way a union would be used in C, but as unions aren't widely used, the differences shouldn't significantly reduce the educational value of Jtux.

Constants

It isn't possible to initialize Java versions of constants like, say, ENOSYS or O_CREAT with literal numbers because POSIX/SUS doesn't specify actual numbers. Instead, the class UConstant contains 300+ variables that are initialized at start up by calling a Jtux native function that returns the correct value.

Error Handling

POSIX/SUS is all over the map in how it indicates an error (return value of -1, NULL, positive error value, special value, etc.) and how it indicates what the error was (errno, return value, special function call). All of the differences are smoothed out by Jtux and it universally throws a single exception, UErrorException, when an error occurs.

All POSIX/SUS errors are considered to be Jtux exceptions, even if it's only access saying the permission doesn't exist or pause returning because it was interrupted.

While this is a little cumbersome to program with, it does lead to a simple rule: If it's a POSIX/SUS error, it's always a Jtux exception.

Naming

In all cases the name of the Jtux method is identical to the POSIX/SUS function. There are a few Jtux methods that are unique to Jtux (such as jaddr_to_seg, as mentioned above).

Arguments

In all cases (unless a mistake's been made), the Jtux arguments are identical to the POSIX/SUS arguments, except that the type may be different, as discussed above. This means that all Jtux methods are static. While it would make a lot of sense, say, to define a class for an open file so that the file descriptor wouldn't have to be passed as an argument to each method, this would make the Jtux API different from that of POSIX/SUS, which goes against the goals of the project.

Some arguments have no use in Jtux, such as the length of a socket address. These arguments were left in anyway.

When a value of a primitive type has to be returned through an argument, the class IntHolder (defined in Jtux) is used.

Signals

Signals are the only area where Jtux couldn't implement the POSIX/SUS semantics exactly, because a signal mask can affect only the thread, not the whole process, and the Jtux program may be running on a JVM that's doing multi-threading internally. In other words, you can mask out, say, SIGTERM, but if that signal arrives and another thread has it unmasked, it will be delivered to that thread, and the attempt to mask it will be ineffective. There's no way around this, so you should consider Jtux's implementation of signals to be defective and you should not use Jtux to learn about UNIX signals.

The other area where Jtux falls down is in returning a siginfo_t object to a real-time signal handler. It isn't legal for the Jtux implementation to build the Java object in the signal handler (the functions are not async signal safe), so it doesn't. Unfortunately, you'll find that your real-time signal handlers will always get a null reference to the siginfo_t object.

Aside from the above, signals do work, and sigaction is fully implemented.

Examples

Socket Communication with Datagrams (Jython)

Recursively Descending the Directory Tree (Java)

2003, 2005 by Marc J. Rochkind. All rights reserved.