The Icon Programming Language[1] provides a large set of
platform-independent facilities for non-numerical processing, graphics
etc. Icon runs on everything from Unix machines to Amigas and
Macs. This strong point, its platform independence, is also a weak point:
it could not offer access
to the underlying system and so could not be used as a system administration
and scripting language like Perl[2]. This was a great
disappointment to the author, who has had to write many Perl
scripts over the years. While it is true that Perl
substitutes for a congolmeration of sed, awk and shell
scripts, it does so with some of the worst language features from
them.
Icon, on the other hand, has always been a good clean language with lots of support for high-level control and data structures. If we could add the Unix system calls to the language, we would have the best of both worlds: a sensible and powerful VHLL as a Unix scripting language. Icon even has integrated support for X11 graphics!
This document describes a set of functions that implement access to POSIX system calls offered by the host system; it is the definitive reference for the POSIX functions of Unicon. Several functions are only available on Unix systems; programs that need to run on the multitudinous varieties of Windows should not use them.
The POSIX subsystem includes
an include file posix.icn that defines the
constants and the record types that are required. This file
should be included by programs desirous of using the Posix interface.
All the common system calls (Section 2 of the Unix manuals) are available
under the same names. Some of these are already implemented in standard Icon
(chdir, rename). For system calls that return
struct
types, a record is created and returned; the components of the record have
names that are similar to the elements of the struct.
Whenever possible, the type system of Icon is used to advantage. For example
instead of having separate functions stat and fstat,
the function stat calls the appropriate system procedure based
on the type of the argument.
A new keyword &errno has been added to the language.
If an error occurs during the execution of any of these system functions,
the function
will fail and &errno will be set. The string corresponding to
an error ID is returned by the function sys_errstr. The first
few errors (EPERM to EPIPE) seem to be common between systems,
and these are defined in the header file; &errno can be
directly compared
against constants like ENOENT etc. In general, however, it is
safer to format the error with the sys_errstr function.
Another keyword &now will return the system time expressed as
an integer. This value can be used to compare file modification dates etc.
Its exact meaning is implementation dependent. (On Unix systems it is the
number of seconds since the epoch, i.e. 00:00:00 Jan. 1, 1970 UTC.)
In this document, Unix system calls and commands are represented with the
manpage section number and set in a typewriter font,
thus: select(2); whereas
Icon names and
functions are set in a sans serif font: select().
Signals may be trapped or ignored with the trap function. The
signal argument is passed by name, and may be system dependent, e.g. Linux
systems don't have a SIGLOST. The signal handler defaults to the
default provided by the system -- for instance, SIGHUP is
ignored by default but SIGFPE will cause a core
dump. See Fig. 1 for an example.
global oldhandler
...
trap("SIGFPE", sig_ignore)
oldhandler := trap("SIGSEGV", handler)
...
trap("SIGSEGV", oldhandler)
end
procedure sig_ignore(s); end
procedure handler(s)
write("Got signal ", s)
oldhandler(s) # propagate the signal
end
On Unix systems,
programs may be forked in the usual Unix manner of calling fork(2)
and then exec*(2). The function fork behaves exactly as
the Unix version; exec subsumes all of the Unix exec*
system calls. The first argument is the filename of the program to execute,
and the remaining arguments are the values of argv that the program
will get, starting with argv[0].
if fork() = 0 then
exec("/bin/echo", "echo", "Hello,", "world!")
Currently there is no way of passing the environment (execve style).
However, for portability to non-Unix systems, system should be
used. The usual usage of fork is to manipulate file descriptors
for stdin, stdout and stderr and then perform an exec; this functionality is
provided by the full form of the system function.
...
L := pipe()
system(["/bin/wc", "-x"], L[1], , , "nowait")
close(L[1])
system("/bin/egrep -i procedure filename.c", , L[2], , "nowait")
close(L[2])
...
select
The first argument is either a list of strings or a string, and represents the command to execute (along with its arguments); the next three arguments are files that represent the values of stdin, stdout and stderr that the new process should have; and the last signifies whether the function should wait for the new process to terminate, a value of "nowait" will cause the function to return leaving the new process running in the background.
When the string form is used, it [the string] is passed to the shell for interpretation. If you need wildcards use this form; if the arguments to the process have embedded whitespace and you don't want to mess with shell quoting, use the list form. N. B. A trailing `&' in the string form will also cause the spawned process to run in the background.
The portable way to redirect streams for spawn processes is with
system as described above. However on Unix systems, dup is also
available.
Fig. 3 shows pipes and
fdup being used to redirect a child process' input.
L := pipe() | stop("Couldn't get pipe: ", sys_errstr(&errno))
if fork() = 0 then {
close(L[2])
fdup(L[1], &input)
exec(...)
}
close(L[1])
write(L[2], ...) # write to child's stdin
The function filepair is similar to pipe
except that the connection is bidirectional.
Icon provides a much simpler interface to BSD-style sockets.
Instead of the four different system calls that are required to
start a TCP/IP server on Unix systems, Icon provides only one--the
"na" (network accept) flags to open. The first argument to
open
is the network address to connect to -- host:port for Internet
domain connections, and a filename for Unix domain sockets. If the
address starts with ":" i.e. no host name, the socket is opened
on the same machine. The returned value from open is a file that
can be used in select etc. as well as normal reading and writing.
procedure main()
while f := open(":1888", "na") do
if fork() = 0 then {
servicerequest(f)
exit()
} else
close(f)
(&errno = 0) | stop("Open failed: ", sys_errstr(&errno))
end
procedure finger(n)
static fserv
initial fserv := getserv("finger") |
stop("Couldn't get service: ", sys_errstr(&errno))
n ? {
name := n; host := ""
name := tab(upto('@')) & ="@" & host := tab(0)
}
if *host > 0 then write("[", host, "]")
f := open(host || ":" || fserv.port, "n") |
stop("Couldn't open connection: ", sys_errstr(&errno))
write(f, name) | stop("Couldn't write: ", sys_errstr(&errno))
while line := read(f) do
write(line)
end
finger(1)
Fig. 4 shows Icon code
that implements a simple Internet domain TCP server that listens on
port 1888.
To connect to this server, the "n" (network connect) flag is
used. Fig. 5 shows a function that connects to a
`finger' server.
UDP networking is similar to the TCP examples above, except
that the additional character "u" is passed to
open. When a call to writes is made, a message is
sent to the
address that was specified when the socket was
created. The send function can also be used
to send a UDP datagram.
To receive
a UDP datagram,
the receive function is used, which returns a record
with two fields: the addr field contains the address of
the sender in "host:port" form, and the msg
field contains the message. See Fig. 6 for an example
of a UDP server program, and Fig. 7 for a UDP client.
(Note: since UDP is not reliable, the receive in
Fig. 7 is guarded with a select, or it might
hang forever if the reply is lost.)
The difference between using send and writes is that
the latter keeps the socket open between calls, whereas the former
doesn't. Typically a server will use open/receive to
accept messages and send to reply; a client will use
open/writes. In general, use the approach that makes the
meaning of the program clearer.
f := open(":1025", "nua")
while r := receive(f) do {
# Process the request in r.msg
...
send(r.addr, reply)
}
procedure main(args)
(*args = 1) | stop("Usage: rdate host")
host := args[1]
s := getserv("daytime", "udp")
f := open(host||":"||s.port, "nu") |
stop("Open failed: ", sys_errstr(&errno))
writes(f, " ")
if *select(f, 5000) = 0 then
stop("Connection timed out.")
r := receive(f)
write("Time on ", host, " is ", r.msg)
end
select() system call
The function select() implemented in Icon performs a subset of
the select(2) system call. Only the `read' fd_set is passed
in; no provision is made to wait for exceptions on files or to ensure that
writes don't block. (For non-blocking writes, use fcntl.)
It is hoped that this somewhat weaker version of select will still be
usable in the majority of the cases. (Appendix B shows an
implementation of the script(1) command.)
Instead of modifying the sets of file descriptors in place,
select() returns a list of files that have data to be read.
If the timeout expires instead, an empty list is returned.
Fig. 8 shows an example of the usage.
while *(L := select(f1, f2, f3, timeout)) = 0 do handle_timeout()
(&errno = 0) | stop("Select failed: ", sys_errstr(&errno))
every f := !L do {
# Dispatch reads pending on f
...
}
Care must be taken that the buffering used by stdio does not
interfere with the files being used with select. Consider this
code:
while L := select(f, &window) do
if L[1] === f then
c := read(f)
If the string "hello" is ready on f, Icon will try to read till
the next newline character and block, even though input can be read.
When used with a network connection or with a file that has been used with
select, the function reads(f, n) will perform
exactly one low-level read and will try to read up to n characters,
bypassing any buffering that stdio may be doing. Since the
unprocessed input is still in the low-level buffers, select will
work correctly.
while L := select(f, &window) do
if L[1] === f then
c := reads(f, 3)
The first time reads is called, it will return the
string "hel"; the subsequent call to select
finds input still waiting on f so it will return,
resulting in a value of "lo" being read. If
the size argument is omitted, reads will read as much as
it can without blocking. Important: Do not mix this usage of
reads with the usual read! There lie deadlocks.
The script(1) example (Appendix B) shows the usage of
select and reads.
Known bug: if you plan to use select on a file, make
sure that select is called before you
perform any reads calls on it. If you will
be reading from it before you need to call select, this will
suffice:
select(f, 0)
If you do not do that, you will get a runtime error (180 low-level read or
select mixed with buffered read) the first time you
call select.
The open function can open directories in the manner of
readdir(2). They can only be opened for reading, and every
read returns the name of one entry. Entries are not guaranteed
to be in any specific order. Fig. 9 shows an implementation
of a simple for of ls(1).
$include "posix.icn"
link printf
procedure main(args)
every name := !args do {
f := open(name) | stop(sys_errstr(&errno), name)
L := list()
while line := read(f) do
push(L, line)
every write(format(stat(n := !sort(L)), n))
}
end
procedure format(p, name)
s := sprintf("%7s %4s %s %3s %-8s %-8s %8s %s %s",
p.ino, p.blocks, p.mode, p.nlink,
p.uid, p.gid, p.size, ctime(p.mtime)[5:17], name)
s ||:= " -> " || \p.symlink
return s
end
regexp library in the Icon Program Library may be used for
regular expression searching and search-and-replace operations.
link regexp
...
result := ""
s ? {
while j := ReFind(re) do {
result ||:= tab(j) || replacement
tab(ReMatch(re))
}
result ||:= tab(0)
}
Since the Icon program has access to the operation at a finer grain, more complex operations (rather than only search-and-replace) are possible.
There are four functions that read information from system files:
getpw to read the password file, getgr for the group file,
gethost for hostnames and getserv for network
services. Called with an argument (usually a string) they perform a lookup in
the system file. When called with no arguments, these functions step through
the files one entry at a time.
The functions setpwent, setgrent,
sethostent, setservent do the same things as their Unix
counterparts, i.e. they reset the file position used by the get*
routines to the beginning of the file.
They return records whose members are similar to the structs returned
by the system functions like getpwuid(2), gethostbyname(2) etc.
DBM databases may be opened by the open function. The only
permissible values for the second argument are "d" and
"dr", for opening the database read/write and read-only
respectively.
Values are inserted into the database with insert(d, k, v) and
are read from it with fetch(d, k).
The POSIX functions described here are part of the Unicon language, hosted at Sourceforge. It is distributed as source code under the GPL. (Arizona Icon is in the public domain.)
The POSIX functions have been tested on Solaris 8, OpenBSD 3.1, FreeBSD 4.6-STABLE and Linux 2.4. They should work on all Unix or Unix-like platforms; if you have any problems, please send me email.
Of course, Icon and Unicon come with no warranties. What you see is all you get.
My thanks to Clint Jeffery for the long discussions on the right Unix interface, and for inciting me to do commit this act of implementation, and for taking charge of the Unicon language. Thanks to Steve Lumos for porting and testing on FreeBSD, and for implementing the messaging extensions -- a fine addition to the language. Thanks also to Ralph Griswold and the Icon Project for creating and maintaining a fine language.
And of course thanks to Richard Stallman, Linus Torvalds and a cast of millions!
Some additions have been made to the arguments and functionality of these Icon functions:
open(s1, s2) : f -- Open a file
open are:
"na" |
listen on a TCP network socket |
|---|---|
"n" |
connect to a TCP network socket |
"nau" |
listen on a UDP network socket |
"nu" |
connect to a UDP network socket |
"d" |
open a DBM database |
When opening a network socket: the first argument s1 is
the name of the socket to connect to: if of the form
"s:i", it is an Internet domain socket on host s and
port i; otherwise, it's the name of a Unix domain socket.
If the host name is null, it represents the current host.
For a UDP socket, `connect' means that any writes to
that file will send a datagram to that address, so that
the address doesn't have to specified each time. Also,
read or reads cannot be
performed on a UDP socket; use receive.
UDP sockets must be in the INET domain, i.e. the address must have a colon.
For a DBM database, only one modifier character may be used:
if s1 is "dr" it indicates that the
database should be opened in read-only mode.
system(args, stdin, stdout, stderr, waitflag) : i -- Run a process
The first argument can be either a string (as in the original meaning of
system or a list of strings. In the former case, whitespace is
used to separate the arguments. In the second case, each member of the list
is an argument.
When a string is the first argument, it is passed to the shell to evaluate. When the list form is used, the new process is created directly. If you want to use shell wildcards etc. use the string form, and be careful about the usual shell quoting and stuff. The list form is clear and unambiguous but you don't get all those features the shell gives you.
If the waitflag argument is "nowait", system will
return immediately after spawning the new process. The default is for it to
wait for the spawned process to exit.
The three file arguments are the files that should be used for the new process' standard input, standard output and standard error.
The return value is an integer: the pid of the process if it was run with
"nowait", otherwise the exit status from the process.
Event(W, i) : a -- return next window event
The second argument i is a timeout value in
milliseconds. If the timeout expires before an event is available,
then Event() fails. The default for i
signifies that Event() should wait for the
next window event.
&errno If an error occurs during the execution of these
functions, the function will fail and &errno will be set. The
string corresponding to an error ID is returned by the function
sys_errstr.
&now The system time, represented as an integer. On Unix
systems, this is the number of seconds since Jan 1 1970; on other systems it
will be system dependent. The only safe usage for the value returned is to
use it to compare file modification dates against, or to use as an argument
to ctime.
chmod(f, mode) -- Change file mode
f to mode. The
mode can be an integer mode or a string representing the change to be
performed. The string is of the form
[ugoa]*[+-=][rwxRWXstugo]*
or
[r-][w-][xsS-][r-][w-][xsS-][r-][w-][xtT-]
The first group describes the set of mode bits to be changed: u
is the owner set, g is the group and o is the group
`other.' The character a represents all the fields. The
operator (+-=) describes the operation to be performed:
+ adds a permission, - removes a permission, and
= sets a permission. The permissions themselves are:
r |
read |
|---|---|
w |
write |
x |
execute |
R |
read if any other set already has r |
W |
write if any other set already has w |
X |
execute if any other set already has x |
s |
setuid (if the first part contains u |
and/or setgid if the first part contains g |
|
t |
sticky if the first part has o |
u |
the u bits on the same file |
g |
the g bits on the same file |
o |
the o bits on the same file |
If the first group is missing, then it is treated as a
except that any bits in the user's umask will not be modified
in the mode.
If the mode string is of the second form i.e. as returned by
stat, then it represents the mode the file is to have.
chown(f, u, g) -- Change file owner
Set the owner of a file f to owner u and group
g. The user and
group arguments can be numeric ID's or names.
chroot(f) -- Change root
Change the root of the filesystem to f.
ctime(t) : s -- Format a time value into local time
Converts system time (an integer) into a string in the local timezone. (On Unix systems, system time is the number of seconds since the epoch, Jan 1, 1970 00:00:00. Its meaning on other systems varies.)
crypt(s1, s2) : s -- Encrypt a password
Encrypt the password s1 with the salt s2.
(The first two characters of the returned string will be the salt.)
exec(f, arg0, arg1, arg2, ...) -- Replace the executing Icon program
with another.
The current program is replaced by another program f. The
remaining arguments are passed to the program. Consult the exec(2)
manpages for more details. Warning: f must point to an
executable program, not to a shell script or Icon program. If you want to
run those, the first argument to exec should be /bin/sh,
or iconx, etc.
Warning: This is only available on Unix
systems! For portable programs use system.
fetch(d, k) : s -- Fetch a value from a dbm database
Fetch the value corresponding to key k from the dbm database
d.
fcntl(file, cmd, arg) -- Miscellaneous operations on opened files
Perform a number of miscellaneous operations on the open file. See the
fcntl(2) manpage for more details. Directories
and dbm files cannot be arguments to fcntl.
The following characters are the possible values for cmd:
f |
Get flags (F_SETFL) |
|---|---|
F |
Set flags (F_GETFL) |
x |
Get close-on-exec flags (F_GETFD) |
X |
Set close-on-exec flag (F_SETFD) |
l |
Get file lock (F_GETLK) |
L |
Set file lock (F_SETLK) |
W |
Set file lock and wait (F_SETLKW) |
o |
Get file owner or process group (F_GETOWN) |
O |
Set file owner or process group (F_SETOWN) |
In the case of L, the
arg value should be a string that describes the lock.
A record will be returned by F_GETLK:
record posix_lock(value, pid)
The lock string consists of three parts separated by commas: the type of
lock (r, w or u), the starting position
and the length. The starting position can be an offset from the beginning of
the file (e.g. 23), end of the file (e.g. -50) or from
the current position in the file (e.g. +200). A length
of 0 means lock till EOF.
The file flags set by F_SETFL and accessed by F_GETFL are represented by these characters:
d |
FNDELAY |
|---|---|
s |
FASYNC |
a |
FAPPEND |
fdup(src, dest) -- Copy a file descriptor
This function provides a functionality similar to the dup2(2) system
call. It only needs to be used when you are concerned about the actual Unix
file descriptor used, such as just before calling exec. The
dest file is closed; src is made to have its
Unix file descriptor; and the second file is replaced by the first.
Warning: This is only available on Unix
systems! For portable programs use system.
filepair() : L -- Create a pair of connected files
This is analogous to socketpair(2) - it returns a list of two
files, such that writes on one will be available on the other. The
connection is bi-directional, unlike pipe. The two
files are indistinguishable. Caution: Typically, the pair is
created just before a fork or system; after it, one
process should close L[1] and the other should close
L[2] or
you will not get proper end-of-file notification.
flock(file, op) -- Apply or remove a lock on a file
An advisory lock is applied to the file. Consult the flock(2) manpage
for more details.
The following characters can be used to make up the operation string:
s |
shared lock |
|---|---|
x |
exclusive lock |
b |
don't block when locking |
u |
unlock |
Locks cannot be applied to directories or dbm files.
fork() : pid -- Create a copy of the process.
This function creates a new process that is identical to the current process
in all respects except in the return value. The parent gets a return value
that is the PID of the child, and the child gets 0. Warning:
This is only available on Unix systems; for portability use
system instead.
getegid() : gid -- get group identity
Get the effective gid of the current process.
geteuid() : uid -- get user identity
Get the effective uid of the current process.
getgid() : gid -- get group identity
Get the real gid of the current process.
getgr(g) : r -- Get a group file entry
Returns a record that contains group file information. If g
is null,
each successive call to getgr returns the next entry.
setgrent resets the sequence to the beginning. g can
be a numeric gid or a group name.
Return type:
record posix_group(name, passwd, gid, members)
gethost(h) : r -- Get a host entry
Returns a record that contains host information. If h
is null,
each successive call to gethost returns the next entry.
sethostent resets the sequence to the beginning. The aliases and
addresses are comma separated lists of aliases and addresses (in a.b.c.d
format) respectively.
Return type:
record posix_hostent(name, aliases, addresses)
getpgrp() -- Get the process group
Returns the process group of the current process.
getpid() : pid -- get process identity
Get the pid of the current process.
getppid() : pid -- get parent's identity
Get the pid of the parent process.
getpw(u) : r -- Get a password file entry
Returns a record that contains password file information. If u
is null, each successive call to getpw returns the next entry and
setpwent resets the sequence to the beginning. u can
be a numeric uid or a user name.
Return type:
record posix_password(name, passwd, uid, gid, age, comment, gecos, dir, shell)
getserv(s1, s2) : r -- Get a serv entry
Returns a record that contains serv information for the service
s1 using protocol s2. If s1
is null,
each successive call to getservent returns the next entry.
setservent resets the sequence to the beginning.
Return type:
record posix_servent(name, aliases, port, proto)
If s2 is defaulted, it will return the first matching entry.
gettimeofday() : r -- Return the time of day.
Returns the current time in seconds and microseconds since the epoch, Jan 1,
1970 00:00:00. The sec value may be converted to a date string
with
ctime or gtime.
Return value: record posix_timeval(sec, usec)
getuid() : uid -- get user identity
Get the real uid of the current process.
gtime(t) : s -- Format a time value into UTC
Converts a system time (an integer) into a string in UTC. (On Unix systems, the time is the number of seconds since the epoch, Jan 1, 1970 00:00:00.)
ioctl() -- Unimplemented
Since ioctl(2) relies so heavily on opaque pointers to structs, it is
hard to implement in Icon; accordingly its implementation has been deferred
till we can figure out what the right use model should be.
Calls to ioctl are inherently not portable. Most ioctl functions
can be done with system, running programs like stty(1) or
mt(1).
link(src, dest) -- Make a link
Make a (hard) link dest that points to src.
mkdir(path, mode) -- Create a new directory
Create a new directory named path with a mode of
mode. The mode can be numeric or a string of the form accepted by
chmod().
pipe() : L -- Create a pipe.
Create a pipe and return a list of two file objects. The first
is for reading, the second is for writing.
readlink(l) : s -- Read a link
Returns the value of a symbolic link. (Obsolete.)
receive(f) : r -- Receive a UDP datagram.
This function reads a datagram addressed to the port
associated with f,
waiting if necessary. The returned value is a record of type
posix_message(addr, msg), containing the address of
the sender and the contents of the message respectively.
rmdir(d) -- Remove a directory
Removes an empty directory.
select(file1, file2, ..., timeout) : L -- Select among files
Wait for a input to become available on a number of files. If timeout is specified, it is an upper bound on the
time elapsed before select returns. The unit
for the timeout is milliseconds (ms). A timeout of 0 may be specified
in which case select will return immediately with a list of files on
which input is currently pending.
| Defaults: | files |
Wait for timeout to expire and return. |
|---|---|---|
timeout |
Wait forever. |
Directories and dbm files cannot be arguments to select.
send(s1, s2) -- Send a UDP datagram.
This function sends a datagram to the address s1 with the
contents s2.
setenv(name, value) -- Set an environment variable.
Set an environment variable named name to
the value value. If it did not exist, it
is created; if it did, it is overwritten.
setgrent() -- Resets the group file
This function resets and rewinds the pointer to the group file used by
getgr when called with no arguments.
sethostent(stayopen) -- Resets the host file
This function resets and rewinds the pointer to the host file used by
gethost. The argument defines whether the file should be kept open
between calls to gethost; the default is to keep it
open.
setpgrp() -- Set the process group
Sets the process group. This is the equivalent of setpgrp(0, 0) on
BSD systems.
setpwent() -- Resets the password file
This function resets and rewinds the pointer to the password file used by
getpw when called with no arguments.
setgid(g) -- Set the gid
Set the gid of the current process to g. Consult the SysV
setgid(2) manpage.
setuid(u) -- Set the uid
Set the uid of the current process to u.Consult the SysV
setuid(2) manpage.
setservent(stayopen) -- Resets the network services file
This function resets and rewinds the pointer to the srvices file used by
getserv. The argument defines whether the file should be kept open
between calls to getserv; the default is to keep it
open.
stat(f) : r -- Get information about a file
Returns a record with information about the file f
which may be a path or a file object.
The times are integers that may be formatted with the ctime and
mtime functions. If the file is a link, its value is in the
symlink member of the returned record.
Return value: record posix_stat(dev, ino, mode, nlink, uid, gid,
rdev, size, atime, mtime, ctime, blksize, blocks, symlink)
The mode is a string similar to the output of ls(1). For
example, "-rwxrwsr-x" represents a plain file with a mode of
2775 (octal).
symlink(src, dest) -- Make a symbolic link
Make a symbolic link dest that points to src.
sys_errstr(&errno) : s -- Format an error id
This function returns the string corresponding to the error code. If called with an invalid code (negative, or greater than the number of error messages) this function fails.
trap(s, proc) : proc -- Trap or ignore a signal
Set up a signal handler for the signal s (the name of the
signal). The old handler (if any) is returned. If proc is
&null, the signal is reset to its default value.
Caveat: This is not supported with the compiler!
truncate(f, len) -- Truncate a file
Truncate the file f (which may be a path to the file, or a
file object that points to the file) to be of length
len.
umask(u) : u -- Set the file creation mask
Set the umask of the process to u. The old value of the umask is
returned.
The umask can either be specified in the Unix way with an integer whose bits
represent the permissions that should not be granted; or as a permission
string. umask(8r22) and umask("rwxr-xr-x") are
equivalent. The return value is the old value of the umask, and it is
returned in the same format as its argument, i.e. if called with an integer
it will return an integer umask, and if called with a string it will return
a mode string.
With a value of &null it will return the present value of the
umask (as a string) without changing that value.
utime(f, atime, mtime) -- Set file modification/access times.
Set the access time for file f to atime and the
modification time to mtime. The ctime is set to the
current time.
wait(pid, options) : status -- Wait for process
to terminate or stop
The options argument is a string constructed from the following characters:
"n" |
NOHANG - don't wait for a child to terminate
(wait will fail if there are no more) |
|---|---|
"u" |
UNTRACED - report status for untraced children also |
The return value is a string that represents the pid and the exit status as defined in this table:
| Unix equivalent | example of returned string |
WIFSTOPPED(status) |
"1234 stopped:SIGTSTP" |
WIFSIGNALLED(status) |
"1234 terminated:SIGHUP" |
WIFEXITED(status) |
"1234 exit:1" |
WIFCORE(status) |
"1234 terminated:SIGSEGV:core" |
Currently the rusage
facility is unimplemented.
| Defaults: | pid |
Wait for all children |
|---|
Here is an example implementation of the BSD script(1) command:
# script: capture a script of a shell session (as in BSD)
# Usage: script [-a] [filename}
# filename defaults to "typescript"
$include "posix.icn"
procedure main(L)
if L[1] == "-a" then {
flags := "a"; pop(L)
} else
flags := "w"
# Find a pty to use
every c1 := !"pqrs" do
every c2 := !(&digits || "abcdef") do
if pty := open("/dev/pty" || c1 || c2, "rw") then {
# Aha!
capture(fname := L[1] | "typescript", pty, c1 || c2, flags)
stop("Script is done, file ", image(fname))
}
stop("Couldn't find a pty!")
end
procedure capture(scriptfile, pty, name, flags)
f := open(scriptfile, flags) | stop("Couldn't open ", image(scriptfile))
tty := open("/dev/tty" || name, "rw") | stop("Couldn't open tty!")
shell := getenv("SHELL") | "/bin/sh"
system([shell, "-i"], tty, tty, tty, "nowait")
# Parent
close(tty)
system("stty raw -echo")
# Handle input
while L := select(pty, &input) do {
if L[1] === &input then
writes(pty, reads()) | break
else if L[1] === pty then {
writes(f, inp := reads(pty)) | break
writes(inp)
}
}
(&errno = 0) | write(&errout, "Unexpected error: ", sys_errstr(&errno))
system("stty cooked echo")
close(f)
end
$Date: 2004/02/21 19:52:54 $
![]()
© 1997-2002 Shamim Mohamed
Last modified: Wed Aug 7 14:04:31 PDT 2002