#
Chapter 9
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.12 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-syslog` | POSIX logging facility
`posix-errnos` | POSIX error codes
`posix` | all of the above

Scheme 48’s POSIX interface differs from Scsh’s [11, 12] 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) --> process-id or `#f``

- `(fork-and-forget thunk)`

`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? x) --> boolean`

- `(process-id=? process-id0 process-id1) --> boolean`

- `(process-id->integer process-id) --> integer`

- `(integer->process-id integer) --> process-id`

`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.

- `(process-id-exit-status process-id) --> integer or `#f``

- `(process-id-terminating-signal process-id) --> signal or `#f``

- `(wait-for-child-process process-id)`

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.

- `(exit status)`

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

### 9.1.2 `Exec`

- `(exec program-name arg0 `...`)`

- `(exec-with-environment program-name env arg0 `...`)`

- `(exec-file filename arg0 `...`)`

- `(exec-file-with-environment filename env arg0 `...`)`

- `(exec-with-alias name lookup? maybe-env arguments)`

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.

- `(signal signal-name) --> signal` (syntax)

- `(name->signal symbol) --> signal or `#f``

- `(integer->signal integer) --> signal`

- `(signal? x) --> boolean`

- `(signal-name signal) --> symbol or `#f``

- `(signal-os-number signal) --> integer`

- `(signal=? signal0 signal1) --> boolean`

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

- `(signal-process process-id signal)`

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 signals) --> signal-queue`

- `(signal-queue? x) --> boolean`

- `(signal-queue-monitored-signals signal-queue) --> list of signals`

- `(dequeue-signal! signal-queue) --> signal`

- `(maybe-dequeue-signal! signal-queue) --> signal or `#f``

`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))))

- `(add-signal-queue-signal! signal-queue signal)`

- `(remove-signal-queue-signal! signal-queue signal)`

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

- `(get-process-id) --> process-id`

- `(get-parent-process-id) --> process-id`

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

- `(get-user-id) --> user-id`

- `(get-effective-user-id) --> user-id`

- `(set-user-id! user-id)`

- `(set-effective-user-id! user-id)`

- `(get-group-id) --> group-id`

- `(get-effective-group-id) --> group-id`

- `(set-group-id! group-id)`

- `(set-effective-group-id! group-id)`

Every process has both the original and effective user id and group id. The effective values may be set, but the original ones can only be set if the process has appropriate privelages.

- `(get-groups) --> group-ids`

- `(get-login-name) --> os-string`

`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 os-string-thing) --> os-string or `#f``

- `(set-environment-variable! name value)`

- `(environment-alist) --> alist`

`Lookup-environment-variable` looks up its argument in the environment list and returns the corresponding value or `#f` if there is none. `Set-environment-variable!` sets the value of `name` in the environment list to `value`. If `name` is not already an environment variable, it’s created. If it already exists, its value is overwritten with `value`. Both arguments must be os-string-things. `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-id? x) --> boolean`

- `(user-id=? user-id0 user-id1) --> boolean`

- `(user-id->integer user-id) --> integer`

- `(integer->user-id integer) --> user-id`

- `(group-id? x) --> boolean`

- `(group-id=? group-id0 group-id1) --> boolean`

- `(group-id->integer group-id) --> integer`

- `(integer->group-id integer) --> group-id`

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

- `(user-id->user-info user-id) --> user-info`

- `(name->user-info os-string) --> user-info`

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

- `(user-info? x) --> boolean`

- `(user-info-name user-info) --> os-string`

- `(user-info-id user-info) --> user-id`

- `(user-info-group user-info) --> group-id`

- `(user-info-home-directory user-info) --> os-string`

- `(user-info-shell user-info) --> os-string`

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

- `(group-id->group-info group-id) --> group-info`

- `(name->group-info os-string) --> group-info`

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

- `(group-info? x) --> boolean`

- `(group-info-name group-info) --> os-string`

- `(group-info-id group-info) --> group-id`

- `(group-info-members group-info) --> user-ids`

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`.

- `(os-name) --> string`

- `(os-node-name) --> string`

- `(os-release-name) --> string`

- `(os-version-name) --> string`

- `(machine-name) --> string`

## 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 name) --> directory`

