* Copyright (c) 1983 The Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)library.c 5.5 (Berkeley) %G%";
* General purpose routines.
#define ord(enumcon) ((int) enumcon)
#define nil(type) ((type) 0)
typedef enum { FALSE
, TRUE
} boolean
;
String cmdname
; /* name of command for error messages */
Filename errfilename
; /* current file associated with error */
short errlineno
; /* line number associated with error */
* Definitions for doing memory allocation.
#define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type)))
#define dispose(p) { free((char *) p); p = 0; }
* Macros for doing freads + fwrites.
#define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp)
#define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp)
extern String
strcpy(), index(), rindex();
#define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s)
#define streq(s1, s2) (strcmp(s1, s2) == 0)
#define ERR_IGNORE ((IntFunc *) 0)
#define ERR_CATCH ((IntFunc *) 1)
* call, callv - call a program and wait for it, returning status
* back, backv - call a program and don't wait, returning process id
* The command's standard input and output are passed as FILE's.
#define MAXNARGS 1000 /* unchecked upper limit on max num of arguments */
#define BADEXEC 127 /* exec fails */
#define ischild(pid) ((pid) == 0)
public int call(name
, in
, out
, args
)
while (*ap
!= nil(String
)) {
return callv(name
, in
, out
, argv
);
public int back(name
, in
, out
, args
)
while (*ap
!= nil(String
)) {
return backv(name
, in
, out
, argv
);
public int callv(name
, in
, out
, argv
)
pid
= backv(name
, in
, out
, argv
);
public int backv(name
, in
, out
, argv
)
if (ischild(pid
= fork())) {
onsyserr(EACCES
, ERR_IGNORE
);
* Swap file numbers so as to redirect standard input and output.
private fswap(oldfd
, newfd
)
* Invoke a shell on a command line.
if ((sh
= getenv("SHELL")) == nil(String
)) {
if (s
!= nil(String
) and *s
!= '\0') {
call(sh
, stdin
, stdout
, "-c", s
, 0);
call(sh
, stdin
, stdout
, 0);
* Wait for a process the right way. We wait for a particular
* process and if any others come along in between, we remember them
* in case they are eventually waited for.
* This routine is not very efficient when the number of processes
* to be remembered is large.
* To deal with a kernel idiosyncrasy, we keep a list on the side
* of "traced" processes, and do not notice them when waiting for
private Pidlist
*pidlist
, *ptrclist
, *pfind();
register Pidlist
*p
, *prev
;
while (p
!= nil(Pidlist
*) and p
->pid
!= pid
) {
if (p
!= nil(Pidlist
*)) {
if (prev
== nil(Pidlist
*)) {
private boolean
isptraced(pid
)
while (p
!= nil(Pidlist
*) and p
->pid
!= pid
) {
return (boolean
) (p
!= nil(Pidlist
*));
public pwait(pid
, statusp
)
if (p
!= nil(Pidlist
*)) {
while (pnum
!= pid
and pnum
>= 0) {
if (not isptraced(pnum
)) {
if (p
== nil(Pidlist
*)) {
panic("pwait: pid %d not found", pid
);
* Look for the given process id on the pidlist.
* Unlink it from list if found.
private Pidlist
*pfind(pid
)
register Pidlist
*p
, *prev
;
for (p
= pidlist
; p
!= nil(Pidlist
*); p
= p
->next
) {
if (p
!= nil(Pidlist
*)) {
if (prev
== nil(Pidlist
*)) {
* System call error handler.
* The syserr routine is called when a system call is about to
* set the c-bit to report an error. Certain errors are caught
* and cause the process to print a message and immediately exit.
extern char *sys_errlist
[];
* Before calling syserr, the integer errno is set to contain the
* number of the error. The routine "_mycerror" is a dummy which
* is used to force the loader to get my version of cerror rather
* Initialize error information, setting defaults for handling errors.
private ErrInfo
*errinfo
;
errinfo
= alloc(sys_nerr
, ErrInfo
);
for (i
= 0; i
< sys_nerr
; i
++) {
errinfo
[i
].func
= ERR_CATCH
;
errinfo
[0].func
= ERR_IGNORE
;
errinfo
[EPERM
].func
= ERR_IGNORE
;
errinfo
[ENOENT
].func
= ERR_IGNORE
;
errinfo
[ESRCH
].func
= ERR_IGNORE
;
errinfo
[EBADF
].func
= ERR_IGNORE
;
errinfo
[ENOTTY
].func
= ERR_IGNORE
;
errinfo
[EOPNOTSUPP
].func
= ERR_IGNORE
;
if (errno
< 0 or errno
> sys_nerr
) {
fatal("errno %d", errno
);
if (errinfo
== nil(ErrInfo
*)) {
if (e
->func
== ERR_CATCH
) {
fatal(sys_errlist
[errno
]);
} else if (e
->func
!= ERR_IGNORE
) {
* Catcherrs' purpose is to initialize the errinfo table, get this module
* loaded, and make sure my cerror is loaded (only applicable when this is
* Turn off the error catching mechanism completely by having all errors
* ignored. This is most useful between a fork and an exec.
for (i
= 0; i
< sys_nerr
; i
++) {
errinfo
[i
].func
= ERR_IGNORE
;
* Change the action on receipt of an error, returning the previous action.
public IntFunc
*onsyserr(n
, f
)
if (errinfo
== nil(ErrInfo
*)) {
* Print the message associated with the given signal.
* Like a "perror" for signals.
public int sys_nsig
= NSIG
;
* This table is correct for 4.2-like systems but will
* be inadequate for System V (which is the sort of
public String sys_siglist
[] = {
"floating point exception",
"segmentation violation",
"bad argument to system call",
"stop signal not from tty",
"exceeded CPU time limit",
"exceeded file size limit"
public int sys_nsig
= sizeof sys_siglist
/ sizeof sys_siglist
[0];
extern String sys_siglist
[];
if (n
>= 0 and n
< sys_nsig
) {
write(2, msg
, strlen(msg
));
* Standard error handling routines.
* Main driver of error message reporting.
private errmsg(errname
, shouldquit
, s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
)
if (shouldquit
and cmdname
!= nil(String
)) {
fprintf(stderr
, "%s: ", cmdname
);
if (errfilename
!= nil(Filename
)) {
fprintf(stderr
, "%s: ", errfilename
);
fprintf(stderr
, "%d: ", errlineno
);
if (errname
!= nil(String
)) {
fprintf(stderr
, "%s: ", errname
);
fprintf(stderr
, s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
);
* For when printf isn't sufficient for printing the error message ...
if (errfilename
!= nil(String
)) {
fprintf(stderr
, "%s: ", errfilename
);
fprintf(stderr
, "%d: ", errlineno
);
* The messages are listed in increasing order of seriousness.
public warning(s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
)
errmsg("warning", FALSE
, s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
);
* Errors are a little worse, they mean something is wrong,
* but not so bad that processing can't continue.
* The routine "erecover" is called to recover from the error,
* a default routine is provided that does nothing.
public error(s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
)
errmsg(nil(String
), FALSE
, s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
);
* Non-recoverable user error.
public fatal(s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
)
errmsg("fatal error", TRUE
, s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
);
* Panics indicate an internal program error.
public panic(s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
)
errmsg("internal error", TRUE
, s
, a
, b
, c
, d
, e
, f
, g
, h
, i
, j
, k
, l
, m
);
* This is the default routine which we aren't using since we have our own.
* Default way to quit from a program is just to exit.
* Compare n-byte areas pointed to by s1 and s2
* if n is 0 then compare up until one has a null byte.
public int cmp(s1
, s2
, n
)
if (s1
== nil(char *) || s2
== nil(char *)) {
panic("cmp: nil pointer");
return(*(s1
-1) - *(s2
-1));
* Move n bytes from src to dest.
* If n is 0 move until a null is found.
register char *src
, *dest
;
panic("mov: nil source");
panic("mov: nil destination");
while ((*dest
++ = *src
++) != '\0');
#ifdef IRIS /* or in general for 4.2 - System V C library interface */
public bcopy (fromaddr
, toaddr
, n
)
blt(toaddr
, fromaddr
, n
);
public char *index (s
, c
)
public char *rindex (s
, c
)