diff options
Diffstat (limited to 'usr.bin/rdist/common.c')
-rw-r--r-- | usr.bin/rdist/common.c | 995 |
1 files changed, 995 insertions, 0 deletions
diff --git a/usr.bin/rdist/common.c b/usr.bin/rdist/common.c new file mode 100644 index 00000000000..80c9b119f62 --- /dev/null +++ b/usr.bin/rdist/common.c @@ -0,0 +1,995 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char RCSid[] = +"$Id: common.c,v 1.1 1996/02/03 12:12:12 dm Exp $"; + +static char sccsid[] = "@(#)common.c"; + +static char copyright[] = +"@(#) Copyright (c) 1983 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* !lint */ + +/* + * Things common to both the client and server. + */ + +#include "defs.h" +#if defined(NEED_UTIME_H) +#include <utime.h> +#endif /* defined(NEED_UTIME_H) */ + +/* + * Variables common to both client and server + */ +char host[MAXHOSTNAMELEN]; /* Name of this host */ +UID_T userid = (UID_T)-1; /* User's UID */ +GID_T groupid = (GID_T)-1; /* User's GID */ +char *homedir = NULL; /* User's $HOME */ +char *locuser = NULL; /* Local User's name */ +int isserver = FALSE; /* We're the server */ +int amchild = 0; /* This PID is a child */ +int do_fork = 1; /* Fork child process */ +char *currenthost = NULL; /* Current client hostname */ +char *progname = NULL; /* Name of this program */ +int rem_r = -1; /* Client file descriptor */ +int rem_w = -1; /* Client file descriptor */ +struct passwd *pw = NULL; /* Local user's pwd entry */ +int contimedout = FALSE; /* Connection timed out */ +int proto_version = -1; /* Protocol version */ +int rtimeout = RTIMEOUT; /* Response time out */ +jmp_buf finish_jmpbuf; /* Finish() jmp buffer */ +char **realargv; /* Real main() argv */ +int realargc; /* Real main() argc */ +opt_t options = 0; /* Global install options */ + +/* + * Front end to write() that handles partial write() requests. + */ +extern WRITE_RETURN_T xwrite(fd, buf, len) + int fd; + void *buf; + WRITE_AMT_T len; +{ + WRITE_AMT_T nleft = len; + WRITE_RETURN_T nwritten; + register char *ptr = buf; + + while (nleft > 0) { + if ((nwritten = write(fd, ptr, nleft)) <= 0) { + return nwritten; + } + nleft -= nwritten; + ptr += nwritten; + } + + return len; +} + +/* + * Set program name + */ +extern void setprogname(argv) + char **argv; +{ + register char *cp; + + if (!progname) { + progname = strdup(argv[0]); + if (cp = strrchr(progname, '/')) + progname = cp + 1; + } +} + +/* + * Do run-time initialization + */ +extern int init(argc, argv, envp) + /*ARGSUSED*/ + int argc; + char **argv; + char **envp; +{ + register int i; + register char *cp; + + if (!isserver) + (void) signal(SIGSEGV, sighandler); + + setprogname(argv); + + /* + * Save a copy of our argc and argv before setargs() overwrites them + */ + realargc = argc; + realargv = (char **) xmalloc(sizeof(char *) * (argc+1)); + for (i = 0; i < argc; i++) + realargv[i] = strdup(argv[i]); + +#if defined(SETARGS) + setargs_settup(argc, argv, envp); +#endif /* SETARGS */ + + pw = getpwuid(userid = getuid()); + if (pw == NULL) { + error("Your user id (%d) is not known to this system.", + getuid()); + return(-1); + } + + debugmsg(DM_MISC, "UserID = %d pwname = '%s' home = '%s'\n", + userid, pw->pw_name, pw->pw_dir); + homedir = strdup(pw->pw_dir); + locuser = strdup(pw->pw_name); + groupid = pw->pw_gid; + gethostname(host, sizeof(host)); + if ((cp = strchr(host, '.')) != NULL) + *cp = CNULL; + + /* + * If we're not root, disable paranoid ownership checks + * since normal users cannot chown() files. + */ + if (!isserver && userid != 0) { + FLAG_ON(options, DO_NOCHKOWNER); + FLAG_ON(options, DO_NOCHKGROUP); + } + + return(0); +} + +/* + * Finish things up before ending. + */ +extern void finish() +{ + extern jmp_buf finish_jmpbuf; + + debugmsg(DM_CALL, + "finish() called: do_fork = %d amchild = %d isserver = %d", + do_fork, amchild, isserver); + cleanup(); + + /* + * There's no valid finish_jmpbuf for the rdist master parent. + */ + if (!do_fork || amchild || isserver) { + longjmp(finish_jmpbuf, 1); + /*NOTREACHED*/ + error("Unexpected failure of longjmp() in finish()"); + exit(2); + } else + exit(1); +} + +/* + * Handle lost connections + */ +extern void lostconn() +{ + /* Prevent looping */ + (void) signal(SIGPIPE, SIG_IGN); + + rem_r = rem_w = -1; /* Ensure we don't try to send to server */ + checkhostname(); + error("Lost connection to %s", + (currenthost) ? currenthost : "(unknown)"); + + finish(); +} + +/* + * Do a core dump + */ +extern void coredump() +{ + error("Segmentation violation - dumping core [PID = %d, %s]", + getpid(), + (isserver) ? "isserver" : ((amchild) ? "amchild" : "parent")); + abort(); + /*NOTREACHED*/ + fatalerr("Abort failed - no core dump. Exiting..."); +} + +/* + * General signal handler + */ +extern void sighandler(sig) + int sig; +{ + debugmsg(DM_CALL, "sighandler() received signal %d\n", sig); + + switch (sig) { + case SIGALRM: + contimedout = TRUE; + checkhostname(); + error("Response time out"); + finish(); + break; + + case SIGPIPE: + lostconn(); + break; + + case SIGFPE: + debug = !debug; + break; + + case SIGSEGV: + coredump(); + break; + + case SIGHUP: + case SIGINT: + case SIGQUIT: + case SIGTERM: + finish(); + break; + + default: + fatalerr("No signal handler defined for signal %d.", sig); + } +} + +/* + * Function to actually send the command char and message to the + * remote host. + */ +static int sendcmdmsg(cmd, msg) + char cmd; + char *msg; +{ + int len; + + if (rem_w < 0) + return(-1); + + /* + * All commands except C_NONE should have a newline + */ + if (cmd != C_NONE && !strchr(msg + 1, '\n')) + (void) strcat(msg + 1, "\n"); + + if (cmd == C_NONE) + len = strlen(msg); + else { + len = strlen(msg + 1) + 1; + msg[0] = cmd; + } + + debugmsg(DM_PROTO, ">>> Cmd = %c (\\%3.3o) Msg = \"%.*s\"", + cmd, cmd, + (cmd == C_NONE) ? len-1 : len-2, + (cmd == C_NONE) ? msg : msg + 1); + + return(!(xwrite(rem_w, msg, len) == len)); +} + +/* + * Send a command message to the remote host. + * Called as sendcmd(char cmdchar, char *fmt, arg1, arg2, ...) + * The fmt and arg? arguments are optional. + */ +#if defined(ARG_TYPE) && ARG_TYPE == ARG_STDARG +/* + * Stdarg frontend to sendcmdmsg() + */ +extern int sendcmd(char cmd, char *fmt, ...) +{ + static char buf[BUFSIZ]; + va_list args; + + va_start(args, fmt); + if (fmt) + (void) vsprintf((cmd == C_NONE) ? buf : buf + 1, fmt, args); + else + buf[1] = CNULL; + va_end(args); + + return(sendcmdmsg(cmd, buf)); +} +#endif /* ARG_TYPE == ARG_STDARG */ + +#if defined(ARG_TYPE) && ARG_TYPE == ARG_VARARGS +/* + * Varargs frontend to sendcmdmsg() + */ +extern int sendcmd(va_alist) + va_dcl +{ + static char buf[BUFSIZ]; + va_list args; + char cmd; + char *fmt; + + va_start(args); + /* XXX The "int" is necessary as a workaround for broken varargs */ + cmd = (char) va_arg(args, int); + fmt = va_arg(args, char *); + if (fmt) + (void) vsprintf((cmd == C_NONE) ? buf : buf + 1, fmt, args); + else + buf[1] = CNULL; + va_end(args); + + return(sendcmdmsg(cmd, buf)); +} +#endif /* ARG_TYPE == ARG_VARARGS */ + +#if !defined(ARG_TYPE) +/* + * Stupid frontend to sendcmdmsg() + */ +/*VARARGS2*/ +extern int sendcmd(cmd, fmt, a1, a2, a3, a4, a5, a6, a7, a8) + char cmd; + char *fmt; +{ + static char buf[BUFSIZ]; + + if (fmt) + (void) sprintf((cmd == C_NONE) ? buf : buf + 1, + fmt, a1, a2, a3, a4, a5, a6, a7, a8); + else + buf[1] = CNULL; + + return(sendcmdmsg(cmd, buf)); +} +#endif /* !ARG_TYPE */ + +/* + * Internal variables and routines for reading lines from the remote. + */ +static u_char rembuf[BUFSIZ]; +static u_char *remptr; +static int remleft; + +#define remc() (--remleft < 0 ? remmore() : *remptr++) + +/* + * Back end to remote read() + */ +static int remread(fd, buf, bufsiz) + int fd; + u_char *buf; + int bufsiz; +{ + return(read(fd, (char *)buf, bufsiz)); +} + +static int remmore() +{ + (void) signal(SIGALRM, sighandler); + (void) alarm(rtimeout); + + remleft = remread(rem_r, rembuf, sizeof(rembuf)); + + (void) alarm(0); + + if (remleft < 0) + return (-2); /* error */ + if (remleft == 0) + return (-1); /* EOF */ + remptr = rembuf; + remleft--; + return (*remptr++); +} + +/* + * Read an input line from the remote. Return the number of bytes + * stored (equivalent to strlen(p)). If `cleanup' is set, EOF at + * the beginning of a line is returned as EOF (-1); other EOFs, or + * errors, call cleanup() or lostconn(). In other words, unless + * the third argument is nonzero, this routine never returns failure. + */ +extern int remline(buffer, space, doclean) + register u_char *buffer; + int space; + int doclean; +{ + register int c, left = space; + register u_char *p = buffer; + + if (rem_r < 0) { + error("Cannot read remote input: Remote descriptor not open."); + return(-1); + } + + while (left > 0) { + if ((c = remc()) < -1) { /* error */ + if (doclean) { + finish(); + /*NOTREACHED*/ + } + lostconn(); + /*NOTREACHED*/ + } + if (c == -1) { /* got EOF */ + if (doclean) { + if (left == space) + return (-1);/* signal proper EOF */ + finish(); /* improper EOF */ + /*NOTREACHED*/ + } + lostconn(); + /*NOTREACHED*/ + } + if (c == '\n') { + *p = CNULL; + + if (debug) { + static char mbuf[BUFSIZ]; + + (void) sprintf(mbuf, + "<<< Cmd = %c (\\%3.3o) Msg = \"%s\"", + buffer[0], buffer[0], + buffer + 1); + + debugmsg(DM_PROTO, "%s", mbuf); + } + + return (space - left); + } + *p++ = c; + left--; + } + + /* this will probably blow the entire session */ + error("remote input line too long"); + p[-1] = CNULL; /* truncate */ + return (space); +} + +/* + * Non-line-oriented remote read. + */ +readrem(p, space) + char *p; + register int space; +{ + if (remleft <= 0) { + /* + * Set remote time out alarm. + */ + (void) signal(SIGALRM, sighandler); + (void) alarm(rtimeout); + + remleft = remread(rem_r, rembuf, sizeof(rembuf)); + + (void) alarm(0); + remptr = rembuf; + } + + if (remleft <= 0) + return (remleft); + if (remleft < space) + space = remleft; + + bcopy((char *) remptr, p, space); + + remptr += space; + remleft -= space; + + return (space); +} + +/* + * Get the user name for the uid. + */ +extern char *getusername(uid, file, opts) + UID_T uid; + char *file; + opt_t opts; +{ + static char buf[100]; + static UID_T lastuid = (UID_T)-1; + struct passwd *pwd = NULL; + + /* + * The value of opts may have changed so we always + * do the opts check. + */ + if (IS_ON(opts, DO_NUMCHKOWNER)) { + (void) sprintf(buf, ":%d", uid); + return(buf); + } + + /* + * Try to avoid getpwuid() call. + */ + if (lastuid == uid && buf[0]) + return(buf); + + lastuid = uid; + + if ((pwd = getpwuid(uid)) == NULL) { + message(MT_WARNING, + "%s: No password entry for uid %d", file, uid); + (void) sprintf(buf, ":%d", uid); + } else + (void) strcpy(buf, pwd->pw_name); + + return(buf); +} + +/* + * Get the group name for the gid. + */ +extern char *getgroupname(gid, file, opts) + GID_T gid; + char *file; + opt_t opts; +{ + static char buf[100]; + static GID_T lastgid = (GID_T)-1; + struct group *grp = NULL; + + /* + * The value of opts may have changed so we always + * do the opts check. + */ + if (IS_ON(opts, DO_NUMCHKGROUP)) { + (void) sprintf(buf, ":%d", gid); + return(buf); + } + + /* + * Try to avoid getgrgid() call. + */ + if (lastgid == gid && buf[0]) + return(buf); + + lastgid = gid; + + if ((grp = (struct group *)getgrgid(gid)) == NULL) { + message(MT_WARNING, "%s: No name for group %d", file, gid); + (void) sprintf(buf, ":%d", gid); + } else + (void) strcpy(buf, grp->gr_name); + + return(buf); +} + +/* + * Read a response from the remote host. + */ +extern int response() +{ + static u_char resp[BUFSIZ]; + u_char *s; + int n; + + debugmsg(DM_CALL, "response() start\n"); + + n = remline(s = resp, sizeof(resp), 0); + + n--; + switch (*s++) { + case C_ACK: + debugmsg(DM_PROTO, "received ACK\n"); + return(0); + case C_LOGMSG: + if (n > 0) { + message(MT_CHANGE, "%s", s); + return(1); + } + debugmsg(DM_PROTO, "received EMPTY logmsg\n"); + return(0); + case C_NOTEMSG: + if (s) + message(MT_NOTICE, "%s", s); + return(response()); + + default: + s--; + n++; + /* fall into... */ + + case C_ERRMSG: /* Normal error message */ + if (s) + message(MT_NERROR, "%s", s); + return(-1); + + case C_FERRMSG: /* Fatal error message */ + if (s) + message(MT_FERROR, "%s", s); + finish(); + } + /*NOTREACHED*/ +} + +/* + * This should be in expand.c but the other routines call other modules + * that we don't want to load in. + * + * Expand file names beginning with `~' into the + * user's home directory path name. Return a pointer in buf to the + * part corresponding to `file'. + */ +extern char *exptilde(ebuf, file) + char *ebuf; + register char *file; +{ + register char *s1, *s2, *s3; + extern char *homedir; + + if (*file != '~') { + (void) strcpy(ebuf, file); + return(ebuf); + } + if (*++file == CNULL) { + s2 = homedir; + s3 = NULL; + } else if (*file == '/') { + s2 = homedir; + s3 = file; + } else { + s3 = file; + while (*s3 && *s3 != '/') + s3++; + if (*s3 == '/') + *s3 = CNULL; + else + s3 = NULL; + if (pw == NULL || strcmp(pw->pw_name, file) != 0) { + if ((pw = getpwnam(file)) == NULL) { + error("%s: unknown user name", file); + if (s3 != NULL) + *s3 = '/'; + return(NULL); + } + } + if (s3 != NULL) + *s3 = '/'; + s2 = pw->pw_dir; + } + for (s1 = ebuf; *s1++ = *s2++; ) + ; + s2 = --s1; + if (s3 != NULL) { + s2++; + while (*s1++ = *s3++) + ; + } + return(s2); +} + +#if defined(DIRECT_RCMD) +/* + * Set our effective user id to the user running us. + * This should be the uid we do most of our work as. + */ +extern int becomeuser() +{ + int r = 0; + +#if defined(HAVE_SAVED_IDS) + r = seteuid(userid); +#else + r = setreuid(0, userid); +#endif /* HAVE_SAVED_IDS */ + + if (r < 0) + error("becomeuser %d failed: %s (ruid = %d euid = %d)", + userid, SYSERR, getuid(), geteuid()); + + return(r); +} +#endif /* DIRECT_RCMD */ + +#if defined(DIRECT_RCMD) +/* + * Set our effective user id to "root" (uid = 0) + */ +extern int becomeroot() +{ + int r = 0; + +#if defined(HAVE_SAVED_IDS) + r = seteuid(0); +#else + r = setreuid(userid, 0); +#endif /* HAVE_SAVED_IDS */ + + if (r < 0) + error("becomeroot failed: %s (ruid = %d euid = %d)", + SYSERR, getuid(), geteuid()); + + return(r); +} +#endif /* DIRECT_RCMD */ + +/* + * Set access and modify times of a given file + */ +extern int setfiletime(file, atime, mtime) + char *file; + time_t atime; + time_t mtime; +{ +#if SETFTIME_TYPE == SETFTIME_UTIMES + struct timeval tv[2]; + + if (atime != 0 && mtime != 0) { + tv[0].tv_sec = atime; + tv[1].tv_sec = mtime; + tv[0].tv_usec = tv[1].tv_usec = (time_t) 0; + return(utimes(file, tv)); + } else /* Set to current time */ + return(utimes(file, (struct timeval *) NULL)); + +#endif /* SETFTIME_UTIMES */ + +#if SETFTIME_TYPE == SETFTIME_UTIME + struct utimbuf utbuf; + + if (atime != 0 && mtime != 0) { + utbuf.actime = atime; + utbuf.modtime = mtime; + return(utime(file, &utbuf)); + } else /* Set to current time */ + return(utime(file, (struct utimbuf *)NULL)); +#endif /* SETFTIME_UTIME */ + +#if !defined(SETFTIME_TYPE) + There is no "SETFTIME_TYPE" defined! +#endif /* SETFTIME_TYPE */ +} + +/* + * Get version info + */ +extern char *getversion() +{ + static char buff[BUFSIZ]; + + (void) sprintf(buff, + "Version %s.%d (%s) - Protocol Version %d, Release %s, Patch level %d", + DISTVERSION, PATCHLEVEL, DISTSTATUS, + VERSION, DISTVERSION, PATCHLEVEL); + + return(buff); +} + +/* + * Execute a shell command to handle special cases. + * This is now common to both server and client + */ +void runcommand(cmd) + char *cmd; +{ + int fd[2], pid, i; + int status; + register char *cp, *s; + char sbuf[BUFSIZ], buf[BUFSIZ]; + + if (pipe(fd) < 0) { + error("pipe of %s failed: %s", cmd, SYSERR); + return; + } + + if ((pid = fork()) == 0) { + /* + * Return everything the shell commands print. + */ + (void) close(0); + (void) close(1); + (void) close(2); + (void) open(_PATH_DEVNULL, O_RDONLY); + (void) dup(fd[PIPE_WRITE]); + (void) dup(fd[PIPE_WRITE]); + (void) close(fd[PIPE_READ]); + (void) close(fd[PIPE_WRITE]); + (void) execl(_PATH_BSHELL, "sh", "-c", cmd, 0); + _exit(127); + } + (void) close(fd[PIPE_WRITE]); + s = sbuf; + *s++ = C_LOGMSG; + while ((i = read(fd[PIPE_READ], buf, sizeof(buf))) > 0) { + cp = buf; + do { + *s++ = *cp++; + if (cp[-1] != '\n') { + if (s < (char *) &sbuf[sizeof(sbuf)-1]) + continue; + *s++ = '\n'; + } + /* + * Throw away blank lines. + */ + if (s == &sbuf[2]) { + s--; + continue; + } + if (isserver) + (void) xwrite(rem_w, sbuf, s - sbuf); + else { + *s = CNULL; + message(MT_INFO, "%s", sbuf+1); + } + s = &sbuf[1]; + } while (--i); + } + if (s > (char *) &sbuf[1]) { + *s++ = '\n'; + if (isserver) + (void) xwrite(rem_w, sbuf, s - sbuf); + else { + *s = CNULL; + message(MT_INFO, "%s", sbuf+1); + } + } + while ((i = wait(&status)) != pid && i != -1) + ; + if (i == -1) + status = -1; + (void) close(fd[PIPE_READ]); + if (status) + error("shell returned %d", status); + else if (isserver) + ack(); +} + +/* + * Malloc with error checking + */ +char *xmalloc(amt) + int amt; +{ + char *ptr; + extern POINTER *malloc(); + + if ((ptr = (char *)malloc(amt)) == NULL) + fatalerr("Cannot malloc %d bytes of memory.", amt); + + return(ptr); +} + +/* + * realloc with error checking + */ +char *xrealloc(baseptr, amt) + char *baseptr; + unsigned int amt; +{ + char *new; + extern POINTER *realloc(); + + if ((new = (char *)realloc(baseptr, amt)) == NULL) + fatalerr("Cannot realloc %d bytes of memory.", amt); + + return(new); +} + +/* + * calloc with error checking + */ +char *xcalloc(num, esize) + unsigned num; + unsigned esize; +{ + char *ptr; + extern POINTER *calloc(); + + if ((ptr = (char *)calloc(num, esize)) == NULL) + fatalerr("Cannot calloc %d * %d = %d bytes of memory.", + num, esize, num * esize); + + return(ptr); +} + +/* + * Private version of basename() + */ +extern char *xbasename(path) + char *path; +{ + register char *cp; + + if (cp = strrchr(path, '/')) + return(cp+1); + else + return(path); +} + +/* + * Take a colon (':') seperated path to a file and + * search until a component of that path is found and + * return the found file name. + */ +extern char *searchpath(path) + char *path; +{ + register char *cp; + register char *file; + struct stat statbuf; + + for (; ;) { + if (!path) + return((char *) NULL); + file = path; + cp = strchr(path, ':'); + if (cp) { + path = cp + 1; + *cp = CNULL; + } else + path = NULL; + if (stat(file, &statbuf) == 0) + return(file); + /* Put back what we zapped */ + if (path) + *cp = ':'; + } +} + +/* + * Set line buffering. + */ +extern int +mysetlinebuf(fp) + FILE *fp; +{ +#if SETBUF_TYPE == SETBUF_SETLINEBUF + return(setlinebuf(fp)); +#endif /* SETBUF_SETLINEBUF */ +#if SETBUF_TYPE == SETBUF_SETVBUF + return(setvbuf(stdout, NULL, _IOLBF, BUFSIZ)); +#endif /* SETBUF_SETVBUF */ +#if !defined(SETBUF_TYPE) + No SETBUF_TYPE is defined! +#endif /* SETBUF_TYPE */ +} + +/* + * Our interface to system call to get a socket pair. + */ +int +getsocketpair(domain, type, protocol, sv) + int domain; + int type; + int protocol; + int sv[]; +{ +#if SOCKPAIR_TYPE == SOCKPAIR_SOCKETPAIR + return(socketpair(domain, type, protocol, sv)); +#endif /* SOCKPAIR_SOCKETPAIR */ +#if SOCKPAIR_TYPE == SOCKPAIR_SPIPE + return(spipe(sv)); +#endif /* SOCKPAIR_SPIPE */ +#if !defined(SOCKPAIR_TYPE) + No SOCKPAIR_TYPE is defined! +#endif /* SOCKPAIR_TYPE */ +} |