- `(directory-stream? x) --> boolean`

- `(read-directory-stream directory) --> name or `#f``

- `(close-directory-stream 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.

- `(list-directory name) --> list of os-strings`

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

### 9.6.2 Working directory

- `(working-directory) --> os-string`

- `(set-working-directory! os-string-thing)`

These return and set the working directory.

### 9.6.3 File creation and removal

- `(open-file path file-options) --> port`

- `(open-file path file-options file-mode) --> port`

`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.

- `(file-options file-option-name `...`) --> file-options` (syntax)

- `(file-options-on? file-options file-options) --> boolean`

- `(file-options-union file-options file-options) --> file-options`

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.

- `(set-file-creation-mask! file-mode)`

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.

- `(link existing new)`

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.

- `(make-directory path file-mode)`

- `(make-fifo path file-mode)`

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

- `(unlink path)`

- `(remove-directory path)`

- `(rename old-path new-path)`

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? path access-mode . more-modes) --> boolean`

- `(access-mode mode-name) --> access-mode` (syntax)

`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 path) --> file-info`

- `(get-file/link-info name) --> file-info`

- `(get-port-info fd-port) --> file-info`

`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? x) --> boolean`

- `(file-info-name file-info) --> os-string`

`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 file-info) --> file-type`

- `(file-type? x) --> boolean`

- `(file-type-name file-type) --> symbol`

- `(file-type type) --> file-type` (syntax)

`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.

- `(file-info-device file-info) --> integer`

- `(file-info-inode file-info) --> integer`

The device and inode numbers uniquely determine a file.

- `(file-info-link-count file-info) --> integer`

- `(file-info-size file-info) --> integer`

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

- `(file-info-owner file-info) --> user-id`

- `(file-info-group file-info) --> group-id`

- `(file-info-mode file-info) --> file-mode`

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

- `(file-info-last-access file-info) --> time`

- `(file-info-last-modification file-info) --> time`

- `(file-info-last-status-change file-info) --> time`

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 permission-name `...`) --> file-mode` (syntax)

- `(file-mode? x) --> boolean`

- `(file-mode+ file-mode `...`) --> file-mode`

- `(file-mode- file-mode0 file-mode1) --> file-mode`

`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=? file-mode0 file-mode1) --> boolean`

- `(file-mode<=? file-mode0 file-mode1) --> boolean`

- `(file-mode>=? file-mode0 file-mode1) --> boolean`

`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.

- `(file-mode->integer file-mode) --> integer`

- `(integer->file-mode integer) --> file-mode`

`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.6.6 Symbolic links

- `(create-symbolic-link path1 path2)`

This creates a symbolic link at path2 that contains path1. Path1 and path2 must be os-string-thing arguments.

- `(read-symbolic-link path) --> os-string`

This returns contents of the symbolic link at path. Path must be an os-string-thing argument.

## 9.7 Time and Date

These procedures are in structures `posix-time` and `posix`.

### 9.7.1 Time

- `(make-time integer) --> time`

- `(current-time) --> time`

- `(time? x) --> boolean`

- `(time-seconds time) --> integer`

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 `time`s, with `make-time`’s using its argument while `current-time`’s has the current time. `Time?` is a predicate that recognizes `time`s and `time-seconds` returns the number of seconds time represents.

- `(time=? time time) --> boolean`

- `(time<? time time) --> boolean`

- `(time<=? time time) --> boolean`

- `(time>? time time) --> boolean`

- `(time>=? time time) --> boolean`

These perform various comparison operations on the `time`s.

- `(time->string time) --> string`

`Time->string` returns a string representation of time in the locale’s version of the following form.

    "Wed Jun 30 21:49:08 1993
    "

### 9.7.2 Date

A date is a time specification relative to a specific but implicit time zone, broken out into the familar year-month-day-hour-minute-second format.

- `(make-date second minute hour month-day month year week-day year-day dst) --> date`

- `(date? x) --> boolean`

- `(date-second date) --> second`

- `(date-minute date) --> minute`

- `(date-hour date) --> hour`

- `(date-month-day date) --> month-day`

- `(date-month date) --> month`

- `(date-year date) --> year`

- `(date-week-day date) --> week-day`

- `(date-year-day date) --> year-day`

- `(date-date-dst date) --> dst`

These are the constructor, predicate and corresponding accessors for date objects. The meaning of the various field types are as follows:

seconds | seconds | (0--60)
minutes | minutes | (0--59)
hour | hours | (0--23)
month-day | day of month | (1--31)
mon | month of year | (0--11)
year | year | since 1900
week-day | day of week | (Sunday = 0)
year-day | day of year | (0--365)
dst | is summer time in effect? | `#t`, `#f` or unspecific

