Access to POSIX

This chapter describes Scheme 48’s interface to the POSIX C calls [1]. Scheme versions of most of the functions in POSIX are provided. Both the interface and implementation are new and are likely to change in future releases. Section 9.10 lists which Scheme functions call which C functions.

Scheme 48’s POSIX interface will likely change significantly in the future. The implementation is new and may have significant bugs.

The POSIX bindings are available in several structures:

posix-processes fork, exec, and friends
posix-process-data information about processes
posix-files files and directories
posix-i/o operations on ports
posix-time time functions
posix-users users and groups
posix-regexps regular expression matching
posix all of the above

Scheme 48’s POSIX interface differs from Scsh’s [1112] in several ways. The interface here lacks Scsh’s high-level constructs and utilities, such as the process notation, awk procedure, and parsing utilities. Scheme 48 uses distinct types for some values that Scsh leaves as symbols or unboxed integers; these include file types, file modes, and user and group ids. Many of the names and other interface details are different, as well.

9.1  Process primitives

The procedures described in this section control the creation of processes and the execution of programs. They are in the structures posix-process and posix.

9.1.1  Process creation and termination

Fork creates a new child process and returns the child’s process-id in the parent and #f in the child. Fork-and-forget calls thunk in a new process; no process-id is returned. Fork-and-forget uses an intermediate process to avoid creating a zombie process.

Process-id? is a predicate for process-ids, process-id=? compares two to see if they are the same, and process-id-uid returns the actual Unix id. Process-id->integer and integer->process-id convert process ids to and from integers.

If a process terminates normally process-id-exit-status will return its exit status. If the process is still running or was terminated by a signal then process-id-exit-status will return #f. Similarly, if a child process was terminated by a signal process-id-terminating-signal will return that signal and will return #f if the process is still running or terminated normally. Wait-for-child-process blocks until the child process terminates. Scheme 48 may reap child processes before the user requests their exit status, but it does not always do so.

Terminates the current process with the integer status as its exit status.

9.1.2  Exec