- `(date->string date) --> string`

returns a string representation of date in the locale’s version of the following form:

    "Wed Jun 30 21:49:08 1993
    "

- `(time->utc-date time) --> date`

- `(time->local-date time) --> date`

These convert a time object into a date object; the first does this relative to the UTC time zone, the second relative to the current timezone setting.

- `(date->time date) --> time`

This converts a date object into a time object relative to the current timezone setting.

- `(format-date string date) --> string`

This formats a date into a string, according to the format specification in the first argument. The format specification is according to the specification of the C `strftime` function:

lp0.9 `%a` & is replaced by the locale’s abbreviated weekday name.
`%A` & is replaced by the locale’s full weekday name.
`%b` & is replaced by the locale’s abbreviated month name.
`%B` & is replaced by the locale’s full month name.
`%c` & is replaced by the locale’s appropriate date and time representation.
`%C` & is replaced by the year divided by 100 and truncated to an integer, as a decimal number (00--99).
`%d` & is replaced by the day of the month as a decimal number (01--31).
`%D` & is equivalent to ‘‘`%m/%d/%y`’’.
`%e` & is replaced by the day of the month as a decimal number (1--31); a single digit is preceded by a space.
`%F` & is equivalent to ‘‘`%Y‑%m‑%d`’’ (the ISO 8601 date format).
`%g` & is replaced by the last 2 digits of the week-based year (see below) as a decimal number (00--99).
`%G` & is replaced by the week-based year (see below) as a decimal number (e.g., 1997).
`%h` & is equivalent to ‘‘`%b`’’.
`%H` & is replaced by the hour (24-hour clock) as a decimal number (00--23).
`%I` & is replaced by the hour (12-hour clock) as a decimal number (01--12).
`%j` & is replaced by the day of the year as a decimal number (001--366).
`%m` & is replaced by the month as a decimal number (01--12).
`%M` & is replaced by the minute as a decimal number (00--59).
`%n` & is replaced by a new-line character.
`%p` & is replaced by the locale’s equivalent of the AM/PM designations associated with a 12-hour clock.
`%r` & is replaced by the locale’s 12-hour clock time.
`%R` & is equivalent to ‘‘`%H:%M`’’.
`%S` & is replaced by the second as a decimal number (00--60).
`%t` & is replaced by a horizontal-tab character.
`%T` & is equivalent to ‘‘`%H:%M:%S`’’ (the ISO 8601 time format).
`%u` & is replaced by the ISO 8601 weekday as a decimal number (1--7), where Monday is 1.
`%U` & is replaced by the week number of the year (the first Sunday as the first day of week 1) as a decimal number (00--53).
`%V` & is replaced by the ISO 8601 week number (see below) as a decimal number (01--53).
`%w` & is replaced by the weekday as a decimal number (0--6), where Sunday is 0.
`%W` & is replaced by the week number of the year (the first Monday as the first day of week 1) as a decimal number (00--53).
`%x` & is replaced by the locale’s appropriate date representation.
`%X` & is replaced by the locale’s appropriate time representation.
`%y` & is replaced by the last 2 digits of the year as a decimal number (00--99).
`%Y` & is replaced by the year as a decimal number (e.g., 1997).
`%z` & is replaced by the offset from UTC in the ISO 8601 format ‘‘`‑0430`’’ (meaning 4 hours 30 minutes behind UTC, west of Greenwich), or by no characters if no time zone is determinable.
`%Z` & is replaced by the locale’s time zone name or abbreviation, or by no characters if no time zone is determinable.
`%%` & is replaced by `%`.

## 9.8 I/O

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

- `(open-pipe) --> input-port + output-port`

`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? port) --> boolean`

- `(port->fd port) --> integer or `#f``