All of these replace the current program with a new one. They differ in how the new program is found, what its environment is, and what arguments it is passed. Exec and exec-with-environment look up the new program in the search path, while exec-file and exec-file-with-environment execute a particular file. The environment is either inherited from the current process (exec and exec-file) or given as an argument (...-with-environment). Program-name and filename and any argi should be os-string-thing arguments (see section 5.15. Env should be a list of os-string-thing arguments of the form "name=value". The first four procedures add their first argument, program-name or filename, before the arg0 ... arguments.

Exec-with-alias is an omnibus procedure that subsumes the other four. Name is looked up in the search path if lookup? is true and is used as a filename otherwise. Maybe-env is either a list of os-string-things for the environment of the new program or #f in which case the new program inherits its environment from the current one. Arguments should be a list of os-string-things; unlike with the other four procedures, name is not added to this list (hence -with-alias).

9.2  Signals

There are two varieties of signals available, named and anonymous. A named signal is one for which we have a symbolic name, such as kill or pipe. Anonymous signals, for which we only have the current operating system’s signal number, have no meaning in other operating systems. Named signals preserve their meaning in image files. Not all named signals are available from all OS’s and there may be multiple names for a single OS signal number.

The syntax signal returns a (named) signal associated with signal-name. Name->signal returns a (named) signal or #f if the the signal name is not supported by the operating system. The signal returned by integer->signal is a named signal if integer corresponds to a named signal in the current operating system; otherwise it returns an anonymous signal. Signal-name returns a symbol if signal is named and #f if it is anonymous. Signal=? returns #t if signal0 and signal1 have the same operating system number and #f if they do not.

9.2.1  POSIX signals

The following lists the names of the POSIX signals.

abrt abort - abnormal termination (as by abort())
alrm alarm - timeout signal (as by alarm())
fpe floating point exception
hup hangup - hangup on controlling terminal or death of controlling process
ill illegal instruction
int interrupt - interaction attention
kill kill - termination signal, cannot be caught or ignored
pipe pipe - write on a pipe with no readers
quit quit - interaction termination
segv segmentation violation - invalid memory reference
term termination - termination signal
usr1 user1 - for use by applications
usr2 user2 - for use by applications
chld child - child process stopped or terminated
cont continue - continue if stopped
stop stop - cannot be caught or ignored
tstp interactive stop
ttin read from control terminal attempted by background process
ttou write to control terminal attempted by background process
bus bus error - access to undefined portion of memory

9.2.2  Other signals

The following lists the names of the non-POSIX signals that the system is currently aware of.

trap trace or breakpoint trap
iot IOT trap - a synonym for ABRT
emt
sys bad argument to routine (SVID)
stkflt stack fault on coprocessor
urg urgent condition on socket (4.2 BSD)
io I/O now possible (4.2 BSD)
poll A synonym for SIGIO (System V)
cld A synonym for SIGCHLD
xcpu CPU time limit exceeded (4.2 BSD)
xfsz File size limit exceeded (4.2 BSD)
vtalrm Virtual alarm clock (4.2 BSD)
prof Profile alarm clock
pwr Power failure (System V)
info A synonym for SIGPWR
lost File lock lost
winch Window resize signal (4.3 BSD, Sun)
unused Unused signal

9.2.3  Sending signals

Send signal to the process corresponding to process-id.

9.2.4  Receiving signals

Signals received by the Scheme process can be obtained via one or more signal-queues. Each signal queue has a list of monitored signals and a queue of received signals that have yet to be read from the signal-queue. When the Scheme process receives a signal that signal is added to the received-signal queues of all signal-queues which are currently monitoring that particular signal.

Make-signal-queue returns a new signal-queue that will monitor the signals in the list signals. Signal-queue? is a predicate for signal queues. Signal-queue-monitored-signals returns a list of the signals currently monitored by signal-queue. Dequeue-signal! and maybe-dequeue-signal both return the next received-but-unread signal from signal-queue. If signal-queue’s queue of signals is empty dequeue-signal! blocks until an appropriate signal is received. Maybe-dequeue-signal! does not block; it returns #f instead.

There is a bug in the current system that causes an erroneous deadlock error if threads are blocked waiting for signals and no other threads are available to run. A work around is to create a thread that sleeps for a long time, which prevents any deadlock errors (including real ones):

> ,open threads
> (spawn (lambda ()
           ; Sleep for a year
           (sleep (* 1000 60 60 24 365))))

These two procedures can be used to add or remove signals from a signal-queue’s list of monitored signals. When a signal is removed from a signal-queue’s list of monitored signals any occurances of the signal are removed from that signal-queue’s pending signals. In other words, dequeue-signal! and maybe-dequeue-signal! will only return signals that are currently on the signal-queue’s list of signals.

9.3  Process environment

These are in structures posix-process-data and posix.

9.3.1  Process identification

These return the process ids of the current process and its parent. See section 9.1.1 for operations on process ids.

Every process has both the original and effective user id and group id. The effective values may be set, but not the original ones.

Get-groups returns a list of the supplementary groups of the current process. Get-login-name returns a user name for the current process.

9.3.2  Environment variables

Lookup-environment-variable looks up its argument in the environment list and returns the corresponding value or #f if there is none. Environment-alist returns the entire environment as a list of (name-os-string . value-os-string) pairs.

9.4  Users and groups

User-ids and group-ids are boxed integers representing Unix users and groups. The procedures in this section are in structures posix-users and posix.

User-ids and group-ids have their own own predicates and comparison, boxing, and unboxing functions.

These return the user info for a user identified by user-id or name.

A user-info contains information about a user. Available are the user’s name, id, group, home directory, and shell.

These return the group info for a group identified by group-id or name.

A group-info contains information about a group. Available are the group’s name, id, and a list of members.

9.5  OS and machine identification

These procedures return strings that are supposed to identify the current OS and machine. The POSIX standard does not indicate the format of the strings. The procedures are in structures posix-platform-names and posix.

9.6  Files and directories

These procedures are in structures posix-files and posix.

9.6.1  Directory streams

Directory streams are like input ports, with each read operation returning the next name in the directory.

Open-directory-stream opens a new directory stream. Directory-stream? is a predicate that recognizes directory streams. Read-directory-stream returns the next name in the directory or #f if all names have been read. Close-directory-stream closes a directory stream.

This is the obvious utility; it returns a list of the names in directory name.

9.6.2  Working directory

These return and set the working directory.

9.6.3  File creation and removal

Open-file opens a port to the file named by path, which must be a os-string-thing argument. The file-options argument determines various aspects of the returned port. The optional file-mode argument is used only if the file to be opened does not already exist. The returned port is an input port if file-options includes read-only; otherwise it returns an output port. Dup-switching-mode can be used to open an input port for output ports opened with the read/write option.

The syntax file-options returns a file-option with the indicated options set. File-options-on? returns true if its first argument includes all of the options listed in the second argument. File-options-union returns a file-options argument containing exactly all of the options listed in either argument. The following file options may be used with open-file.

create create file if it does not already exist; a file-mode argument is required with this option
exclusive an error will be raised if this option and create are both set and the file already exists
no-controlling-tty if path is a terminal device this option causes the terminal to not become the controlling terminal of the process
truncate file is truncated
append writes are appended to existing contents
nonblocking read and write operations do not block
read-only port may not be written
read-write file descriptor may be read or written
write-only port may not be read

Only one of the last three options may be used. If read-write is specified, an output port is returned.

For example

(open-file "some-file.txt"
           (file-options create write-only)
           (file-mode read owner-write))

returns an output port that writes to a newly-created file that can be read by anyone and written only by the owner. Once the file exists,

(open-file "some-file.txt"
           (file-options append write-only))

will open an output port that appends to the file.

The append and nonblocking options and the read/write nature of the port can be read using i/o-flags. The append and nonblocking options can be set using set-i/o-flags!.

To keep port operations from blocking the Scheme 48 process, output ports are set to be nonblocking at the time of creation (input ports are managed using select()). You can use set-i/o-flags! to make an output port blocking, for example just before a fork, but care should be exercised. The Scheme 48 runtime code may get confused if an I/O operation blocks.

Sets the file creation mask to be file-mode. Bits set in file-mode are cleared in the modes of any files or directories created by the current process.

Both existing and new must be os-string-thing arguments. Link makes path new be a new link to the file pointed to by path existing. The two paths must be in the same file system.

These two procedures make new directories and fifo files. In both cases, path must be a os-string-thing argument.

Path, old-path and new-path must all be os-string-thing arguments. Unlink removes the link indicated by path. Remove-directory removes the indicated (empty) directory. Rename moves the file pointed to by old-path to the location pointed to by new-path (the two paths must be in the same file system). Any other links to the file remain unchanged.

Accessible? returns true if path (which must be a os-string-thing argument) is a file that can be accessed in the listed mode. If more than one mode is specified accessible? returns true if all of the specified modes are permitted. The mode-names are: read, write, execute, exists.

9.6.4  File information

Get-file-info and get-file/link-info both return a file info record for the file named by path, which must be a os-string-thing argument. Get-file-info follows symbolic links while get-file/link-info does not. Get-port-info returns a file info record for the file which port reads from or writes to. An error is raised if fd-port does not read from or write to a file descriptor.

File-info? is a predicate for file-info records. File-info-name is the name which was used to get file-info, either as passed to get-file-info or get-file/link-info, or used to open the port passed to get-port-info.

File-info-type returns the type of the file, as a file-type object File types may be compared using eq?. The valid file types are:

regular
directory
character-device
block-device
fifo
symbolic-link
socket
other

Symbolic-link and socket are not required by POSIX.

The device and inode numbers uniquely determine a file.

These return the number of links to a file and the file size in bytes. The size is only meaningful for regular files.

These return the owner, group, and access mode of a file.

These return the time the file was last read, modified, or had its status modified

9.6.5  File modes

A file mode is a boxed integer representing a file protection mask.

File-mode is syntax for creating file modes. The mode-names are listed below. File-mode? is a predicate for file modes. File-mode+ returns a mode that contains all of permissions of its arguments. File-mode- returns a mode that has all of the permissions of file-mode0 that are not in file-mode1.

File-mode=? returns true if the two modes are exactly the same. File-mode<=? returns true if file-mode0 has a subset of the permissions of file-mode1. File-mode>=? is file-mode<=? with the arguments reversed.

Integer->file-mode and file-mode->integer translate file modes to and from the classic Unix file mode masks. These may not be the masks used by the underlying OS.

Permission name Bit mask
set-uid #o4000 set user id when executing
set-gid #o2000 set group id when executing
owner-read #o0400 read by owner
owner-write #o0200 write by owner
owner-exec #o0100 execute (or search) by owner
group-read #o0040 read by group
group-write #o0020 write by group
group-exec #o0010 execute (or search) by group
other-read #o0004 read by others
other-write #o0002 write by others
other-exec #o0001 execute (or search) by others

Names for sets of permissions
owner #o0700 read, write, and execute by owner
group #o0070 read, write, and execute by group
other #o0007 read, write, and execute by others
read #o0444 read by anyone
write #o0222 write by anyone
exec #o0111 execute by anyone
all #o0777 anything by anyone

9.7  Time

These procedures are in structures posix-time and posix.

A time record contains an integer that represents time as the number of second since the Unix epoch (00:00:00 GMT, January 1, 1970). Make-time and current-time return times, with make-time’s using its argument while current-time’s has the current time. Time? is a predicate that recognizes times and time-seconds returns the number of seconds time represents.

These perform various comparison operations on the times.

Time->string returns a string representation of time in the following form.

"Wed Jun 30 21:49:08 1993
"

9.8  I/O

These procedures are in structures posix-i/o and posix.

Open-pipe creates a new pipe and returns the two ends as an input port and an output port.

A file descriptor port (or fd-port) is a port that reads to or writes from an OS file descriptor. Fd-ports are returned by open-input-file, open-output-file, open-file, open-pipe, and other procedures.

Fd-port? returns true if its argument is an fd-port. Port->fd returns the file descriptor associated with or #f if port is not an fd-port.

Remap-file-descriptors reassigns file descriptors to ports. The fd-specs indicate which port is to be mapped to each file descriptor: the first gets file descriptor 0, the second gets 1, and so forth. A fd-spec is either a port that reads from or writes to a file descriptor, or #f, with #f indicating that the corresponding file descriptor is not used. Any open ports not listed are marked ‘close-on-exec’. The same port may be moved to multiple new file descriptors.

For example,

(remap-file-descriptors (current-output-port)
                        #f
                        (current-input-port))

moves the current output port to file descriptor 0 and the current input port to file descriptor 2.

These change fd-port’s file descriptor and return a new port that uses ports’s old file descriptor. Dup uses the lowest unused file descriptor and dup2 uses the one provided. Dup-switching-mode is the same as dup except that the returned port is an input port if the argument was an output port and vice versa. If any existing port uses the file descriptor passed to dup2, that port is closed.

Close-all-but closes all file descriptors whose associated ports are not passed to it as arguments.

Close-on-exec? returns true if port will be closed when a new program is exec’ed. Set-close-on-exec?! sets port’s close-on-exec flag.

These two procedures read and write various options for port. The options that can be read are append, nonblocking, read-only, write-only, and read/write. Only the append and nonblocking can be written.

Port-is-a-terminal? returns true if port has an underlying file descriptor that is associated with a terminal. For such ports port-terminal-name returns the name of the terminal, for all others it returns #f.

9.9  Regular expressions

The procedures in this section provide access to POSIX regular expression matching. The regular expression syntax and semantics are far too complex to be described here. Due to limitations in the underlying facility, only Latin-1 strings are guaranteed to work here—on some platforms, only ASCII may function correctly. Moreover, because the C interface uses zero bytes for marking the ends of strings, patterns and strings that contain zero bytes will not work correctly.

These procedures are in structures posix-regexps and posix.

An abstract data type for creating POSIX regular expressions is described in section 5.20.

Make-regexp makes a new regular expression, using string as the pattern. The possible option names are:

extended use the extended patterns
ignore-case ignore case when matching
submatches report submatches
newline treat newlines specially

The regular expression is not compiled until it matched against a string, so any errors in the pattern string will not be reported until that point.

This is a predicate for regular expressions.

Regexp-match matches the regular expression against the characters in string, starting at position start. If the string does not match the regular expression, regexp-match returns #f. If the string does match, then a list of match records is returned if submatches? is true, or #t is returned if it is not. Each match record contains the index of the character at the beginning of the match and one more than the index of the character at the end. The first match record gives the location of the substring that matched regexp. If the pattern in regexp contained submatches, then the results of these are returned in order, with a match records reporting submatches that succeeded and #f in place of those that did not.

Starts-line? should be true if string starts at the beginning of a line and ends-line? should be true if it ends one.

9.10  C to Scheme correspondence

The following table lists the Scheme procedures that correspond to particular C procedures. Not all of the Scheme procedures listed are part of the POSIX interface.

C procedure Scheme procedure(s)
C procedure Scheme procedure(s)
accessaccessible?
chdirset-working-directory!
closeclose-input-port, close-output-port,
close-channel, close-socket
closedirclose-directory-stream
creatopen-file
ctimetime->string
dupdup, dup-switching-mode
dup2dup2
exec[l|v][e|p|ε] exec, exec-with-environment,
exec-file, exec-file-with-environment,
exec-with-alias
_exitexit
fcntlio-flags, set-io-flags!,
close-on-exec, set-close-on-exec!
forkfork, fork-and-forget
fstatget-port-info
getcwdworking-directory
getegidget-effective-group-id
getenvlookup-environment-variable,
environment-alist
geteuidget-effective-user-id
getgidget-group-id
getgroupsget-groups
getloginget-login-name
getpidget-process-id
getppidget-parent-process-id
getuidget-user-id
isattyport-is-a-terminal?
linklink
lstatget-file/link-info
mkdirmake-directory
mkfifomake-fifo
openopen-file
opendiropen-directory-stream
pipeopen-pipe
readread-char, read-block
readdirread-directory-stream
renamerename
rmdirremove-directory
setgidset-group-id!
setuidset-user-id!
statget-file-info
timecurrent-time
ttynameport-terminal-name
umaskset-file-creation-mask!
unameos-name, os-node-name,
os-release-name, os-version-name,
machine-name
unlinkunlink
waitpidwait-for-child-process
writewrite-char, write-block