`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 fd-spec `...`)`

`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`.

- `(dup fd-port) --> fd-port`

- `(dup-switching-mode fd-port) --> fd-port`

- `(dup2 fd-port file-descriptor) --> fd-port`

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 port `...`)`

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

- `(close-on-exec? port) --> boolean`

- `(set-close-on-exec?! port boolean)`

`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.

- `(i/o-flags port) --> file-options`

- `(set-i/o-flags! port file-options)`

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? port) --> boolean`

- `(port-terminal-name port) --> string`

`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.21.

- `(make-regexp string . regexp-options) --> regexp`

- `(regexp-option option-name) --> regexp-option` (syntax)

`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.

- `(regexp? x) --> boolean`

This is a predicate for regular expressions.

- `(regexp-match regexp string start submatches? starts-line? ends-line?)`

  `--> boolean or list of matches`

- `(match? x) --> boolean`

- `(match-start match) --> integer`

- `(match-end match) --> integer`

`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 Syslog facility

The procedures in this section provide access to the POSIX syslog facility. The functionality is in a structure called `posix-syslog`. The Scheme 48 interface to the syslog facility differs significantly from that of the Unix library functionality in order to support multiple simultaneous connections to the syslog facility.

Log messages carry a variety of parameters beside the text of the message itself, namely a set of options controlling the output format and destination, the facility identifying the class of programs the message is coming from, an identifier specifying the concrete program, and the level identifying the importance of the message. Moreover, a log mask can prevent messages at certain levels to be actually sent to the syslog daemon.

### Log options

A log option specifies details of the I/O behavior of the syslog facility. A syslog option is an element of a finite type (see Section 5.10) constructed by the `syslog-option` macro. The syslog facility works with sets of options which are represented as enum sets (see Section 5.11).

- `(syslog-option option-name) --> option` (syntax)

- `(syslog-option? x) --> boolean`

- `(make-syslog-options list) --> options`

- `(syslog-options option-name `...`) --> options` (syntax)

- `(syslog-options? x) --> boolean`

`Syslog-option` constructs a log option from the name of an option. (The possible names are listed below.) `Syslog-option?` is a predicate for log options. Options are comparable using `eq?`. `Make-syslog-options` constructs a set of options from a list of options. `Syslog-options` is a macro which expands into an expression returning a set of options from names. `Syslog-options?` is a predicate for sets of options.

Here is a list of possible names of syslog options:

`console`
  If syslog cannot pass the message to syslogd it will attempt to write the message to the console.

`delay`
  Delay opening the connection to syslogd immediately until the first message is logged.

`no-delay`
  Open the connection to syslogd immediately. Normally the open is delayed until the first message is logged. Useful for programs that need to manage the order in which file descriptors are allocated.

  NOTA BENE: The `delay` and `no-delay` options are included for completeness, but do not have the expected effect in the present Scheme interface: Because the Scheme interface has to multiplex multiple simultaneous connections to the syslog facility over a single one, open and close operations on that facility happen at unpredictable times.

`log-pid`
  Log the process id with each message: useful for identifying instantiations of daemons.

`no-wait`
  Do not wait for child processes.

### Log facilities

A log facility identifies the originator of a log message from a finite set known to the system. Each originator is identified by a name:

- `(syslog-facility facility-name) --> facility` (syntax)

- `(syslog-facility? x) --> boolean`

`Syslog-facility` is macro that expands into an expression returning a facility for a given name. `Syslog-facility?` is a predicate for facilities. Facilities are comparable via `eq?`.

Here is a list of possible names of syslog facilities:

`authorization`
  The authorization system: login, su, getty, etc.

`cron`
  The cron daemon.

`daemon`
  System daemons, such as routed, that are not provided for explicitly by other facilities.

`kernel`
  Messages generated by the kernel.

`lpr`
  The line printer spooling system: lpr, lpc, lpd, etc.

`mail`
  The mail system.

`news`
  The network news system.

`user`
  Messages generated by random user processes.

`uucp`
  The uucp system.

`local0` `local1` `local2` `local3` `local4` `local5` `local6` `local7`
  Reserved for local use.

### Log levels

A log level identifies the importance of a message from a fixed set of possible levels.

- `(syslog-level level-name) --> level` (syntax)

- `(syslog-level? x) --> boolean`

`Syslog-level` is macro that expands into an expression returning a facility for a given name. `Syslog-level?` is a predicate for facilities. Levels are comparable via `eq?`.

Here is a list of possible names of syslog levels:

`emergency`
  A panic condition. This is normally broadcast to all users.

`alert`
  A condition that should be corrected immediately, such as a corrupted system database.

`critical`
  Critical conditions, e.g., hard device errors.

`error`
  Errors.

`warning`
  Warning messages.

`notice`
  Conditions that are not error conditions, but should possibly be handled specially.

`info`
  Informational messages.

`debug`
  Messages that contain information normally of use only when debugging a program.

### Log masks

A log masks can mask out log messages at a set of levels. A log mask is an enum set of log levels.

- `(make-syslog-mask list) --> mask`

- `(syslog-mask level-name `...`) --> mask` (syntax)

- `syslog-mask-all` ( mask)

- `(syslog-mask-upto level) --> mask`

- `(syslog-mask? x) --> boolean`

`Make-syslog-mask` constructs a mask from a list of levels. `Syslog-mask` is a macro which constructs a mask from names of levels. `Syslog-mask-all` is a predefined log mask containing all levels. `Syslog-mask-upto` returns a mask consisting of all levels up to and including a certain level, starting with `emergency`.

### Logging

Scheme 48 dynamically maintains implicit connections to the syslog facility specifying a current identifier, current options, a current facility and a current log mask. Every thread maintains it own implicit connection to syslog. Note that the connection is not implicitly preserved across a `spawn`.

- `(with-syslog-destination string options facility mask thunk) --> value`

`With-syslog-destination` dynamically binds parameters of the implicit connection to the syslog facility and runs thunk within those parameter bindings, returning what thunk returns. Each of the parameters may be `#f` in which case the previous values will be used.

- `(syslog level message)`

- `(syslog level message string)`

- `(syslog level message string options)`

- `(syslog level message string options syslog-facility)`

- `(syslog level message channel)`

`Syslog` actually logs a message. Each of the parameters of the implicit connection (except for the log mask) can be explicitly specified as well for the current call to `syslog`, overriding the parameters of the channel. The parameters revert to their original values after the call.

The final form specifies the destination of the log message as a channel; see the next section.

### Syslog channels

These procedures allow direct manipulation of syslog channels, the objects that represent connections to the syslog facility. Note that it is not necessary to explicitly open a syslog channel to do logging.

- `(open-syslog-channelstring options facility mask) --> channel`

- `(close-syslog-channelchannel)`

- `(with-syslog-destination channel thunk) --> value`

`Open-syslog-channel` and `close-syslog-channel` create and destroy a connection to the syslog facility, respectively. The specified form of calling `syslog` logs to the specified channel.

`With-syslog-channel` dynamically binds parameters of the implicit connection to the syslog facility to those specified in channel and runs thunk within those parameter bindings, returning what thunk returns.

## 9.11 Error codes

POSIX functions report the nature of an error via system error numbers---OS-specific integers that encode a variety of different error situations. At the Scheme level, error numbers are represented as errnos, objects that specify a name for the error sitation. Errnos are definted in the structures `posix-errnos` and `posix`.

Currently, the system reports such error situations by raising exceptions with condition type `&os-error`. The `&os-error` condition type has a field `code` that contains the system error number.

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

- `(errno errno-name) --> errno` (syntax)

- `(name->errno symbol) --> errno or `#f``

- `(integer->errno integer) --> errno`

- `(errno? x) --> boolean`

- `(errno-name errno) --> symbol or `#f``

- `(errno-os-number errno) --> integer`

- `(errno=? errno0 errno1) --> boolean`

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

### 9.11.1 POSIX errnos

The following lists the names of the POSIX errnos.

@``lp0.6 toobig Argument list too long.
acces Permission denied.
addrinuse Address in use.
addrnotavail Address not available.
afnosupport Address family not supported.
again Resource unavailable, try again.
already Connection already in progress.
badf Bad file descriptor.
badmsg Bad message.
busy Device or resource busy.
canceled Operation canceled.
child No child processes.
connaborted Connection aborted.
connrefused Connection refused.
connreset Connection reset.
deadlk Resource deadlock would occur.
destaddrreq Destination address required.
dom Mathematics argument out of domain of function.
dquot Reserved.
exist File exists.
fault Bad address.
fbig File too large.
hostunreach Host is unreachable.
idrm Identifier removed.
ilseq Illegal byte sequence.
inprogress Operation in progress.
intr Interrupted function.
inval Invalid argument.
io I/O error.
isconn Socket is connected.
isdir Is a directory.
loop Too many levels of symbolic links.
mfile Too many open files.
mlink Too many links.
msgsize Message too large.
multihop Reserved.
nametoolong Filename too long.
netdown Network is down.
netreset Connection aborted by network.
netunreach Network unreachable.
nfile Too many files open in system.
nobufs No buffer space available.
nodata No message is available on the STREAM head read queue.
nodev No such device.
noent No such file or directory.
noexec Executable file format error.
nolck No locks available.
nolink Reserved.
nomem Not enough space.
nomsg No message of the desired type.
noprotoopt Protocol not available.
nospc No space left on device.
nosr No STREAM resources.
nostr Not a STREAM.
nosys Function not supported.
notconn The socket is not connected.
notdir Not a directory.
notempty Directory not empty.
notsock Not a socket.
notsup Not supported.
notty Inappropriate I/O control operation.
nxio No such device or address.
opnotsupp Operation not supported on socket.
overflow Value too large to be stored in data type.
perm Operation not permitted.
pipe Broken pipe.
proto Protocol error.
protonosupport Protocol not supported.
prototype Protocol wrong type for socket.
range Result too large.
rofs Read-only file system.
spipe Invalid seek.
srch No such process.
stale Reserved.
time Stream ioctl() timeout.
timedout Connection timed out.
txtbsy Text file busy.
wouldblock Operation would block.
xdev Cross-device link.

## 9.12 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)
`access` | `accessible?`
`asctime` | `date->string`
`chdir` | `set-working-directory!`
`close` | `close-input-port, close-output-port,`
| `close-channel, close-socket`
`closedir` | `close-directory-stream`
`creat` | `open-file`
`ctime` | `time->string`
`dup` | `dup, dup-switching-mode`
`dup2` | `dup2`
`exec[l|v][e|p|ε]` | `exec, exec-with-environment,`
| `exec-file, exec-file-with-environment,`
| `exec-with-alias`
`_exit` | `exit`
`fcntl` | `io-flags, set-io-flags!,`
| `close-on-exec, set-close-on-exec!`
`fork` | `fork, fork-and-forget`
`fstat` | `get-port-info`
`getcwd` | `working-directory`
`getegid` | `get-effective-group-id`
`getenv` | `lookup-environment-variable,`
| `environment-alist`
`geteuid` | `get-effective-user-id`
`getgid` | `get-group-id`
`getgroups` | `get-groups`
`getlogin` | `get-login-name`
`getpid` | `get-process-id`
`getppid` | `get-parent-process-id`
`getuid` | `get-user-id`
`gmtime` | `time->local-date`
`isatty` | `port-is-a-terminal?`
`link` | `link`
`localtime` | `time->utc-date`
`lstat` | `get-file/link-info`
`mkdir` | `make-directory`
`mkfifo` | `make-fifo`
`mktime` | `date->time`
`open` | `open-file`
`opendir` | `open-directory-stream`
`pipe` | `open-pipe`
`read` | `read-char, read-block`
`readdir` | `read-directory-stream`
`readlink` | `read-symbolic-link`
`rename` | `rename`
`rmdir` | `remove-directory`
`setgid` | `set-group-id!`
`setegid` | `set-effective-group-id!`
`setuid` | `set-user-id!`
`seteuid` | `set-effective-user-id!`
`stat` | `get-file-info`
`strftime` | `format-date`
`symlink` | `create-symbolic-link`
`syslog` | `syslog`
`time` | `current-time`
`ttyname` | `port-terminal-name`
`umask` | `set-file-creation-mask!`
`uname` | `os-name, os-node-name,`
| `os-release-name, os-version-name,`
| `machine-name`
`unlink` | `unlink`
`waitpid` | `wait-for-child-process`
`write` | `write-char, write-block`